MAKE A ONE-BUTTON GAME USING PICO8 #6 – BLOCK WITH NO WALLS
In this post, we will modify the block data structure to support remove left/right walls from the block. It will add more challenge to the game. What we need to do to support this feature.
– modify the function for creating block data.
– modify the function for drawing block.
– modify the function for checking collision between the player’s character and the block.
– add a condition for checking when the player’s character runs outside the block. It should start appling gravity.
ADD VARIABLES TO BLOCK DATA
It needs to have 2 boolean variables for left/right walls. If the value is false then it means no wall for that side.
function create_block(x,y,w,h,left_wall,right_wall) return {x=x,y=y,w=w,h=h,obstacles={},left_wall=left_wall,right_wall=right_wall} end
SUPPORT DRAWING BLOCK WITHOUT WALL
Currently, we draw the block using “rect()” function. This function uses for drawing a rectangle on the screen. It doesn’t work for drawing some parts of the rectangle. we will use “line()” for drawing each side of the block instead.
function draw_block(b,c)
if (b == nil) return
line(b.x,b.y,b.x+b.w,b.y,c)
line(b.x,b.y-b.h,b.x+b.w,b.y-b.h,c)
if b.left_wall == true then
line(b.x,b.y,b.x,b.y-b.h,c)
end
if b.right_wall == true then
line(b.x+b.w,b.y,b.x+b.w,b.y-b.h,c)
end
for obs in all(b.obstacles) do
print("✽", b.x + (b.w*obs.value), b.y - 6, 8)
end
end
PLAYER'S CHARACTER WILL NOT CHECK COLLISION WHEN RUN TO "NO WALL"
We need to add conditions in the “player_running()” function to make it support block with no left/right walls. When the player’s character hit the wall. It will use the current running direction and status of wall/no wall from block data to decide that it should hit the wall or not.
function player_running() local next_px = player.x + player.di if is_inside_block(player.x, player.y, current_block) == true and is_inside_block(next_px, player.y, current_block) == false then if player.di == 1 and current_block.right_wall == false then elseif player.di == -1 and current_block.left_wall == false then else player.di = player.di * -1 next_px = player.x + player.di end end player.x = next_px end
APPLY GRAVITY WHEN THE PLAYER'S CHARACTER RUNS OUTSIDE THE BLOCK
Currently, The code starts applying gravity when the player’s character jump. If it runs outside the block without jumping. It will keep running without falling. It can fix by adding a condition to check that if the player’s character runs outside the block. It will stop staying on the ground.
function player_apply_gravity() local next_py = player.y if player.ground == false then if player.jump_counter <= 0 then next_py += 1 if is_inside_block(player.x, player.y, current_block) == true and is_inside_block(player.x, next_py, current_block) == false then next_py = player.y player.ground = true end end else if is_inside_block(player.x, player.y, current_block) == false then player.ground = false end end player.y = next_py end
RESULT
SOURCE CODE
player = {x=64,y=64,di=1,jump_counter=0,ground=true} current_block = nil block_list = {} function create_block(x,y,w,h,left_wall,right_wall) return {x=x,y=y,w=w,h=h,obstacles={},left_wall=left_wall,right_wall=right_wall} end function draw_block(b,c) if (b == nil) return line(b.x,b.y,b.x+b.w,b.y,c) line(b.x,b.y-b.h,b.x+b.w,b.y-b.h,c) if b.left_wall == true then line(b.x,b.y,b.x,b.y-b.h,c) end if b.right_wall == true then line(b.x+b.w,b.y,b.x+b.w,b.y-b.h,c) end for obs in all(b.obstacles) do print("✽", b.x + (b.w*obs.value), b.y - 6, 8) end end function distance(x1,y1,x2,y2) local dx = x1-x2 local dy = y1-y2 local distance = sqrt(dx*dx+dy*dy) return distance end function change_current_block(b) current_block = b local d = distance(camera_data.target_x + 64, camera_data.target_y + 64, current_block.x + current_block.w/2, current_block.y - current_block.h/2) _debug = d if d > 12 then set_camera_target(current_block) end end function add_obstacle(b,v) if (b == nil) return add(b.obstacles, {value=v}) end function is_inside_block(x,y,b) if (b == nil) return if x >= b.x and x < b.x + b.w then if y <= b.y and y > b.y - b.h then return true end end return false end function player_running() local next_px = player.x + player.di if is_inside_block(player.x, player.y, current_block) == true and is_inside_block(next_px, player.y, current_block) == false then if player.di == 1 and current_block.right_wall == false then elseif player.di == -1 and current_block.left_wall == false then else player.di = player.di * -1 next_px = player.x + player.di end end player.x = next_px end function player_jumping() if btnp(4) then if player.jump_counter == 0 and player.ground == true then player.jump_counter = 20 player.ground = false end end local next_py = player.y if player.jump_counter > 0 then player.jump_counter -= 1 if player.jump_counter > 10 then next_py = player.y - 1 else next_py = player.y end end player.y = next_py end function player_apply_gravity() local next_py = player.y if player.ground == false then if player.jump_counter <= 0 then next_py += 1 if is_inside_block(player.x, player.y, current_block) == true and is_inside_block(player.x, next_py, current_block) == false then next_py = player.y player.ground = true end end else if is_inside_block(player.x, player.y, current_block) == false then player.ground = false end end player.y = next_py end function player_find_new_current_block() if player.ground == false and is_inside_block(player.x, player.y, current_block) == false then for b in all(block_list) do if is_inside_block(player.x, player.y, b) == true then change_current_block(b) break end end end end function player_hit_obstacle(b) if b == nil then return false end if is_inside_block(player.x, player.y, current_block) == false then return false end for o in all(b.obstacles) do local d = distance(player.x, player.y, (b.x + b.w * o.value), b.y) if d < 3 then return true end end end function player_reset() player = {x=64,y=64,di=1,jump_counter=0,ground=true} change_current_block(block_list[1]) end camera_data = {x=0,y=0,target_x=0,target_y=0} function set_camera_target(b) if b == nil then return end local block_center_x = b.x + b.w/2 local block_center_y = b.y - b.h/2 camera_data.target_x = block_center_x - 64 camera_data.target_y = block_center_y - 64 end function update_camera() if camera_data.x > camera_data.target_x then camera_data.x -= 1 elseif camera_data.x < camera_data.target_x then camera_data.x += 1 end if camera_data.y > camera_data.target_y then camera_data.y -= 1 elseif camera_data.y < camera_data.target_y then camera_data.y += 1 end camera(camera_data.x, camera_data.y) end function _init() add(block_list, create_block(16,64,96,8,true,true)) add(block_list, create_block(16,56,96,8,true,false)) add(block_list, create_block(16,48,96,8,false,false)) add(block_list, create_block(16,40,96,8,true,true)) add(block_list, create_block(16,32,96,8,false,true)) player_reset() add_obstacle(block_list[2], 0.8) add_obstacle(block_list[3], 0.2) add_obstacle(block_list[3], 0.5) add_obstacle(block_list[5], 0.7) end function _update60() player_running() player_jumping() player_apply_gravity() player_find_new_current_block() local hit_result = player_hit_obstacle(current_block) if hit_result == true then player_reset() end update_camera() end function _draw() cls(0) print("웃", player.x-3, player.y - 5, 7) for b in all(block_list) do draw_block(b, 7) end end