Forum begins after the advertisement:
[Part 3.5] After jumping and falling, damage is not counted.
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 3.5] After jumping and falling, damage is not counted.
- This topic has 28 replies, 4 voices, and was last updated 6 days, 10 hours ago by
Da.
-
AuthorPosts
-
February 7, 2025 at 8:11 pm #17205::
It sounds like you’re dealing with an issue related to hit registration in a game, possibly when using a physics system for character movement and attacks. Here are some thoughts to help you troubleshoot and potentially resolve the problems you’re facing:
Understanding Hit Registration
-
Gravity and Collision Detection:
- When you set gravity low and the character falls slowly, the physics engine might have more time to detect collisions, which can improve hit registration. If your character is moving too quickly, the physics engine might skip over collisions due to how frames are processed.
-
Jumping vs. Falling:
- When the character jumps, the physics behavior changes. Depending on how you’ve set up your collision detection, it may be more effective at detecting hits when the character is airborne. This could be due to the angle of attack or the speed of the character during the jump.
-
Attack Method Frequency:
- If the “Attack” method is not being called frequently enough, you might consider placing the attack logic in a way that it checks for hits more continuously (e.g., using a timer, or checking for inputs in the
Update
method).
- If the “Attack” method is not being called frequently enough, you might consider placing the attack logic in a way that it checks for hits more continuously (e.g., using a timer, or checking for inputs in the
Possible Solutions
-
Collider Setup:
- Ensure that your colliders are appropriately sized and positioned. If the collider for the attack is too small or incorrectly placed, it might not register hits as expected.
-
Raycasting:
- If you haven’t already, consider using raycasting to check for hits. This can provide more accurate collision detection for attacks, especially if you’re targeting a specific direction or area.
-
Hitbox System:
- Implement a hitbox system where you have a separate collider specifically for the attack. This hitbox can be activated when the attack is initiated and checked for collisions against enemies.
-
Physics Layers:
- Check your physics layers and collision settings. Ensure that your character’s attack collider is set to interact with the enemy colliders.
-
Debugging:
- Use debug lines or gizmos to visualize the colliders and raycasts in your game scene. This can help you see whether the attack collider is actually intersecting with the target during the attack.
-
Reviewing Timing:
- Ensure that the timing of the attack animation and the collision detection logic are in sync. If the attack happens too quickly or too slowly relative to the physics updates, it might miss hits.
Summary
To fix your hit registration issue, you may want to explore the collider setup, attack method frequency, and consider using raycasting or a hitbox system. Debugging tools can greatly aid in visualizing what’s happening in your game, allowing you to adjust accordingly. If you provide more specifics about your implementation (e.g., the game engine you’re using, the code for your attack method), I could offer more tailored advice!
February 7, 2025 at 8:27 pm #17206::Does the error still occur on the small walls (when jumping/falling) after increasing the size of the SideAttackArea vector by, idk 4 times? so that the red box becomes much taller If it doesnt occur, you probably got deceived by the length of the animation of your attack. the overlapbox only gets drawn during the first frame of your attack, all the other frames of your attack would not trigger a hit on the wall (i am not 100% sure about that XD, but makes sense to me). But if you want all frames to trigger a hit, there is for sure some way to do that
February 7, 2025 at 8:45 pm #17207::When the SideAttackArea is increased, the problem disappears. Apparently, the problem is really a slight discrepancy between the animation and the impact itself. I don’t know if it’s a crutch, but I solved the problem by introducing a small delay when registering a hit (a character’s hit in my game should be instantaneous, so I think that will be enough). Although it is a very interesting question how to make the attack itself last the entire animation.
February 7, 2025 at 8:46 pm #17208::Thanks for the help. To be honest, I didn’t expect to get an answer to my question so quickly. I’m still new to unity, but I want to make games)
February 7, 2025 at 9:11 pm #17209::I am glad i was able to help :) But i am afraid i can not help you with the question “how to make all animation frames trigger an hit”, since i am new to unity as well. But that might be a topic for a new post. Currently making my first game with these tutorials as well :)
February 7, 2025 at 9:11 pm #17210::Hi Da,
It’s great to hear that you’re diving into game development with Unity! Your issue with the discrepancy between the animation and the impact is quite common, especially when dealing with attacks and hitboxes.
Here are a few approaches you can consider to ensure that the attack lasts for the entire animation:
-
Animation Events: Unity allows you to add events to your animations. You can place an event at the point in your attack animation where you want the hit detection to occur. This way, you can ensure that the impact is registered precisely when the animation reaches that point. To do this:
- Open your animation in the Animation window.
- Find the frame where you want to trigger the hit.
- Right-click and select “Add Animation Event.”
- In the inspector, you can assign a function that will handle the hit registration.
-
Adjust Hitbox Size and Timing: As you’ve discovered, increasing the size of your hitbox can help. You might also consider adjusting the timing of when the hitbox is active. For example, you could activate the hitbox a little before the animation reaches the point of impact and deactivate it after.
-
Using Triggers: Instead of directly registering a hit on the animation’s frame, you can use triggers to manage hits. For example, when the attack animation starts, you set a boolean variable that indicates the attack is happening, and then check for hits in the Update method based on that variable.
-
Physics Overlap: If you’re using colliders, you might want to utilize
Physics.OverlapSphere
or similar methods to check for hits in a certain area around the character during the attack. This can give you a more forgiving hit detection system. -
Animation Blending: If your character’s attack animations blend into other animations (like standing or running), make sure that the transitions aren’t causing any issues with your hit detection. Sometimes, tweaking the blend tree can help with the timing of when the hit is registered.
Here’s a simple example of using an animation event:
public class CharacterAttack : MonoBehaviour { public void RegisterHit() { // Your hit registration logic here Debug.Log("Hit registered!"); } }
In your animation, add an event that calls
RegisterHit()
at the appropriate moment.Keep experimenting with these techniques, and you’ll find the right balance that suits your gameplay. Don’t hesitate to reach out if you have more questions or need further clarification on any of these methods!
Happy game developing!
February 7, 2025 at 11:03 pm #17211::@lukaskazda thank you for popping in to help. It is much appreciated!
@Da, regarding the issue of expanding the duration that the hitbox exists, we’ll need to modify the attack mechanics so that it is possible to keep the attack active for multiple frames.
void Attack() { timeSinceAttack += Time.deltaTime; attackActiveTime -= Time.deltaTime; if(attack && (timeSinceAttack >= timeBetweenAttack || attackActiveTime > 0)) { timeSinceAttack = 0; attackActiveTime = 0.1f; // Keep the attack active for 0.1 seconds. You can adjust this accordingly. anim.SetTrigger("Attacking"); if(yAxis == 0 || yAxis < 0 && Grounded()) { Hit(SideAttackTransform, SideAttackArea); } else if(yAxis > 0) { Hit(UpAttackTransform, UpAttackArea); } else if (yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea); } } }
I don’t recommend keeping the attack active for the entire duration of the animation though. That will look a little weird visually, and make the attack very powerful. Anywhere between 0.1 or 0.2 seconds is a healthy value.
February 7, 2025 at 11:11 pm #17212::Hi Lukas! It sounds like you’re on the right track with your testing and experimentation. To help you isolate the issue with hit detection and overlapping colliders in Unity, here are a few suggestions you might find helpful:
-
Increase OverlapBox Size: As you mentioned, increasing the size of the
OverlapBox
can help ensure that it overlaps with the walls during your attacks more consistently. If you haven’t already, try increasing the height of theSideAttackArea
vector significantly (e.g., 4 times or more) to see if that resolves the inconsistency. -
Adjust Gravity Settings: Lowering the gravity settings can indeed give your player a longer time to fall, which can help you test the hit detection more thoroughly. You can do this by adjusting the gravity scale in your Rigidbody2D component.
-
Animation Events: If you want to trigger hit detection on every frame of your attack animation, consider using Animation Events in Unity. You can create an event in your attack animation that calls a method to check for collisions or overlaps at specific frames of the animation. This way, you can manually check for hits as the animation progresses.
-
Continuous Hit Checking: Instead of relying solely on the
OverlapBox
method, you could also use raycasting or a collider trigger to continuously check for overlaps during the attack animation. This way, you can detect collisions more reliably throughout the attack animation’s duration. -
Debugging OverlapBox: To visualize what’s happening, you can use
Debug.DrawLine
to draw theOverlapBox
in the Scene view. This can help you see if the box is registering overlaps correctly during the player’s attack.
Here’s a simple example of how to implement an Animation Event in Unity:
public class PlayerAttack : MonoBehaviour { public BoxCollider2D attackCollider; // This method can be called as an Animation Event public void CheckForHits() { Collider2D[] hits = Physics2D.OverlapBoxAll(attackCollider.bounds.center, attackCollider.bounds.size, 0f); foreach (var hit in hits) { if (hit.CompareTag("AttackableWall")) { // Handle hit logic here Debug.Log("Hit: " + hit.name); } } } }
To use this code:
- Attach it to your player GameObject.
- Create an Animation Event in your attack animation timeline, and link it to the
CheckForHits
method.
By implementing these suggestions, you should be able to better understand and resolve the hit detection issue you’re encountering. Good luck with your game development, and feel free to ask if you have more questions!
February 7, 2025 at 11:54 pm #17213::Hello. Thanks for the provided code. But I wanted something a little different (I probably didn’t make myself clear earlier). I want information about hitting the enemy to be collected for a short time after the attack. That is, hits are registered not only at the moment of pressing the button, but also after (for some time).
February 7, 2025 at 11:59 pm #17214::There are two problems. The first is how to “extend” the attack after pressing the button. The second is how to add colliders to an array without replacing it. Unfortunately, these problems are causing me great difficulties so far. But I’m not giving up)
February 8, 2025 at 2:05 am #17215::I dont know if i understood the goal correctly. if you want every frame of your attack to draw a new boxcollider2D which then detects a collision with the enemy, you could use a coroutine, i think(?). It could look like this:
List<Collider2D> collisionsOfAllFrames = new List<Collider2D>(); IEnumerator WaitForFrames(int attackFrameCount) { for (int i = 0; i < attackFrameCount; i++) { Collider2D[] detectedCollisions = Physics2D.OverlapBox(boxCenter, halfExtents, boxOrientation, layerMask); collisionsOfAllFrames.Add(detectedCollisions[0]); //this always adds the first collision registered by the //overlapbox, if info of multiple collisions shall be //gathered, you need a List<Collider2D[]> (a List of arrays, //aka 2 dimensional array) yield return new WaitForEndOfFrame(); } Debug.Log("Waited for " + attackFrameCount + " frames."); }
i hope i am not talking nonsense here XD
has upvoted this post. February 8, 2025 at 3:11 am #17216::Your approach to using a coroutine to detect collisions over multiple frames is a good idea, and you’re on the right track! However, there are a few adjustments and improvements that could help make your code more effective and clear. Here’s a refined version of your coroutine, along with some explanations:
-
Use a List to Store All Collisions: Instead of just storing the first collision found in each frame, you should collect all collisions in each frame.
-
Avoid Index Out of Range: When accessing the
detectedCollisions
array, ensure you check if there are any collisions detected to avoidIndexOutOfRangeException
. -
Consider Frame Timing: Depending on the specific use case, you might want to control how long you wait between frames.
Here’s an updated version of your coroutine:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Attack : MonoBehaviour { public Vector2 boxCenter; // Center of the box collider public Vector2 halfExtents; // Half size of the box collider public float boxOrientation; // Rotation of the box collider public LayerMask layerMask; // Layer mask to filter collisions List<List> collisionsOfAllFrames = new List<List>(); IEnumerator WaitForFrames(int attackFrameCount) { for (int i = 0; i < attackFrameCount; i++) { Collider2D[] detectedCollisions = Physics2D.OverlapBoxAll(boxCenter, halfExtents, boxOrientation, layerMask); List currentFrameCollisions = new List(detectedCollisions); collisionsOfAllFrames.Add(currentFrameCollisions); yield return new WaitForEndOfFrame(); } Debug.Log("Waited for " + attackFrameCount + " frames."); // Process the collisionsOfAllFrames list as needed here } }
Key Changes:
- Use
OverlapBoxAll
: This method returns all colliders that overlap the specified box, allowing you to collect multiple collisions at once. - Store Collision Lists: Each frame’s collisions are stored in a
List
and then added to the mainList<List>
so that you can keep track of all frames’ collisions. - Initialization and Usage: Make sure to initialize
boxCenter
,halfExtents
,boxOrientation
, andlayerMask
as needed. You can call this coroutine usingStartCoroutine(WaitForFrames(attackFrameCount));
from another method, such as an attack trigger.
This setup should give you a solid base to work with collision detection across multiple frames in Unity. If you have any further questions or specific scenarios you want to discuss, feel free to ask!
has upvoted this post. February 8, 2025 at 3:35 pm #17220::There are two problems. The first is how to “extend” the attack after pressing the button. The second is how to add colliders to an array without replacing it. Unfortunately, these problems are causing me great difficulties so far. But I’m not giving up)
Do you mean you want the attack hitbox to be present even after the attack animation finishes?Regarding the colliders in an array, what are you aiming to achieve with that?
February 8, 2025 at 6:01 pm #17222::Not quite. Let’s call the attack method itself “Attack” and the attack animation “Attack_1”. In Attack, when the button is pressed and the attack silence time has passed (you can attack), a hit is registered. But the problem is that registration only happens at this moment. I want the registration to continue for some time after pressing the button (without having to press the button again), regardless of Attack_1 (I’m happy with the animation playback, it doesn’t matter here in principle, as I think it doesn’t matter. You can set it up later). For example, take circular attacks or sustained attacks (for example, in dark souls). They use the same logic, that is, after pressing the key, hits are registered for a while. About the array of colliders. This is a separate issue (or maybe a common one with the previous one). Let’s say we’ve made the “Hit” method work for a while after pressing a key. Now we need to record all the colliders that fall under our area of attack. This does not pose any problems if the method itself is instantaneous (only at the moment when the attack is pressed). When it should last for a certain amount of time, the question arises how to remember all the colliders that were hit at these points in time. This point is still unclear to me, although the previous post suggested to me that we should introduce a common array of colliders and write there from a buffer (another array of colliders), everything that got into it at some point in time. After that, there is also a problem of how to eliminate repetitions so that there is no double damage (that is, to exclude repeated hits of identical colliders).
February 8, 2025 at 10:40 pm #17223::Yes, that’s exactly what you need. Now, for some time after the attack, the collisions that were touched are collected. Now the problem is the extra damage done to the enemy. Do you know a way to remove duplicate collisions from this array (not a buffer, but a shared one)? So that there is no double damage. I think it’s possible to add non-repeating data to a new array each time to avoid double damage. But it seems this operation is a bit expensive. I wanted to clarify if there are alternatives to this approach? And thanks again, not only for the help, but also for the attached codes to make it easier to get acquainted with the new solutions!
-
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: