ニャオニャオ21世紀

レトロゲーム(MSX、PCエンジン、セガサターン)と、MSXぽいアプリ開発と、最新ゲーム(PS4、SWITCH)、身体(身体意識など)、ライフハックほか雑記を綴っています

MSX BASICの基礎 その8 プレイヤーと敵キャラとの当たり判定。ここまで出来れば1画面ゲームを作ることができます^^






f:id:nyaonyaokun:20181019041317p:plain

敵キャラとの当たり判定が出来れば、

ゲームとしての基礎は完成です。

1画面のゲームならどんなものでも作ることができます!

(あっ、BGMがまだでした^^;)

youtu.be

 

サンプルの実行はこちらWebMSX

 

ダウンロード

 

 

 サンプルプログラム(ソースコード)

10 COLOR15,1,1:SCREEN2:SCREEN1,2:COLOR15,1,1:WIDTH32:DEFINTA-Z:KEYOFF
20 DEFUSR=&H7E:A=USR(0)
30 KEY1,"SCREEN1"+CHR$(13)
40 'EN<TEKI NO NUMBER>,EK<TEKI NO KAZU>,EX()<TEKI X ZAHYOU>,EY()<TEKI Y ZAHYOU>,EM()<TEKI NO MOVE RYOU>
44 EN=0:EK=4:DIMEX(4):DIMEY(4):DIMEM(4):DIMUX(4):DIMUY(4)
45 X=160:Y=120:H=0
46 EX(0)=160:EY(0)=8:EX(1)=96:EY(1)=32:EX(2)=160:EY(2)=144:EX(3)=96:EY(3)=104
47 EM(0)=8:EM(1)=-8:EM(2)=8:EM(3)=-8
48 IF GO=1 THEN GO=0:GOTO500
50 'MOJI TEIGI
51 N=ASC("A")
52 FOR J=0 TO 25
53 FOR I=0 TO 7
54 VPOKE &H800+N*8+I,VPEEK(N*8+I)
55 VPOKE &H1000+N*8+I,VPEEK(N*8+I)
56 'COLOR TEIGI
57 VPOKE &H2000+N*8+I,&HF1
58 VPOKE &H2800+N*8+I,&HF1
59 VPOKE &H3000+N*8+I,&HF1
60 NEXT
61 N=N+1
62 NEXT
63 LOCATE10,10:PRINT"PLEASE WAIT!"
70 'SPRITE TEIGI
75 RESTORE 2000
77 FOR J=0 TO 9
80 S$=""
90 FOR I=0 TO31
100 READ DT$:
110 S$=S$+CHR$(VAL("&H"+DT$))
120 NEXT
130 SPRITE$(J)=S$
140 NEXT
160 'BLOCK TEIGI
170 M=ASC("a")
175 RESTORE 4000
178 FOR J=0 TO 10
180 FOR I=0 TO 7
190 READ BG$
200 VPOKE M*8+I,VAL("&H"+BG$)
210 VPOKE &H800+M*8+I,VAL("&H"+BG$)
220 VPOKE &H1000+M*8+I,VAL("&H"+BG$)
222 NEXT
225 M=M+1
230 NEXT
234 M=ASC("a")
235 RESTORE 5000
236 FOR J=0 TO 10
240 FOR I=0 TO 7
250 READ CR$
260 VPOKE &H2000+M*8+I,VAL("&H"+CR$)
270 VPOKE &H2800+M*8+I,VAL("&H"+CR$)
280 VPOKE &H3000+M*8+I,VAL("&H"+CR$)
283 NEXT
285 M=M+1
290 NEXT
490 'MAP
500 LOCATE 0,0:PRINT "caaaaaaaaaaaaaaaaaaaaaaaaaaaaaad"
510 LOCATE 0,1:PRINT "b b"
520 LOCATE 0,2:PRINT "b b"
530 LOCATE 0,3:PRINT "b j haaaaaaad haaaaaaaaaai b"
540 LOCATE 0,4:PRINT "b b b b"
550 LOCATE 0,5:PRINT "b b b b"
560 LOCATE 0,6:PRINT "b eaaaaaaai b caaaaaaaaaad b"
570 LOCATE 0,7:PRINT "b b b b b"
580 LOCATE 0,8:PRINT "b k b b b"
590 LOCATE 0,9:PRINT "b cd caaad b j cad b b"
600 LOCATE 0,10:PRINT"b bb b b b b b b b b"
610 LOCATE 0,11:PRINT"b bb b b j b b eaf k b"
620 LOCATE 0,12:PRINT"b ef eaaaf b b b b"
630 LOCATE 0,13:PRINT"b b b b b"
640 LOCATE 0,14:PRINT"b b b eaaaaaaai b"
650 LOCATE 0,15:PRINT"b cd caaaaaab b b"
660 LOCATE 0,16:PRINT"b bb b b b b"
670 LOCATE 0,17:PRINT"b ef b k eaaaaaaaaaai b"
680 LOCATE 0,18:PRINT"b b b"
690 LOCATE 0,19:PRINT"b b b"
700 LOCATE 0,20:PRINT"eaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaf"
995 'MAIN LOOP
996 'PLAYER
998 M=ASC("a")-1
999 H=4
1000 S=STICK(0) OR STICK(1)
1005 'PLAYER
1010 TX=X:TY=Y
1020 IF S=1 THEN Y=Y-8:H=(H+1)MOD 2
1040 IF S=3 THEN X=X+8:H=( (H+1)MOD 2)+2
1060 IF S=5 THEN Y=Y+8:H=( (H+1)MOD 2)+4
1080 IF S=7 THEN X=X-8:H=( (H+1)MOD 2)+6
1100 A$=CHR$(VPEEK(&H1800+(X\8)+(Y\8)*32))
1110 B$=CHR$(VPEEK(&H1800+(X\8)+1+(Y\8)*32))
1120 C$=CHR$(VPEEK(&H1800+(X\8)+(Y\8+1)*32))
1130 D$=CHR$(VPEEK(&H1800+(X\8)+1+(Y\8+1)*32))
1140 IF ASC(A$)>M THEN X=TX:Y=TY
1150 IF ASC(B$)>M THEN X=TX:Y=TY
1160 IF ASC(C$)>M THEN X=TX:Y=TY
1170 IF ASC(D$)>M THEN X=TX:Y=TY
1210 'ENEMY
1220 UX(EN)=EX(EN):UY(EN)=EY(EN)
1230 EX(EN)=EX(EN)+EM(EN)
1240 AE$="#":BE$="#":CE$="#":DE$="#"
1250 AE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+(EY(EN)\8)*32))
1260 BE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+1+(EY(EN)\8)*32))
1270 CE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+(EY(EN)\8+1)*32))
1280 DE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+1+(EY(EN)\8+1)*32))
1290 IF ASC(AE$)>M THEN EX(EN)=UX(EN):EY(EN)=UY(EN)
1300 IF ASC(BE$)>M THEN EX(EN)=UX(EN):EY(EN)=UY(EN)
1310 IF ASC(CE$)>M THEN EX(EN)=UX(EN):EY(EN)=UY(EN):EM(EN)=-EM(EN)
1320 IF ASC(DE$)>M THEN EX(EN)=UX(EN):EY(EN)=UY(EN):EM(EN)=-EM(EN)
1322 'ATARI HANTEI
1325 GOSUB1680
1327 'GAME OVER HANTEI
1330 IF GO=1 THEN GOTO1820
1332 'SPRITE HYOUJI
1333 PUT SPRITE 0,(X ,Y-1),11,H
1335 PUT SPRITE EN+1,(EX(EN),EY(EN)-1),13,8
1340 EN=EN+1:IF EN>EK-1 THEN EN=0
1350 GOTO1000
1680 'PLAYER ATARI HANTEI
1690 ED=99
1700 FOR I=0 TO EK-1
1710 IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I
1720 NEXT
1730 IF ED=99 THEN RETURN
1740 X=TX:Y=TY
1747 'PLAYER OUT SPRITE
1750 PUT SPRITE 0,(X,Y-1),8,9
1760 'WAIT
1770 FOR I=0 TO 25
1775 BEEP
1780 NEXT
1790 GO=1
1800 RETURN
1810 'GAME OVER
1820 LOCATE 11,10:PRINT"GAME OVER"
1830 LOCATE 10,12:PRINT"PUSH RETURN"
1840 IF INKEY$<>CHR$(13) GOTO1840
1850 GOTO45
1995 'SPRITE UP0 DATA
2000 DATA 0F,1F,3F,7F,7F,7F,7F,7F,3F,1F,0F,30,03,01,1C,1C
2010 DATA F0,F8,FC,FE,FE,FE,FE,FE,FC,F8,F0,0C,CC,C0,38,00
2015 'SPRITE UP1 DATA
2020 DATA 0F,1F,3F,7F,7F,7F,7F,7F,3F,1F,0F,18,1B,03,1C,00
2030 DATA F0,F8,FC,FE,FE,FE,FE,FE,FC,F8,F0,0C,C0,B8,38,38
2035 'SPRITE RIGHT2 DATA
2040 DATA 0F,1F,3D,7D,7F,7F,7F,7F,3F,1F,0F,00,03,19,04,0E
2050 DATA F0,F8,F0,E0,C0,80,00,00,80,E0,F0,0C,CC,C0,30,38
2055 'SPRITE RIGHT3 DATA
2060 DATA 0F,1F,3F,7F,7F,7F,7E,7F,3F,1F,0F,00,1B,19,03,03
2070 DATA E0,F0,B8,B8,FC,FC,FC,00,F8,F0,E0,00,D8,C0,60,60
2075 'SPRITE DOWN4 DATA
2080 DATA 0F,1F,3B,7B,7B,7F,7F,77,38,1F,0F,30,03,1D,1E,1C
2090 DATA F0,F8,DC,DE,DE,FE,FE,EE,1C,F8,F0,0C,CC,C0,38,00
2095 'SPRITE DOWN5 DATA
2100 DATA 0F,1F,3B,7B,7F,7F,7B,7B,3C,1F,0F,18,1B,03,1C,00
2110 DATA F0,F8,DC,DE,FE,FE,DE,DE,3C,F8,F0,0C,C0,B8,78,38
2115 'SPRITE LEFT6 DATA
2120 DATA 0F,1F,0F,07,03,01,00,00,01,07,0F,30,33,03,0C,1C
2130 DATA F0,F8,BC,BE,FE,FE,FE,FE,FC,F8,F0,00,C0,98,20,70
2135 'SPRITE LEFT7 DATA
2140 DATA 07,0F,1D,1D,3F,3F,3F,00,1F,0F,07,00,1B,03,06,06
2150 DATA F0,F8,FC,FE,FE,FE,7E,FE,FC,F8,F0,00,D8,98,C0,C0
3275 'SPRITE SLIME DATA
3280 DATA 3F,7F,FF,FF,FF,CF,F3,FF,EB,E3,FF,FF,FF,FF,FF,ED
3290 DATA FC,FE,FF,FF,E7,DB,FF,C7,D7,C7,FF,FF,FF,FF,FF,B7
3300 'SPRITE DAMAGE
3310 DATA 00,01,21,11,09,04,00,78,00,04,09,11,21,01,00,00
3320 DATA 00,00,08,10,20,40,00,3C,00,40,20,10,08,00,00,00
3990 'YUKA
4000 'DATAE7,E7,E7,00,7E,7E,7E,00
4010 DATAFF,FF,00,00,00,00,FF,FF
4020 DATAC3,C3,C3,C3,C3,C3,C3,C3
4030 DATA0F,1F,38,70,E0,C0,C1,C3
4040 DATAF0,F8,1C,0E,07,03,83,C3
4050 DATAC3,C1,C0,E0,70,38,1F,0F
4060 DATAC3,83,03,07,0E,1C,F8,F0
4070 DATAC3,83,03,07,0E,1C,F8,F0
4080 DATA7F,FF,E0,C0,C0,E0,FF,7F
4090 DATAFE,FF,07,03,03,07,FF,FE
4100 DATA7E,FF,E7,C3,C3,C3,C3,C3
4110 DATAC3,C3,C3,C3,C3,E7,FF,7E
4990 'COLOR
5000 DATAF1,51,41,41,41,41,51,41
5010 DATA41,41,41,41,41,41,41,41
5020 DATAF1,51,41,41,41,41,41,41
5030 DATAF1,51,41,41,41,41,41,41
5040 DATA41,41,41,41,41,41,51,41
5050 DATA41,41,41,41,41,41,51,41
5060 DATA41,41,41,41,41,41,41,41
5070 DATAF1,51,41,41,41,41,51,41
5080 DATAF1,51,41,41,41,41,51,41
5090 DATAF1,51,41,41,41,41,41,41
5100 DATA41,41,41,41,41,41,51,41

 

 当たり判定の解説

今回のプログラムはいろいろと変更点があります。

最初にアルファベットの文字データをコピーしていたり、

スプライトデータが16進数になっていたり。

その辺りは一度置いておいて、当たり判定のプログラムの箇所を

貼ります。

 

1680 'PLAYER ATARI HANTEI
1690 ED=99
1700 FOR I=0 TO EK-1
1710 IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I
1720 NEXT
1730 IF ED=99 THEN RETURN
1740 X=TX:Y=TY
1747 'PLAYER OUT SPRITE
1750 PUT SPRITE 0,(X,Y-1),8,9
1760 'WAIT
1770 FOR I=0 TO 25
1775 BEEP
1780 NEXT
1790 GO=1
1800 RETURN

 

1322行 'ATARI HANTEI
1325行 GOSUB1680

で、当たり判定のサブルーチンを呼びます。

 

実際に当たっているかどうかは、1680行以降で判定しています。

 

まず1700行〜1720行で、

プレイヤーと、すべての敵キャラの座標を全部チェックしています。

(敵0番 ~ 敵キャラEK-1番まで)

 

IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16

ABSという命令がなんぞ?と思うと思います。

これは絶対値をとります。

例えば、+8でも-8でも、8という値になるので扱いやすいですよね!

 

X-EX(I)で、

プレーヤーのX座標 - 敵キャラ( I )番のX座標 の差をとります。

 

IF文の条件

ABS(X-EX(I))<16

ですが、自分のX座標と敵キャラのX座標の差が16ドット以下ということは、

X座標だけでみれば、キャラ同士が重なっていることはわかると思います。

(キャラクターが16x16ドットのサイズのため 16未満を判定してます)

 

Y座標でも同じことをやります。

ABS(Y-EY(I))<16

 

そして、X座標とY座標の両方が重なっていれば、

プレイヤーと敵キャラクターが重なっていることになります。

IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I

 

IF文の条件を満たした場合、そのぶつかっている敵キャラの番号を

EDに入れて覚えておきます。

 

ふぅ〜。

これで一番重要なところは終わりました^^

 

 

1730 IF ED=99 THEN RETURN

1730行は、EDが99の場合、何もせずにもとのプログラムに戻っていきます。

敵キャラとの当たりがあった場合、

1710 IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I

IF文で、

EDに 0 ~ EK-1までのどれかの数字をいれています。

ED=99というのは、初期値なので、どのキャラとも当たっていないということです。

(もっといい方法があるような気がしますが、僕にはこれぐらいしかわかりません。

申し訳ないです^^;)

 

プレイヤーと当たっている敵キャラがいれば1740行以降に進んでいきます。

 

1740行で、

1740 X=TX:Y=TY

としているのは、

プレイヤーと敵キャラを重ならせないために、移動前の座標の戻します。

 

 

1750 PUT SPRITE 0,(X,Y-1),8,9

プレイヤーのスプライトを、

色が9、スプライトパターン9に変更します。

これは、花火のような消える感じのスプライトです。

 

そして、敵に当たったら、今回は即ゲームオーバーなので、

1790 GO=1

ゲームオーバーフラグのGOに1を入れます。

 

 

 ゲームオーバー処理

 1810 'GAME OVER
1820 LOCATE 11,10:PRINT"GAME OVER"
1830 LOCATE 10,12:PRINT"PUSH RETURN"
1840 IF INKEY$<>CHR$(13) GOTO1840
1850 GOTO45

 

ゲームオーバーを表示します。

 

1840行は、リターンキーを押すまで、1840行を繰り返します。

入力待ち状態となります。

CHR$(13)というのは、リターンキーを表してます。

 

アスキーコード(CHR$(65)はAを表すというような)の

最初の32個(0~32)は、コントロールキャラクターといい、

リターンキーのような特殊なキャラクターが入っています。

 

1850行でゲームのリスタートとなります。 

 

 

 SCREEN1.5(多色刷り)に必要なこと

50 'MOJI TEIGI
51 N=ASC("A")
52 FOR J=0 TO 25
53 FOR I=0 TO 7
54 VPOKE &H800+N*8+I,VPEEK(N*8+I)
55 VPOKE &H1000+N*8+I,VPEEK(N*8+I)
56 'COLOR TEIGI
57 VPOKE &H2000+N*8+I,&HF1
58 VPOKE &H2800+N*8+I,&HF1
59 VPOKE &H3000+N*8+I,&HF1
60 NEXT
61 N=N+1
62 NEXT

 

これは、何をやっているかといいますと、

文字を表示するために必要なことなのです。

(1820行で、GAME OVERという文字を表示しています)

 

SCREEN1.5(多色刷り)は、

画面が上中下と3分割されていて、

それぞれ文字の形を定義してやらないとダメでした。

(&H0、&H800、&H1000からの3つに)

 

じつは初めに、

20行 DEFUSR=&H7E:A=USR(0)

で、

SCREEN1.5にした時に

文字のキャラクターデータが入っているのは、

画面の上中下のうちの、上の部分だけなのです。

(&H0~&H7FF)

 

そのため、何もしていないと、

中、下に文字を表示しようとしても空白となってしまうのです。

 

そこで、上のデータを、中・下にコピーしてやります。

51 N=ASC("A")

 

54 VPOKE &H800+N*8+I,VPEEK(N*8+I)
55 VPOKE &H1000+N*8+I,VPEEK(N*8+I)

 

VPEEK(N*8+I)

で、

VPEEK (アドレス&H0 + Aのアスキーコード * 8 + I)

で、Aの形のデータを取得。

(VPEEKは、VRAMの( )内のアドレスのデータを取得する命令でした。)

 

それを大文字のアルファベットの26文字分やります。

 

 

 

ARPGに使えそうな、当たり判定プログラム 

 

youtu.be

ハイドライド もどきを作るための

当たり判定のプログラムです。

 

敵と当たったら即死ではありません。

それと、敵とプレイヤーが重なって表示されないようにしないといけません。

 

さきほどのプログラムとは若干違います。

 

(じつはこちらのプログラムを先に書いたので、スプライトデータは2進数のままですし、文字データのコピーもしていません^^;)

 

サンプルの実行はこちらWebMSX

 

ダウンロード

 

 サンプルプログラム(ソースコード)

それではソースコードを見ていきます。

10 SCREEN1,2:COLOR15,1,1:WIDTH32:DEFINTA-Z:KEYOFF
20 DEFUSR=&H7E:A=USR(0)
30 KEY1,"SCREEN1"+CHR$(13)
40 X=160:Y=120:H=0
42 'EN<TEKI NO NUMBER>,EK<TEKI NO KAZU>,EX()<TEKI X ZAHYOU>,EY()<TEKI Y ZAHYOU>,EM(8)<TEKI NO MOVE RYOU>
45 EN=0:EK=6:DIMEX(6):DIMEY(6):DIMEM(6):DIMUX(6):DIMUY(6)
46 EX(0)=24:EY(0)=8:EX(1)=96:EY(1)=32:EX(2)=16:EY(2)=56:EX(3)=96:EY(3)=104:EX(4)=192:EY(4)=144:EX(5)=160:EY(5)=144
47 EM(0)=-8:EM(1)=8:EM(2)=-8:EM(3)=8:EM(4)=-8:EM(5)=8
50 'SPRITE TEIGI
60 RESTORE 2000
70 FOR J=0 TO 9
80 FOR I=0 TO 15
90 READ DT$
100 L$=L$+CHR$(VAL("&B"+LEFT$(DT$,8)))
110 R$=R$+CHR$(VAL("&B"+RIGHT$(DT$,8)))
120 NEXT
130 SPRITE$(J) =L$+R$
140 L$="":R$=""
150 NEXT
160 'BLOCK TEIGI
170 M=ASC("a")
175 RESTORE 4000
180 FOR I=0 TO 7
190 READ BG$
200 VPOKE M*8+I,VAL("&B"+BG$)
210 VPOKE &H800+M*8+I,VAL("&B"+BG$)
220 VPOKE &H1000+M*8+I,VAL("&B"+BG$)
230 NEXT
240 FOR I=0 TO 7
250 READ CR$
260 VPOKE &H2000+M*8+I,VAL("&H"+CR$)
270 VPOKE &H2800+M*8+I,VAL("&H"+CR$)
280 VPOKE &H3000+M*8+I,VAL("&H"+CR$)
290 NEXT
490 'MAP
500 LOCATE 0,0:PRINT "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
510 LOCATE 0,1:PRINT "a a"
520 LOCATE 0,2:PRINT "a a"
530 LOCATE 0,3:PRINT "a a aaaaaaaaa aaaaaaaaaaaa a"
540 LOCATE 0,4:PRINT "a a a a"
550 LOCATE 0,5:PRINT "a a a a"
560 LOCATE 0,6:PRINT "a aaaaaaaaa a aaaaaaaaaaaa a"
570 LOCATE 0,7:PRINT "a a a a a"
580 LOCATE 0,8:PRINT "a a a a a"
590 LOCATE 0,9:PRINT "a aa aaaaa a a aaa a a"
600 LOCATE 0,10:PRINT"a aa aaaaa a a aaa a a"
610 LOCATE 0,11:PRINT"a aa aaaaa a a a aaa a a"
620 LOCATE 0,12:PRINT"a aa aaaaa a a a a"
630 LOCATE 0,13:PRINT"a a a a a"
640 LOCATE 0,14:PRINT"a a a aaaaaaaaa a"
650 LOCATE 0,15:PRINT"a aa aaaaaaaa a a"
660 LOCATE 0,16:PRINT"a aa a a a a"
670 LOCATE 0,17:PRINT"a aa a a aaaaaaaaaaaa a"
680 LOCATE 0,18:PRINT"a a a"
690 LOCATE 0,19:PRINT"a a a"
700 LOCATE 0,20:PRINT"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
995 'MAIN LOOP
996 'PLAYER
1000 S=STICK(0) OR STICK(1)
1010 TX=X:TY=Y
1020 IF S=1 THEN Y=Y-8:H=(H+1)MOD 2
1040 IF S=3 THEN X=X+8:H=( (H+1)MOD 2)+2
1060 IF S=5 THEN Y=Y+8:H=( (H+1)MOD 2)+4
1080 IF S=7 THEN X=X-8:H=( (H+1)MOD 2)+6
1100 A$=CHR$(VPEEK(&H1800+(X\8)+(Y\8)*32))
1110 B$=CHR$(VPEEK(&H1800+(X\8)+1+(Y\8)*32))
1120 C$=CHR$(VPEEK(&H1800+(X\8)+(Y\8+1)*32))
1130 D$=CHR$(VPEEK(&H1800+(X\8)+1+(Y\8+1)*32))
1140 IF ASC(A$)=ASC("a") THEN X=TX:Y=TY
1150 IF ASC(B$)=ASC("a") THEN X=TX:Y=TY
1160 IF ASC(C$)=ASC("a") THEN X=TX:Y=TY
1170 IF ASC(D$)=ASC("a") THEN X=TX:Y=TY
1175 GOSUB1680
1180 PUT SPRITE 0,(X ,Y-1),15,H
1210 'ENEMY
1220 UX(EN)=EX(EN):UY(EN)=EY(EN)
1230 EX(EN)=EX(EN)+EM(EN)
1240 AE$="#":BE$="#":CE$="#":DE$="#"
1250 AE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+(EY(EN)\8)*32))
1260 BE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+1+(EY(EN)\8)*32))
1270 CE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+(EY(EN)\8+1)*32))
1280 DE$=CHR$(VPEEK(&H1800+(EX(EN)\8)+1+(EY(EN)\8+1)*32))
1290 IF ASC(AE$)=ASC("a") THEN EX(EN)=UX(EN):EY(EN)=UY(EN)
1300 IF ASC(BE$)=ASC("a") THEN EX(EN)=UX(EN):EY(EN)=UY(EN)
1310 IF ASC(CE$)=ASC("a") THEN EX(EN)=UX(EN):EY(EN)=UY(EN):EM(EN)=-EM(EN)
1320 IF ASC(DE$)=ASC("a") THEN EX(EN)=UX(EN):EY(EN)=UY(EN):EM(EN)=-EM(EN)
1325 GOSUB1810
1330 PUT SPRITE EN+1,(EX(EN),EY(EN)-1),7,8
1340 EN=EN+1:IF EN>EK-1 THEN EN=0
1350 GOTO1000
1680 'PLAYER ATARI HANTEI
1690 ED=99
1700 FOR I=0 TO EK-1
1710 IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I
1720 NEXT
1730 IF ED=99 THEN RETURN
1740 X=TX:Y=TY
1745 PUT SPRITE 0,(X,Y-1),15,H
1747 'DAMAGE ENEMY SPRITE
1750 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),9,9
1760 'WAIT
1770 FOR I=0 TO 1000
1780 NEXT
1785 'ENEMY SPRITE
1790 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),7,8
1800 RETURN
1805 'ENEMY ATARI HANTEI
1810 IF ABS(X-EX(EN))<16 AND ABS(Y-EY(EN))<16 THEN GOTO1830
1820 RETURN
1830 EX(EN)=UX(EN):EY(EN)=UY(EN)
1840 PUT SPRITE 0,(X,Y-1),9,9
1845 'WAIT
1850 FOR I=0 TO 1000
1860 NEXT
1865 'PLAYER SPRITE
1870 PUT SPRITE 0,(X,Y-1),15,H
1880 RETURN
1995 'SPRITE UP0 DATA
2000 DATA1000000000000000
2010 DATA1000000000000000
2020 DATA1010011111110010
2030 DATA1010111111111010
2040 DATA1011111111111110
2050 DATA1001111111111100
2060 DATA1001111111111100
2070 DATA1001111111111100
2080 DATA1001111111111100
2090 DATA1110111111111000
2100 DATA1110011111110111
2110 DATA1110000000001111
2120 DATA1000011101111111
2130 DATA0000000111001111
2140 DATA0000011000110110
2150 DATA0000011000000000
2155 'SPRITE UP1 DATA
2160 DATA0000000000000000
2170 DATA0000000000000000
2180 DATA1010011111110010
2190 DATA1010111111111010
2200 DATA1011111111111110
2210 DATA1001111111111100
2220 DATA1001111111111100
2230 DATA1001111111111100
2240 DATA1001111111111100
2250 DATA1000111111111011
2260 DATA1000011111110111
2270 DATA1110000000011111
2280 DATA1110011101111111
2290 DATA1110000111001110
2300 DATA1000011000110000
2310 DATA0000000000110000
2315 'SPRITE RIGHT2 DATA
2320 DATA0000000000000000
2330 DATA0000000000000000
2340 DATA1001111111000000
2350 DATA1011111111101000
2360 DATA1101111111111000
2370 DATA0011111111110001
2380 DATA1111111011010001
2390 DATA1111111011010001
2400 DATA1111111111110010
2410 DATA0111001111110010
2420 DATA1111101111100100
2430 DATA1101100000000100
2440 DATA1000101101011000
2450 DATA1101101111011000
2460 DATA0111110000000000
2470 DATA0000111011000000
2475 'SPRITE RIGHT3 DATA
2480 DATA0000000000000000
2490 DATA0000000000000000
2500 DATA0100111111100010
2510 DATA0101111111110110
2520 DATA0110111111111110
2530 DATA0001111111111010
2540 DATA0111111101101010
2550 DATA0111111101101010
2560 DATA0111111111111010
2570 DATA0011100111111010
2580 DATA0111110111110010
2590 DATA0110110000000010
2600 DATA0100010110100111
2610 DATA0110110111000111
2620 DATA0011110000010010
2630 DATA0001110000011100
2635 'SPRITE DOWN4 DATA
2640 DATA0000000000000000
2650 DATA0000000000000000
2660 DATA1010011111110010
2670 DATA1010111111111010
2680 DATA1011111111111110
2690 DATA1001111111111100
2700 DATA1001110111011100
2710 DATA1001110111011100
2720 DATA1001111111111100
2730 DATA1000111111111111
2740 DATA1000011111111011
2750 DATA1000000000010001
2760 DATA1110011101111011
2770 DATA1110000111001110
2780 DATA1000011000110000
2790 DATA0000000000110000
2795 'SPRITE DOWN5 DATA
2800 DATA0000000000000000
2810 DATA1000000000000000
2820 DATA1010011111110010
2830 DATA1010111111111010
2840 DATA1011111111111110
2850 DATA1001111111111100
2860 DATA1001110111011100
2870 DATA1001110111011100
2880 DATA1001111111111100
2890 DATA1000111111111000
2900 DATA1110011111111111
2910 DATA1110000000011011
2920 DATA1110011101110001
2930 DATA1000000111011011
2940 DATA0000011000111110
2950 DATA0000011000000000
2955 'SPRITE LEFT6 DATA
2960 DATA0000000000000000
2970 DATA0000000000000000
2980 DATA0000001111111001
2990 DATA0001011111111101
3000 DATA0001111111111011
3010 DATA1000111111111100
3020 DATA1000101101111111
3030 DATA1000101101111111
3040 DATA0100111111111111
3050 DATA0100111111001110
3060 DATA0010011111011111
3070 DATA0010000000011011
3080 DATA0001101011010001
3090 DATA0001101111011011
3100 DATA0000000000111110
3110 DATA0000001101110000
3115 'SPRITE LEFT7 DATA
3120 DATA0000000000000000
3130 DATA0000000000000000
3140 DATA0100011111110010
3150 DATA0110111111111010
3160 DATA0111111111110110
3170 DATA0101111111111000
3180 DATA0101011011111110
3190 DATA0101011011111110
3200 DATA0101111111111110
3210 DATA0101111110011100
3220 DATA0100111110111110
3230 DATA0100000000110110
3240 DATA1110010110100010
3250 DATA1110001110110110
3260 DATA0100100000111100
3270 DATA0011100000111000
3275 'SPRITE SLIME DATA
3280 DATA0000000000000000
3290 DATA0000000000000000
3300 DATA0000000000000000
3310 DATA0000000000000000
3320 DATA0000000000000000
3330 DATA0000000000000000
3340 DATA0000000000000000
3350 DATA0000000000000000
3360 DATA0000111111110000
3370 DATA0011111111111100
3380 DATA0111111111111110
3390 DATA1111111111111111
3400 DATA1111111111111111
3410 DATA1111111111111111
3420 DATA1111111111111111
3430 DATA0111111001111110
3435 'SPRITE DAMAGE
3440 DATA1111111111111111
3450 DATA1111111111111111
3460 DATA1111111111111111
3470 DATA1111111111111111
3480 DATA1111111111111111
3490 DATA1111111111111111
3500 DATA1111111111111111
3510 DATA1111111111111111
3520 DATA1111111111111111
3530 DATA1111111111111111
3540 DATA1111111111111111
3550 DATA1111111111111111
3560 DATA1111111111111111
3570 DATA1111111111111111
3580 DATA1111111111111111
3590 DATA1111111111111111
3990 'YUKA
4000 DATA11100111
4010 DATA11100111
4020 DATA11100111
4030 DATA00000000
4040 DATA01111110
4050 DATA01111110
4060 DATA01111110
4070 DATA00000000
4990 'COLOR
5000 DATAF1,71,51,51,51,41,41,41

 

 当たり判定の解説

赤文字が今回の当たり判定の箇所です。

結構長いプログラムになってしまいました^^;

 

でもやっていることは意外と簡単です^^

まず、

この追加した箇所は二つに分かれます。

 

プレイヤーから見た当たり判定と、敵キャラから見た当たり判定です。

 

 プレイヤーからみた当たり判定

まずプレイヤーから見た当たり判定をみていきましょう。

1680 'PLAYER ATARI HANTEI
1690 ED=99
1700 FOR I=0 TO EK-1
1710 IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I
1720 NEXT
1730 IF ED=99 THEN RETURN
1740 X=TX:Y=TY
1745 PUT SPRITE 0,(X,Y-1),15,H
1747 'DAMAGE ENEMY SPRITE
1750 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),9,9
1760 'WAIT
1770 FOR I=0 TO 1000
1780 NEXT
1785 'ENEMY SPRITE
1790 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),7,8
1800 RETURN

 

プレイヤーの移動の処理を終えて、地形との当たり判定を済ました

あとで、

1175行 GOSUB1680

で敵キャラとの当たり判定のサブルーチンに飛びます。

プレイヤーが移動するときに、移動先が敵キャラと当たっていないか?判定してやります。

 

1680行 ~ 1800行までがそのサブルーチンです。

これのサブルーチンでやっていることは、

おおまかに3つに分かれます。

 

1.敵キャラスプライトとプレイヤースプライトが当たっているか

の判定

 

2.当たっている場合、敵キャラをダメージを受けている画像に変更

 

3.硬直時間

 

となります。

 

 

1. 当たっているかの判定

1700 FOR I=0 TO EK-1
1710 IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I
1720 NEXT

 

パッ◯マンもどきと同じです。

一応、同じ説明をしておきます。

 

実際に当たっているかどうかは、ここで判定しています。

プレイヤーと、すべての敵キャラの座標を全部チェックしています。

(敵キャラ0番 ~ 敵キャラEK-1番まで)

 

ABSという命令がなんぞ?と思うと思います。

これは絶対値をとります。

例えば、+8でも-8でも、8という値になるので扱いやすいですよね!

 

X-EX(I)で、

プレーヤーのX座標 - 敵キャラ( I )番のX座標 の差をとります。

 

IF文の条件

ABS(X-EX(I))<16

ですが、自分のX座標と敵キャラのX座標の差が16ドット以下ということは、

X座標だけでみれば、キャラ同士が重なっていることはわかると思います。

(キャラクターが16x16ドットのサイズのため 16未満を判定してます)

 

Y座標でも同じことをやります。

ABS(Y-EY(I))<16

 

そして、X座標とY座標の両方が重なっていれば、

プレイヤーと敵キャラクターが重なっていることになります。

IF ABS(X-EX(I))<16 AND ABS(Y-EY(I))<16 THEN ED=I

 

IF文の条件を満たした場合、その敵キャラの番号をEDに入れて覚えておきます。

 

 

 

 2.当たっていたらダメージ画像を表示

1730 IF ED=99 THEN RETURN
1740 X=TX:Y=TY
1745 PUT SPRITE 0,(X,Y-1),15,H

1747 'DAMAGE ENEMY SPRITE
1750 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),9,9

 

今回は、自分が敵に突撃していったら、敵に攻撃をしたというプログラムになります。

いわゆるハイドライド です^^ 

 

1730行は、EDが99の場合、何もせずにもとのプログラムに戻っていきます。

敵キャラとの当たりがあった場合、

先ほどのIF文で、

EDに 0 ~ EK-1までのどれかの数字をいれています。

ED=99というのは、初期値なので、どのキャラとも当たっていないといことです。

(もっといい方法があるような気がしますが、僕にはこれぐらいしかわかりません。

申し訳ないです^^;)

 

当たっている敵キャラがいれば1740行以降に進んでいきます。

 

1740行で、

1740 X=TX:Y=TY

としているのは、

プレイヤーと敵キャラをめり込ませないために、移動前の座標の戻します。

 

(1745行 PUT SPRITE 0,(X,Y-1),15,Hは、一度プレイヤーを表示しておかないと横向きで硬直したりしてしまいます。一度コメントアウトして(  '  )みるとよくわかります^^)

 

1750 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),9,9

 先ほどのED番の敵キャラのスプライトを、

色が9、スプライトパターン9に変更します。

(数秒でもとのスプライトに戻さないといけません。もし敵キャラを消したい場合は、

座標を( 0 ,192 ) に設定してやりましょう。外へ追い出すだけですが^^)

 

 3.硬直させる

敵に当たった場合、 少しの間、ダメージ絵を表示させておきます。

そのために、

1770 FOR I=0 TO 1000
1780 NEXT

で何もしないFOR文で時間稼ぎです^^;

(もっといい方法がありそうです~~;)

 

そのあと、もとの敵キャラの絵に戻してやります。

1790 PUT SPRITE ED+1,(EX(ED),EY(ED)-1),7,8

今回は、色が7で、スプライトパターン8(スライムの絵を設定しています)

ですが、

様々な絵の敵キャラがいる場合は、

色も、スプライトパターン番号も配列に入れておくといいです。

色を、EC( )とか

スプライトパターン番号を、EP ( )

にするとか。

1790 PUT SPRITE ED+1,(EX(ED),EY(ED)-1) , EC(EN) , EP(EN)

 

(EC( ) とか、EP( )を最初に設定しておいてください。

EP (0) = スプライトパターン番号 8 <スライムの絵>

EP (1) = スプライトパターン番号 10<黒騎士の絵>

などと設定してあればいいのではないでしょうか?)

 

こういう敵キャラの作りかたのコツは、

敵キャラ関係の配列をまずいくつか作ります。

EX(),EY(),EH(),EX(),EC(),EP()などと。

敵キャラの座標とか、敵キャラのHPとか、敵キャラの経験値とか、敵キャラの色とか、敵キャラの絵とか。

色々と敵キャラのデータがあると思います。

 

0番は、スライム。

1番は、オクトパス。

2番は、ゾンビ。

3番は、マジシャン。

などと決めておいて、それぞれの配列にデータを入れていきます。

 

1面で、敵キャラがスライムならば、配列( 0 ) でやっていきます。

2面なら、配列( 1 ) にするとか。

ステージが変わって、敵が変わっても、

配列の数値を変えてやるだけで、同じプログラムを使うことができます。

 

 

 敵キャラからみた当たり判定

1805 'ENEMY ATARI HANTEI
1810 IF ABS(X-EX(EN))<16 AND ABS(Y-EY(EN))<16 THEN GOTO1830
1820 RETURN
1830 EX(EN)=UX(EN):EY(EN)=UY(EN)
1840 PUT SPRITE 0,(X,Y-1),9,9
1845 'WAIT
1850 FOR I=0 TO 1000
1860 NEXT
1865 'PLAYER SPRITE
1870 PUT SPRITE 0,(X,Y-1),15,H
1880 RETURN

 

先ほどとほとんど同じです。

敵キャラが移動したときに呼び出されるので、

当たり判定のところは、プレイヤーとだけチェックすればOKです。

(例えば、0番の敵キャラの処理をしているときだったら、

0番の敵キャラとプレイヤーとが重なっているか判定します)

 

当たっていた場合は、その敵キャラを移動する前の座標に戻してやります。

 

そもそもなぜ、プレイヤー目線の当たり判定と敵キャラ目線の当たり判定をやるのかといいますと、

プレイヤーと敵キャラが重なって表示させないためなのです。

 

プレイヤー移動 -> 当たり判定 ->当たっていたらプレイヤーを移動前の座標へ

(例えば)

0番の敵キャラ移動 -> 当たり判定 -> 当たっていたら0番の敵キャラを移動前の座標へ

 

分けていないと、

それぞれのキャラクターの座標をもとの座標に戻すことがややこしくなります^^

 

 

 

 まとめ

 まずは敵キャラから逃げまくるゲームなんてのがいいかもしれません^^

 

今回のプログラムはスピードが少し遅いですねぇ。

ゲームとしては厳しいです(^^;)

敵キャラが2体なら、プレイヤーのスピードの1/2なので、

ちょうどいいのかもしれません。

(今回は4体だったので、プレーヤーの1/4のスピードでした;)

 

全体的にもう少し速くしたいです(`・∀・´)

BASICの基礎のページなので、マシン語は使いません。

(BASICでやるだけやって、これ以上は無理となったら

一番最後にマシン語を使うかも)

 

あと敵のアルゴリズムが必要になりますね。

そのあたりは全くわかっていないので、少し勉強したいと思います^^

結構難しそうです(^_^*)

 

一番よくあるのが、左右に動いていて壁で反転するだけのもの。

それは今回のでもできています。

 

パック◯ンだと追いかけてくるんですよねぇ〜。

 

あとはランダムに動き回る敵ですか。

これは簡単にできそう。

 

次回は、プログラムの高速化か、敵キャラのアルゴリズムか、BGMの鳴らし方をやる予定です。

 

MSX関係のお買い物はこちらでどうぞ^^

msx | 通販ショップの駿河屋

(MSX本体、ゲーム、MSXの雑誌など)

 

つづき

www.nyaonyao21.com

 


「ニャオニャオ21世紀は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。」

当サイトは第三者配信の広告サービス「Google Adsense グーグルアドセンス」を利用しています。 広告配信事業者は、ユーザーの興味に応じた広告を表示するためにCookie(クッキー)を使用することがあります。 Cookie(クッキー)を無効にする設定およびGoogleアドセンスに関する詳細は「広告 – ポリシーと規約 – Google」をご覧ください