2D Platformer WaveSpawner Issue

Updated on March 13, 2018 in [A] 2D
Share on Facebook0Tweet about this on TwitterShare on Google+0Share on Reddit0
1 on March 13, 2018

Hello! I was running through Brackey’s 2D Platformer tutorial, and for some reason, the third wave of the wave spawner spawns the enemies, but they don’t follow the player in certain circumstances. Only the third/last wave. Here’s the thing:

If the player never moves, they do follow the player, but if the player walks or jumps to another platform, the enemies just stand still.

My initial thoughts were that the enemies weren’t finding the player as a target, but that’s not true. The prefab finds it with ease, and when enabling gizmos, I can even see that the enemies are properly drawing a path to the player. They work perfectly fine for the first two waves.

I’ll post my wave spawner code below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WaveSpawner : MonoBehaviour {

public enum SpawnState { SPAWNING, WAITING, COUNTING };

[System.Serializable] // allows for changing instances of class
public class Wave {
public string name;
public Transform enemy;
public int count;
public float rate;
}

public Wave[] waves;
private int nextWave = 0;
public int NextWave {
get { return nextWave + 1; }
}

public Transform[] spawnPoints;

public float timeBetweenWaves = 5f;
private float waveCountdown;
public float WaveCountdown {
get { return waveCountdown; }
}

private float searchCountdown = 1f;

private SpawnState state = SpawnState.COUNTING;
public SpawnState State {
get { return state; }
}

void Start () {
if (spawnPoints.Length == 0) {
Debug.LogError (“No spawn points referenced.”);
}

waveCountdown = timeBetweenWaves;
}

void Update () {
if (state == SpawnState.WAITING) {
if (!EnemyIsAlive ()) {
WaveCompleted ();
return;
} else {
return;
}
}

if (waveCountdown <= 0) { // time to start waves
if (state != SpawnState.SPAWNING) {
StartCoroutine (SpawnWave (waves [nextWave]));
}
} else {
waveCountdown -= Time.deltaTime;
}
}

void WaveCompleted () {
Debug.Log (“Wave Completed!”);

state = SpawnState.COUNTING;
waveCountdown = timeBetweenWaves;

if (nextWave + 1 > waves.Length – 1) {
nextWave = 0;
Debug.Log (“ALL WAVES COMPLETE! Looping…”);
} else {
nextWave++;
}
}

bool EnemyIsAlive () {
searchCountdown -= Time.deltaTime;
if (searchCountdown <= 0f) {
searchCountdown = 1f;
if (GameObject.FindGameObjectWithTag (“Enemy”) == null) {
return false;
}
}

return true;
}

IEnumerator SpawnWave (Wave _wave) { // want to wait certain amount of seconds before continuing
Debug.Log (“Spawning Wave: ” + _wave.name);
state = SpawnState.SPAWNING;

for (int i = 0; i < _wave.count; i++) {
SpawnEnemy (_wave.enemy);
yield return new WaitForSeconds (1f / _wave.rate);
}

state = SpawnState.WAITING;

yield break;
}

void SpawnEnemy (Transform _enemy) {
Debug.Log (“Spawning Enemy: ” + _enemy.name);
Transform _sp = spawnPoints[Random.Range (0, spawnPoints.Length)];
Instantiate (_enemy, _sp.position, _sp.rotation);
}

}

I’d really appreciate the help! Thank you so much.

  • Liked by
Reply
0 on March 13, 2018

Update: Here’s my enemy code:

using System.Collections;
using UnityEngine;

public class Enemy : MonoBehaviour {

[System.Serializable]
public class EnemyStats {
public int maxHealth = 100;

private int _curHealth;
public int curHealth {
get { return _curHealth; }
set { _curHealth = Mathf.Clamp (value, 0, maxHealth); }
}

public int damage = 40;

public void Init() {
curHealth = maxHealth;
}

}

public EnemyStats stats = new EnemyStats(); // creating instance of player stats class

public Transform deathParticles;

public float shakeAmt = 0.1f;
public float shakeLength = 0.1f;

public string deathSoundName = “Explosion”;

[Header (“Optional: “)]
[SerializeField]
private StatusIndicator statusIndicator;

void Start () {
stats.Init ();

if (statusIndicator != null) {
statusIndicator.SetHealth(stats.curHealth, stats.maxHealth);
}
if (deathParticles == null) {
Debug.LogError (“No death particles referenced on Enemy”);
}
}

public void DamageEnemy (int damage) {
stats.curHealth -= damage;
if (stats.curHealth <= 0) {
GameMaster.KillEnemy (this);
}
if (statusIndicator != null) {
statusIndicator.SetHealth(stats.curHealth, stats.maxHealth);
}
}

void OnCollisionEnter2D (Collision2D _colInfo) {
Player _player = _colInfo.collider.GetComponent<Player> ();
if (_player != null) {
_player.DamagePlayer (stats.damage);
DamageEnemy (9999999);
}
}
}

 

and my Enemy AI code:

using Pathfinding;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;

[RequireComponent (typeof (Rigidbody2D))]
[RequireComponent (typeof (Seeker))]
public class EnemyAI : MonoBehaviour {

// What to chase?
public Transform target;

// How many times per second we update our path
public float updateRate = 2f;

// Caching
private Seeker seeker;
private Rigidbody2D rb;

// The calculated path
public Path path;

// The AI’s speed per second
public float speed = 300f;
public ForceMode2D fMode; // a way to change between force and impulse, how forces are applied to rigidbody

[HideInInspector]
public bool pathHasEnded = false;

// The max distance from the AI to a waypoint for it to continue to the next waypoint
public float nextWaypointDistance = 3f;

// The waypoint we are currently moving toward
private int currentWaypoint = 0;

private bool searchingForPlayer = false;

void Start () {
seeker = GetComponent<Seeker> ();
rb = GetComponent<Rigidbody2D> ();

if (target == null) {

if (!searchingForPlayer) {
searchingForPlayer = true;
StartCoroutine (SearchForPlayer ());
}

return;
}

// Start a new path to the target position, return the result to the OnPathCompleted method
seeker.StartPath (transform.position, target.position, OnPathComplete);

StartCoroutine (UpdatePath ());
}

IEnumerator SearchForPlayer () {
GameObject sResult = GameObject.FindGameObjectWithTag (“Player”);
if (sResult == null) {
yield return new WaitForSeconds (0.5f);
StartCoroutine (SearchForPlayer ());
} else {
target = sResult.transform;
searchingForPlayer = false;
StartCoroutine (UpdatePath ());
yield return false;
}
}

IEnumerator UpdatePath () {
if (target == null) {
if (!searchingForPlayer) {
searchingForPlayer = true;
StartCoroutine (SearchForPlayer ());
}
yield return false;
}

if (target != null) {
seeker.StartPath (transform.position, target.position, OnPathComplete);
}

yield return new WaitForSeconds (1f / updateRate);
StartCoroutine (UpdatePath ());

}

public void OnPathComplete (Path p) {
Debug.Log (“We got a path. Did it have an error? ” + p.error);
if (!p.error) {
path = p;
currentWaypoint = 0;
}
}

void FixedUpdate () {
if (target == null) {
// TODO: Insert a player search here.
return;
}

// TODO: Always look at player?

if (path == null) {
return;
}

if (currentWaypoint >= path.vectorPath.Count) {
if (pathHasEnded)
return;
Debug.Log (“End of path reached.”);
pathHasEnded = true;
return;
}

pathHasEnded = false;

// Direction to the next waypoint
Vector3 dir = (path.vectorPath[currentWaypoint] – transform.position).normalized;
dir *= speed * Time.fixedDeltaTime; // fixedDeltaTime in FixedUpdate

// Move the AI
rb.AddForce (dir, fMode);

float dist = Vector3.Distance (transform.position, path.vectorPath[currentWaypoint]);
if (dist < nextWaypointDistance) {
currentWaypoint++;
return;
}
}

}

  • Liked by
Reply
Cancel