Hoping you are all doing great, I was trying to implement slopes in the runner tutorial, and I want to know if anyone has tried it before, because but I don’t get it…
I looked into the Platypus engine by @Britzl, but the slope implementation is totally different, in the runner tutorial the “hero” is static (velocity.x = 0) and the “ground” is moving, and in Platypus, the ground is static and the hero is moving.
But @Britzl specifies the concept very well in the comments:
- detect if hero is moving up or down the slope?
- if slope_normal.x > 0 and the hero is going to the RIGHT then
move up - push up
the right amount depends on how the slope (goes?)
too much = airborne
too little = pushing into slope
move down - push down
So the concept is there and my idea is to have another contact group for the ground, let’s say “slope”, and then modify the message response:
function on_message(self, message_id, message, sender) if message_id == hash("contact_point_response") then -- check if we received a contact point message. One message for each contact point if message.group == hash("geometry") then handle_geometry_contact(self, message.normal, message.distance) elseif message.group == hash("slope") then handle_slope_contact(self, message.normal, message.distance) end end end
If we don’t do anything the hero bounces and is projected forward…
Here’s how the function is going till now
local function handle_slope_contact(self, normal, distance) local movement = vmath.vector3() print("handle_slope_contact", normal, distance, self.velocity, movement) -- moving up or down the slope? if normal.x > 0 then -- moving down movement.y = -self.velocity.x * math.abs(normal.x) movement.x = self.velocity.x * normal.y print("SLOPE DOWN?", movement) else -- moving up local ratio = 1 - math.abs(normal.x / normal.y) print("SLOPE UP?", ratio, movement, self.velocity, normal) movement.y = -self.velocity.x * normal.x * ratio movement.x = self.velocity.x * normal.y print("SLOPE UP->", ratio, movement) end -- project the correction vector onto the contact normal -- (the correction vector is the 0-vector for the first contact point) local proj = vmath.dot(self.correction, normal) -- calculate the compensation we need to make for this contact point local comp = (distance - proj) * normal -- add it to the correction vector self.correction = self.correction + comp -- apply the compensation to the player character go.set_position(go.get_position() + comp) -- check if the normal points enough up to consider the player standing on the ground -- (0.7 is roughly equal to 45 degrees deviation from pure vertical direction) -- (1 is equal to 0 degrees deviation from pure vertical direction = flat horizon) if normal.y > 0.7 then self.ground_contact = true end -- project the velocity onto the normal proj = vmath.dot(self.velocity, normal) -- if the projection is negative, it means that some of the velocity points towards the contact point if proj < 0 then -- remove that component in that case self.velocity = self.velocity - proj * normal end end
It’s not working because I’m really doing nothing yet…
Following the Platypus example, in the main script.update we have:
function update(self, dt) ... if input.is_pressed(RIGHT) then self.platypus.right(ground_contact and 120 or 100) --where ground_contact is true or false ... self.platypus.update(dt)
And in the Lua module we have, first the direction input:
--- Move the game object right -- @param velocity Horizontal velocity (a number, not a vector) function platypus.right(velocity) ... if slope_normal then -- moving up or down the slope? -- the right amount depends on how the slope -- to much = airborne -- too little = pushing into slope movement.y = ... movement.x = ... else movement.x = velocity end
And then the actual platypus update:
--- Call this every frame to update the platformer physics -- @param dt function platypus.update(dt) ... -- move the game object local distance = (platypus.velocity * dt) + (movement * dt) local position = go.get_position() go.set_position(position + distance)
So the slope dampens the displacement, because the hero moves, but again, in the Runner Tutorial the hero does not move, it’s the ground that moves…
Then… Shall I just zero-out the x speed?..
What do you think?