你听说过 AWS Game Builder Challenge 吗?这是一个很棒的挑战,你可以用你喜欢的 AWS 服务来创建一个游戏:欢迎所有技能水平的参赛者!
在最近的一篇帖子(https://community.aws/content/2oAoQyCZWhRMpHWecW6dGykzP0T/how-i-built-an-arcade-scrolling-game-in-one-day)中,我谈到了如何借助Amazon Q Developer快速创建了一个横向视角的卷轴街机游戏。我和几位网友聊了起来,他们想了解更多,我们讨论了Amazon Q Developer是否可以开发一个能在我的第一台电脑Commodore 64上运行的游戏。为了验证这个想法,我花了一个多小时进行了一番尝试,这篇文章会分享我在实验过程中的一些发现。准备好体验一番复古电脑的乐趣吧!
写我的第一个C64 Basic程序
创建了一个新的项目工作区,并启动了VSCode之后,我在聊天窗口向Amazon Q Developer提出了以下提示:
Amazon Q Chat
编写一个简单的Commodore 64 BASIC程序,让一个小精灵在屏幕上平滑移动。确保首先重置屏幕,并将其颜色设置为随机颜色。
我打开代码并启动VICE,这是我的首选C64模拟器。我从模拟机中选择了标准的C64,然后粘贴代码进去。哦,这看起来不妙。
我让亚马逊Q提供建议来修复,它提供了许多想法,然而立即看起来合理的建议是下面这一行:
请换成小写字母(注意C64会自动将输入转换为大写)
我让亚马逊Q把代码改成小写,再试一次。这次成功了,现在亚马逊Q生成的代码已经在我的虚拟C64中了。这就是它生成的代码。
10 print chr$(147): 注释:清屏
20 poke 53280,int(rnd(1)*16): 注释:随机边框颜色
30 poke 53281,int(rnd(1)*16): 注释:随机背景颜色
40 注释:初始化精灵数据
50 for i = 0 to 62: read a: poke 832+i,a: next i
60 注释:精灵数据(简单的正方形)
70 data 255,255,255,255,255,255,255,255,255,255,255,255
80 data 255,255,255,255,255,255,255,255,255,0,0,0,0,0,0
90 data 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
100 data 0,0,0,0,0,0,0,0,0,0,0,0
110 注释:设置精灵
120 poke 53248,0: 注释:x 坐标(低字节)
130 poke 53249,100: 注释:y 坐标
140 poke 2040,13: 注释:精灵 0 的数据来自块 13(832/64)
150 poke 53287,1: 注释:精灵 0 颜色(白色)
160 poke 53269,1: 注释:启用精灵 0
170 注释:主循环
180 for x = 0 to 320
190 poke 53248,x and 255: 注释:更新 x 坐标(低字节)
200 if x > 255 then poke 53264, 1 else poke 53264, 0: 注释:更新 x 坐标(高位)
210 for d = 1 to 10: next d: 注释:延迟以实现平滑移动
220 next x
230 goto 180: 注释:跳转到主循环的开始
全屏模式,退出全屏
它运行……好吧,算是差不多。我看到一个方形精灵在屏幕上流畅地移动着,当它移动到屏幕尽头时,它就崩溃了,出现了一个错误:在200处出现了非法数量错误
我转向Amazon Q寻求帮助解决这个问题,让它帮我搞定这个错误。它很快给出了更新后的代码和解释,并解释了为什么会出错。
这里这是怎么运作的:(x>255)
是一个布尔条件,在 Commodore 64 BASIC 中,当该条件为真时结果为 -1,为假时结果为 0。表达式 (x>255)
前的负号会将其结果取反,因此当 x > 255
时结果为 1,而 x <= 255
时结果为 0。这样修改确保了当精灵的 X 坐标大于 255 时,高比特位被正确设置,让精灵可以横跨整个屏幕移动。
我再试一次,成功了。
让它更有趣一些
我想让它更有趣一点,所以让Amazon Q帮我改一下代码。
Amazon Q Chat > 你可以更新代码,这次让屏幕上有四个不同颜色的精灵,它们可以在屏幕上跳来跳去。
它给我提供了一些更新的代码
10 print chr$(147): rem 清除屏幕
20 poke 53280,0: poke 53281,0: rem 黑色边框和黑色背景
30 rem 初始化精灵数据
40 for i = 0 to 62: read a: poke 832+i,a: next i
50 rem 简单的方形精灵图案数据
60 data 255,255,255,255,255,255,255,255,255,255,255,255
70 data 255,255,255,255,255,255,255,255,255,0,0,0,0,0,0
80 data 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
90 data 0,0,0,0,0,0,0,0,0,0,0,0
100 rem 初始化精灵
110 for s = 0 to 3
120 poke 2040+s,13: rem 精灵数据从块13 (832/64)
130 poke 53287+s,s+2: rem 精灵颜色(红、青、紫、绿)
140 x(s) = int(rnd(1)*320): rem 随机位置
150 y(s) = int(rnd(1)*200)+30: rem 随机位置
160 dx(s) = (rnd(1)>0.5)*2-1: rem 随机选择左右方向
170 dy(s) = (rnd(1)>0.5)*2-1: rem 随机选择上下方向
180 next s
190 poke 53269,15: rem 启用前四个精灵
200 rem 主循环开始
210 for s = 0 to 3
220 x(s) = x(s) + dx(s)
230 y(s) = y(s) + dy(s)
240 if x(s) < 24 or x(s) > 320 then dx(s) = -dx(s)
250 if y(s) < 50 or y(s) > 229 then dy(s) = -dy(s)
260 poke 53248+s*2,x(s) and 255: rem x坐标(低字节)
270 poke 53264,peek(53264) and (255-2^s) or (-(x(s)>255))*2^s
280 poke 53249+s*2,y(s): rem y坐标
290 next s
300 for d = 1 to 10: next d: rem 延迟以平滑移动
310 goto 200: rem 重复上述移动
进入全屏模式;退出全屏模式
我知道,这个程序第一次运行时,有四个精灵在屏幕上跳跃。
更新精灵图像
下一步我想做的是让精灵变得更有趣。
亚马逊Q聊天:有没有在线的C64精灵编辑工具能帮我做自己的精灵?
它提供了许多很棒的资源,包括一个叫做spritemate.com的网站,我直接去了那个网站,很快拼凑了一个更有趣的角色图像。
我可以直接从工具里抓取数据,接着更新一下我的代码。
其中一个很酷的功能是可以调整CPU的运行速度。上面的视频都是以原C64 6502 CPU速度的800%运行的。以基础速度运行时,角色的移动会慢很多。这在意料之中——当年,人们用Basic编写简单的程序,性能不是那么重要。如果需要更好的性能,你得学习汇编语言。
编写 6502 汇编程序:
我对如何在Mac上的VSCode里进行这个操作一点头绪也没有。查看了一些Reddit小组的帖子后,显然下一步就是使用Kick Assembler工具(Kick Assembler),并搭配一个VSCode插件。一旦这些工具安装并配置好,我就可以开始了。
我选中所有代码,发送到代码解释器,然后问亚马逊Q:
亚马逊问答 > 将这个 Commodore Basic 程序转换成可以在 Vice c64 模拟器上运行的 6502 汇编代码。我想用 Kick Assembler 工具。
这让我想起了我青少年时期的一些东西,它能迅速提供出来,这让我感到非常惊讶。
// 常量
.const SPRITE_DATA = $0340 // 十进制为832
.const SPRITE_POINTER = $07F8 // 十进制为2040
.const VIC_SPRITE_X = $D000 // 十进制为53248
.const VIC_SPRITE_Y = $D001 // 十进制为53249
.const VIC_SPRITE_MSB_X = $D010 // 十进制为53264
.const VIC_SPRITE_COLOR = $D027 // 十进制为53287
.const VIC_SPRITE_ENABLE = $D015 // 十进制为53269
.const VIC_SPRITE_EXPAND_Y = $D017 // 十进制为53271
.const VIC_SPRITE_EXPAND_X = $D01D // 十进制为53277
.const CHROUT = $FFD2
.const RASTER = $D012
.const RANDOM = $D41B
// 零页变量
.const zp_x = $FB
.const zp_y = $FE
.const zp_dx = $101
.const zp_dy = $104
BasicUpstart2(start)
* = $0810 "Main Program"
start:
jsr clear_screen
jsr init_sprite_data
jsr setup_sprites
jsr init_variables
jmp main_loop
clear_screen:
lda #147 // 清屏(清除屏幕上的字符)
jsr CHROUT
rts
init_sprite_data:
ldx #0
load_sprite_data:
lda sprite_data,x
sta SPRITE_DATA,x
inx
cpx #63
bne load_sprite_data
rts
setup_sprites:
ldx #0
setup_sprite_loop:
txa
asl
tay
txa
asl
asl
asl
asl
asl
clc
adc #80
sta VIC_SPRITE_X,y // X 坐标 (80, 112, 144)
txa
asl
asl
asl
asl
asl
clc
adc #80
sta VIC_SPRITE_Y,y // Y 坐标 (80, 112, 144)
lda #13
sta SPRITE_POINTER,x // 精灵数据指针
txa
clc
adc #2
sta VIC_SPRITE_COLOR,x // 精灵颜色 (每个精灵不同)
inx
cpx #3
bne setup_sprite_loop
lda #7
sta VIC_SPRITE_ENABLE // 启用前三个精灵
sta VIC_SPRITE_EXPAND_Y // Y 方向扩展前三个精灵
sta VIC_SPRITE_EXPAND_X // X 方向扩展前三个精灵
rts
init_variables:
ldx #0
init_var_loop:
lda #160
sta zp_x,x
lda #100
sta zp_y,x
jsr random_direction
sta zp_dx,x
jsr random_direction
sta zp_dy,x
inx
cpx #3
bne init_var_loop
rts
random_direction:
lda RANDOM
and #3 // 0-3 而不是 0-1
beq positive_slow
cmp #1
beq positive_fast
cmp #2
beq negative_slow
negative_fast:
lda #$FE // -2
rts
negative_slow:
lda #$FF // -1
rts
positive_slow:
lda #1
rts
positive_fast:
lda #2
rts
main_loop:
ldx #0
sprite_loop:
jsr update_sprite_position
jsr check_boundaries
jsr update_sprite_position
inx
cpx #3
bne sprite_loop
jsr delay
jmp main_loop
update_sprite_position:
txa
asl
tay
lda zp_x,x
sta VIC_SPRITE_X,y
lda zp_x,x
cmp #255
bcc msb_clear
lda VIC_SPRITE_MSB_X
ora bit_masks,x
jmp msb_set
msb_clear:
lda VIC_SPRITE_MSB_X
and bit_masks_inv,x
msb_set:
sta VIC_SPRITE_MSB_X
lda zp_y,x
sta VIC_SPRITE_Y,y
rts
delay:
ldx #3
delay_loop:
ldy #255
inner_delay:
nop
nop
nop
nop
dey
bne inner_delay
dex
bne delay_loop
rts
bit_masks:
.byte 1, 2, 4
bit_masks_inv:
.byte $FE, $FD, $FB
sprite_data:
.byte 0,0,0,12,66,112,18,66,136,51,66,128,33,90,112,63
.byte 90,8,33,102,136,33,66,112,0,0,0,0,0,60,0,0
.byte 4,96,0,36,56,0,228,15,131,128,0,254,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4
全屏模式;退出全屏
我编译了代码,并通过插件自动运行它,成功之后,我们的角色就能在屏幕上跳来跳去。
这还不是完美的,因为更新后的代码丢失了几样东西:背景色和三个角色!不过,现在它已经跑得飞快,你可以明显感受到性能的大幅提升。
我让Amazon Q更新一下汇编器,加点额外的sprite。
Amazon Q,发送到提示框 > 更新C64汇编器,使其有三个精灵,而不是一个。
我需要来回确认一下,因为Amazon Q只给我提供更新代码的小部分。我接着追问提示:
Amazon Q 聊天界面
提供了完整的代码更新
这为我提供了可编译和运行的更新后的代码。
正如你所见,用汇编运行要快得多,相比之下,在Commodore Basic中运行则更慢。
收尾与下一步
在这篇文章中,我展示了如何利用Amazon Q Developer帮助你编写代码,即使这些代码是在超过40年的机器上运行的。Amazon Q Developer是一个非常棒的工具,我发现它可以帮我完成任何任务,包括在Commodore 64上创建基本和汇编程序。
你可能有一些旧代码或汇编程序,正寻求将其现代化、更新或重构。希望这篇文章能给你带来灵感,让你了解像Amazon Q Developer这样的工具所提供的各种可能性。
你可以今天免费试用 Amazon Q 开发者工具,通过注册一个 Builder ID 来,然后安装插件到 VSCode 或 IntelliJ 并用它登录。
来看看我在 community.aws 上的其他帖子,因为我分享了很多关于使用 Amazon Q Developer 的小技巧和实际案例。你也可以通过查看更改日志 来了解它的所有新功能和改进。
行动呼吁
如果你准备好创建你自己的游戏了,AWS 在整个11月举办黑客松。从简单的井字游戏(如使用 HTML/CSS/JS 构建)到复杂的 Unity 游戏——所有技术水平和工具栈都欢迎参加。立即在 DevPost 上加入:https://awsdevchallenge.devpost.com!希望能激励一些人加入,并提交一些怀旧游戏。
共同学习,写下你的评论
评论加载中...
作者其他优质文章