Melee Damage/Health Script problem

So i’m running into a very simple problem with Melee and A health script.

I apply the script by dragging and dropping on a cube or a capsule and I have my melee script attached to the weapon. When I play in game, the cube or capsule doesn’t receive the damage done to it.

Is there something I am missing?

Melee Script

var TheDamage : int = 50;
var Distance : float;
var MaxDistance : float = 1.5;
var cutter02 : Transform;

function Update ()
{
    if (Input.GetButtonDown ("Fire1"))
    {
        cutter02.GetComponent.<Animation>().Play("Attack");
    }

    if (cutter02.GetComponent.<Animation>().isPlaying == false)
    {
        cutter02.GetComponent.<Animation>().CrossFade("Idle");
    }
}

function Damage ()
{
        var hit : RaycastHit;
        if (Physics.Raycast (cutter02.transform.position, cutter02.transform.TransformDirection(Vector3.forward), hit))
        {
            Distance = hit.distance;
            if (Distance < MaxDistance)
            {
                hit.transform.SendMessage("Damage", TheDamage, SendMessageOptions.DontRequireReceiver);
            }
        }
}

Health Script

var Health = 100;

function ApplyDamage (TheDamage : int)
{
    Health -= TheDamage;
   
    if(Health <= 0)
    {
        Dead();
    }
}

function Dead()
{
    Destroy (gameObject);
}

two problems:

The function Damage() in the first script is never called.
The message being sent is sending itself… if you want to do damage via the health script you need to send “ApplyDamage” in the message

2 Likes

My question now is how do I call the function Damage()?

Does the code look correct on the melee script now?

#pragma strict

var TheDamage : int = 50;
var Distance : float;
var MaxDistance : float = 1.5;
var cutter02 : Transform;

function Update ()
{
    if (Input.GetButtonDown ("Fire1"))
    {
        cutter02.GetComponent.<Animation>().Play("Attack");
    }

    if (cutter02.GetComponent.<Animation>().isPlaying == false)
    {
        cutter02.GetComponent.<Animation>().CrossFade("Idle");
    }
}

function Damage ()
{
        var hit : RaycastHit;
        if (Physics.Raycast (cutter02.transform.position, cutter02.transform.TransformDirection(Vector3.forward), hit))
        {
            Distance = hit.distance;
            if (Distance < MaxDistance)
            {
                hit.transform.SendMessage("ApplyDamage", TheDamage, SendMessageOptions.DontRequireReceiver);
            }
        }
}

When I see correct your Damage function checks first if it’s even a hit or not. So you can call it after or before playing your “Attack” animation in the same IF

a few ways to call Damage(), you can add it to the animation as an Animation Event, or just add it in after line 12.

as an aside, lines 26 and 27 are a little redundant, you can use the maxDistance within a raycast

So if I remove line 27 will it cause my script to crash? MonoDevelop is loading super slow. If I move the script inbetween lines 12-13 will it work as intended? I’m trying to apply it to function but it’s not showing the function in the animation events when trying to add it.

Adding an “event” to the animation, you’ll have to point it at the object that’s supposed to process the damage (in this case, the player) and you have to name it the exact same as your function, so “Damage”, then it should work. You have to add the event to the spot in the animation where you want the damage to happen.

To clarify for @LeftyRighty here:

You could also just add the function Damage() to line 12-13 or so, and it’ll work, but it will happen immediately when the animation starts and not later when it makes more sense, visually.

And as for 27, what he means was that you can add the “distance” to the end of the Raycast as a parameter like this:

if (Physics.Raycast (cutter02.transform.position, cutter02.transform.TransformDirection(Vector3.forward), hit, MaxDistance))

You can then delete all of this:

Distance = hit.distance;
if (Distance < MaxDistance)
    {

If you’re curious, you can also add a bit on the end that makes it so it only hits objects on a specific layer, or set of layers, or not on a specific layer. Fun stuff :slight_smile:

1 Like

Fixed up the script but the item itself isn’t taking any damage when hitting them with my sword at the certain time I placed the animation event. I’ll do a quick video… Link to the video

#pragma strict

var TheDamage : int = 50;
var Distance : float;
var MaxDistance : float = 1.5;

function Update ()
{
    if (Input.GetButtonDown ("Fire1"))
    {
        GetComponent.<Animation>().Play("Attack");
    }

    if (GetComponent.<Animation>().isPlaying == false)
    {
        GetComponent.<Animation>().CrossFade("Idle");
    }
}

function Damage ()
{
        var hit : RaycastHit;
        if (Physics.Raycast (transform.position, transform.TransformDirection(Vector3.forward), hit, MaxDistance))
        {

                hit.transform.SendMessage("ApplyDamage", TheDamage, SendMessageOptions.DontRequireReceiver);
        }
}

Add in a debug.log inside of the Damage function, first line, then another one inside of the raycast conditional to see if it’s actually hitting anything.

1 Like

Added a debug log inside both areas and I only get a mouse click on the first line. The second debug doesn’t make contact with the Capsule.

function Damage ()
{        Debug.Log ("Mouse Click!");
        var hit : RaycastHit;
        if (Physics.Raycast (transform.position, transform.TransformDirection(Vector3.forward), hit, MaxDistance))
        {
                Debug.Log ("Hit");
                hit.transform.SendMessage("ApplyDamage", TheDamage, SendMessageOptions.DontRequireReceiver);
        }
}

The “transform.position” is stuck on the ground and probably off to one side- if this is first person then just replace the first two arguments with Camera.main.position and Camera.main.forward instead.

Do I apply it here?

function Damage ()
{        Debug.Log ("Mouse Click!");
        var hit : RaycastHit;
        if (Physics.Raycast (Camera.main.position, Camera.main.forward(Vector3.forward), hit, MaxDistance))
        {
                Debug.Log ("Hit");
                hit.transform.SendMessage("ApplyDamage", TheDamage, SendMessageOptions.DontRequireReceiver);
        }
}

haven’t done so much with raycast till yet but wouldn’t be Collider3D and a collision event when sword hits capsule better ?

I have no idea how to do that though.

if(Physics.Raycast(Camera.main.position, Camera.main.forward, hit, MaxDistance))

There are literally like a dozen “better” ways to do this, yes. The best way that I’ve found for “basic attacks” is to place an event on the animation, which he did, but then the event actually calls a function which instantiates a new “attack” prefab that’s invisible, but has a collider in the shape that you want the “attack” to be (sword slice), which is created directly in front of the player. Anything within that collider when it’s instantiated gets “hit”, where a script determines how much damage is supposed to be done to each thing that’s hit, deals the damage, instantiates a new GUI element that will live for 2-3 seconds while floating up (damage taken numbers) and then destroy itself, and then the attack instance destroys itself too (or rather, re-pools itself, but that’s another story). That happens in a single frame.

However, “what’s the best way?” wasn’t the question, and my way has drawbacks too. shrugs

Now i’m running into errors…
“Assets/Scripts/MeleeScript.js(23,48): BCE0019: ‘position’ is not a member of ‘UnityEngine.Camera’.”
“Assets/Scripts/MeleeScript.js(23,70): BCE0019: ‘forward’ is not a member of ‘UnityEngine.Camera’.”

My goal is to create a couple different animations and attach certain functions to them to create the illusion of directional attacking.

Errr… Camera.main.transform.position and Camera.main.transform.forward…

1 Like

This works now! Thank you sooooooooo much. I’ve spent over 6 hours trying on my own but since I have no idea what I am doing it’s so confusing. One more question though, on animation event is there a way to add say the damage function at .3 milliseconds and the have it span all the way to .6 milliseconds?

Span? It’s fired, does the damage, and dies all in a single frame. I’m not exactly sure what you want to span some length of time.

Meaning so when I swing it doesn’t just do the damage on the one .6 millisecond but does it from .3 - .6.