Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Hitboxes and Rotations

I'm having some minor problems with working with rotated hitboxes on projectiles.
Let me give some information on how my hitboxes generally work:

- All projectiles have a hitbox of either of the two:
- A custom hitbox decided by custom width and height (used for projectiles that use sprites that have some glow or other effects that shouldn't be included in the actual hitbox).
OR
- A hitbox that is identical to the sprite the projectile uses.

For the second type of hitbox, there are no particular issues, but for the first type, it causes some weird problems - the reason why I consider it to be weird is because of my lack of math understanding.

Here's the code I'm using for the hitboxes and the actual visible sprites (noted as Animation):

Hitbox Property (will always be an empty rectangle if not set as the second type of hitbox)
Code:
        /// <summary>

        /// The hitbox rectangle. Can be null.

        /// </summary>

        public Rectangle Hitbox

        {

            get {

                Rectangle rect = _hitbox;

                Vector2 offset = GetOffset(rect.Width, rect.Height);

                rect.X = (int)Position.X - (int)offset.X;

                rect.Y = (int)Position.Y - (int)offset.Y;

                return rect;

            }

            set

            {

                _hitbox = value;

            }

        }

        Rectangle _hitbox = new Rectangle();

The actual hitbox. As shown, this will be set to the sprite's hitbox if the above hitbox returns empty.
Code:
public Rectangle HitboxFinal

        {

            get

            {

                // If a hitbox is provided: check if intersecting

                if (_hitbox != new Rectangle())

                    return Hitbox;

                else if (Animation != null)

                    return new Rectangle((int)Position.X - (int)GetOffset(Animation.Width, Animation.Height).X,

                        (int)Position.Y - (int)GetOffset(Animation.Width, Animation.Height).Y, Animation.Width,

                        Animation.Height);

                else

                    return new Rectangle((int)Position.X - 16,

                        (int)Position.Y - 16, 32, 32);

            }

        }

The GetOffset() method. I reckon this is where I am doing something wrong (since, you know, math..).
Code:
        public Vector2 GetOffset(int width, int height)

        {

            // If not rotation: return vector

            if (Effect.Properties.ContainsKey("rotate"))

            {

                if (Effect.Properties["rotate"].Value == "false")

                    return new Vector2(width / 2, height / 2);

            }else

                return new Vector2(width / 2, height / 2);

 

            // Set up the rotated rectangle

            RotatedRectangle rect = new RotatedRectangle(

                new Rectangle((int)Position.X, (int)Position.Y, width, height), Angle);

            rect.Origin = new Vector2(width / 2, height);

 

            // Set up the offset

            Vector2 offset = new Vector2();

 

            // Set the X-offset

            offset.X = (float)Math.Sqrt(Math.Pow(rect.UpperLeftCorner().X - rect.UpperRightCorner().X, 2) +

                Math.Pow(rect.UpperLeftCorner().Y - rect.UpperLeftCorner().Y, 2)) / 2f;

            offset.Y = (float)Math.Sqrt(Math.Pow(rect.UpperLeftCorner().X - rect.LowerLeftCorner().X, 2) +

                Math.Pow(rect.UpperLeftCorner().Y - rect.LowerLeftCorner().Y, 2)) / 2f;

 

            // Return the offset

            return offset;

        }

To explain, the "Position" vector is the center point of the projectile.
However, when the sprite rotates, the actual width and height of the sprite changes, and the hitbox seems to incorrectly function when its smaller than the sprite itself.
The code for this works relatively well, but has some slight inaccuracy which I don't really want to have there.

If anyone sees any obvious mistakes in the code, I'd appreciate any pointers.

Thanks!
 
It looks like you're making this harder than it is, each entity has a sprite and a hit box, it may be easier to give the entity a default hit box for the entity based on sprite and then on initialisation have a function to reset the entity's hitbox, that way you don't need to muck around with calculating if it already has one.

On the collision check (should be done after every step) you can rotate the point you're checking around the centre of the collision rectangle in the opposite angle of the entity's rotation, that will give you a correct grid to do an isInsideRectangle() call, the hardest part is the rotating back but there are plenty of examples on Google
 
Thing is, not all actions have a sprite associated with them, and many of these sprites have outer edges that shouldn't be included with their hit box.
Thing is, if a projectile rotates, the hitbox has to rotate in the same fashion, and to make this accurate I have to figure out the width and height (on aligned planes) after the rotation has occured.

Such as if a sprite is at the size 100 x 50 when it's being fired straight up (0 degrees), it would have the dimensions of 50 x 100 when its fired to the left or to the right, and in between those angles it would gradually change between those two values. But the hit box assigned to it could be 80 x 30 which then should align from the center point. When pointing straight up this is a simple calculation:

sprite position = Effect X - Width / 2 , Effect Y - Height / 2
hit box position = Effect X - Box Width / 2 , Effect Y - Box Height / 2

Makes the hitbox perfectly centered within the sprite and creating the result that I want.
However once the sprite gets rotated, the Width and Height value is different, but the actual values stored into those properties do not.
This is where the core of the problem lies.

I feel that the code does most of what it should do, but the hit boxes are slightly inaccurate, and I just want to get that sorted out.

If I misunderstood your proposition, please do clarify in better detail so I might understand it properly. If anything simpler would do the same and result in better detection, I wouldn't say no to it!

Thanks for the reply.
 
I did try to explain about the rotation.

Here's code to eat.
Code:
 

struct Rectangle

{

    float width;

    float height;

};

 

struct Vector2D

{

    float x;

    float y;

};

 

class Hitbox

{

private:

    Rectangle bounding;

    Vector2D offset;

public:

    Hitbox(Rectangle _bounding, Vector2D _offset) // Constructor

    {

        bounding = _bounding;

        offset = _offset;

    };

 

    Vector2D rotateAboutPivot(Vector2D point, Vector2D pivot, float radian)

    {

        float sinRad = sin(radian);   

        float cosRad = cos(radian);  

 

        // Translate point back to origin:  

        point.x -= pivot.x;   

        point.y -= pivot.y;   

 

        // Rotate point   

        Vector2D finalPoint;

        finalPoint.x = point.x * cosRad - point.y * sinRad;   

        finalPoint.y = point.x * sinRad + point.y * cosRad; 

 

        // Translate point back to original offset:

        finalPoint.x += pivot.x;  

        finalPoint.y += pivot.y; 

 

        return finalPoint;

    };

    

    bool checkHit(Vector2D point, Vector2D entityPosition, float entityAngle)

    {

        float width2 = width / 2.0f;

        float height2 = height / 2.0f;

        

        point = rotateAboutPivot(point, entityPosition, entityAngle * 0.0174532925f);

        

        // Check if point x and y are within the bounding box

        if ((point.x < offset.x + point.x + width2)

        && point.x > offset.x - point.x - width2)

        point.y < offset.y + point.y + height2)

        point.y > offset.y - point.y - height2))

        {

            return true;

        }

        return false;

    };

};

 

Hope you can make sense of that for your language here.
 
Thanks for the code. That is probably going to be very useful.
Although, since all my angle values are always in radians, I assume the "entityAngle * 0.0174532925f" can just be changed into "entityAngle" with no conversion.

Thanks for this, looks just about right.
 
Oh yes it should be -entityAngle so it is rotated the other direction to match the bounding box that is always in fixed position, otherwise it is sending the point further round the bounding box.

There is also probably a way to eliminate the sin and cos to improve performance, lookup tables is one but something tells me you can replace that with some thing else entirely that would perform better.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top