Last active
July 28, 2025 23:52
-
-
Save RandyGaul/31d9c7d6ad7d15c994a362e8353158ed to your computer and use it in GitHub Desktop.
Climbing example of 2d platformer coroutine use case
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Player:climb() | |
self.climbing = true | |
self:set_facing(self.climbable_wall_facing) | |
-- Initially zero out all y-vel to "latch" onto the wall. | |
if not self.climb_sliding then | |
self.vy = 0 | |
end | |
self.vx = 0 | |
self.climbing_needs_reset = true | |
joypad_rumble(1, 0.15, 0.15, 0.25) | |
yield() | |
-- Handles all cases to exit the climbing state. | |
local was_climbing_on = collide_at(self, self.climbable_wall_facing * climb_pixel_grace, 0) | |
local function should_stop_climbing() | |
if self.input_jump:just_pressed() then | |
self:wall_jump() | |
return true | |
end | |
-- Exit if there's no more wall. | |
local dx = self.climbable_wall_facing * climb_pixel_grace | |
local climb_on = collide_at(self, dx, 0) | |
if not climb_on then | |
-- Start a little hop to just above the ledge for convenience if you've climbed up something. | |
self.vy = self.vy + 15 | |
self.vx = self.vx + 75*sign(dx) | |
self.climbing = false | |
self.climbing_fall_grace_timer = fall_grace_time | |
assert(was_climbing_on) | |
self:climb_onto_ledge(was_climbing_on) | |
return true | |
else | |
was_climbing_on = climb_on | |
end | |
-- Exit if let go of climbing trigger. | |
if not self.input_climb:down() then return true end | |
end | |
-- This happens if you slide down a wall and touch the ground. | |
::climb_again:: | |
-- Climbing state. | |
while true do | |
yield() | |
if should_stop_climbing() then | |
goto stop_climbing | |
end | |
if not self.on_ground and on_interval(0.4) then | |
joypad_rumble(1, 0.15, 0.15, 0.1) | |
end | |
if self.on_ground then | |
self.climbing_elapsed = 0 | |
end | |
-- Climbing. | |
local sign_x, sign_y = self.input_move:sign() | |
if sign_y >= 0 or sign_y <= 0 then | |
local down_boost = 1 | |
if sign_y < 0 then down_boost = 1.5 end | |
self.vy = approach(self.vy, climb_speed * sign_y * down_boost, climb_accel * DELTA_TIME) | |
else | |
self.vy = approach(self.vy, 0, climb_accel * DELTA_TIME) | |
end | |
-- Grace period to hang on the wall before sliding. | |
self.climbing_elapsed = self.climbing_elapsed + DELTA_TIME | |
if self.climbing_elapsed > climb_time then break end | |
end | |
self.climb_sliding = true | |
self.vy = min(self.vy, 0) -- Prevent weird upwards sliding. | |
-- Sliding down the wall state. | |
while true do | |
if should_stop_climbing() then | |
goto stop_climbing | |
end | |
if self.on_ground then | |
goto climb_again | |
end | |
-- Slide down wall. | |
self.vy = approach(self.vy, -wall_slide_speed, wall_slide_accel * DELTA_TIME) | |
if on_interval(0.2) then | |
joypad_rumble(1, 0.25, 0.25, 0.2) | |
end | |
::continue:: | |
yield() | |
end | |
::stop_climbing:: | |
self.climbing_fall_grace_timer = fall_grace_time | |
self.climbing = false | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment