Hello,
I’m trying to make a platformer game, so I started to learning how to use collision in Defold and how to resolve them. I also checked out the platformer tutorial and the pixelLinePlateformer exemple .
I was happy with my results until I found a bug…
It occurs when my player falls after a jump, sometimes it doesn’t stop on the ground and just goes through it. I tried to solve the probleme myself, but I haven’t found a solution yet. I think it mostly happens when the player falls from a great height.
I’m using Defold 1.9.8. Below, you can find my player’s script, or you can check my repository on GitHub: GitHub - Kevallion/MetroidVania.
Thanks in advance for your help!
local input_left = hash("move_left")
local input_jump = hash("jump")
local input_right = hash("move_right")
local anim_run = hash("run")
local anim_idle = hash("idle")
local anim_jump = hash("jump")
local anim_fall = hash("fall")
-- physics variable
local gravity = -1800
local acceleration = 8
local deceleration = 6
local jump_force = 600
local contact_point_response = hash("contact_point_response")
local group_ground_collision = hash("ground")
-- function to update animation and save it
local function play_animation(self,pAnim)
if self.anim ~= pAnim then
sprite.play_flipbook("#sprite", pAnim)
self.anim = pAnim
end
end
-- function to update animation
local function update_animation(self)
if self.dir ~= 0 then
sprite.set_hflip("#sprite", self.dir < 0)
end
if self.isOnFloor then
if math.abs(self.dir) > 0 then
play_animation(self, anim_run)
else
play_animation(self, anim_idle)
end
else
local dir_velocity = vmath.normalize(self.velocity)
if dir_velocity.y > 0 then
play_animation(self, anim_jump)
elseif dir_velocity.y < 0 and self.velocity.y < -100 then
play_animation(self, anim_fall)
end
end
end
function init(self)
-- get_input focus
msg.post(".", "acquire_input_focus")
-- msg.post("@render:", "use_camera_projection")
-- init variable
self.anim = nil
self.maxSpeed = 200
self.jumpForce = jump_force
self.velocity = vmath.vector3()
self.correction = vmath.vector3()
self.dir = 0
self.isOnFloor = false
end
-- function to lerp the velocity x and apply the current velocity
local function move(self,dt)
-- if the player is pressing left or right
if self.dir ~= 0 then
local desired_velocity_x = self.dir * self.maxSpeed
self.velocity.x = vmath.lerp(dt * acceleration, self.velocity.x, desired_velocity_x)
else
self.velocity.x = vmath.lerp(dt * deceleration, self.velocity.x, 0)
end
-- apply velocity
go.set_position(go.get_position() + (self.velocity * dt))
end
function fixed_update(self, dt)
self.velocity.y = self.velocity.y + (gravity * dt)
-- move player
move(self, dt)
update_animation(self)
-- restet volatile variable
self.dir = 0
self.correction = vmath.vector3()
self.isOnFloor = false
end
local NORMAL_THRESHOLD = 0.7
local function handle_obstacle_contact(self, normal, distance)
if normal.y < NORMAL_THRESHOLD and normal.y > -NORMAL_THRESHOLD then
normal.y = 0
end
if normal.x < NORMAL_THRESHOLD and normal.x > -NORMAL_THRESHOLD then
normal.x = 0
end
if distance > 0 then
local projection = vmath.project(self.correction, normal * distance)
if projection < 1 then
local compensation = (distance - (distance * projection)) * normal
go.set_position(go.get_position() + compensation)
self.correction = self.correction + compensation
end
end
if math.abs(normal.x) > NORMAL_THRESHOLD then
self.velocity.x = 0
end
if normal.y > NORMAL_THRESHOLD then
self.isOnFloor = true
self.velocity.y = 0
end
if normal.y < 0 then
self.velocity.y = 0
end
end
function on_message(self, message_id, message, sender)
if message_id == contact_point_response then
if message.group == group_ground_collision then
handle_obstacle_contact(self,message.normal, message.distance)
end
end
end
function on_input(self, action_id, action)
if action_id == input_left then
self.dir = -1
elseif action_id == input_right then
self.dir = 1
end
if action_id == input_jump and action.pressed then
if self.isOnFloor then
self.velocity.y = self.jumpForce
self.isOnFloor = false
end
end
end