Wednesday, March 16, 2016

xna - How to "swing" bounding box and update collision for sprite swinging a weapon?


I have a simple question about sprite swinging weapons. I am making an RPG and would like something other than stabby-swords, so why not swinging swords?


I have a bounding rectangle for them, and the player equips them. Great, but I cannot grasp around my head how to swing both the sprite AND the bounding box (in XNA).


The sprite is easy, I specify it's origin and rotate by a specified amount over a certain amount of time (the swing time), but the bounding rectangle poses another issue for me.



Edit: A bit of clarity on my swinging animation. It's basically the player holding out their arm and the weapon swings in a curve from about +45 degree angle to a -45 degree angle.



Answer



Top-down Zelda style? One way to approach and simplify the problem is to instead of using an entire bounding box for the sword, reduce it to just one or two points of contact (lying inside the sword) and rotate them instead. In fact, the tip of the sword should be more than enough to detect most hits!


I've seen this used before in a few games. For instance this Muramasa-like sidescroller game made in XNA used points to handle player-enemy collisions. If I remember correctly from one of his YouTube comments, he placed collision points manually in each frame of the animations, and then uses them to detect hits with enemies.


In your case there's not much variation between frames. Just assign a single point to the sword's tip. When performing a stab, move that point back and forth along the player's Forward vector. When performing a slash, rotate it around the player. That's the only tricky part, which I'll describe below - rotating the point around the player no matter what transformations he has.




Implementation - How to rotate a point around the player


The easiest way to rotate a point around the player is to start with its definition in local space, i.e. in relation to the player, and then apply a series of transformations to get it into world space. This is not too hard to achieve. Here's a possible implementation:


(Step 1)


Calculate the player's world matrix. This is just a regular SRT matrix (scale-rotation-transform). Here's an example:



private Matrix GetPlayerWorldMatrix()
{
return Matrix.CreateScale(_playerScale, _playerScale, 1f) *
Matrix.CreateRotationZ(_playerRotation) *
Matrix.CreateTranslation(new Vector3(_playerPosition, 0f));
}

If your player can't rotate and/or scale just remove the corresponding lines.


(Step 2)


Start with the sword's position in local space, rotate it, and then apply the player's transform to it in order to get the final, world space position. It's simpler than it looks! Here's the code:



Vector2 localSword = new Vector2(0, _swordDistance);
Matrix swordMatrix = Matrix.CreateRotationZ(_swordRotation) * GetPlayerWorldMatrix();
Vector2 swordPosition = Vector2.Transform(localSword, swordMatrix);

All you need to do is interpolate the _swordRotation value when doing the swing.


(Step 3)


In my case I used the swordPosition for rendering so that you could see where it's placed, but in your case you should use that position for collision detection and hitting your mobs. Check the video and source code below for more details.


Video: http://www.youtube.com/watch?v=JoTxu-yiJKg


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...