- Home /
First Person Melee System - How to attach a weapon which swings and hits an enemy?
I'm designing a mini RPG which uses a first person melee system and I'm wondering about the best approach when creating this with Unity. I've been programming games for years but completely new to Unity and it seems Unity does things a bit different than I'm used to! :)
So in my first attempt I use the first person controller which I've attached a couple of scripts to in order to manage the player state. I've got enemies which chase after the player when he gets close enough (thanks Lerpz tutorial!) and when within "melee" distance the enemy will "hit" the player and the player can hit the enemy when they press the attack button.
My issue is this, I'd like to attach some kind of weapon to the player which swings and hits the enemy. I've got no player model loaded as it's first person I don't need one therefore no weapon models or animations either. However I want a melee weapon to appear and swing when the player attacks, what is the best way of doing this?
Do I just load a weapon prefab and run its animation as soon as the attack button is hit? Or is there a better way?
How would a Unity expert implement a first person melee system?
Answer by duck · Oct 11, 2010 at 09:20 AM
Yes, it sounds like you are thinking along the right lines.
Keep a reference(s) to your weapon prefab(s) in your script. Then, when the weapon is first equipped, you can create an instance of your weapon prefab, and set its parent to your character object, using code something like this:
public Transform[] weapons; // array of available weapons private Transform currentWeapon; private selectedWeaponIndex = 0;
void Update() {
// your other movement/weapon select/general game code here...
if (attacking) {
if (currentWeapon == null)
Equip(weapons[selectedWeaponIndex]);
}
selectedWeapon.animation.Play();
}
}
void Equip(Transform weaponPrefab) {
// instantiate weapon at character position:
Transform weapon = (Transform) Instantiate(weaponPrefab, transform.position, transform.rotation);
// attach weapon to character:
weapon.parent = transform;
}
The above example is illustrative only, and assumes there's an array of available weapon prefabs. It also does not include all your other code for moving, selecting weapons, etc, so you'll need some basic general Unity scripting knowledge to get it set up correctly.
As illustrated above, if your weapon prefab itself has an imported bones-based animation attached to it, you can play the animation using the Animation scripting commands, such as Animation.Play.
If you don't have a bones-based animation created outside Unity for each weapon, there are a few alternatives to this technique.
One would be to have a single generic imported bones-based animation set up on your character which could be used for all weapons (such as a generic "swinging arm" animation), and you could then instantiate any suitable weapon (such as a sword, axe, club) at the position of the hand, and parent it to the "hand bone" of the animation, so that it follows the animated movement of the hand.
Alternatively, you could Unity's built in Animation Editor to define an animation for each weapon within Unity. These animation clips can then be used in a similar manner to that described above for imported bones-based animation.
Once you have all this in place, you need to move on to the problem of detecting hits and inflicting damage.
You may want to do this based on a simple Radius approach (i.e. if you attack within a certain radius, you incur a hit on the enemy). You can do this by simply checking the distance between the two characters using code something like this:
if ((enemy.transform.position - transform.position).magnitude < 2) {
enemy.InflictDamage(1);
}
The above assumes that "enemy" is a reference to a script on your enemy character, and that script has an "InflictDamage" function. It inflicts 1 point of damage, if the player is within 2 units of the enemy.
If the player has the ability to turn around and face any direction, you'd probably also want to check whether they're facing the correct direction (eg, not attacking with their back to the enemy!). Something like:
Vector3 enemyDelta = (enemy.transform.position - transform.position); if ( Vector3.Angle( transform.forward, enemyDelta ) < 45 ) { // we are facing the right way!
if ((enemy.transform.position - transform.position).magnitude < 2) {
enemy.InflictDamage(1);
}
}
A completely different method would be to use colliders with Unity's physics system, to detect whether the weapon actually passes through the enemy's collider. To implement this, you'd need to set up a trigger collider on the weapon object, and make sure your characters have a collider & rigidbody component. You could then use the OnTriggerEnter function on your enemy scripts to detect if the player's weapon actually came into contact, and incur damage from within that function.
Hope this helps get you started.
Thanks a lot for your detailed and informative answer! It will certainly help me get this system in place. After reading through, I had a couple of questions:
Is there a specific reason why we store an array of the Transform component of the weapon prefabs rather than an array of GameObjects? Is this just convention?
I currently have the damage dealing & enemy facing in place already however I use Send$$anonymous$$essage("ApplyDamage") ins$$anonymous$$d of directly accessing the enemy script as you do in your example (enemy.InflictDamage). Is your method a preferred method in Unity? If so, why?
Thanks!
Actually, from most of the code I see around, it seems the "convention" is to use GameObject references, however I generally find it better to use references to more useful types of object. GameObjects themselves don't really have much use as a reference, since you almost always want to access some other kind of component attached to it.
For this reason, I usually either use "transform" (because I'm usually interested in accessing the position/rotation of the object) or even better, a reference to a particular script on the prefab - because if you do this, then when you instantiate the object you get a reference back to that script itself, rather than the GameObject.
Also, I find using direct references and function calls to be better than using "Send$$anonymous$$essage" because (aside from a small performance benefit) you get the benefit of compile-time error checking (rather thing finding errors by chance at runtime), auto completion of function names and parameters when coding in $$anonymous$$onoDevelop/Visual Studio, easy refactoring, and probably other good-pratice benefits that I can't think of off the top of my head at the moment :-)
Well, thanks again for the info! I like your reasons, especially for using direct references rather than Send$$anonymous$$essage and shall be refactoring my code accordingly. You've been extremely helpful, time for me to get coding! :)
Answer by Gmanmyers · Apr 02, 2017 at 10:07 AM
can someone help me i am making a survival game and i want to chop trees with a axe model but when i use other ppl scripts they never work
Your answer
Follow this Question
Related Questions
How do you make a weapon swing in layman terms? 1 Answer
Melee attacking, using force and health values 1 Answer
Not identifying the collider? 2 Answers
Why won't my animation play? 1 Answer
FP Mouse Look and Animating 0 Answers