Hello there! Now I’m testing things about platform game and the question arises when I tried to make the one-way platforms. The final effect I want is as this site described:
On the x axis, the tile is never an obstacle
On the y axis, the tile is only an obstacle if, prior to the movement, the player was entirely above it (that is, bottom-most coordinate of player was at least one pixel above top-most coordinate of one-way platform). …
And I don’t only want the player to step on but also to step off the platform.
I’m using the contact_point_response message and my setup is a tile map + a game object (as the player), which is popular and typical. I have considered a couple of ways, but none of them can match my need perfectly.
I have checked britzl’s public example, there’re two problems:
This example doesn’t mention the stepping off;
If two platforms are close and the player contacts with both of them, there’ll be a bug (see the demo below).
I have checked this post and this tutorial (btw. why is it marked as “old”?) as well - both are only about stepping on the platform.
The site mentioned above gives an algorithm too. It’s simple, but totally different from the collision detection which I’m using now.
Can you explain what you mean by wanting to be able to step off as well as step on? Thank you for that link you posted, seems like a very detailed analysis of different approaches.
My need is: When the player is standing on a platform, he’s able to get off that platform to get lower (perhaps to return to the ground), for example, by pressing the DOWN button.
There’s a demo showing the result I want (Notice: it doesn’t mean that I have reached my goal. The effect showed in this video is made by modifying the code in that public example by britzl a little bit and problem still exists. See the 2nd “problem” in my description)
This kind of setting is no new thing and one can see it in plenty of platform games.
(I don’t know if this type of platforms is still called “one-way platforms”)
I haven’t done this with Defold, only with Love2D, so I can’t give you working code, but I have some tips on what worked for me:
Keep a table of all the one-way platforms that you are currently in contact with, each with a true/false value for whether you are falling through that platform or not. (Doing it per-platform solves problem #2.)
The key is to remember the last state (for each platform). Never fall through if you were colliding last frame, never collide if you were falling through last frame.
Obviously, just ignore contacts from platforms that you are falling through.
To “step off”, simply go through the list of platforms and set them all to the “falling through” value.
In my case, I did this when pressing “jump” while “down” was pressed.
For simpler controls, you might set every new platform to “falling through” if down is currently pressed (after setting all of them on the “down” press event).
Indeed, taking focus on every contacted platform helps solve the problem. (It’s like a modification of britzl’s example.)
These are some parts of my code of the player’s script:
local IGNORED = true
...
function update(self, dt)
...
-- copy from contacted platform states of last frame
self.contacted_platform_states_last_frame = {}
for index, platform in pairs(self.contacted_platform_states) do
self.contacted_platform_states_last_frame[index] = platform
end
self.contacted_platform_states = {}
end
function on_input(self, action_id, action)
...
elseif action_id == hash("move_down") then
for index, _ in pairs(self.contacted_platform_states) do
self.contacted_platform_states[index] = IGNORED
end
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("contact_point_response") then
if message.group == hash("normal_obstacle") then
handle_geometry_contact(self, message)
elseif message.group == hash("oneway_obstacle") then
local bound_left, bound_bottom, bound_width, bound_height = tilemap.get_bounds("main:/map#main_map")
local platform = absolute_coord_to_map_coord(self, message.position, bound_left, bound_bottom)
local index = platform.x * bound_width + platform.y
if self.contacted_platform_states_last_frame[index] ~= IGNORED then
if message.normal.y > 0 then
self.contacted_platform_states[index] = not IGNORED
else
self.contacted_platform_states[index] = IGNORED
end
else
self.contacted_platform_states[index] = IGNORED
end
if self.contacted_platform_states[index] == not IGNORED then
handle_geometry_contact(self, message)
end
end
end
end
(By the way, I have also used LÖVE2D for a while before using Defold!)