MAKE A ONE-BUTTON GAME USING PICO8 #5 – CAMERA
This week, we will work on moving the camera to follow the player’s character when it changes the current block. The code that need to add can divide into 2 parts.
1. Move the camera to the target position
2. Detect when changing the current block and calculate for the target position.
MOVING CAMERA
For moving camera, It requires new variables to keep the current position and target position.
camera_data = {x=0,y=0,target_x=0,target_y=0}
And a new function for calculating the target position from a given block data. Why we need this function? because we want the target position shows at the center of the screen. It means we need to add offset values to the target position.
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
Now we have variables and a function for calculating the target position for the camera. we will implement a function to update the camera position.
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
CHANGE THE CAMERA'S TARGET POSITION
The last part is about to decide when to start moving the camera. The condition for changing is every time when the player’s character changes the current block and distance between the camera’s target position and center of the current block exceed the threshold.
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
PUT EVERYTHING TOGETHER
We will start modifying code follow these steps.
1. Replacing the places that we assign value to the current block variable directly into set value via the new function.
2. Add update_camerat() into _update60()
3. Add more blocks in _init()
4. Modify player_hit_obstacle() to use distance()
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 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
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
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))
add(block_list, create_block(16,56,96,8))
add(block_list, create_block(16,48,96,8))
add(block_list, create_block(16,40,96,8))
add(block_list, create_block(16,32,96,8))
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










