Search Unity

combat system, triggers on melee weapons

Discussion in 'Scripting' started by Corva-Nocta, Apr 16, 2019.

  1. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    I'm trying to set up a melee system for my game that has the speed and weighty feeling of games like Dark Souls, slow animations and hitboxes that are very exact. My thought process has been to attach a trigger to every weapon and when the trigger makes contact with a target it will do damage. (with a few more checks along the way) It sounds like a simple system but I am actually having a lot of trouble making it work. I am beginning to think I might need to scrap the idea and start from scratch, but I wanted to see what the wisdom of the forums can bring first.

    So here is the code that I have on each weapon:
    Code (csharp):
    1.  
    2. public GameObject wielder;
    3.     public CombatController combatController;
    4.     public EnemyController enemyController;
    5.  
    6.     public int damage;
    7.  
    8.     public bool isPlayer;
    9.     public bool didDamage;
    10.  
    11.     void OnTriggerEnter(Collider collider)
    12.     {
    13.         if (didDamage)
    14.         {
    15.  
    16.         }
    17.         else
    18.         {
    19.             if (collider != wielder.GetComponent<Collider>())
    20.             {
    21.                 if (collider.gameObject.tag == "Weapon")
    22.                 {
    23.  
    24.                 }
    25.                 else
    26.                 {
    27.                     if (isPlayer)
    28.                     {
    29.                         if (combatController.state == PlayerState.attacking)
    30.                         {
    31.                             collider.gameObject.GetComponent<HealthController>().TakeDamage(damage);
    32.                             didDamage = true;
    33.                         }
    34.                     }
    35.                     else
    36.                     {
    37.                         if (enemyController.state == EnemyState.attacking)
    38.                         {
    39.                             collider.gameObject.GetComponent<HealthController>().TakeDamage(damage);
    40.                             didDamage = true;
    41.                         }
    its fairly simple. When the trigger collides it first checks if it has done any damage or not, then makes sure the collider is not itself, then makes sure it isn't hitting another weapon, then if its hitting the player or an enemy, then doing damage. Simple. well, it should be simple.

    the first problem is this code that is on my players and enemies:
    Code (csharp):
    1. rightWeapon.GetComponent<WeaponController>().didDamage = false;
    this code should be setting that didDamage bool to false for the weapon so it knows to start looking at dishing out the numbers. However, it does not ever set it back to false. I have no idea why. I can run this code 10 times in a row but it will never set the bool back to false.



    [This problem is solved]
    the second problem is whenever my player uses the weapon, it will damage himself if he gets touched with the weapon. This should not be happening. The if (collider != wielder) is supposed to be checking for that but it is definitely not working. I've thrown various Debug.Logs in there and I've seen multiple times where a weapon does damage to another weapon, which isn't supposed to happen.
    [This problem is solved]


    I am also wondering if I am just doing this all wrong. I have never done combat this way before so I am hoping it is working properly. If anyone has any tutorial videos I can look at that would be acceptable as well. I am trying to get melee (and ranged eventually) combat based on trigger boxes on weapons.
     
    Last edited: Apr 16, 2019
  2. Reedex

    Reedex

    Joined:
    Sep 20, 2016
    Posts:
    389
    so,... i was thinking about making the same trigger hits melee combat too..
    firstly i think you should start with something easier like,
    player raycasts at enemy, getcomponent of his health for example ,does damage,
    and build on that.
    second i think its much easier to fake these triggers and collisions and much more performant.
    imagine two sides each with 100 people, should they all check for collisions or just subtract one number from other with some timed animations?
    but hey what. it's just my silly opinion . :)
     
  3. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Yeah there are certainly way easier ways to do combat, I'm used to those. The advantage in my game is there's only ever going to be 2 or 3 units on the screen at a time (player and 1-2 enemie) so I'm not worried about lots of calculations. I just want it to work haha
     
  4. Reedex

    Reedex

    Joined:
    Sep 20, 2016
    Posts:
    389
    well you could try to add empty child to player and enemy just with collider and tag. chceck that tag instead of directly actors. (for the uninteded self-damaging)
    + i see now the if (collider != wielder) should probably be if (collider != weilder.GetComponent<Collider>());
     
    Last edited: Apr 16, 2019
  5. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    That might work. I'll try making the hitboxes separate entities, maybe it'll help. Would probably make things more organized if nothing else, and I could turn them off and on as needed too (rather than the bool "didDamage")

    Oh that might be a part of the code I'm missing. I'll definitely try that out and report back later today.

    Thanks for the help so far!
     
  6. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    So the wielder.GetComponent<Collider>() works like a charm! Thanks! My player no longer smacks hinself in the face and does damage haha.

    I've been noticing something else that is weird. After I make the first attack, if I don't touch anything at all the weapons will keep doing damage just by touching the enemy, its in an idle animation but will still deal damage. What else is weird, the line that is supposed to make sure the player is attacking is not working.
    Code (csharp):
    1. if (combatController.state == PlayerState.attacking)
    This line should prevent any damage from being done if my player state is anything other than attacking. After the first attack, the player's state is changed feom attacking to normal, but the weapon still acts like the player state is set to attacking. Any ideas why this might be the case?

    What else is weird, after the first attack the bool didDamage is set to true (so that I don't do damage when I don't want it to) but, when I go to do a second attack it is never changed back to false. My combatController script has the line:
    Code (csharp):
    1. leftWeapon.GetComponent<WeaponController>().didDamage = false;
    I've debugged this line several times and in several ways and it gets the correct weapon, and gets the weaponcontroller script, but it never changes the bool. I am not sure why this is happening. It really feels like my weaponcontroller script doesn't update to what is going on in the world.
     
  7. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Bump. Still can't figure out why the bool won't change. Any help is always welcome!
     
  8. Reedex

    Reedex

    Joined:
    Sep 20, 2016
    Posts:
    389
    sorry it was night time ,( diff time zone, you know the drill )
    maybe it would help to know few lines(at least those most important) above leftWeapon.GetComponent<WeaponController>().didDamage = false; in combatController
    and maybe somewhere down under, in you very first code snippet, you could do somehting like
    if(did damage) {state == idle;} or whatever you do to set it
    p.s. arent you mixing leftWapon and rightWeapon Somewhere?
     
    Last edited: Apr 17, 2019
  9. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Yeah I know that struggle haha, its a similar situation for me.

    So here is the full code that is called when I attack:
    Code (csharp):
    1.  
    2. public void AttackLeft()
    3.     {
    4.         if (state == PlayerState.normal)
    5.         {
    6.             leftWeapon.GetComponent<WeaponController>().didDamage = false;
    7.             animator.SetTrigger(attackL.animationTrigger);
    8.             attackSpeed = attackL.attackSpeed;
    9.             staminaController.UseStamina(attackL.staminaCost);
    10.  
    11.             state = PlayerState.attacking;
    12.         }
    13.     }
    its not much that would be changing the bool. Here is more code:
    Code (csharp):
    1.  
    2. public Transform leftHand;
    3.     public Transform rightHand;
    4.  
    5.     public GameObject leftWeapon;
    6.     public GameObject rightWeapon;
    7.  
    8.     public Weapon weaponL;
    9.     public Weapon weaponR;
    Code (csharp):
    1.  
    2. void Awake()
    3.     {
    4.         if (weaponL)
    5.         {
    6.             GameObject wL = Instantiate(weaponL.weaponModel);
    7.             wL.transform.position = leftHand.transform.position;
    8.             wL.transform.rotation = leftHand.transform.rotation;
    9.             wL.transform.parent = leftHand;
    10.             wL.GetComponent<WeaponController>().wielder = gameObject;
    11.             wL.GetComponent<WeaponController>().combatController = this;
    12.             wL.GetComponent<WeaponController>().isPlayer = true;
    13.             leftWeapon = wL;
    14.         }
    all of this is in the CombatController script. I know its not all the most efficient way for me to write things, but I'm going to fix that all later.

    haha yeah I did switch saying leftWeapon and rightWeapon, but actually they are effectively exactly the same, and I'm having the same problem on both sides. So they are effectively interchangable.
     
  10. Reedex

    Reedex

    Joined:
    Sep 20, 2016
    Posts:
    389
    for clarity, simply put, you press space and what happens.? whats the chain of functions.
    i imagine it's you press space , it calls AttackLeft(), it sets the didDamage to false and
    player state to attacking
    then the weapon collider collides and check if didDamage then checks for playerstate.
    it's ok the first time. but i never see you set playerstate back to normal so attackLeft() wont get called.
    in these lines
    Code (CSharp):
    1. if (isPlayer)
    2.     {
    3.         if (combatController.state == PlayerState.attacking)
    4.         {
    5.             collider.gameObject.GetComponent<HealthController>().TakeDamage(damage);
    6.             didDamage = true;
    7.             // is this working?
    8.             combatController.state = PlayerState.normal
    9.         }
    10.     }
     
    Last edited: Apr 19, 2019
  11. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Yeah I probably should have put those into a more logical order. Maybe I should make a separate script just for this function.

    Yes the process functions just like you said. AttackLeft() will set did damage to false, then the trigger on the weapon sets it back to true (after dealing damage of course). The trouble is if I call AttackLeft() a second time the bool for didDamage is never set to false. The PlayerState gets set back to normal after the attack animation is finished.

    I may try simply disabling the trigger rather than trying to set a bool. Maybe that will make the script work better
     
  12. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    So I rewrote the code to switch the trigger off when it does damage and everything works (well close to it, more on that later) The weird part is though is that I switched back to the bool and now its working fine. So I changed something and now the bool is working. I think I was referencing the weapon incorrectly before, since that was one of the only things I changed. I think I wasn't calling the instantiated weapon.

    So here's the last part that is not working quite right. Regardless of wether or not I use the bool system or toggle the trigger, when I toggle the bool/trigger to off it will still do damage if the trigger hits the player. So not sure what to do about that. It kinda seems like its not switching fast enough so it touches the player again before the bool/trigger toggles
     
    Last edited: Apr 19, 2019