Search Unity

Melee Combat?

Discussion in 'Scripting' started by DaleNation, Jul 20, 2014.

  1. DaleNation

    DaleNation

    Joined:
    Jul 6, 2014
    Posts:
    30
    Hello,

    My game has a melee combat system. I parented the melee weapon to the hand bone and gave the weapon a "weapon" script. I gave a box a "health" script. I want to make it so when I hit the box the box loses health. I was thinking about using triggers, but I only want the box to lose health if the object colliding with the box has the "weapon" script and during the players attack animation state. How would I go about doing this?
     
  2. DaleNation

    DaleNation

    Joined:
    Jul 6, 2014
    Posts:
    30
  3. TRALLALAL

    TRALLALAL

    Joined:
    Sep 7, 2013
    Posts:
    132
    You check the distance between the player and the box, if for example the box is 5 m away from the player and the player presses LMB you decrease its damage.
    If the health is in a different script you can go around by using GetComponent
    Code (CSharp):
    1. scriptName variablename;
    2.  
    3. void Start()
    4. {
    5.     variablename = GetComponent<scriptName>();
    6. }
    7.  
    8. void Update()
    9. {
    10.     if(Vector3.Distance(transform.position, enemyGameObject.transform.position) <= 5.0f && Input.GetKeyDown(KeyCode.Mouse0)) //transform.position is the position of the player in case the script is attached to him
    11.     {
    12.         variableName.Health -= damage;
    13.     }
    14. }
    15.  
    Note that it doesn't check if the box is in the player field of view as checking if an object is in the field of view never worked for me.
    You have to set the health variable to public.
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,706
    Triggers are the way to go. You just described in plain English exactly what the code will need to do.

    Tick Is Trigger on your box's collider. Then add an OnTriggerEnter() method to your health script, like in the example below. (Warning -- I just typed this into the reply; it could have typos.)

    Code (csharp):
    1. void OnTriggerEnter(Collider other) {
    2.     var weapon = other.GetComponent<Weapon>();
    3.     if (IsAttacking(other.gameObject) && (weapon != null)) {
    4.         LoseHealth(weapon.damage);
    5.     }
    6. }
    7.  
    8. bool IsAttacking(GameObject go) {
    9.     var animator = go.GetComponentInParent<Animator>();
    10.     return (animator != null) &&
    11.         animator.GetCurrentAnimatorStateInfo(0).IsName("Attacking");
    12. }
    The code above assumes that:
    • Your weapon script is named Weapon, and has a property named damage.
    • You're using Mecanim, and the attack state is on layer 0 and named "Attacking".
     
  5. b1gry4n

    b1gry4n

    Joined:
    Sep 11, 2013
    Posts:
    146
    The above post works, but keep in mind your actual attack animation if you are going to parent your trigger to your weapon. An issue I was running into with triggers is that my attack animation was so fast (the swing was 4-5 frames) that the collision was not being registered. The trigger on my weapon would jump from frame 3-4 for example and completely "pass through", or jump from one side to the other, of the enemy.

    In that case it was just better to have the trigger be parented to my player, just in front of him, and have it "float" in the direction I wanted to attack.
     
  6. Moosetaco

    Moosetaco

    Joined:
    Jan 27, 2013
    Posts:
    77
    would it be possible to use a raycast from the hands with a length of the blade to determine if contact is made during the animation??
     
  7. msl_manni

    msl_manni

    Joined:
    Jul 5, 2011
    Posts:
    272
    Yes, its done easily. Create two bones - start, end, then find if there is any other collider between position of these bones. I suppose you can code it easily. :)
     
  8. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,706
    To improve collision detection, set Collision Detection to Continuous for fast-moving objects. Depending on your fixed update interval and other factors, this might resolve the issue with fast sword swings. It adds a little overhead to Physics.

    You could also raycast from the hands. But you'd really want to do something like a CapsuleCast or multiple rays. Here's the reason: Say the player swings his sword down really fast. One frame 1, the player's sword is over his head. On frame 2, the player's sword is down between his enemy's knees. On both frames, the sword is not in contact with the enemy. But between frame 1 and frame 2, the sword must have passed down through the enemy's head and body.

    If you do a single raycast on frame 1 or frame 2, you won't detect the hit.

    Instead, on frame 1, record the position of the sword. On frame 2, run a CapsuleCast from frame 1's position to frame 2's position. This basically covers the entire arc. I say "basically" because it casts in a straight line, whereas the sword probably moves in a slight curve. But in practice the difference shouldn't be noticeable. The size of the capsule for the CapsuleCast should be roughly the size of the sword's blade.