なつかしのビデオゲーム「サーカス」を IchigoJam でつくる
*この記事は IchigoJam Advent Calendar 2022 に参加しています。
大昔、「サーカス(1977年・エキシディ)」というゲームがありました。シーソーで交互に人をジャンプさせて空中に浮かぶ風船を割って行くというものです。インベーダーやブロック崩しの時代を知っている方ならおなじみのゲームかと思います。このゲームを「こどもパソコン IchigoJam」でつくってみることにしました。
○ 概要
今回は、IchigoJam BASIC でなるべくかんたんに実現できる範囲で本家のサーカスに近づけようと思い、以下のような内容でつくることにしました。
- ゲーム画面は IchigoJam の既存のキャラクター(以下「キャラ」と略す)を使って表示する。PCG(ユーザー定義文字)は使わない。
- 人、シーソーなど動く物体の移動はキャラ単位でおこなう。
- 人のサイズは、1キャラとする。アニメーションはしない。
- 操作は、キーボード、パドルコントローラーの両対応とする。
(パドルコントローラーは、「電子工作マガジン2021年冬号(電波新聞社)」で紹介されている IchigoJam 用ゲームコントローラーを使用)
- 音は、基本BEEP音のみとするが、できれば曲も入れたい(特に、葬送行進曲)。
○ 完成
ということで、完成した様子がこちらです(でも本当は制作途中の動画なので、まだスコア表示がないですけど・・・)。
遊び方は、スペースキー(or ボタン)を押すと台に立っている人がジャンプしてゲームがスタートします。カーソルキーの左右(or コントローラーのつまみ)でシーソーが左右に移動するので、落下してくる人をシーソーで受け止めて跳ね返してください。
○ プログラム
プログラムは思っていたよりもかなり大きくなってしまいました。プログラム0〜2の3つで、計3KB近くあります。プログラム0から実行してください。最初にスペースキーか、ボタンを押すことで、キーボードかコントローラーのどちらかで操作できるようになります。スピードが速すぎると感じる時は、プログラム2の760行目のWAITを大きくしてください。
(2022/12/21)現在、まだまだテストプレイ不足のため、随時更新する可能性があります。特にコントローラーでの操作があまり試せていないのできちんと動作するか自信がありません。
(2022/12/21)IchigoCake BASIC 用のプログラムを追加しました。こちらはプログラム1つにまとめてあります。内容は IchigoJam 用と全く同じです。
IchigoJam BASIC 用(Ver.1.2.3 以降)
(2022/12/20版)
※(2023/3/20)プログラム2の670行目に余計なLC命令が入っていたのを削除
<プログラム0>
NEW
10 'CIRCUS-0
20 CLV
30 POKE#8C8,19,19,19,19
40 POKE#8A0,#13,#91,#91,#14,#14,#00,#F9,#00,#00,#00,#00,#9F,#9E,#13,#13,#91
50 POKE#8B0,#00,#F9,#00,#14,#14,#91,#91,#13,#91,#13,#13,#9F,#9E,#00,#00,#00
60 LET[0],0,4,6,1
70 LET[4],-1,-1,-1,1,-1,1,1,1
80 LET[12],50,25,0,0,0,0,25,50
90 LET[24],100,50,20
100 LET[28],3,12,75,-200,28,12,-75,-200,3,17,100,-200,28,17,-100,-200
200 '
210 CLS:FOR I=0 TO 31:POKE#BE0+I,3:NEXT:LC0,0:?"SCORE ";S:LC13,0:?"JUMPS ";H
220 COPY#AA0,#8C8,4:COPY#ABC,#8C8,4:COPY#B40,#8C8,4:COPY#B5C,#8C8,4
230 LC9,8:?"Ichigo Circus":LC4,12:?"PUSH SPACE KEY OR BUTTON":GSB1300
240 IF BTN(32) G=1 ELSE IF BTN() G=2 ELSE CONT
250 COPY#900,#880,32:COPY#A00,#880,32:COPY#A40,#880,32:COPY#A80,#880,32
260 H=3:K=0:L=0:N=13:S=0:LET[21],0,0,0
270 WAIT8:LRUN1
1200 '
1210 IF H=0 Z=3:A=200:LC11,8:?"GAME OVER" ELSE A=150
1220 IF[20]<S [20]=S
1230 PLAY"O3T120B8R32B8R64B16R64B8O4D8C#16R64C#8O3B16R64B8A#16B8"
1240 GSB1300:WAIT A:COPY#A40,#880,32
1250 IF Z=2 LRUN1 ELSE GOTO200
1300 '
1310 LC5,10:?"TODAYS HIGH SCORE ";[20]
1320 RTN
SAVE0
<プログラム1>
NEW
300 'CIRCUS-1
310 COPY#BC0,#880,32:Z=0:T=30:U=-350:M=-1
320 A=RND(4):X=[28+A*4]:Y=[29+A*4]:P=[30+A*4]:Q=[31+A*4]
330 E=X*100:F=Y*100:V=X:W=Y
400 '
410 FOR I=0 TO 2:IF[21+I]=0 [21+I]=8:FOR J=0 TO 7:POKE#920+I*64+J*4,#FF:NEXT:NEXT ELSE NEXT
500 'Main_Start
510 COPY#AA0,#8C8,4:COPY#ABC,#8C8,4:COPY#B40,#8C8,4:COPY#B5C,#8C8,4
520 IF(X<4)|(X>27) GSB800
530 IF X=0 P=T ELSE IF X=31 P=-T
540 A=X-N:B=A-[L]:IF(Y>19)&(B>=0)&(B<=3) GSB900
550 IF Y>=22 Y=22:Z=2:H=H-1:Q=0:BEEP30,20
560 IF(K<>L)|(N<>M) COPY#BA0+M,0,8:COPY#BC0+M,0,8:COPY#BA0+N,#8A0+L*16,8:COPY#BC0+N,#8A8+L*16,8:K=L
570 LRUN2
800 '
810 A=0
820 IF(Y>=12)&(W<12) A=1:Y=12:F=1200:Q=-200:U=-400
830 IF(Y>=17)&(W<17) A=1:Y=17:F=1700:Q=-200:U=-400
840 IF A=1 T=75:IF X<4 P=T ELSE P=-T
850 RTN
900 '
910 BEEP:X=N+[L+2]:Y=20:E=X*100:F=2000:Q=U:IF U>-450 U=U-50
920 IF T<200 T=T+[12+A]
930 P=T*[4+A]:K=L:L=L^1
940 RTN
SAVE1
<プログラム2>
NEW
600 'CIRCUS-2
610 IF Z>0 LCV,W:?" ";
620 O=O^1:IF O=1 FOR I=0 TO 1:A=PEEK(#920+I*128):COPY#920+I*128,#921+I*128,31:POKE#93F+I*128,A:NEXT:B=PEEK(#97F):COPY#97F,#97E,-31:POKE#960,B
630 A=0:IF SCR(X,Y)=255 A=1:P=-P:Q=-Q:B=Y/2:S=S+[24+B]:[21+B]=[21+B]-1:IF[21+B]=0 A=2
640 LC0,0:?"SCORE ";S;:LC13,0:?"JUMPS ";H;
650 IF P>0 R=251 ELSE R=253
660 LCX,Y:?CHR$(R);:IF A=1 BEEP4,4:WAIT5 ELSE IF A=2 GSB1400:LC0,-1:LRUN1,400
670 IF Z=2 WAIT30:LRUN0,1200
700 M=N:IF G=1 GSB1000 ELSE IF G=2 GSB1100
710 IF Z=0 IF(BTN(32))|(BTN()) Z=1
720 IF Z=1 E=E+P:Q=Q+49:F=F+Q:IF F<0 F=0:Q=0
730 IF E<0 E=0 ELSE IF E>3199 E=3100
740 V=X:W=Y:X=E/100:Y=F/100
750 'Main_End
760 WAIT4:LRUN1,500
1000 '
1010 D=-BTN(28)+BTN(29):IF D=0 C=0 ELSE C=C+1:IF C>4 D=D*3 ELSE IF C>2 D=D*2
1020 N=N+D:IF N<0 N=0 ELSE IF N>24 N=24
1030 RTN
1100 '
1110 A=ANA(2):IF A<320 A=320 ELSE IF A>619 A=619
1120 N=(A-320)/12
1130 RTN
1400 '
1410 A=[24+B]*10:LC10,8:?"BONUS ";A:S=S+A
1420 BEEP3,20:WAIT100:COPY#A00,#880,32:COPY#920+B*64,#880,32
1430 RTN
SAVE2
IchigoCake BASIC 用(Ver.1.3.2以降)
(2022/12/21版)
<プログラム>
10 'CIRCUS
20 CLV
30 POKE#8C8,19,19,19,19
40 POKE#8A0,#13,#91,#91,#14,#14,#00,#F9,#00,#00,#00,#00,#9F,#9E,#13,#13,#91
50 POKE#8B0,#00,#F9,#00,#14,#14,#91,#91,#13,#91,#13,#13,#9F,#9E,#00,#00,#00
60 LET[0],0,4,6,1
70 LET[4],-1,-1,-1,1,-1,1,1,1
80 LET[12],50,25,0,0,0,0,25,50
90 LET[24],100,50,20
100 LET[28],3,12,75,-200,28,12,-75,-200,3,17,100,-200,28,17,-100,-200
200 '
210 CLS:FOR I=0 TO 31:POKE#BE0+I,3:NEXT:LC0,0:?"SCORE ";S:LC13,0:?"JUMPS ";H
220 COPY#AA0,#8C8,4:COPY#ABC,#8C8,4:COPY#B40,#8C8,4:COPY#B5C,#8C8,4
230 LC9,8:?"Ichigo Circus":LC4,12:?"PUSH SPACE KEY OR BUTTON":GSB1300
240 IF BTN(32) G=1 ELSE IF BTN() G=2 ELSE CONT
250 COPY#900,#880,32:COPY#A00,#880,32:COPY#A40,#880,32:COPY#A80,#880,32
260 H=3:K=0:L=0:N=13:S=0:LET[21],0,0,0
270 WAIT8
300 '
310 COPY#BC0,#880,32:Z=0:T=30:U=-350:M=-1
320 A=RND(4):X=[28+A*4]:Y=[29+A*4]:P=[30+A*4]:Q=[31+A*4]
330 E=X*100:F=Y*100:V=X:W=Y
400 '
410 FOR I=0 TO 2:IF[21+I]=0 [21+I]=8:FOR J=0 TO 7:POKE#920+I*64+J*4,#FF:NEXT:NEXT ELSE NEXT
500 'Main_Start
510 COPY#AA0,#8C8,4:COPY#ABC,#8C8,4:COPY#B40,#8C8,4:COPY#B5C,#8C8,4
520 IF(X<4)|(X>27) GSB800
530 IF X=0 P=T ELSE IF X=31 P=-T
540 A=X-N:B=A-[L]:IF(Y>19)&(B>=0)&(B<=3) GSB900
550 IF Y>=22 Y=22:Z=2:H=H-1:Q=0:BEEP30,20
560 IF(K<>L)|(N<>M) COPY#BA0+M,0,8:COPY#BC0+M,0,8:COPY#BA0+N,#8A0+L*16,8:COPY#BC0+N,#8A8+L*16,8:K=L
610 IF Z>0 LCV,W:?" ";
620 O=O^1:IF O=1 FOR I=0 TO 1:A=PEEK(#920+I*128):COPY#920+I*128,#921+I*128,31:POKE#93F+I*128,A:NEXT:B=PEEK(#97F):COPY#97F,#97E,-31:POKE#960,B
630 A=0:IF SCR(X,Y)=255 A=1:P=-P:Q=-Q:B=Y/2:S=S+[24+B]:[21+B]=[21+B]-1:IF[21+B]=0 A=2
640 LC0,0:?"SCORE ";S;:LC13,0:?"JUMPS ";H;
650 IF P>0 R=251 ELSE R=253
660 LCX,Y:?CHR$(R);:IF A=1 BEEP4,4:WAIT5 ELSE IF A=2 GSB1400:GOTO400
670 IF Z=2 WAIT30:GOTO1200
700 M=N:IF G=1 GSB1000 ELSE IF G=2 GSB1100
710 IF Z=0 IF(BTN(32))|(BTN()) Z=1
720 IF Z=1 E=E+P:Q=Q+49:F=F+Q:IF F<0 F=0:Q=0
730 IF E<0 E=0 ELSE IF E>3199 E=3100
740 V=X:W=Y:X=E/100:Y=F/100
750 'Main_End
760 WAIT4:GOTO500
800 '
810 A=0
820 IF(Y>=12)&(W<12) A=1:Y=12:F=1200:Q=-200:U=-400
830 IF(Y>=17)&(W<17) A=1:Y=17:F=1700:Q=-200:U=-400
840 IF A=1 T=75:IF X<4 P=T ELSE P=-T
850 RTN
900 '
910 BEEP:X=N+[L+2]:Y=20:E=X*100:F=2000:Q=U:IF U>-450 U=U-50
920 IF T<200 T=T+[12+A]
930 P=T*[4+A]:K=L:L=L^1
940 RTN
1000 '
1010 D=-BTN(28)+BTN(29):IF D=0 C=0 ELSE C=C+1:IF C>4 D=D*3 ELSE IF C>2 D=D*2
1020 N=N+D:IF N<0 N=0 ELSE IF N>24 N=24
1030 RTN
1100 '
1110 A=ANA(2):IF A<320 A=320 ELSE IF A>619 A=619
1120 N=(A-320)/12
1130 RTN
1200 '
1210 IF H=0 Z=3:A=200:LC11,8:?"GAME OVER" ELSE A=150
1220 IF[20]<S [20]=S
1230 PLAY"O3T120B8R32B8R64B16R64B8O4D8C#16R64C#8O3B16R64B8A#16B8"
1240 GSB1300:WAIT A:COPY#A40,#880,32
1250 IF Z=2 GOTO300 ELSE GOTO200
1300 '
1310 LC5,10:?"TODAYS HIGH SCORE ";[20]
1320 RTN
1400 '
1410 A=[24+B]*10:LC10,8:?"BONUS ";A:S=S+A
1420 BEEP3,20:WAIT100:COPY#A00,#880,32:COPY#920+B*64,#880,32
1430 RTN