- Home /
Attack combos and collision detection
Hi,
So, I'm making a action/fighting game on Unity and I have started to notice that my damage application script for the main attack was pretty inconsistent. This is either due to my bad coding or the unity colliders being inconsistent.
The main problem is that sometimes the attack animation will play while the damage application does not go through. Like I said, this happens very inconsistently. My main character has a three hit combo as his main attack string and he will miss at least 20% of the time. This can happen on first, second or third hit. I started with discrete collision detection but I have slowly moved to continuous and then continuous dynamic. It has made some difference but there are still times where it will fail.
Here is the code I have:
This is the part that tracks how many times you have hit and plays the appropriate animation.
if (atkready && rightbox.dmgReady ||
atkready && leftbox.dmgReady)
{
if (!blocking && !gettinghit)
{
if (attackcounter > 3)
{
attackcounter = 1;
}
if (attackcounter == 3)
{
karateman.Play("attack3");
attackcounter++;
atktimer = true;
atkreset = 0;
spacebar++;
atkready = false;
}
if (attackcounter == 2)
{
karateman.Play("attack2");
attackcounter++;
atktimer = true;
atkreset = 0;
spacebar++;
atkready = false;
}
if (attackcounter == 1)
{
karateman.Play("attack1");
attackcounter++;
atktimer = true;
atkreset = 0;
spacebar++;
atkready = false;
}
}
}
This next part handles the attack reset. Since the animations have different lengths, the next attack animation will not be ready until a certain amount of time has passed.
if (!atkready && attackcounter == 1)
{
atkCD += Time.deltaTime;
if (atkCD >= 1.4f)
{
atkready = true;
atkCD = 0;
}
}
if (!atkready && attackcounter == 2)
{
atkCD += Time.deltaTime;
if (atkCD >= 0.3f)
{
atkready = true;
atkCD = 0;
}
}
if (!atkready && attackcounter == 3)
{
atkCD += Time.deltaTime;
if (atkCD >= 0.3f)
{
atkready = true;
atkCD = 0;
}
}
if (!atkready && attackcounter > 3)
{
atkCD += Time.deltaTime;
if (atkCD >= 1.4f)
{
atkready = true;
atkCD = 0;
}
}
These 2 above code snippets are only dealing with animation. Next up is where the problem is. This next code tries to mirror the attack reset code so that the damage will only apply when the animations are correct.
//delay after THE WHOLE combo
if (!dmgReady && playerscript.attackcounter == 1)
{
dmgCD += Time.deltaTime;
if (dmgCD >= 1.4f)
{
dmgReady = true;
dmgCD = 0;
}
}
//delay after FIRST attack
if (!dmgReady && playerscript.attackcounter == 2)
{
dmgCD += Time.deltaTime;
if (dmgCD >= 0.3f)
{
dmgReady = true;
dmgCD = 0;
}
}
//delay after SECOND attack
if (!dmgReady && playerscript.attackcounter == 3)
{
dmgCD += Time.deltaTime;
if (dmgCD >= 0.3f)
{
dmgReady = true;
dmgCD = 0;
}
}
//delay after THIRD attack
if (!dmgReady && playerscript.attackcounter > 3)
{
dmgCD += Time.deltaTime;
if (dmgCD >= 1.4f)
{
dmgReady = true;
dmgCD = 0;
}
}
Finally, this last part is inside OnTriggerStay() of the damage hitbox. If an enemy is within this box, and you press the main attack button this code will execute.
if (Input.GetButtonDown("fight") && playerscript.state != Player.State.Explosion && !playerscript.stunned && !playerscript.blocking && !playerscript.gettinghit)
{
if (dmgReady)
{
if (otherObject.tag == "Enemy")
{
//All the dmg and effects code omitted for clarity
dmgReady = false;
}//end | tag: enemy
As I was saying earlier, this system works for the most part. But it is extremely frustrating when it doesn't because it will cause the main character to drop combos from the air, when it was clearly supposed to hit.
Atkready and Dmgready should be basically in sync but sometimes the animation comes out while none of the dmg script goes through. Has anyone else experienced this? Is it coming from the coding or the colliders?
Here is the link for a requested minimal pack from ScroodgeM
fuf... too much letters...
it's hard a little to debug all your code without other parts. needs to write all stuff around to make this working. understand and debug it without executing in unity is also takes time 8)
so, use a very powerful tool Debug.Log("something"); - insert it in every point in code that works incorrect and monitor states of your variables. check what is executed and when, may be something executing twice etc.
i'm sure you'll get much more information about your issue and get a solution, or, issue becomes more specific and can be asked in few lines of text 8)
if you'd try this and still stuck, write a line here again, i'll try to penetrate your code 8)
Hi!
Thanks for reading. I am aware of Debug.Log and I have used it as well as other various debugging methods. I even have a Devmode display that displays whatever variables I want to check on real-time in the unity GUI.
$$anonymous$$y problem is not that I don't know what's going wrong, but rather, that I don't understand why. As I said earlier, There are 2 main bools involved that should mirror each other but they do not. Today I have tried 2 more methods to try to make them execute in sync.
What you seem to be saying is that I am providing too much information and too little information at the same time! If you want more code, I am 100% willing to post it. The whole reason I am omitting stuff is to avoid the TL;DR problem.
I'm probably a little out of my depth here especially without being able to see all of the animations but I will offer 1 small piece of advice. The formatting on the code tool here in answers is junk. If you keep heading down this rabbit hole you might want to start tossing some of that into pastebin ins$$anonymous$$d just to ease readability.
usually when I hit these points I just start putting a debug log into any "breakpoint" I might conceive in my code /shrug
$$anonymous$$inda the best novice class advice I can give here.
i would recomend you to use OnTriggerEnter() at the last part and OntriggerExit(), and use some flags
var isInRange : bool; var enemy : bool;
function onTriggerEnter() { enemy = other.gameObject.tag== "enemy"; isInRange = true; }
function onTriggerExit() { isInRange = false; }
function Update(){ if (Input.GetButtonDown("fight") && isInRange == true && enemy){ //more code } }
this will make everything more accurate. i had the same problem some days ago and used this flag and it now works perfectly
share a $$anonymous$$imal pack to reproduce issue, i'll check it.
Answer by ScroodgeM · Aug 20, 2012 at 09:31 PM
leftrightbox.cs:
... void OnTriggerStay (Collider otherObject) { #region... if (Input.GetButton("fight")... ...
don't use GetButtonDown in any place except Update() function. GetButtonDown hits once a frame and you can't be sure that OnTriggerStay hits at this frame.
Brilliant! Thanks so much. This works perfectly. I have been using GetButtonDown so much that I hadn't even thought that the problem might be there.
Hey Scroodge,
I don't know if you're still around, but, after implementing your fix, I discovered something bad. I suppose I'm a noob for not noticing in the first place, but when GetButton is used ins$$anonymous$$d of GetButtonDown, the user is able to hold down the button and continuously do damage. This seems obvious in hindsight but I was just so happy that it worked, I didn't have a care.
Is there a way to keep this system but disable this exploit? If I find a good way myself, I will post it. Any help would be appreciated.
make a bool variable
private bool buttonPressed;
check button pressed in Update()
void Update() { buttonPressed = buttonPressed | Input.GetButtonDown("fight"); }
use this in apply action method
void OnTriggerStay (Collider otherObject) { #region... if (buttonPressed...
don't forget to reset it after use
... buttonPressed = false;
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Zombie Damage Parts Problem 0 Answers
Distribute terrain in zones 3 Answers
Raycast isn't working as expected 1 Answer
How to check if two objects collide without a collider 1 Answer