MAKE A ONE-BUTTON GAME USING PICO8 #4 – OBSTACLES

In this port, we will add obstacles into the block and the game will reset the player’s character position into starting position when the player’s character touch obstacles.

ADD VARIABLE AND FUNCTION FOR SUPPORT OBSTACLES IN THE BLOCK

First, we need to modify the function for creating a block by adding a variable for keeping obstacles data.

function create_block(x,y,w,h)
  return {x=x,y=y,w=w,h=h,obstacles={}}
end

Second, we add a new function to create obstacle data into the block data. currently, It only data for obstacle’s position inside the block. The value between 0 to 1. 0 = left, 1 = right

function add_obstacle(b,v)
   if (b == nil) return
   add(b.obstacles, {value=v})
end
And the last one, we need to modify the function for drawing block to support obstacle.

function draw_block(b,c)
   if (b == nil) return
   rect(b.x,b.y,b.x+b.w,b.y-b.h,c)
   
   for obs in all(b.obstacles) do
      print("✽", b.x + (b.w*obs.value), b.y - 6, 8)
   end
end

ADD FUNCTIONS FOR THE PLAYER'S CHARACTER

We need to make the player’s character interact with obstacles. We will add 2 new functions for collision detect and reset the player’s character to start position.

function player_hit_obstacle(b)

   if b == nil then return false end

   for o in all(b.obstacles) do
      local dx = player.x - (b.x + b.w * o.value)
      local dy = player.y - b.y
      local distance = sqrt(dx*dx+dy*dy)

      if distance < 3 then
         return true
      end
   end
end
function player_reset()
  player = {x=64,y=64,di=1,jump_counter=0,ground=true}
  current_block = block_list[1]
end
PUT EVERYTHING TOGETHER

We will add obstacles into a second and third block and make _update60() call function to detect collision between the player’s character and obstacles in the current block.

function _init()
   add(block_list, create_block(16,64,96,8))
   add(block_list, create_block(16,56,96,8))
   add(block_list, create_block(16,48,96,8))
   current_block = block_list[1]

   add_obstacle(block_list[2], 0.8)
   add_obstacle(block_list[3], 0.2)
   add_obstacle(block_list[3], 0.5)
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
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)
   return {x=x,y=y,w=w,h=h,obstacles={}}
end

function draw_block(b,c)
   if (b == nil) return
   rect(b.x,b.y,b.x+b.w,b.y-b.h,c)
   
   for obs in all(b.obstacles) do
      print("✽", b.x + (b.w*obs.value), b.y - 6, 8)
   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

      player.di = player.di * -1
      next_px = player.x + player.di
   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
   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
            current_block = b
            break
         end
      end
   end
end

function player_hit_obstacle(b)
   if b == nil then return false end

   for o in all(b.obstacles) do
      local dx = player.x - (b.x + b.w * o.value)
      local dy = player.y - b.y
      local distance = sqrt(dx*dx+dy*dy)

      if distance < 3 then
         return true
      end
   end
end

function player_reset()
   player = {x=64,y=64,di=1,jump_counter=0,ground=true}
   current_block = block_list[1]
end


function _init()
   add(block_list, create_block(16,64,96,8))
   add(block_list, create_block(16,56,96,8))
   add(block_list, create_block(16,48,96,8))
   current_block = block_list[1]

   add_obstacle(block_list[2], 0.8)
   add_obstacle(block_list[3], 0.2)
   add_obstacle(block_list[3], 0.5)
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
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






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

Related Posts