- Home /
Colliders/Triggers going through each other
I'm making a game, similar to the game Cartoon Wars (don't know if you've heard of it) and Plants vs Zombies. You set down your troops and they attack your enemy's base, while your enemy is attacking yours.
It is working fine, except for one problem. When the enemies or defenders get stacked up to each other, and one of them dies, it registers to the other side that their target has been killed and they continue walking right past the enemies in front of them. Basically, they think that since they killed one guy, the rest in front of them are dead, too.
Here's my code for the Defenders (the Attacker code is basically the same. I have Kinematic Rigidbody2Ds and Box Collider2Ds with Triggers set on them). using UnityEngine; using System.Collections;
public class Defenders : MonoBehaviour {
public int cost = 50;
private float defenderSpeed;
private Animator anim;
private bool standGuard;
private GameObject defenderTarget;
void Start () {
defenderSpeed = .5f;
anim = GetComponent<Animator>();
}
void Update () {
transform.Translate (Vector3.right * defenderSpeed * Time.deltaTime);
if (!defenderTarget) {
defenderSpeed = .5f;
anim.SetBool ("isAttacking", false);
}
}
void OnTriggerEnter2D(Collider2D collider) {
GameObject obj = collider.gameObject;
defenderTarget = obj;
if (obj.GetComponent<Attacker>()) {
defenderSpeed = 0f;
anim.SetBool ("isAttacking", true);
}
}
void OnMouseDown() {
if (standGuard == true) {
anim.SetBool ("standGuard", false);
standGuard = false;
} else if (standGuard == false) {
anim.SetBool ("standGuard", true);
standGuard = true;
}
}
public void StrikeCurrentTarget (float damage) {
if (defenderTarget) {
Health health = defenderTarget.GetComponent<Health>();
if (health) {
health.DealDamage (damage);
}
}
}
public void Attack (GameObject obj) {
defenderTarget = obj;
}
}
Is there a way that I can make the unit check to make sure there isn't another unit in front of him before carrying on?
$$anonymous$$inematic rigidbodies and triggers are unhindered by collisions. It sounds as though you do not want collisions to be possible anyway, since apparently your game should never allow a collision to occur in the first place. Otherwise, where is the code responsible for responding to kinematic collisions, or, where are your non-kinematic bodies?
Your logic does not seem to account for occasions where a third agent is detected while two are fighting. Perhaps you assume that that situation is not possible, but I'm guessing the result you're observing is caused by a failure to respond to a situation where one agent detects a third agent while still engaging the second. (I'm not totally confident this is the problem or the only problem, but this logic has no provisions to account for "unexpected" behavior, which is what's likely occurring.)
I'm familiar enough with plants/zombies to recall the basic format of the game. It would seem that some kind of queue system is called for here, whereby each agent knows about all other agents in its lane. Decisions are then based upon the existence and position of enemy agents in that lane. You could even ditch trigger-based detection altogether. To continue using triggers, you must devise a way to account for situations where agents detect one another while still engaging their nearest neighbors. Other odd cases may exist; the gist is, you have to account for every conceivable combination of events. Your current approach seems very inflexible; consider an alternative way for agents to discover and react to one another in a sensible way.
The game I'm making has five different lanes. When you click on a lane, it spawns a unit (at the moment, I only have a "Soldier" unit for a defender, and a "Fallen" unit for attackers). Once spawned, the defenders moves to the right, and when it meets an attacker (Fallen), they start the attack animation (they both have swords).
At the time of posting, I am somewhat new to coding and Unity. I have been taking classes, and I decided to go off and make this on my own, so please understand I have limited knowledge of C# and Unity.
There's nothing "wrong" with your approach to this per se, but depending upon the size of the triggers, I'd wager you are detecting more than one enemy at a time and failing to respond to those additional enemies appropriately.
You might try enforcing an attack state. When an agent detects an enemy, it enters the attack state and does not leave that state until the enemy is defeated. During the attack state, additional enemy contacts are ignored. When the current enemy is slain, the attack state ends, and the next enemy contact is registered and responded to.
This is the most basic example of a Finite State $$anonymous$$achine; a program$$anonymous$$g design principle most game devs first encounter when designing AI.
Okay, could you tell me how I'd go about doing that? Like I said, I'm relatively new to this, and I'm kind of stumped. Everything I've tried has ended in failure.
Answer by AlwaysSunny · Apr 17, 2015 at 12:46 AM
I'll try a quickie example, but you should be prepared to research such well-documented design techniques on your own.
In a more complicated Finite State Machine, you'd use some variable like an enum to track which state(s) your agents are currently in.
public enum AgentState { idle, patrol, attack }
public AgentState currentState;
//...
switch ( currentState ) {
case AgentState.idle : DoIdleBehavior(); break;
// etc...
}
In this example, because there are only two states (lookForTargets and attackTarget) you can safely determine the state based on whether a currentTarget variable is null or populated. You'll need a way to detect and select the "best target" among detected agents.
// where Agent is the name of some script your characters derive from
private Agent currentTarget;
// it really makes the most sense to discover all nearby objects,
// check whether they're agents,
// verify that they belong to the same lane,
// then sort through those agents to select the nearest one.
// Failure to do so may allow the "wrong" agent to get selected
// which might lead to all sorts of problems.
// This isn't hard, but there are many valid ways to do this so I'm leaving it to you.
// You could use OnTriggerStay() but I would recommend Physics.OverlapSphere()
// which bypasses triggers altogether, and conveniently
// hands you a collection of all detected objects.
// don't look for a target if you already have one
if (currentTarget == null) {
// do whatever you're gonna do to discover and select the best agent, then...
Agent otherAgent = (other.gameObject.GetComponent<Agent>() as Agent;
if (otherAgent != null) currentTarget = otherAgent;
}
// now, if you have a target, attack it until the target is no longer valid
// somewhere in your attack method...
if (currentTarget.health <= 0) {
GameObject.Destroy( currentTarget.gameObject );
currentTarget = null;
}
You'll then allow your look-for-targets code to run again, starting the cycle over.
Then, you'd probably want a way for friendly agents to detect each other too, so they can "wait" on friendlies in front of them. "Waiting" should really constitute a third state, so you might need to have a more complicated FSM after all...
http://docs.unity3d.com/ScriptReference/Physics.OverlapSphere.html
I'll try this later today! Thanks for bearing with me and for the help!
Your answer
Follow this Question
Related Questions
Destroying objects with the same name that are touching eachother. 1 Answer
Why does my counter keep going up after pickup is destroyed? 1 Answer
Target touching enemy collision 1 Answer
Destroy Clone Game Object On Collision Doesn't work 3 Answers
using Contains(gameObject) to find and destroy a gameObject from a list 2 Answers