Below is my code but I don't know why when the _lazerPrefab spawns it doesn't move, even though _lazerSpeed != 0. I dont't know where the problem is.
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(_lazerPrefab, transform.position, Quaternion.identity);
_lazerPrefab.transform.Translate(Vector3.up * _lazerSpeed * Time.deltaTime);
}
You cannot move the prefab itself, as prefabs are like "blueprints" that are used to construct real object instances, hence the name. You can indeed move those instances. Instantiate() will return the reference to the newly created copy/instance!
if (Input.GetKeyDown(KeyCode.Space))
{
GameObject new_lazer = Instantiate(_lazerPrefab, transform.position, Quaternion.identity);
new_lazer.transform.Translate(Vector3.up * _lazerSpeed * Time.deltaTime);
}
But this code will always spawn a new instance when you press Space. And once you spawned a 2nd, you will no longer move the first as the Translate call for the first instance is not done anymore.
So you need to adapt your logic. Either put a "move/accelerate forward" script on the lazers, or keep the references returned from Instantiate() in a list and maintain them and their lifetime. Another way could be adding a RigidBody and giving it a velocity so it keeps moving on it's own. Impact can be handled with a collider and the OnCollisionEnter or OnTriggerEnter (if the collider is marked as trigger) functions, where you can trigger sounds, damage etc.
You are only moving the _lazerprefab when Input.GetKeyDown(KeyCode.Space) is true.
If you want to move the gameObject more than once after you press space you would need to add the move code into the gameObjects Update() Method itself.
You would need to attach this script to the _lazerprefab GameObject.
Example Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveObstacles : MonoBehaviour {
[SerializeField]
private float _lazerSpeed = 10f;
private void FixedUpdate() {
gameObject.transform.Translate(Vector3.up * _lazerSpeed * Time.deltaTime);
}
}
We are now able to just call the Instantiate() Function and the instantiated GameObject will move automatically each frame.
Example Move Call:
if (Input.GetKeyDown(KeyCode.Space)) {
Instantiate(_lazerPrefab, transform.position, Quaternion.identity);
}
Related
I'm new, and I've got hard time to respawn my AI (right now he just a cube that follow my player) after he been destroy. I believe its because the script sits on the object that get destroyed. but what I need to do to respawn it?
(although I'm sure my respawn code is not good :\ (It's mobile-android project) )
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyTesting : MonoBehaviour
{
[SerializeField]
public GameObject player;
public GameObject enemy;
private Rigidbody body;
Vector3 accelerationDir;
// Use this for initialization
void Start()
{
body = GetComponent<Rigidbody>();
}
private void Update()
{
accelerationDir = Input.acceleration;
if (accelerationDir.sqrMagnitude>=5)
{
EnemyDead();
}
}
void EnemyDead()
{
Destroy(enemy);
Invoke("Respawn", 5);
}
void Respawn()
{
enemy = (GameObject)Instantiate(enemy);
enemy.transform.position = transform.position;
}
// Update is called once per frame
void FixedUpdate()
{
Vector3 toTarget = player.transform.position - transform.position;
float speed = 1.5f;
transform.Translate(toTarget * speed * Time.deltaTime);
}
}
Thanks very much!
I am supposing that your enemy GameObject is inside the scene holding your EnemyTesting MonoBehaviour instance (correct me if I'm wrong).
If this is the case, you cannot instantiate a gameObject that is destroyed.
As #derHugo pointed out, you should not use Destroy and Instantiate for your use case. It would be better to set inactive the enemy GameObject, move it to the position that you want, an (re)set it active. It will look like the enemy respawned.
If you want to dig the subject later, look at the object pooling game optimization pattern.
Otherwise, if you still want to use Instantiate for respawning, I would create a prefab of your enemy GameObject. The enemy GameObject referenced in the EnemyTesting field (in the Inspector view), would be your prefab from the project hierarchy instead of a GameObject inside the scene.
This way, you would be able to instantiate an enemy GameObject as many times as you want (and use it in other scenes!). Don't forget to hold a reference to the instantiated enemy GameObject so you can know which one you want to destroy. It would looke like this :
enemy = Instantiate(enemyPrefab, transform.position, transform.rotation);
You can replace transform with the transform of your choice, for example the transform of an empty enemyRespawnPoint GameObject in your Scene.
Do you see any error in the console ?
In my platform game I have just added some checkpoints, so that if the player dies doesn't necessarily spawn at the beginning of the track.
ghfdghdggfhfg
using UnityEngine;
public class CheckPoints : MonoBehaviour
{
[SerializeField] private Grounded game;
void Update()
{
transform.Rotate(0, 0, 5);
}
private void OnTriggerEnter() {
game.updatedCheckPointPosition = transform.position;
Destroy(this);
}
}
What I unsuccessfully tried to do is to set the public float variable of the Grounded script to the current position of the CheckPoint itself, which should be destroyed after doing that.
Any information or help on how to do this is really appreciated.
From Destroy
The object obj will be destroyed now or if a time is specified t seconds from now.
If obj is a Component it will remove the component from the GameObject and destroy it. [But keep the rest of the GameObject intact!]
If obj is a GameObject it will destroy the GameObject, all its components and all transform children of the GameObject.
this refers to the according component instance. What you want is rather
Destroy(gameObject);
OnTriggerEnter requires a parameter of type Collider in order to work
private void OnTriggerEnter(Collider other)
{
game.updatedCheckPointPosition = transform.position;
Destroy(this);
}
Note however that this way round the player has to be a trigger while the checkpoint a non-trigger! I would actually rather do it the other way round and make the chackpoint a trigger and rather let the player object check for OnTriggerEnter.
I want my objects to fall when the player got to that scene . My game have a long map and I want them not to fall when I start the game .There is any code for player detection in the view? for the objects to fall?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FallDown : MonoBehaviour
{
public float fallSpeed = 8.0f;
//Variables for starting position and length until reset
private Vector3 _startingPos;
public float FallDistance = 5f;
void Start()
{
transform.Translate(Vector3.down * fallSpeed * Time.deltaTime, Space.World);
// Save starting position
_startingPos = transform.position;
}
void Update()
{
transform.Translate(Vector3.down * fallSpeed * Time.deltaTime, Space.World);
// If the object has fallen longer than
// Starting height + FallDistance from its start position
if (transform.position.y > _startingPos.y + FallDistance)
{
transform.position = _startingPos;
}
}
}
While the answer above is correct, Colliders might not be what you want to implement in this case. Colliders are used to, well, detect collisions, while you want the objects to fall when the player is at a specific distance from them. For this, I'd suggest adding a reference to the player GameObject first:
private GameObject playerRef;
And in the Start function find the player:
playerRef = GameObject.Find("yourPlayerGameObjectNameHere");
Get the GameObjects that you want to fall either by finding them, like above, or by passing a public reference to them through the inspector. Afterwards, you can use Vector3.distance between each GameObject and the player, like so:
if( Vector3.Distance(player.transform.position, fallingObject.transform.position) < yourDistanceHere ){
// Make the object fall
}
Have you tried implementing this behavior using Colliders?
To do it so, all you've got to do is add both a Collider Component and a RigidBody to your player and to the falling objects.
Once you've added them and configured their parameters, you can check the collision by using the method OnColissionEnter. This method will be triggered every time that a collision is detected by the GameObject that is holding the script. In your case, the falling objects should hold it.
private void OnCollisionEnter(Collision other)
{
//MAKE THE OBJECTS FALL
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BoxCollider : MonoBehaviour {
private float degree = 180f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider c)
{
GameObject character = GameObject.Find(c.name);
character.transform.rotation = Quaternion.Slerp(character.transform.rotation, Quaternion.Euler(0, 0, degree), Time.deltaTime);
}
}
I have two ThirdPersonController characters.
When the event OnTriggerEnter is trigger i see in c.Name "ThirdPersonController"
I also added 4 empty gameobjects each one added a box collider set IsTrigger on and also attached each gameobject this script.
And i checked when the character get to the wall they stop moving but keep walking on place.
Now i want at this point that the current character( or both ) that triggered the event to rotate 180 degrees. But instead it's not making rotation the character/s keep walking out of the terrain in some degree changed on the z axis i think.
I guess i did something wrong with the Quaternion.Slerp line.
Use Collider.gameObject
As you have two gameobjects with the same name, your GameObject.Find(c.name) line will always be returning the same one, regardless of which Collider actually triggered the collision.
GameObject.Find is also very slow in comparison to directly using the gameObject property of Collider, so you'll want to avoid using Find as often as possible.
Here's a modified version:
void OnTriggerEnter(Collider c)
{
// Don't use GameObject.Find here - just use the gameObject ref on the given collider:
GameObject character = c.gameObject;
character.transform.rotation = Quaternion.Slerp(character.transform.rotation, Quaternion.Euler(0, 0, degree), Time.deltaTime);
}
Time.deltaTime is for Update only
It's just a fairly random, very small number otherwise.
I started making a simple game in Unity3d: a tank to shoot at a wall (see image).
A GameObject is attached to the turret of the tank, and to this GameObject is attached the following script :
using UnityEngine;
using System.Collections;
public class Shooter : MonoBehaviour {
public Rigidbody bullet;
public float power = 1500f;
void Update () {
if (Input.GetButtonDown ("Fire1")) {
Rigidbody bulletRB = Instantiate (bullet, transform.position, transform.rotation) as Rigidbody;
Vector3 fwd = transform.TransformDirection(Vector3.forward);
bulletRB.AddForce(fwd*power);
}
}
}
When I press on the Fire1 button the bullet does not shoot. I put (for test) a Debug.Log("BULLET SHOOT") after bulletRB.addForce(). The message is displayed, so the script reached this point. What is wrong with my code?
Based on this somewhat similar question on Unity Answers, you should probably be instantiating the GameObject of the bullet prefab/instance, rather than its Rigidbody directly. Then, access the Rigidbody component of that new bullet and add the force.
Your adjusted Update() method would then look like:
void Update () {
if (Input.GetButtonDown ("Fire1")) {
GameObject newBullet = Instantiate (bullet.gameObject, transform.position, transform.rotation) as GameObject;
RigidBody bulletRB = newBullet.GetComponent<Rigidbody>();
Vector3 fwd = transform.TransformDirection(Vector3.forward);
bulletRB.AddForce(fwd*power);
}
}
Another thing you may want to change is using transform.forward (aka. Forward vector of the turret) rather than Vector3.forward (global forward vector Vector3(0, 0, 1), which may not match the direction of the turret).
Hope this helps! Let me know if you have any questions.
Force can be applied only to an active rigidbody. If a GameObject is inactive, AddForce has no effect.
Wakes up the Rigidbody by default. If the force size is zero then the Rigidbody will not be woken up.
The above description is taken from Unity
Therefore, I would suggest to check if the GameObject is active first.
You can test it by doing the following:
if (newBullet.activeInHierarchy === true)
{
//active
}else{
//inactive
}