Hello.
My game involves two castles and enemy character spawns from one, and player spawns his characters from the other. The characters meet in the middle, they fight, winner goes to the castle to destroy it provided it does not meet another enemy on its way.
When the character reaches the other castle, it starts to damage the castle. And the other player can still spawn a new character. What I am trying to do is, stop character from damaging the castle while there is another enemy colliding with it.
I tried to add the contact to an array list, then check if an enemy character is in the array list, make the enemy stop damaging castle and start damaging the player again. I use coroutines to start damaging the castle and/or other character.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyChar : MonoBehaviour
{
private float charSpeed;
private float charHP;
private float charAttack;
private float attackSpeed;
private bool shouldStop = false; //Checks whether the char should move
private bool isPlayerDamageRunning = false; //Checks if Player damage coroutine runs
private bool isPlayerCastleRunning = false; //Checks if Castle damage coroutine runs
private ArrayList contacts = new ArrayList();
private bool playerHasContact;
void Start()
{
charSpeed = 5f;
charHP = 150f;
charAttack = 40f;
attackSpeed = 5f;
}
void Update()
{
if (!shouldStop) //Colliders are triggers, so I manually stop them from moving.
{
transform.Translate(Vector3.left * charSpeed * Time.deltaTime);
}
if (charHP <= 0)
{
Destroy(gameObject);
}
}
public void GetDamaged(float damage) //PlayerChar calls this to damage the enemy chars.
{
charHP -= damage;
}
private void OnTriggerEnter2D(Collider2D collision)
{
shouldStop = true;
contacts.Add(collision.gameObject);
if (!isPlayerDamageRunning && collision.tag == "Player")
{
StartCoroutine(DamagePlayer(collision));
}
if (!playerHasContact && !isPlayerCastleRunning && collision.tag == "PlayerCastle")
{
StartCoroutine(DamageCastle(collision));
Debug.Log("Damage castle coroutine started");
}
if(collision.tag == "EnemyCastle") //Char spawn point is behind the castle collider, so we are ignoring it
{
Physics2D.IgnoreCollision(gameObject.GetComponent<Collider2D>(), collision);
}
}
private void OnTriggerExit2D(Collider2D collision)
{
shouldStop = false;
contacts.Remove(collision.gameObject);
if (isPlayerDamageRunning)
{
StopCoroutine(DamagePlayer(collision));
isPlayerDamageRunning = false;
}
if (isPlayerCastleRunning)
{
StopCoroutine(DamageCastle(collision));
isPlayerCastleRunning = false;
}
}
private void OnTriggerStay2D(Collider2D collision)
{
bool playerOnScene = FindObjectOfType<PlayerChar>() != null;
if (playerOnScene && contacts.Contains(FindObjectOfType<PlayerChar>().gameObject))
{
playerHasContact = true;
StopCoroutine("DamageCastle"); //This actually does not stop that coroutine
Debug.Log("Stopped DamageCastle coroutine?"); //NOT REALLY
}
}
IEnumerator DamagePlayer(Collider2D collision)
{
isPlayerDamageRunning = true;
while (true)
{
if (null != collision.gameObject)
{
PlayerChar player = collision.GetComponent<PlayerChar>();
player.GetDamaged(charAttack);
}
yield return new WaitForSeconds(attackSpeed);
}
}
IEnumerator DamageCastle(Collider2D collision)
{
isPlayerCastleRunning = true;
Debug.Log("DamageCastle coroutine started");
while (true)
{
if (null != collision.gameObject)
{
PlayerCastle player = collision.GetComponent<PlayerCastle>();
player.GetDamaged(charAttack);
}
yield return new WaitForSeconds(attackSpeed);
}
}
}
I realized that the coroutine actually does not stop although the Debug message below is working.
I think because the coroutine takes a Collider2D parameter, and when it gets different parameter, it is basically looking for another coroutine which took that particular parameter (PlayerChar instead of PlayerCastle or vice versa). Is that correct? If so, do I have any other solution other than finding a way to calling that coroutine without any parameters?