- Home /
RPG Swing attack hit detection
Heya,
I am making a small RPG, has currently a player that swings a sword around. I got some enemys running around that I want to hit. My problem is detecting when the sword hit the enemies. So far I have tested two ways of doing it:
Calculating where the enemies are compared to myself (using distance and angle to enemies)
When the enemies collid with the sword.
The 1. solution I didn't like because it feels like alot of calculations. I have maybe up to 150 enemies on the screen at a time, it didn't lag on my comp but i can imagine it could be a problem on some machines.
The 2. solution in theory felt like a nice one, having the physics engine to take care of it. Problem is, it doesn't detect all the hits. Alot of the times the sword is passing through the enemy, but doesn't trigger an collision. It is rather random sometimes it triggers alot of collisions, other times non. I have tried debug stepping through an sword attack, and even through the sword is right in(colliding with) an enemy, it doesn't trigger an collision. The animation of the sword is rather fast, which could be an explanation (the sword is on one side of the enemy in one frame, and on the other side of the enemy in the next). The animation takes about 0.3 seconds. Making it take longer is not an option. The sword is the one getting triggered, and tells my swingAttackScript it has hit an enemy.
My code on the sword that gets called when there is a collision is:
var swingAttack : SwingAttacksScript;
private var enable : boolean = false;
private var enemiesHitThisSeason : ArrayList;
function SetEnable(setEnable : boolean)
{
enemiesHitThisSeason = new ArrayList();
enable = setEnable;
}
function OnTriggerEnter(other:Collider)
{
OnTrig(other);
}
function OnTriggerStay(other:Collider)
{
OnTrig(other);
}
function OnTriggerExit(other:Collider)
{
OnTrig(other);
}
function OnTrig(other:Collider)
{
if(enable)
{
var enemy : BaseEnemy = FindBaseEnemy(other.transform);
if(enemy!=null && !enemiesHitThisSeason.Contains(enemy))
{
enemiesHitThisSeason.Add(enemy);
swingAttack.EnemyHitWithMainWeapon(enemy);
}
}
}
function FindBaseEnemy(from : Transform)
{
var parent= from;
while(parent!=null){
var enemy =parent.GetComponent(BaseEnemy);
if(enemy !=null)
{
return enemy;
}
else
{
parent=parent.parent;
}
}
return null;
}
I keep an array that knows all the enemies, so I can always get an array with all my enemies (Takes O(1) time (constant time)).
So ye, my question is, how do i make a good "sword hit detection"?
Answer by Owen-Reynolds · Oct 08, 2011 at 06:15 AM
If all you're worried about for angle+distance is checking against every enemy, Physics.OverlapSphere(transform.position, weaponRange, ~(1<<enemyLayer));
should get you a quick list of potentials. The note about getting only AABB's means it will grab a few more than you need, but not miss any.
For #2, you have to worry about always missing dogs (swing over their heads,) thrusts through armpits and between legs, halberds with a downswing and left follow-through that never hit to the right... . Are you making King`s Field or Monster Hunter, where knowing the weapon arcs is part of fun (I always took a downswinging weapon to fight short enemies, since I hate tilting the camera down.)
My nephew has me playing the DungeonCrawler Fate -- that style of game, no one cares if the weapon animations "hit." You can barely see them. In an MMO-style, no one complains "that baseball bat went completely through my torso. How is that possible, and why am I not cut in half?"
Answer by syclamoth · Oct 08, 2011 at 03:24 AM
I have been making a multiplayer brawler, and I go for a variant of solution 2. What I do is for every weapon, have a set of empty transforms which define a simplified 'edge' for the weapon, and then while it is being swung, I remember the difference between the positions of each empty and their positions last frame, and use Physics.Linecast to find out if anything got hit in between. This provides a very accurate measure of where the weapon is going, because it doesn't rely on an object not 'phasing' through because of the animation. The only thing to check here, is to make sure that the weapon doesn't hit something twice in the same swing- maybe when it hits an enemy, make the enemy stop receiving damage for half a second or so.
Hmm this sounds rather interessting, going to test it =) I will tell you the resualt of it.
Thanks for the idea =)
Answer by christo1745 · Oct 07, 2011 at 10:33 PM
I think solution 1 is your best bet. You are correct in assuming that the sword is moving too fast and the physics engine is missing the collision. I would put a cylinder collider around your player and make it a trigger, when an enemy is in the trigger, play the swing animation and take damage from the enemy.
I just like the idea of solution 2, that way there is alot less maintaince, and if an attackanimation is changed, there is no change in the script. And the animator feels alot more like being in control of how the attack should be.
I have tried making a box with boxcollider around the sword and use that for collision. But still same result, only hitting some of the enemies.
Is there other ways to check if I hit an enemy?
Answer by Skyking · Dec 28, 2012 at 11:23 AM
You could decrease the Fixed Timestep value under Project Settings -> Time. Although depending on the number of rigidbodies in the scene, this might make it laggy.
Answer by Komak57 · Jun 03, 2015 at 01:17 AM
Quick trick to collision compatability is to set the game at a fixed framerate of about 10fps. Animations are based per update on time passed since last. If you only check 10 frames a second, you need to find a way to catch between swings. Usually, this emplies creating multiple collision checks in frames it has gone through, and not just the current frame. this is done with bullet travel using raycasts to where it is assumed to have passed through since last frame. Using a sphere-cast might be a bit much, but is a good anti cheat measure. You could create a collider mesh (or check) for the full swing to determine if it will hit, and set delays accordingly. The other guys collider node is a good eidea, as it pretends like its shooting multiple bullets that follow the animation. Just save the position in a buffer for each n
List item
ext frame.
Your answer
Follow this Question
Related Questions
Best way to detect sword hit 0 Answers
how do i make a weapon swing like a crowbar or a baseball bat 2 Answers
Override animation with another 1 Answer
first person rpg sword 0 Answers
How should i properly do sword combat? (Think: M&B/Oblivion/Skyrim) 3 Answers