I have this script where as to when i hit a trigger my enemy spawns at a random time then the enemy destroy itself at a random time. I want to respawn the enemy again so it can do this over and over again. Any Suggestions:
public class SpawnManager : MonoBehaviour {
public GameObject Enemy; // the enemy prefab
public float mytimer; // the time to wait before spawn
public float transport;// the time it has to destroy itself
private GameObject _spawndEnemy; // the enemy that was spawnd
void SpawnEnemy()
{
var enemySpawnPoint = GameObject.Find("FFEnemySpawn1").transform;
_spawndEnemy = Instantiate(
Enemy, enemySpawnPoint.position, enemySpawnPoint.rotation) as GameObject;
transport = Random.Range (2,15);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "FFTrigger") {
mytimer = Random.Range(0,15);
Invoke("SpawnEnemy", mytimer);
Debug.Log("Spawn Normal");
}
}
void Update()
{
Destroy (_spawndEnemy, transport);
}
}
Hi Ghostdre this question would probably be better answered here Game Dev SO, as for your question I would recommend creating an Enemy class object and data members for the GameObject as well as a time variable which determines how long the Enemy should live before being Destroyed.
e.g.
public class SpawnManager
{
public float lifeTime;
...
void Update()
{
lifeTime -= Time.deltaTime
if (lifeTime <= 0)
{
Destroy (_spawndEnemy, transport);
SpawnEnemy()
}
}
}
Please note that this is an incomplete example, but it should give you an idea of where to go from here.
Related
I'm developing a simple VR shooter in unity, i use object pooling for the bullets (Lasers here)
this is the ObjectPool script, here i istantiate a list of bullets in the start() method and disable them.
public class ObjectPool : MonoBehaviour
{
public static ObjectPool instance;
private List<GameObject> pooledObject = new List<GameObject>();
private int amountToPool = 20;
[SerializeField] private GameObject laserPrefab;
private void Awake()
{
if (instance == null)
{
instance = this;
}
}
// Start is called before the first frame update
void Start()
{
for (int i = 0; i < amountToPool; i++)
{
GameObject obj = Instantiate(laserPrefab);
obj.SetActive(false);
pooledObject.Add(obj);
}
}
public GameObject GetPooledObject()
{
for (int i = 0; i < pooledObject.Count; i++)
{
if (!pooledObject[i].activeInHierarchy)
{
return pooledObject[i];
}
}
return null;
}
}
This is the Script attached to the gun where i get the pooled bullet and set it to active
public class FireLaserGun : MonoBehaviour
{
public GameObject laserBeamModel;
public Transform laserSpawnPoint;
// Start is called before the first frame update
public void FireGun()
{
GameObject laser = ObjectPool.instance.GetPooledObject();
if (laser != null)
{
laser.transform.position = laserSpawnPoint.position;
laser.transform.rotation = laserSpawnPoint.rotation;
laser.SetActive(true);
Debug.Log("BOOM");
}
else
{
Debug.Log("Laser is null");
}
}
}
I'm trying to disable the bullet after two seconds was fired using a coroutine in the script that moves the bullets:
public class LaserBeamMove : MonoBehaviour
{
private Rigidbody rb;
public float thrust = 10.0f;
float waitTime = 2.0f;
private IEnumerator coroutine;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
coroutine = WaitToDisable(waitTime);
StartCoroutine(coroutine);
}
void FixedUpdate()
{
rb.velocity = transform.forward * thrust;
}
private IEnumerator WaitToDisable(float waitTime)
{
yield return new WaitForSeconds(waitTime);
gameObject.SetActive(false);
Debug.Log("bullet disabled after " + waitTime + "seconds");
}
}
Strangely first seconds of the game everything seems fine, all the bullets start as inactive and every bullet becomes active when fired and inactive after two seconds.
After some seconds bullets dont become inactive anymore (actually only some of them do).
this is a screenshot of the console log, when i fire i print "BOOM" and when a bullet becomes inactive i print "bullet disabled after 2 seconds"
As you can see this down't work for every bullet and i don't understand why.
Am i doing something wrong with the courutine?
https://i.stack.imgur.com/rMJgg.png
Take the code you have in void Start() and move it to a new void OnEnable. The reason is that Start is only called once, the first time the object holding the script is enabled (e.g when the scene loads, when you instantiate a bullet etc), OnEnable is called every time the object is enabled, which is what you want here. You could also use Awake but IMHO that's best kept separately for initialisation stuff only so you can keep the code tidy and separate out game logic from init logic.
Okay, so I create an endless runner game that has character selection. The goal is, when the scene starts (with no player in the hierarchy), the game manager will instantiate the player based on the selected player. But, the CameraController, have the error "Object reference not set to an instance of an object", it cannot find the instantiate player object
Here is how I instantiate my player:
void Start()
{
int selectedCharacter = PlayerPrefs.GetInt("selectedChar");
GameObject prefab = characterPrefabs[selectedCharacter];
GameObject clone = Instantiate(prefab, playerStartPoint, Quaternion.identity);
player = FindObjectOfType<PlayerScript>();
platformStartPoint = platformGenerator.position;
scoreManager = FindObjectOfType<ScoreManager>();
Reset();
}
And this is my camera script:
public class CameraController : MonoBehaviour{
public PlayerScript player;
private Vector3 lastPlayerPosition;
private float distToMove;
// Start is called before the first frame update
void Start()
{
player = FindObjectOfType<PlayerScript>();
lastPlayerPosition = player.transform.position;
}
// Update is called once per frame
void Update()
{
distToMove = player.transform.position.x - lastPlayerPosition.x;
transform.position = new Vector3(transform.position.x + distToMove, transform.position.y, transform.position.z);
lastPlayerPosition = player.transform.position;
}
}
The camera should be move along with the character, do you have any idea how to fix this? Thank you
I'm assuming your Camera tries to search for the player before they get instantiated based on what you mentioned. There are several different approaches to fixing this.
Method 1
Have the script that instantiates the player grab the camera and assign the player instance.
Example
// Call this after instantiating a player instance
FindObjectOfType<CameraController>().AssignTarget(player);
// Add this to CameraController.cs
public void AssignTarget(PlayerScript player)
{
this.player = player;
lastPlayerPosition = player.transform.position;
}
Method 2
Add an event field somewhere that informs when player has been instantiated and subscribe to it using your camera.
Example
using System;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
public static event Action<PlayerScript> InstanceStarted;
private void Start()
{
InstanceStarted?.Invoke(this);
}
}
using UnityEngine;
public class CameraController : MonoBehaviour
{
private Player player;
private void Start()
{
player = FindObjectOfType<PlayerScript>();
if (player == null)
PlayerScript.InstanceStarted += OnPlayerInstanceStarted;
}
private void OnPlayerInstanceStarted(PlayerScript instance)
{
PlayerScript.InstanceStarted -= OnPlayerInstanceStarted;
player = instance;
}
}
Method 3
Add DefaultExecutionOrder attribute to your scripts and change the execution order to ensure that the player gets instantiated before the Camera starts to look for one.
Example
[DefaultExecutionOrder(100)]
public class TestScript : MonoBehaviour {}
Method 4
Have a Coroutine that periodically checks whether an instance of a player is available before allowing the Camera to do anything.
Example
using System.Collections;
using UnityEngine;
public class CameraController : MonoBehaviour
{
private PlayerScript player;
private void Start()
{
StartCoroutine(StartOncePlayerIsFound());
}
private IEnumerator StartOncePlayerIsFound()
{
player = FindObjectOfType<PlayerScript>();
while (player == null)
{
// Feel free to yield "WaitForEndOfFrame" or "null"
// if you wish to search for player every frame
yield return new WaitForSeconds(0.1f);
player = FindObjectOfType<PlayerScript>();
}
// ...
}
}
Try this one
transform.position = new Vector3(player.transform.position.x, transform.position.y, transform.position.z);
I have 2 script, playerMachanics and enemyBehavior. My enemyBehavior has a boolean that when the boolean is true it moves away from the player. Instead i'm getting the error: "object reference not set to an instance of an object".
I'm sure it means the script can't find the component but i can't quite figure out what's wrong.
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
// Start is called before the first frame update
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade == true)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = GetComponent<enemyBehavior>();
script.evade = script.evade == true;
}
}
}
I expected that the movementSpeed would go to -4 but now i'm just getting an error.
Calling getComponent by itself will look for the component attached to the parent object of the script, which is the player in this case I think. So it will always return null.
Add
Public GameObject enemy;
to the playerMechanics class and then go into the designer and drag the game object that has the enemyBehavior script attached into it. There are several problems with the onCollisionEnter method. Something like this
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = enemy.GetComponent<enemyBehavior>();
script.evade = false;
}
}
should get you going in the right direction.
Is the enemy behavior on the player object? See here
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
and here
enemyBehavior script = GetComponent<enemyBehavior>();
You need to implement a way to track which enemy instance you are grabbing. Do this by making a variable to hold the enemy script, or by using a singleton on the enemy script (if there is one enemy).
Variable:
public enemyBehaviour enemy;
Singleton:
(enemyBehaviour)
public static enemyBehaviour instance = null;
private static readonly object padLock = new object();
void Awake(){
lock(padLock){
if(instance == null)
instance = this;
}
}
(player)
enemyBehaviour.instance.evade = false;
Look up singletons if you want to learn more.
If I'm right, I think your game mechanics works like this: The player's objective is to collect coins. When they collect one, the enemy near it will come and evade the player.
If that's the case, you should use this:
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
[SerializeField] enemyBehvaior enemy;
void OnCollisionEnter(Collision collision)
{
if (collision.collider.name == "coin")
{
Destroy(collision.collider.gameObject);
enemy.evade = true;
}
}
}
In your code, you wrote 'collision.gameObject.' This refers to the object the script is attached to. If you want to reference to the object that we hit, use 'collision.collider'.
'[SerializeField]' is a unity attribute, which is used to make a field show up in the inspector without making it public.
Just a heads up, if you're using 2D, make sure the method is signatured 'OnCollisionEnter2D(Collision2D collision)'.
I hope I answered your question. :)
Im running into a little problem. As soon as I hit a trigger I want an enemy to spawn. I only want one enemy on the field. Now when I hit the trigger again I want that enemy that is on the field to destroy it self while the next enemy is about to spawn. Any ideas on how to do so? Do I use a "Destroy" Assignment on this? Heres what I have:
public GameObject Enemy;
public float mytimer;
void Start()
{
GameObject player = GameObject.Find("Player");
}
void spawnEnemy() {
Transform enemy;
GameObject enemySpawnPoint = GameObject.Find("EnemySpawn");
enemy = Instantiate(Enemy,enemySpawnPoint.transform.position,enemySpawnPo int.transform.rotation) as Transform;
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "EnemyTrigger") {
mytimer = Random.Range(0,10);
Invoke("spawnEnemy", mytimer);
Debug.Log("Spawn Normal");
}
}
}
You can store your enemy into a private variable and destroy it every time before instantiating a new one. This way you will have only one of them.
private GameObject enemy = null;
void spawnEnemy() {
if(enemy != null){
Destroy(enemy);
}
GameObject enemySpawnPoint = GameObject.Find("EnemySpawn");
enemy = Instantiate(Enemy,enemySpawnPoint.transform.position,enemySpawnPo int.transform.rotation) as GameObject;
}
Not sure why, I've done this sort of this a bunch of times, but this is giving me some issues. Making a project for Game AI, I have a whole bunch of stuff already done, now just making some turrets that if the player is in a certain range it will fire, which I have already. The turret fires the bullet and then for some reason they just start destroying themselves and they don't go towards my player. Wondering if anyone on here can help, thanks in advance!
Some details you may need to know:
I have a Base, a Gun nose and a Gun for my turret. My Gun has a GunLook.cs script that makes it look at the player (so when they shoot it should go towards them), I'm not sure if that has anything to do with why I'm having these issues, but I'll post that code as well just incase
How my Hierchy for my turret is
Turret_AI (Base)
Gun (child of Turret_AI)
bulletSpawn (child of Gun)
Gun_Nose (child of turret_AI)
bulletSpawn is an empty GameObject I created in hopes to solve my problem. I set it just off the Gun so that it wouldn't just collide with gun and destroy itself (what I thought it might be doing, but not correct).
That should be all the info needed, if anyone needs more I will be checking this every 2 seconds so let me know and I will get back to you with quick response.
TurretScript.cs
(I did set the GameObject to Player in Unity, before anyone asks)
using UnityEngine;
using System.Collections;
public class TurretScript : MonoBehaviour {
[SerializeField]
public GameObject Bullet;
public float distance = 3.0f;
public float secondsBetweenShots = 0.75f;
public GameObject followThis;
private Transform target;
private float timeStamp = 0.0f;
void Start () {
target = followThis.transform;
}
void Fire() {
Instantiate(Bullet, transform.position , transform.rotation);
Debug.Log ("FIRE");
}
void Update () {
if (Time.time >= timeStamp && (target.position - target.position).magnitude < distance) {
Fire();
timeStamp = Time.time + secondsBetweenShots;
}
}
}
GunLook.cs
// C#
using System;
using UnityEngine;
public class GunLook : MonoBehaviour
{
public Transform target;
void Update()
{
if(target != null)
{
transform.LookAt(target);
}
}
}
BulletBehavior.cs
using UnityEngine;
using System.Collections;
public class BulletBehavior : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (rigidbody.velocity.magnitude <= 0.5)
Destroy (gameObject);
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider)
{
if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyProjectile")
{
Physics.IgnoreCollision(rigidbody.collider,collision.collider);
//Debug.Log ("Enemy");
}
if(collision.gameObject.tag == "SolidObject")
{
Destroy(gameObject);
}
if(collision.gameObject.tag == "Player")
{
Destroy(gameObject);
}
}
}
}
You're never moving your bullet.
public class BulletBehavior : MonoBehaviour
{
private const float DefaultSpeed = 1.0f;
private float startTime;
public Vector3 destination;
public Vector3 origin;
public float? speed;
public void Start()
{
speed = speed ?? DefaultSpeed;
startTime = Time.time;
}
public void Update()
{
float fracJourney = (Time.time - startTime) * speed.GetValueOrDefault();
this.transform.position = Vector3.Lerp (origin, destination, fracJourney);
}
}
Then call it like so:
void Fire()
{
GameObject bullet = (GameObject)Instantiate(Bullet, transform.position , transform.rotation);
BulletBehavior behavior = bullet.GetComponent<BulletBehavior>();
behavior.origin = this.transform.position;
behavior.destination = target.transform.position;
Debug.Log ("FIRE");
}
Note: If you're trying to mix this approach with trying to use physics to move the bullet you may end up with strange results.