Directional collision rules

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
macromint
Prole
Posts: 4
Joined: Thu May 30, 2024 2:15 pm

Directional collision rules

Post by macromint »

I'm working on a basic platformer, I am very new to coding and love2d.
I've successfully built out a platformer where collisions are detected and if the player hits an enemy the player is sent back to the start of the level, but I want there to be an option for the player to kill enemies.

Is there a way for me to have sideways collisions that make the player respawn, but a collision from the player jumping on top of an enemy make the enemy disappear?

Right now I have rectangle colliders with collision classes, so example code for if a player hits an enemy is

Code: Select all

if player:enter('Danger') then
            player:setPosition(playerStartX, playerStartY)
         end
Can I change this or add new parameters to it that make a collision from the top different?
RNavega
Party member
Posts: 385
Joined: Sun Aug 16, 2020 1:28 pm

Re: Directional collision rules

Post by RNavega »

Hi macromint, welcome.

I think this can be done from the information that you have in that context, mainly the positions of both rectangles on the current frame when a collision happened and on the frame before that.

In these images the player is the red box and the enemy is the white box, and imagine that these represent the previous frame before a collision:
temp.png
temp.png (2.06 KiB) Viewed 3121 times
temp02.png
temp02.png (2.06 KiB) Viewed 3121 times
When a collision happens on the next frame, since the player rectangle was clearly above the enemy rectangle, even if both rectangles are moving, then you know that the player came from above.
By "clearly" I mean, no part of the player was below the highest point of the enemy, so the bottom of the player was completely above the blue line in that image.
You'd do the same to find horizontal collisions: if a collision happens, and on the previous frame the player was clearly to the left of the enemy (no part of the player was to the right of the enemy's leftmost part, that orange-ish line), then the player is coming from the left and bumped their right side on the enemy.
You'd do this for the right and bottom directions as well, so you can know this for all 4 sides of the rectangle.

The problem is what priority to give to each direction when a collision happens: in that image, the player is both clearly above the enemy and also clearly to the left of the enemy, so if a collision happens on the next frame, is it a horizontal or vertical collision? I think you should give priority to the vertical collision so it's easier for players to jump on enemies than it is for them to die. But maybe have some tolerance, like if the player traveled less horizontally than vertically, then up to a certain distance you consider it a vertical collision and so a success for the player, rather than a failure of them touching an enemy.
RNavega
Party member
Posts: 385
Joined: Sun Aug 16, 2020 1:28 pm

Re: Directional collision rules

Post by RNavega »

(To clarify, if the player is closer to that orange horizontal limit instead of the blue vertical limit, then you can consider the collision as vertical, since the player is already pretty close to the infinite vertical extrusion of the enemy, the condition for them to land on top of the enemy. In the opposite situation, with the player closer to the blue limit rather than the orange limit, the player is already near the infinite horizontal extrusion of the enemy, then you can consider the collision horizontal, as it takes less movement for the player to collide with the sides of the enemy than their top or bottom.)

But that's if the player is in those diagonal zones where they're both to the side and above/below the enemy, so two possible sides can be collided with.
If the player is crossing the horizontal or vertical spans, AKA the infinite extrusions of the enemy (those subtle gray lines on those images), and a collision happens, then it's clearly a collision on a single side.

There's someone else's tutorial on 2D rectangle collision for games in here, might be useful:
https://jonathanwhiting.com/tutorial/collision/
Last edited by RNavega on Fri May 31, 2024 3:37 pm, edited 2 times in total.
macromint
Prole
Posts: 4
Joined: Thu May 30, 2024 2:15 pm

Re: Directional collision rules

Post by macromint »

Awesome, thank you for the reply. Like I said I'm very new to coding so this will probably take me a while to figure out how to implement, but it was a great explanation on how to think about this and model it. I appreciate that you took the time to explain the concepts instead of just throwing code at me and going "here this might work.'
I'm gonna get started testing some stuff. I really appreciate how thought out your response was.
zingo
Citizen
Posts: 55
Joined: Mon Jan 16, 2023 7:34 am

Re: Directional collision rules

Post by zingo »

Not sure if I can add anything here (RNavega probably already described a good way to go about this, and I may just end up repeating what's already been said)...but it seems to me that you could have some variables to keep track of where the "top" of an enemy is, and where the "bottom" of the player is, so that when there is a collision, you would then have a way to determine whether or not the "bottom" of the player is far enough above the "top" of the enemy, and if so, then whether or not they are also colliding from either the left or right shouldn't matter, because the player would "technically" be stomping on the enemy anyway. Also, you may have to make sure that when the collision occurs, the player is "falling" as well (their Y speed has become a positive after they've already initiated the jump, or however you would determine that.)

Perhaps you could provide your .love file to give people a better idea of how you've set up your collision detection and player movement.

Sorry that I couldn't be more helpful, but I'm still somewhat new to coding myself, and haven't delved very much into platform physics (beyond just messing about with box2d, which is already integrated into love2d.)
User avatar
togFox
Party member
Posts: 828
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: Directional collision rules

Post by togFox »

Most objects are square or almost square so at the time of collision, I'd compare the the centre points between the two objects. If the angle is < 45 degrees then the collision if from above. Simple geometry can fix this.
Last project:
https://togfox.itch.io/hwarang
A card game that brings sword fighting to life.
Current project:
Idle gridiron. Set team orders then idle and watch: https://togfox.itch.io/idle-gridiron
macromint
Prole
Posts: 4
Joined: Thu May 30, 2024 2:15 pm

Re: Directional collision rules

Post by macromint »

Well I made some progress on it. I had the player query a small area at the bottom of its hitbox. If that query collides with an 'Enemy' collision class, it deletes that enemy.
My problem now is that it deletes every enemy, lol. and it still resets the player as if he was killed by the enemy. So now I have to figure out how to have that code override the potential 'Player died' code, and I have to figure out how to delete the individual enemy instead of all of them.

Code: Select all

local bottomLine = world:queryRectangleArea(player:getX() - 20, player:getY() + 50, 40, 2, {'Enemy'})
        for i,b in ipairs(enemies) do
            if #bottomLine > 0 then 
                b.dead = true
            end
        end 
            
        for i=#enemies, 1, -1 do
            local b = enemies[i]
            if b.dead == true then
                table.remove(enemies, i)
            end 
        end
I thought that would run through the list of individual enemies, check for the bottomLine, and then delete the one enemy that it was true for at a time. But it seems to delete all of them. Time for some more experimentation.
zingo
Citizen
Posts: 55
Joined: Mon Jan 16, 2023 7:34 am

Re: Directional collision rules

Post by zingo »

I think you would need a way to return some sort of "id" of whichever -particular- enemy is -currently- colliding, and include an additional condition that -only- that specific id should be queried.

As it is now...it would seem that -every- enemy that is within the area beneath the hitbox is being included because that is the single condition qualifying -all- of them as being "hit" (since it's checking the Y value in relation to -every- enemy, rather than just the one colliding).

So, the logic may go something like "when an enemy collides, return the id of that enemy (and -just- that enemy), set a "colliding" boolean variable for that enemy to "true". After that, cycle through the list of enemies, determine which one is colliding (if any), and -then- preform the query on that enemy alone...something like:

Code: Select all

local bottomLine = world:queryRectangleArea(player:getX() - 20, player:getY() + 50, 40, 2, {'Enemy'})
        for i,b in ipairs(enemies) do
         --here, somehow determine that the enemy is colliding
            if #bottomLine > 0 and (b.colliding) then
                b.dead = true
            end
        end 
I hope...that makes some sense. I've not done this sort of "enemy stomping" thing before, so not entirely sure what would work best.
macromint
Prole
Posts: 4
Joined: Thu May 30, 2024 2:15 pm

Re: Directional collision rules

Post by macromint »

Yeah, I thought that was what I was doing, lol. I am very new to Lua, I have gone through only one tutorial on how it works. I thought the second part of the code, the " for i =#enemies " part would make it cycle through the list of enemies and delete the one(s) that had dead == true.
But I see what you're saying, every enemy that is underneath the player technically has dead == true when the collision happens. So I'll have to read more about how tables work and how to set unique identifiers for each iteration of the enemy. Either way, I feel like I'm making progress and learning quite a bit while I figure this out. Thank you all for the comments and suggestions!
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 16 guests