Collision library that take rotation in to account

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
ddabrahim
Party member
Posts: 183
Joined: Mon May 17, 2021 8:05 pm
Contact:

Re: Collision library that take rotation in to account

Post by ddabrahim »

Wouldn't it be easier to switch to using center point for your stuff rather than the other way round? Just saying.
It would be easier but this is not what I want. Lets say you have a turret on the ground facing up and you can rotate and move left and right to shoot the planes in the sky. You don’t want to rotate the turret at center point. You want to rotate the turret at the bottom at ground level.

So when I rotate the sprite I apply offset and when I rotate the collision body, I need to apply the same offset.

The problem is that if I move the collision body it is override the offset and this is not what I want. I want to keep the offset of the rotation even if I move the body so I can rotate the turret at ground level and also move it left and right while rotating at ground level. Collision libs doesn’t seems to support this but this is what I want.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Collision library that take rotation in to account

Post by zorg »

So, let's forget for now about any separate collision related bodies or shapes. You have one rectangular sprite for the cannon.
It has some x and y coords that correspond to some point on itself; center / topleft, doesn't matter which.

For movement, you calculate how much it needs to move, and in what direction, and then you modify the x,y coords with the dx,dy offsets.
For rotation (regardless of where the turret is), you take the anchor point rx,ry you want to rotate the turret along, then you do the rotation.
You **do not** overwrite the anchor point nor the position when you rotated the turret, because then you'll have a bad time managing relative rotations considering the turret isn't rotated along its center point, as you said; just save the rotation angle, and mess with that, then apply it with rotation.

All that should work fine with sprites. Colliders should be done similarly, and it should work out the same.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
ddabrahim
Party member
Posts: 183
Joined: Mon May 17, 2021 8:05 pm
Contact:

Re: Collision library that take rotation in to account

Post by ddabrahim »

You **do not** overwrite the anchor point nor the position when you rotated the turret, because then you'll have a bad time managing relative rotations considering the turret isn't rotated along its center point, as you said; just save the rotation angle, and mess with that, then apply it with rotation.

All that should work fine with sprites. Colliders should be done similarly, and it should work out the same.
For the sprite I have implemented my own class and methods that keep track of the angle, offset and draw the sprite relative to offset. Even if I change offset, it does not alter position, rotation value, it is always the same only drawn relative to offset. So I think I am good with the sprite.

I have also implemented my own rectangle collider that works nicely with the sprites. But the math to calculate rotation is beyond me. In theory I need only the 4 corners and check if any of the corner points intersect, overlap, I did also find a book about this topic but the math is way over my head right now.

Figured I look in to 3rd party libs but using them is not as straight forward as I was hoping. Almost but not quite.
I see what I can come up with.

Thank you for the suggestion.
User avatar
ddabrahim
Party member
Posts: 183
Joined: Mon May 17, 2021 8:05 pm
Contact:

Re: Collision library that take rotation in to account

Post by ddabrahim »

Okay. After going through every possible options, libraries to check collision without reading any documentation to make sure I struggle as much as possible, I managed to find a hack in HardonCollider to get it work the way I want it.

The solution I've found is so simple I can't believe it, I share it in case someone need something similar.

So when we create a rectangle collider, it is calculate the center of the shape and use this value every time we move the collider.
So all I have to do is after I create a rectangle collider, Instead applying offset in the setRotation() method every single time I rotate it, I apply the offset directly on the center value.

rectangle._polygon.centroid.x = new X with offset
rectangle._polygon.centroid.y = new Y with offset

I need to do this only once and after every time I move, rotate or scale the rectangle collider, it is using this new center value with the offset.
I can rotate, move the collider from any point just like my sprites, and works perfectly I didn't noticed any problems so far. Collision, movement, rotation and scale is working as I expect it.

Hope it stay that way and it is going to help someone looking for a similar solution.

Thank you for all the help.
User avatar
ddabrahim
Party member
Posts: 183
Joined: Mon May 17, 2021 8:05 pm
Contact:

Re: Collision library that take rotation in to account

Post by ddabrahim »

I have discovered an other "limitation" of HardonCollider that did not really fit my system and that is if I was calling polygon:scale() multiple times, it is constantly multiplied the scale and keep increased the size of the collider.

For example if I set :scale(2) and then scale(3) inside a loop maybe, HardonCollider basically do 2*1 and then 3*2 and then 3*6 and then 3*18 and just keep going forever. But this is not what I wanted.
What I want if I set scale 2 and then 3 even if I keep repeat inside a loop, the scale always remain the same it does not multiply constantly, so if I set it to 2 it is 2*1 and if I set it 3 it is 3*1 instead of 2*1 and 3*2, 3*6 and so on.

I decided to handle this in my library instead of changing the way HC works internally and I have implemented my own setPosition, setRotation and setScale methods for this purpose only.

In case someone hit the same wall, this is the code, note that I have no idea how the code works I did just copy most of it from HC itself and I was using common sense to add what I need without actually understanding the math behind it:

Inside constructor or at the very beginning of your code

Code: Select all

hc = require "HardonCollider"
vector = require "HardonCollider.vector-light"
t = hc.rectangle(x,y,width,height)

--set center of collider to be at the origin of the object
--it is necessary hack so after we can move, rotate, scale the collider around the origin point instead of the center
t._polygon.centroid.x = _object:getX()
t._polygon.centroid.y = _object:getY()
t._polygon.centroid.ix = _object:getX() --we also need the initial position so we can reset when we change the scale
t._polygon.centroid.iy = _object:getY()
setPosition

Code: Select all

t.setPosition = function(self, _x, _y)
        local cx,cy = self._polygon.centroid.x, self._polygon.centroid.y
        local x = _x - cx
        local y = _y - cy
        local icx,icy = self._polygon.centroid.ix, self._polygon.centroid.iy
        local ix = _x - icx
        local iy = _y - icy
	    
        for i,v in ipairs(self._polygon.vertices) do
            v.x = v.x + x
            v.y = v.y + y
            v.ix = v.ix + ix
            v.iy = v.iy + iy
        end

        --apply position also to the center point
        self._polygon.centroid.x = self._polygon.centroid.x + x
        self._polygon.centroid.y = self._polygon.centroid.y + y
        self._polygon.centroid.ix = self._polygon.centroid.ix + ix
        self._polygon.centroid.iy = self._polygon.centroid.iy + iy
end
setRotation

Code: Select all

t.setRotation = function(self, _rotation)
        local angle = math.rad(_rotation) - self._rotation
        self._rotation = self._rotation + angle
        local cx,cy = self._polygon.centroid.x, self._polygon.centroid.y
        local icx,icy = self._polygon.centroid.ix, self._polygon.centroid.iy

        for i,v in ipairs(self._polygon.vertices) do
            -- v = (v - center):rotate(angle) + center
            v.ix,v.iy = vector.add(icx,icy, vector.rotate(angle, v.ix-icx, v.iy-icy))
            v.x,v.y = vector.add(cx,cy, vector.rotate(angle, v.x-cx, v.y-cy))
        end

        --apply rotation also to the center point
        local v = self._polygon.centroid
        v.ix,v.iy = vector.add(icx,icy, vector.rotate(angle, v.ix-icx, v.iy-icy))
        v.x,v.y = vector.add(cx,cy, vector.rotate(angle, v.x-cx, v.y-cy))
end
setScale

Code: Select all

t.setScale = function(self, s)    
        local cx,cy = self._polygon.centroid.x, self._polygon.centroid.y
        for i,v in ipairs(self._polygon.vertices) do
            -- v = (v - center) * s + center
            --before doing anything, reset vertices back to initial position
            v.x = v.ix
            v.y = v.iy
            --now we can apply new scale
            v.x,v.y = vector.add(cx,cy, vector.mul(s, v.x-cx, v.y-cy))
        end
end
I do realise it is not perfect and ugly and I don't really understand the math, but it works and I hope it is going to be useful for some people who struggling with vector math and collision as much as I do.

With this hack, majority of collision related things works fine now I think. I can move, rotate, scale as much as I want and collision detection is working as expected now.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 61 guests