首先,让我们回顾一下目前的进展。我们的初始原型计划是这样的:我们完成了性能优化,确定了子弹的数量(大约500颗),以及这些背景元素对性能的影响(大约占用了25%的预算)。我们还完成了评分原型的制作,现在可以制作理论上无限长的关卡,尽管实际制作时关卡可能会变得相当重复。我们确定了一个良好的关卡目标长度是6分钟,并且已经开发了实现这一目标的技术。
接下来的任务
接下来,我们需要创建一个紧凑的瓦片集,并计划制作第五个原型,即结合滚动和移动原型的关卡。但今天,我们的主要任务是制作第三个原型:确保基本的移动和射击感觉良好。
实现基本移动
为了实现这一目标,我们首先创建了一个新的文件,并定义了几个基本的函数:update
、draw
和function
。然后,我设置了一个飞船精灵,并创建了两个变量px
和py
来控制飞船的位置。接下来,我使用键盘按键来控制飞船的移动,并设置了一个速度变量spd
来调整飞船的移动速度。
pico-8 cartridge // http://www.pico-8.com
version 41
__lua__
-- t: make basic movement feel nice
-- t: normalized diagonals
-- t: make shooting feel nice!
-- 0 - stop
-- 1 - left
-- 2 - right
--3 - l+r = stop
-- 4 - up
-- 5 - diag l/u
-- 6 - diag r/u
--7 - l+u+r = u
-- 8 - down
-- 9 - diag l/d
-- 10 - diag r/d
--11 - l+d+r = d
--12 - u+d = stop
--13 - l+u+d = l
--14 - r+u+d = r
-----
-- 1 - ⬅️
-- 2 - ➡️
-- 3 - ⬆️
-- 4 - ⬇️
-- 5 - ⬅️⬆️
-- 6 - ⬆️➡️
-- 7 - ➡️⬇️
-- 8 - ⬅️⬇️
butarr={1,2,0,3,5,6,3,4,8,7,4,0,1,2,0}
dirx={-1,1, 0,0, -1, 1,1,-1 }
diry={ 0,0,-1,1, -1,-1,1,1 }
butarr[0]=0
function _init()
px,py=64,64
spd=0.3
cls(0)
end
function _draw()
cls(12)
--spr(5,px,py,2,2)
pset(px,py,8)
local btnv=btn()&0b1111
print(btn(),5,5,7)
print(btnv,5,11,7)
print(butarr[btnv],5,17,7)
if butarr[btnv]>=5 then
print("diaginal",5,23,7)
end
end
function _update60()
local dir=butarr[btn()&0b1111]
if dir>0 then
px+=dirx[dir]*spd
py+=diry[dir]*spd
end
end
__gfx__
00000000000000011000000000000001100000000000000110000000000000011000000000000001100000000000000000000000000000000000000000000000
00000000000000167100000000000016710000000000001661000000000000167100000000000016710000000000000000000000000000000000000000000000
00700700000000111d100000000000111d1000000000011111100000000001d111000000000001d1110000000000000000000000000000000000000000000000
00077000000001ccc1100000000001ccc1100000000001cccc1000000000011ccc1000000000011ccc1000000000000000000000000000000000000000000000
0007700000001c77cc11000000001c77cc11000000001c77ccc10000000011c77cc10000000011c77cc100000000000000000000000000000000000000000000
0070070000001c7c1c11000000001c7c1c11000000001c7cc1c10000000011c7c1c10000000011c7c1c100000000000000000000000000000000000000000000
0000000000001c111c11100000011c111c11100000111c1111c11100000111c111c11000000111c111c100000000000000000000000000000000000000000000
0000000000001c111c17100000011c111c17100000171c1111c17100000171c111c11000000171c111c100000000000000000000000000000000000000000000
0000000000011cc17116100000161cc1171610000016117117116100000161711cc16100000161171cc110000000000000000000000000000000000000000000
000000000001d1c711d6d1000016d1c77116d10001d6d117711d6d10001d61177c1d6100001d6d117c1d10000000000000000000000000000000000000000000
00000000001ddd111d6d7d1001dddd1111dd6710176d6d1111d6d6710176dd1111dddd1001d7d6d111ddd1000000000000000000000000000000000000000000
00000000001dd6ddd6d66d1001dd66dddd6d66101666d6dddd6d66610166d6dddd66dd1001d66d6ddd6dd1000000000000000000000000000000000000000000
00000000001d676676d6dd1001d6676676d6dd101dd6d676676d6dd101dd6d6766766d1001dd6d676676d1000000000000000000000000000000000000000000
00000000000176d167d1110000117dd1171111000111171661711110001111711dd7110000111d761d6710000000000000000000000000000000000000000000
000000000000151155d110000001655155d11000000161511516100000011d551556100000011d55115100000000000000000000000000000000000000000000
00000000000001111111000000001111111100000000111111110000000011111111000000001111111000000000000000000000000000000000000000000000
遇到的问题:对角线移动时的“鹅卵石”现象
在测试过程中,我发现当飞船以较慢的速度沿对角线移动时,会出现一种不连贯的、类似“鹅卵石”的视觉效果。这是因为PICO-8的分辨率较低,像素较大,当飞船不处于像素中心时,沿对角线移动会触及多个像素,导致移动路径看起来不连贯。
解决方案:重写控制系统
为了解决这个问题,我决定重写控制系统。首先,我使用btn()
函数来获取按键的数值,并通过二进制运算剥离出与方向键相关的部分。然后,我创建了一个映射表(buttR
),将按键数值转换为自定义的方向编号。接着,我创建了两个数组(drx
和dry
),用于存储不同方向下x
和y
坐标的变化量。
通过这些改动,我现在可以轻松地识别飞船是否在对角线方向上移动。
解决方案
- 重写控制系统:
- 使用
btn()
函数获取按键数值,并通过二进制运算剥离出与方向键相关的部分。 - 创建映射表(
buttR
)将按键数值转换为自定义的方向编号。 - 创建数组(
drx
和dry
)存储不同方向下x
和y
坐标的变化量。
- 使用
- 解决“鹅卵石”问题:
- 在每次更新位置时,将飞船的像素位置重置为像素中心(
px = floor(px) + 0.5
,同理处理py
)。 - 这种方法确保了无论飞船从哪个位置开始,沿对角线移动时都能平滑地穿越像素边界。
- 在每次更新位置时,将飞船的像素位置重置为像素中心(
规范化对角线移动
- 实现方法:调整
drx
和dry
数组中的值,使得对角线移动时x
和y
坐标的变化量相等(如使用0.7或0.75作为变化量)。 - 测试与调整:通过实际测试不同的变化量,找到既平滑又符合预期的移动速度。
运动速度的调整
- 研究背景:通过对比不同射击游戏的移动速度,分析适合PICO-8的移动速度。
- 数据收集:记录不同游戏在60帧每秒下穿越整个屏幕所需的帧数,并转换为PICO-8等效像素速度。
- 确定速度:基于分析和测试,确定了一个合适的移动速度(如14像素/帧)。
银行动画(Banking Animation)
- 目的:增加飞船移动时的视觉反馈,使移动看起来更自然。
- 实现方法:创建多帧动画,根据飞船的移动方向选择不同的动画帧。
- 优化:通过变量控制动画速度,并使用
mid()
函数确保动画值在合理范围内,避免溢出或不足。
pico-8 cartridge // http://www.pico-8.com
version 41
__lua__
-- t: make basic movement feel nice
-- ❎: fixed cobblestoning
-- ❎: what is a good movement speed
-- t: do banking
-- t: make shooting feel nice!
-- x: normalized diagonals
butarr={1,2,0,3,5,6,3,4,8,7,4,0,1,2,0}
dirx={-1,1, 0,0, -0.7, 0.7,0.7,-0.7}
diry={ 0,0,-1,1, -0.7,-0.7,0.7,0.7}
butarr[0]=0
shiparr={1,3,5,7,9}
shipspr=3.5
function _init()
px,py=64,64
spd=1.4
lastdir=0
cls(0)
end
function _draw()
cls(12)
spr(shiparr[flr(shipspr)],px,py,2,2)
--pset(px,py,8)
local btnv=btn()&0b1111
print(btn(),5,5,7)
print(btnv,5,11,7)
print(butarr[btnv],5,17,7)
print(shipspr,5,23,7)
end
function _update60()
local dir=butarr[btn()&0b1111]
if lastdir!=dir and dir>=5 then
--anti-cobblestone
px=flr(px)+0.5
py=flr(py)+0.5
end
local dshipspr=3.5
if dir>0 then
px+=dirx[dir]*spd
py+=diry[dir]*spd
if dirx[dir]<0 then
dshipspr=1
elseif dirx[dir]>0 then
dshipspr=5.95
end
end
local bankspd=0.5
if dshipspr<shipspr then
shipspr-=bankspd
elseif dshipspr>shipspr then
shipspr+=bankspd
end
shipspr=mid(1,shipspr,5.95)
lastdir=dir
end
__gfx__
00000000000000011000000000000001100000000000000110000000000000011000000000000001100000000000000000000000000000000000000000000000
00000000000000167100000000000016710000000000001661000000000000167100000000000016710000000000000000000000000000000000000000000000
00700700000000111d100000000000111d1000000000011111100000000001d111000000000001d1110000000000000000000000000000000000000000000000
00077000000001ccc1100000000001ccc1100000000001cccc1000000000011ccc1000000000011ccc1000000000000000000000000000000000000000000000
0007700000001c77cc11000000001c77cc11000000001c77ccc10000000011c77cc10000000011c77cc100000000000000000000000000000000000000000000
0070070000001c7c1c11000000001c7c1c11000000001c7cc1c10000000011c7c1c10000000011c7c1c100000000000000000000000000000000000000000000
0000000000001c111c11100000011c111c11100000111c1111c11100000111c111c11000000111c111c100000000000000000000000000000000000000000000
0000000000001c111c17100000011c111c17100000171c1111c17100000171c111c11000000171c111c100000000000000000000000000000000000000000000
0000000000011cc17116100000161cc1171610000016117117116100000161711cc16100000161171cc110000000000000000000000000000000000000000000
000000000001d1c711d6d1000016d1c77116d10001d6d117711d6d10001d61177c1d6100001d6d117c1d10000000000000000000000000000000000000000000
00000000001ddd111d6d7d1001dddd1111dd6710176d6d1111d6d6710176dd1111dddd1001d7d6d111ddd1000000000000000000000000000000000000000000
00000000001dd6ddd6d66d1001dd66dddd6d66101666d6dddd6d66610166d6dddd66dd1001d66d6ddd6dd1000000000000000000000000000000000000000000
00000000001d676676d6dd1001d6676676d6dd101dd6d676676d6dd101dd6d6766766d1001dd6d676676d1000000000000000000000000000000000000000000
00000000000176d167d1110000117dd1171111000111171661711110001111711dd7110000111d761d6710000000000000000000000000000000000000000000
000000000000151155d110000001655155d11000000161511516100000011d551556100000011d55115100000000000000000000000000000000000000000000
00000000000001111111000000001111111100000000111111110000000011111111000000001111111000000000000000000000000000000000000000000000