jozza710
jozza710

Reputation: 95

Unity3D - enemy not taking damage

In Unity3D my enemy is not taking damage upon colliding with my projectile explosion.

Although this is not the case as it the health variable is unaffected upon colliding with my projectile explosion.

My Enemy and Barrel classes inherit from Entity which handles the taking of damage (subtracting the damage variable from the health variable). Although only the barrel class is working as intended.

The tags are 100% correct and I would prefer to continue using inheritance so please no suggestions to change the method in which my classes take damage.

the class that Enemy and Barrel inherit from

using UnityEngine;
using System.Collections;

public class Entity : MonoBehaviour {

    public float health = 25;

// Use this for initialization
void Start () {
}

// Update is called once per frame
void Update () {
}

public virtual void takeDamage(float dmg){
    health -= dmg;

    if (health <= 0){


         Destroy(this.gameObject);
        }
    }
}

Enemy class

using UnityEngine;
using System.Collections;

public class Enemy : Entity {
    private NavMeshAgent agent;
    public GameObject target;
    // Use this for initialization
    void Start () {
        agent = GetComponent<NavMeshAgent> ();
    }

    // Update is called once per frame
    void Update () {
        agent.SetDestination (target.transform.position);
    }
}

Barrel class

using UnityEngine;
using System.Collections;

public class Barrel : Entity {

    private Transform myTransform;

    //Effects
    public GameObject barrelExplosion;
    public GameObject explosionDamage;
    public GameObject explosionSound;

    // Use this for initialization
    void Start () {
        myTransform = this.transform;
    }

    // Update is called once per frame
    void Update () {
    }

    public override void takeDamage(float dmg){
        health -= dmg;

        if (health <= 0){
            Instantiate(barrelExplosion, myTransform.position, myTransform.rotation);
            Instantiate(explosionSound, myTransform.position, myTransform.rotation);
            Instantiate(explosionDamage, myTransform.position, myTransform.rotation);
            Destroy(this.gameObject);
        }
    }
}

ExplosionAOE the class that sends the damage

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

public class ExplosionAOE : MonoBehaviour {

    public float damage = 100.0f;

    public float lifeTime = 0.05f;
    private float lifeTimeDuration;

    public List<GameObject> damageTargets = new List<GameObject>();

    public float radius = 15.0f;

    GameManager gameManager;

    void Start() {
        gameManager = GameObject.FindGameObjectWithTag("GameManager").GetComponent<GameManager>();

        //Destroy (this.gameObject, lifeTime);
        lifeTimeDuration = Time.time + lifeTime;

        transform.GetComponent<SphereCollider>().radius = radius;
    }


    void Update() {

        //Explosion finishes, damage targets and remove AOE field
        if (Time.time > lifeTimeDuration) {
            foreach (GameObject target in damageTargets) {
                if (target != null) {
                    //Calculate damage based on proximity to centre of explosion
                    float thisDamage = ((radius - Vector3.Distance(target.transform.position, transform.position)) / radius) * damage;
                    print(thisDamage);
                    target.GetComponent<Entity>().takeDamage(thisDamage);
                    //target.SendMessage("takeDamage", damage);   //<< This is not good code. Let's fix this!
                }
            }
            Destroy(this.gameObject);
        }
    }


    void OnTriggerEnter(Collider otherObject) {

        if (otherObject.gameObject.tag == "Enemy") {
            damageTargets.Add(otherObject.gameObject);
        }
        if (otherObject.gameObject.tag == "Player") {
            Vector3 jumpVector = (otherObject.transform.position - transform.position).normalized;
            jumpVector *= 25;
            otherObject.GetComponent<CharacterMotor>().SetVelocity(jumpVector);
        }
    }
}

Sorry this is a bit of a lengthy one and EVERYTHING is tagged correctly so that is not the issue, thanks.

Upvotes: 1

Views: 1005

Answers (2)

Fattie
Fattie

Reputation: 12590

Problem 1.

Use "Debug.Log" everywhere

 void OnTriggerEnter(Collider otherObject) {
 Debug.Log("in trig");
 Debug.Log("otherObject.gameObject.tag is " + otherObject.gameObject.tag);

        if (otherObject.gameObject.tag == "Enemy") {
Debug.Log("a");
            damageTargets.Add(otherObject.gameObject);
        }
        if (otherObject.gameObject.tag == "Player") {
Debug.Log("b");
            Vector3 jumpVector = (otherObject.transform.position - 
                transform.position).normalized;
            jumpVector *= 25;
            otherObject.GetComponent<CharacterMotor>().SetVelocity(jumpVector);
        }
    }

In particular, in Entity and Enemy.

Questions such as this one are instantly answered by tracking with Debug.Log.


Problem 2.

It's a PITA getting the relationships between triggers, rigidbody, etc.

It's very likely that's a problem here.

http://docs.unity3d.com/Manual/CollidersOverview.html

Go down to the annoying "trigger action matrix" and work from there.


Problem 3.

As a rule, never use the "tags" feature in Unity. (They only added tags to help "hello world" tutorials.)

In practice you use layers everywhere and always:

enter image description here

(Layers are particularly essential in shooting games: every single category needs a layer.)


Problem 4.

The code shown is definitely looking good. Here's some example code not unlike yours for tips.

Trivial example, note the breakaway code (the returns) inside the OnTrigger, you should do that).

Also,

use extentions

everywhere and always in Unity. Quick tutorial

it's the #1 tip if you actually want to work professionally.

public class Enemy:BaseFrite
    {
    public tk2dSpriteAnimator animMain;
    public string usualAnimName;
    
    [System.NonSerialized] public Enemies boss;
    
    [Header("For this particular enemy class...")]
    public float typeSpeedFactor;
    public int typeStrength;
    public int value;
    
    // could be changed at any time during existence of an item!
    
    [System.NonSerialized] public FourLimits offscreen; // must be set by our boss
    
    [System.NonSerialized] public int hitCount;         // that's ATOMIC through all integers
    [System.NonSerialized] public int strength;         // just as atomic!
    
    [System.NonSerialized] public float beginsOnRight;
    
    private bool inPlay;    // ie, not still in runup
    
    void Awake()
        {
        boss = Gp.enemies;
        }
    
..........

    protected virtual void Prepare()    // write it for this type of sprite
        {
        ChangeClipTo(bn);
        // so, for the most basic enemy, you just do that.
        // for other enemy, that will be custom (example, swap damage sprites, etc)
        }
    
    void OnTriggerEnter2D(Collider2D c)
        {
        // we can ONLY touch either Biff or a projectile. to wit: layerBiff, layerPeeps
        
        GameObject cgo = c.gameObject;
        
        if ( gameObject.layer != Grid.layerEnemies ) // if we are not enemy layer....
            {
            Debug.Log("SOME BIZARRE PROBLEM!!!");
            return;
            }
        
        if (cgo.layer == Grid.layerBiff)    // we ran in to Biff
            {
            Gp.billy.BiffBashed();
            // if I am an enemy, I DO NOT get hurt by biff smashing in to me.
            return;
            }
        
        if (cgo.layer == Grid.layerPeeps)   // we ran in to a Peep
            {
            Projectile p = c.GetComponent<Projectile>();
            if (p == null)
                {
                Debug.Log("WOE!!! " +cgo.name);
                return;
                }
            int damageNow = p.damage;
            Hit(damageNow);
            return;
            }
        
        Debug.Log("Weirded");
        }
    
    public void _stepHit()
        {
        if ( transform.position.x > beginsOnRight ) return;
        
        ++hitCount;
        --strength;
        ChangeAnimationsBasedOnHitCountIncrease();
        // derived classes write that one.
        
        if (strength==0)    // enemy done for!
            {
            Gp.coins.CreateCoinBunch(value, transform.position);
            FinalEffect();
            
            if ( Gp.superTest.on )
                {
                Gp.superTest.EnemyGottedInSuperTest(gameObject);
                boss.Done(this);
                return;
                }
            
            Grid.pops.GotEnemy(Gp.run.RunDistance);     // basically re meters/achvmts
            EnemyDestroyedTypeSpecificStatsEtc();       // basically re achvments
            Gp.run.runLevel.EnemyGotted();              // basically run/level stats
            
            boss.Done(this);                            // basically removes it
            }
        }
    
    protected virtual void EnemyDestroyedTypeSpecificStatsEtc()
        {
        // you would use this in derives, to mark/etc class specifics
        // most typically to alert achievements system if the enemy type needs to.
        }
    
    private void _bashSound()
        {
        if (Gp.biff.ExplodishWeapon)
            Grid.sfx.Play("Hit_Enemy_Explosive_A", "Hit_Enemy_Explosive_B");
        else
            Grid.sfx.Play("Hit_Enemy_Non_Explosive_A", "Hit_Enemy_Non_Explosive_B");
        }
    
    public void Hit(int n)  // note that hitCount is atomic - hence strength, too
        {
        for (int i=1; i<=n; ++i) _stepHit();
        
        if (strength > 0) // biff hit the enemy, but enemy is still going.
            _bashSound();
        }
    
    protected virtual void ChangeAnimationsBasedOnHitCountIncrease()
        {
        // you may prefer to look at either "strength" or "hitCount"
        }
    
    protected virtual void FinalEffect()
        {
        // so, for most derived it is this standard explosion...
        Gp.explosions.MakeExplosion("explosionC", transform.position);
        }
    
    public void Update()
        {
        if (!holdMovement) Movement();
        
        if (offscreen.Outside(transform))
            {
            if (inPlay)
                {
                boss.Done(this);
                return;
                }
            }
        else
            {
            inPlay = true;
            }
        }
    
    protected virtual void Movement()
        {
        transform.Translate( -Time.deltaTime * mpsNow * typeSpeedFactor, 0f, 0f, Space.Self );
        }
......



/*
(frite - flying sprite)
The very base for enemies, projectiles etc.
*/

using UnityEngine;
using System.Collections;

public class BaseFrite:MonoBehaviour
    {
    [System.NonSerialized] public float mpsNow;
    // must be set by the boss (of the derive) at creation of the derive instance!
    
    private bool _paused;
    public bool Paused
        {
        set {
            if (_paused == value) return;
            
            _paused = value;
            
            holdMovement = _paused==true;
            
            if (_paused) OnGamePause();
            else OnGameUnpause();
            }
        get { return _paused; }
        }
    
    protected bool holdMovement;
    
    protected virtual void OnGamePause()
        {
        }
    protected virtual void OnGameUnpause()
        {
        }
    
    protected string bn;
    public void SetClipName(string clipBaseName)
        {
        bn = clipBaseName;
        }
    
    }

Upvotes: 4

PacoPGD
PacoPGD

Reputation: 26

Is more easy if in ExplosionAOE/OnTriggerEnter function you call the takeDamage function:

scriptCall = otherObject.GetComponent(EnemyScript);

scriptCall.takeDamage(damage);

Upvotes: 0

Related Questions