- Home /
Problem Spawning Enemys with Health.
I am trying to create a side scrolling game sort of like Gradius and I am spawning in enemies at random positions at the edge of the screen so it looks like they fly in. Right now I only have one enemy spawning in but I am copying the same enemy in with its prefab from the hierarchy and spawning it in with a gameController object and script. The problem I am having is when I shoot the enemies they seem to be inheriting the Scripts and properties of the GameObject prefab that was spawned just before causing the player to have to shoot the one in front or wait for it to be destroyed before attacking the enemies in the back. If the player shoots the ships in the back first, it causes the ship in the front to blow up, basically in order (also giving me a 'Could not find GameObject' error). I will supply code if needed, I am hoping it is a simple fix, I haven't been able to find any solid solution online and I have been searching for days. I would greatly appreciate any help I can get.
In order to adequately diagnose your problem, we'll need some script examples. I could venture a guess regarding what's happening (well, numerous guesses, but that's really the problem here), but we could provide much clearer answers with some more information, such as:
• How are you storing and instantiating your enemies?
• How are you dealing damage to them? For example, are you using trigger/collision through the physics system?
Basically, any script examples you can provide that directly correlate to how you're generating them and how you're accessing them to modify their variables would let us assess the situation you're running into.
For some reason I can't post the code. It isn't letting me. I click "Submit" but it does nothing.
You copy the same enemy with its prefab from the hierarchy? A prefab is stored in the assets folder. That's where you should get it from. And when you access their health to deal damage, make sure you reference the object in the scene, not the prefab.
I have it saved in the Assets folder. Sorry I said it wrong. i will post my code tomorrow, I'm not home At the moment and do know that it would help.
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class EnemyShip : $$anonymous$$onoBehaviour {
private Rigidbody rb;
public GameController gameController;
public GameObject enemyShot;
public GameObject explostion;
public Transform EnemyShotSpawn;
public float enemyFireRate$$anonymous$$in;
public float enemyFireRate$$anonymous$$ax;
public float delay;
public float health;
public int scoreValue;
public float dodge;
public float smoothing;
public float tilt;
public Boundary boundary;
public Vector3 startWait;
public Vector3 maneuverTime;
public Vector3 maneuverWait;
private float target$$anonymous$$aneuver;
private float currentSpeed;
private AudioSource audiosource;
void Start()
{
rb = GetComponent<Rigidbody> ();
audiosource = GetComponent<AudioSource> ();
GameObject gamecontrollerObject = GameObject.FindWithTag ("GameController");
if (gamecontrollerObject != null)
{
gameController = gamecontrollerObject.GetComponent<GameController> ();
}
if (gameController == null)
{
Debug.Log ("Cannont find 'GameController' script");
}
StartCoroutine (Evade ());
}
IEnumerator Evade()
{
yield return new WaitForSeconds (Random.Range (startWait.z, startWait.y));
while (true)
{
target$$anonymous$$aneuver = Random.Range (1, dodge) * -$$anonymous$$athf.Sign (transform.position.y);
yield return new WaitForSeconds (Random.Range(maneuverTime.z, maneuverTime.y));
target$$anonymous$$aneuver = 0;
yield return new WaitForSeconds (Random.Range(maneuverWait.z, maneuverWait.y));
}
}
void Update()
{
}
void FixedUpdate ()
{
float new$$anonymous$$aneuver = $$anonymous$$athf.$$anonymous$$oveTowards (rb.velocity.y, target$$anonymous$$aneuver, Time.deltaTime * smoothing);
rb.velocity = new Vector3 (0.0f, new$$anonymous$$aneuver, -5);
rb.position = new Vector3 (
0.0f,
$$anonymous$$athf.Clamp (rb.position.y, boundary.y$$anonymous$$in, boundary.y$$anonymous$$ax),
$$anonymous$$athf.Clamp (rb.position.z, boundary.z$$anonymous$$in, boundary.z$$anonymous$$ax)
);
rb.rotation = Quaternion.Euler (0.0f, 0.0f, rb.velocity.y * tilt);
if (Time.time > delay)
{
delay = Time.time + Random.Range (enemyFireRate$$anonymous$$in, enemyFireRate$$anonymous$$ax);
Instantiate (enemyShot, EnemyShotSpawn.position, EnemyShotSpawn.rotation);
audiosource.Play ();
}
}
public void EnemyTakeDamage(float amount)
{
health = health - amount;
Debug.Log (health);
if (health <= 0)
{
gameController.AddScore (scoreValue);
//Play an explosion
Instantiate (explostion, transform.position, transform.rotation);
Destroy (gameObject);
}
}
}
using UnityEngine; using UnityEngine.UI; using System.Collections;
public class GameController : $$anonymous$$onoBehaviour { //Veriables public GameObject gameOverPanel; public GameObject continueButton; public GameObject pauseButton; public GameObject exitButton; public GameObject Enemy; public Vector3 spawnValues; public int hazardCount; public float spawnWait; public float startWait; public float waveWait; public Text scoreText;
private int score;
private bool paused;
private bool restart;
private bool gameOver;
Coroutine co;
void Start ()
{
score = 0;
UpdateScore ();
gameOver = false;
paused = false;
gameOverPanel.SetActive (false);
//GameObject enemyObject = GameObject.FindWithTag ("Enemy");
//Screen.orientation = ScreenOrientation.Landscape;
co = StartCoroutine(SpawnWaves());
}
void Update()
{
if (gameOver)
{
GameOver ();
}
}
public void Pause()
{
paused = true;
if (paused)
{
Time.timeScale = 0;
}
}
public void Resume()
{
paused = false;
Time.timeScale = 1;
}
public void GameOver()
{
gameOverPanel.SetActive (true);
pauseButton.SetActive (false);
continueButton.SetActive (true);
exitButton.SetActive (true);
Pause ();
//This stops the spawning enimies
//StopCoroutine(co);
}
IEnumerator SpawnWaves ()
{
//Wait the amount of seconds indicated by startWait in the Editor
yield return new WaitForSeconds (startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
Vector3 spawnPosition = new Vector3 (spawnValues.x, Random.Range(-spawnValues.y, spawnValues.y), spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (Enemy, spawnPosition, spawnRotation);
yield return new WaitForSeconds (spawnWait);
}
yield return new WaitForSeconds (waveWait);
}
}
public void AddScore(int newScoreValue)
{
score += newScoreValue;
UpdateScore ();
}
void UpdateScore()
{
Debug.Log (score);
scoreText.text = score.ToString ();
}
}
I know those didn't come out that good, for some reason I am having issues posting my code in here. I am sorry for that.
Where do you call the EnemyTakeDamage() function from? Which "enemy" is the target of it when you call it?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerShot : $$anonymous$$onoBehaviour {
private EnemyShip Enemy;
private Rigidbody rb;
public float speed;
public int damageAmount;
// Use this for initialization
void Start ()
{
GameObject enemyObject = GameObject.FindWithTag ("Enemy");
//GameObject enemyBoltObject = GameObject.FindWithTag ("EnemyBolt");
if (enemyObject != null)
{
Enemy = enemyObject.GetComponent<EnemyShip> ();
}
rb = GetComponent<Rigidbody> ();
rb.velocity = transform.forward * speed;
}
void OnTriggerEnter(Collider other)
{
//If any other tag enters the "Boundary" then it will be returned and destroyed
if (other.CompareTag ("Boundary") || other.CompareTag ("EnemyBolt") )
{
return;
}
//If the tag is the "Player" tag Instantiate the player explosion and go to the "GameOver()" funtion
if(other.CompareTag ("Enemy") )
{
Enemy.EnemyTakeDamage (damageAmount);
Destroy (gameObject);
}
}
}
Answer by Eno-Khaon · May 05, 2018 at 11:01 PM
The problem lies in your PlayerShot script where it acquires its target information.
In the shot's Start() function, it finds an enemy using
GameObject enemyObject = GameObject.FindWithTag ("Enemy");
... and gets the enemy's script using
Enemy = enemyObject.GetComponent<EnemyShip> ();
This results in a few specific problems:
• Your target is already acquired before your shot hits a target. This is when the wrong target takes damage
• The target is chosen (somewhat) arbitrarily. By simply looking for a GameObject with the right tag, you're simply being given the first-found result.
• If the enemy is gone after a shot is fired, you will have a null reference for the Enemy variable.
Fortunately, the solution to this problem is very simple.
You don't need to prepare your Shot's target when you first create it. With that in mind, you will likely have no need for your
private EnemyShip Enemy;
variable.
Instead, you can get target information when the projectile hits something:
void OnTriggerEnter(Collider other)
{
if(other.CompareTag ("Enemy") )
{
EnemyShip enemy = other.GetComponent<EnemyShip>();
if(enemy != null)
{
enemy.EnemyTakeDamage(damageAmount);
}
}
else if(other.CompareTag("") || other.CompareTag(""))
{
// Currently unused
}
}
You have solve my issue! Thank you so much, I am glad it was an easy fix, wish I would have seen it and your explanation helped it make sense.
Glad to hear it, and thank you for bearing with me on my inquiries. I just wanted to be sure that I was addressing the issues in the right manner, since there are multiple ways of reaching the same state you had been in.
Answer by Koyemsi · May 05, 2018 at 03:35 PM
I think you should use a level manager, that is to say an empty GO with a script that holds all the generic info about your level (number of enemies, rate of spawning etc). The spawning of enemies would be managed by this script, and not within the enemy script. This way I think each enemy would behave independently from the others. Hope that helps.
I think I am already. I believe that is what my GameController Object in my scene is doing, or at least what I was trying to get it to do.
Your answer
Follow this Question
Related Questions
Show only selected enemy's health bar 1 Answer
If Enemy Health (< 10) then Exp (+10)? 1 Answer
Hurt Player if close to Enemy! Need Help 4 Answers
Enemy healthbar script 2 Answers