ニャオニャオ21世紀

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

MSX BASICで地形(ブロック)との当たり判定!これができるとゲームらしくなる!基本その3

今回は、地形との当たり判定を書きます。

じつは、小学校当時はやり方を知りませんでした^^

これが出来たら、当時もゲームも作っていたんだろうなぁと思うと、

もっとがんばっておけよ!俺!って思ってしまいますw

 

だいたい難しいですよね?

ブロックは文字の形を変えたものということは知っていましたが、

マイキャラがいる座標の、となりの座標の文字はなにか?

なんて分かりません(^^;)

 

X,Yの座標を入れたら、その座標の文字が返ってくる命令があれば!

って思ってましたが、残念ながらありません(^^;)

でもたった1行で表せるので、その1行をそのまま使うだけで、先ほどの

欲しい命令文のようなことが出来てしまうのです!!

詳しい仕組みなんか知らなくてもいいという方は、最後のまとめの箇所を

見てください^^

 

>X,Yの座標を入れたら、その座標の文字が返ってくる

というのを実現するのに、

じつはそれにはVRAMの知識がいるのです^^

 

僕が小学生の頃なんて、VRAMの存在自体ほとんど知らなかったんです^^;

それでは無理ですね〜汗

 

今回は、VRAMを覚えなくても、当たり判定のプログラムを

組めるようにサンプルを書きます。

(使っているうちにだんだん馴染みがでてきて、覚えてしまいます^^)

 

今回は地形もブロックの絵に変えず、#で描きます。

文字を並べるだけです^^

 

結構この辺りの、地形との当たり判定でつまずいた人は多いと思います。

今こそ、子供のころ出来なかったことができるチャンスです〜^^

当時は出来たけど、もう忘れてしまったよって方は、

一通り読んでいただければ思い出すと思います^^

 

過去の記事:

MSX BASICの基本を思い出しましょう(その1)! PRINTやIFやGOTOを使ったくらいでやめてしまった方へ。初心者歓迎。 - ニャオニャオ21世紀

 

MSXの特徴であるスプライト表示!初めての方にも。MSX BASICの基本を思い出しましょう、"その2" - ニャオニャオ21世紀

 

MAPの表示

 

まずは、マップを表示します。スクロールとかしません^^

f:id:nyaonyaokun:20180917180120p:plain

 

うーん、文字だけのマップっていうのも、今の時代、面白いかもw

 

じつは、ものすごく単純な方法で表示しております。

文字だとスペースがうまくいかないくて表示が崩れそうなので画像で。

f:id:nyaonyaokun:20180917183240p:plain

こんな感じです。

一応テキストの方も載せます。

 

10 SCREEN1,3:WIDTH32
20    LOCATE 0,0:PRINT"################################"
30    LOCATE 0,1:PRINT"#                                                            #"
40    LOCATE 0,2:PRINT"#                                                            #"
50    LOCATE 0,3:PRINT"# #  ######### ############  #"
60    LOCATE 0,4:PRINT"# #       #        #  #"
70    LOCATE 0,5:PRINT"# #       #        #  #"
80    LOCATE 0,6:PRINT"# #########    # ############   #"
90    LOCATE 0,7:PRINT"#       # #        #     #"
100  LOCATE 0,8:PRINT"#       # # #          #     #"
110  LOCATE 0,9:PRINT"#  ##  #####     # #   ###      #     #"
120LOCATE 0,10:PRINT"#    ##  #####           #   #   ###       #    #"
130LOCATE 0,11:PRINT"#    ##  #####     #    #   #   ###      #  #"
140LOCATE 0,12:PRINT"#    ##  #####     #    #   #                      #"
150LOCATE 0,13:PRINT"#                         #    #   #                      #"
160LOCATE 0,14:PRINT"#                         #    #   #########      #" 
170LOCATE 0,15:PRINT"#    ##   ########    #                           #"
180LOCATE 0,16:PRINT"#    ##   #            #    #                           #"
190LOCATE 0,17:PRINT"#    ##   #            #    #############    #"
200LOCATE 0,18:PRINT"#           #                                                #" 
210LOCATE 0,19:PRINT"#           #                                                #"
220LOCATE 0,20:PRINT"################################"
230 LOCATE 0,21:PRINT"                    HIT ANY KEY                      "
250 '
260 I$=INPUT$(1)
270 END

MSXは、1画面の横が32文字表示できるので、

PRINT "32文字文打つ  "

縦が24文字まで表示できるのですが、改行などの関係で縦22行分としました。

 

こんなバカなプログラムをププゥ〜と笑ってはいけません!

じつはこの方法は、MSX BASICで1画面すべて文字で埋める方法の中では

かなり表示が早い方なのです。

 

BASICで、VRAMにVPOKEで書き込む方法よりも早く、

I/Oポートを使う OUT 152,Aなどよりも早いのです!!

(PRINT"32文字分  " を24行 の方だと約1秒、

VPOKEで1文字づつ書き込むと約5秒。

ものすごくアバウトな方法で計測しましたが;)

 

単純な方法だからといって恥じることはないのです(^^) 

まぁマシン語では1画面表示は一瞬ですが(^^;)

 

マップ表示はできました。

 

あとは、この#という壁に当たり判定をいれて、

マイキャラのスプライトがぶつかったら進めないようにします。

 

カベとの当たり判定

ここでVRAMを使わなくてはいけません。

MSXのCPU(Z80A)には、メモリと、ビデオプロセッサ(VDP)、VRAMが

くっついています。

今のPCでも同じような感じかなぁ。

CPUは演算装置で、画像の表示はビデオプロセッサ(VDP)がやります。

そして画像データが入っているのがVRAMなのです。

 

VRAMには、

文字の形のデータ、表示されている画面のデータ、

スプライトの表示位置データ、文字の色データ、スプライトの形のデータが

入っています。

 

それで、VRAMにはデータがズラーっと並んでいるのですが、

文字の形のデータはここ、表示されている画面のデータはここ、などと、

すべてアドレス(場所)が決まっています。

 

表示されている画面の全部の文字が、左上(0,0)から右下(31,23)まで

順に記録されている場所(アドレス)があります。

そこのアドレス領域に名前が付いていて、

パターンネームテーブル

といいます。

 

SCREEN1とSCREEN2では、

アドレスは、&H1800 ~ &H1AFF  (16進数で表記しています)

                       6144     ~   6911     (上のアドレスを10進数で表すとこうなります)

 

(これで、1画面すべてで768文字ということがわかると思います。32x24=768)

(16進数か、10進数かは、作るプログラムによります。

今回は、16進数にします。<16進数でやっているプログラムの方が多いと思います>)

 

<補足  &Hをつけると16進数です。(&Bをつけると2進数。何もつけないのが10進数>

 

こちらにVRAMのマップが載っているサイト様がありますので

ご覧ください^^

 

Appendix A.5 VRAM マップ - テクハンwiki

 

MSX data base : VRAM MAP

 

とりあえずこんなものなんだ〜と思って頂けたらOKです。

 

  

 

表示画面は32x24文字です。

例えば、

(5 ,10)に表示されている文字は何か?

(5,10)の座標に対応している、VRAMのアドレスがわかれば、

知ることができるのです。

 

こんな文字が画面に表示されていたとします⬇︎

f:id:nyaonyaokun:20180918075737p:plain

MSXdeGAMEヲMAKEシチャイナヨWAOHHHHHHHHH   (32文字)

HYDLIDEみたいなGAMEをYO--------------                        (32文字) 

YEAH!MSXMSXMSX                                                (32文字)

~~~~

~~~

(24行)

などと表示されているときに、

 

パターンネームテーブル”(&H1800 ~ &H1AFF)にはどのように入っているか?

というと、

 

&H1800    M  ->    10進数のアドレス 6144  M  

&H1801    S   ->    10進数のアドレス 6145  S        

&H1802    X   ->    10進数のアドレス 6146  X

&H1803    d   ->    10進数のアドレス 6147  d

&H1804    e    ->    10進数のアドレス 6148  e

&H1805    G   ->    10進数のアドレス 6149  G

~

~

&H1820   H   ->    10進数のアドレス 6176  H

&H1821   Y  ->    10進数のアドレス  6177   Y

&H1822   D  ->    10進数のアドレス  6177   D

 ~~

~~~

&H1AFF        ->    10進数のアドレス 6911  

右上から右へ。1行が終わったら、2行目の一番左から順番に

入っていきます。

 

実際にVRAMのデータを表示する命令は、

VPEEKです。

 

このVPEEKは、目にしたことがある方も多いかもしれませんねぇ〜。

MSX BASICの雑誌のプログラム(MSX FANとか、MSXマガジンとか、

ベーマガも)にはよく出てきていたと思います。

僕は、VPEEKを見たことはありましたが、なんかややこしそうな命令だなぁ、

くらいしかわかりませんでしたw

 

実際の画面上の文字は、

CHR$( VPEEK(アドレス) )で、画面上の文字を知ることが出来ます。

命令自体は簡単ですよね^^

(VPEEK<アドレス>で、画面上の文字のアスキーコードが取得されます)

CHR$についてはこちらへどうぞ。

MSXの特徴であるスプライト表示!初めての方にも。MSX BASICの基本を思い出しましょう、"その2" - ニャオニャオ21世紀

 

それで先ほどの、

パターンネームテーブル”(&H1800 ~ &H1AFF)から、

画面上の座標に値するアドレスをVPEEKに入れてやればいいんです。

 

座標のアドレスの計算方法

(X,Y)座標       <   文字単位 (0,0) ~ (31,23)   >

に表示されている文字のアドレスは、

&H1800+X+32Y

となります。

 

恐らく、MSX少年だった当時であれば、理解できなかったかもしれません、コレ。

簡単に説明します。

文字座標の (5,0) を考えてみます。

X=5 , Y=0 です。

一番上の行でXの6番目(0から始まっていますので)

になります。

先ほどの式に代入してみますと、

&H1800 + 5 + 0

で、

&H1805

となるのはわかると思います。

(16進数の値 + 10進数の値の足し算になっています^^)

(6144 + 5 + 0 = 6149とも表現できます)

 

文字座標の、( 5 ,  1 )だとどうでしょうか?

&H1800 + 5 + 1 * 32 

(*は掛け算です)

で、

&H1825  (10進数では6181)

 

考え方としては、

一番上のX座標が31進んだら、

2行目は32 ~ 63

3行目は64 ~ 95

4行目は96~

となっていきます。

 

一番左だけで考えると、

Y座標の 0行目が32文字表示で、座標としては31までなので、

Y座標の 1行目は32 x 1、

Y座標の 2行目は32 x 2、

となっていきます。

これにX座標の値を足してやるのです^^

 

こうやっていくと、

(X, Y)という座標が1つの数字で表すことができるます。 

これを知った時は、目から鱗でした!

座標を1つの数字で表す方法があるなんてって思いました!!

 

これは意外と今のPCでも使えます。

ある座標のピクセルの色を取得するのもこんな感じで出来ますので^^

(ちなみに僕が作ったiOSの8bit world cameraでもこんな感じでピクセルの色を

取得しています)

 

最後に、

スプライトの座標は、256 x 192で表しますよね!

なぜ文字の座標だと 32 x 24かといいますと、1文字が8ドットだからです!

256 / 8  = 32

192 / 8  = 24

です。

MSXでは、プログラムでよく使われる2つの座標があるのです。

256x192 と 32x24  です。

グラフィックを扱う命令の時は 256 x 192 (PUT SPRITEなど)

文字を扱う命令の時は 32 x 24 (LOCATEなど)

お気をつけください^^

 

<地形とマイキャラとの当たり判定>

マイキャラ(スプライト)の下の文字が何か知るためには、

画面上の文字の座標に直してやらないといけません。

 

スプライトの座標が (160 , 80)だったら、

160 / 8 = 20

80 / 8 = 10

で、文字の座標にすると(20,10)になります。

ここまで分かれば、あとは

VPEEK (&H1800+X+Y*32)

に代入してやるだけです。

スプライト座標が(160,80)の場合、

A$=CHR$ (VPEEK(&H1800+20+10*32))で

スプライトの下の文字が何かわかりますね!

 

ちなみにスプライト座標がいつも8で割り切れる訳ではないので、

8で割った答えだけ取得して、余りを捨てる演算子¥を使います。

スプライト座標が(X , Y)の時、

( X¥8 , Y¥8 )

が文字座標になります。

 

まとめますと、

スプライト座標(X,Y)の下の文字は、

A$ = CHR$ ( VPEEK  &H1800+(X¥8)+(Y¥8)*32 )

でわかります!!!

ちなみにスプライトの座標はスプライト画像の左上角になります。

ど真ん中ではないのでご注意ください。

座標計算がうまくいかなければ、X座標から1引いてみたり足してみたりして、

うまくいくように調整してください^^

 

色々と長々と説明してきましたが、この公式だけ当てはめれば、

プログラムは動きます。

内容が分からなくても使えるというのがいいですよね^^

意味なんて知らなくてもとりあえずはOKかなぁって思っています。

 

まずは自分のプログラムに組み込んでみて、結果を見てみる。

そんなものだと思います^^

 

まだ終わりではありません^^

マイキャラのスプライトの下の文字がわかったとしても

それではダメなんです。

マイキャラの下の文字を判定していたら壁にめり込んでいることになります。

( 昔はたまに壁にめり込むゲームがありましたw

 裏技扱いになっていたかもしれませんw) 

 

横などの壁(文字) にぶつかったら、進めなくなるというのがゲームです。

 

それには、マイキャラの移動予定の座標に、壁( 文字 )があるかどうかを

判定してやらないといけないのです。

 

スプライトの移動は

カーソルの右を押したら、X=X+1 (1ドット移動の場合) として、

右に移動させます。

 

X=X+1をしただけではスプライトはまだ移動していません。

 

PUT SPRITEを使い、変更したX , Y でスプライトを表示してやって

はじめて移動になります。

 

PUT SPRITEで表示する前に、

この移動予定の座標の下に文字があるかどうかをまず判定してやります。

 

TX=X:TY=Y

このあと、

カーソルキーの入力によってX=X+1したりY=Y+1したりする処理をします

そして、 

A$ = CHR$ ( VPEEK (&H1800 + (X¥8) + (Y¥8) * 32))

IF A$="#" THEN X=TX:Y=TY

 

 

 

TXとTYはなにかというのはあとで書きます。

 

A$ = CHR$ ( VPEEK (&H1800 + (X¥8) + (Y¥8) * 32))

で、

移動予定 の座標の下の文字をA$にいれます。

 

 

IF文で、A$が#だったら(今回は#が壁です)、マイキャラは進めないので、

まだ移動していない元の座標に戻します。

この場合は、TX , TYです。

(TX=X、TY=Yで、カーソルキーを入れる前の座標を覚えさせておきました)

(今現在スプライトのスプライトの座標、すなわち移動前の座標です)

 

これで一通りできました!

長かった~ (^○^)/

 

サンプルプログラム

 

f:id:nyaonyaokun:20180918110731p:plain

 

サンプルプログラムをWebMSXで実行

 

ダウンロード

 

サンプルのソースコード

 

10 SCREEN1,2:COLOR15,1,1:KEYOFF:WIDTH32
20 LOCATE 0,0:PRINT"############
####################"
30 LOCATE 0,1:PRINT"#
#"
40 LOCATE 0,2:PRINT"#
#"
50 LOCATE 0,3:PRINT"# # ######
### ############ #"
60 LOCATE 0,4:PRINT"# #
# #"
70 LOCATE 0,5:PRINT"# #
# #"
80 LOCATE 0,6:PRINT"# #########
# ############ #"
90 LOCATE 0,7:PRINT"#
# # # #"
100 LOCATE 0,8:PRINT"#
# # # #"
110 LOCATE 0,9:PRINT"# ## ####
# # # ### # #"
120 LOCATE 0,10:PRINT"# ## ###
## # # ### # ##"
130 LOCATE 0,11:PRINT"# ## ###
## # # # ### # #"
140 LOCATE 0,12:PRINT"# ## ###
## # # # #"
150 LOCATE 0,13:PRINT"#
# # # #"
160 LOCATE 0,14:PRINT"#
# # ######### #"
170 LOCATE 0,15:PRINT"# ## ###
##### # #"
180 LOCATE 0,16:PRINT"# ## #
# # #"
190 LOCATE 0,17:PRINT"# ## #
# ############ #"
200 LOCATE 0,18:PRINT"# #
#"
210 LOCATE 0,19:PRINT"# #
#"
220 LOCATE 0,20:PRINT"##########
######################"
1000 X=96:Y=80
1010 FOR I=0 TO 15
1020 READ DT$
1030 L$=L$+CHR$(VAL("&B"+LEFT$(D
T$,8)))
1040 R$=R$+CHR$(VAL("&B"+RIGHT$(
DT$,8)))
1050 NEXT
1060 SPRITE$(0) =L$+R$
1070 S=STICK(0)
1080 TX=X:TY=Y
1090 IF S=1 THEN Y=Y-8
1100 IF S=2 THEN X=X+8:Y=Y-8
1110 IF S=3 THEN X=X+8
1120 IF S=4 THEN X=X+8:Y=Y+8
1130 IF S=5 THEN Y=Y+8
1140 IF S=6 THEN X=X-8:Y=Y+8
1150 IF S=7 THEN X=X-8
1160 IF S=8 THEN X=X-8:Y=Y-8
1170 A$=CHR$(VPEEK(&H1800+(X\8)+
(Y\8)*32))
1180 B$=CHR$(VPEEK(&H1800+(X\8)+
1+(Y\8)*32))
1190 C$=CHR$(VPEEK(&H1800+(X\8)+
(Y\8+1)*32))
1200 D$=CHR$(VPEEK(&H1800+(X\8)+
1+(Y\8+1)*32))
1210 IF A$="#" THEN X=TX:Y=TY
1220 IF B$="#" THEN X=TX:Y=TY
1230 IF C$="#" THEN X=TX:Y=TY
1240 IF D$="#" THEN X=TX:Y=TY
1250 PUT SPRITE 0,(X ,Y),15,0
1260 GOTO1070

2000 DATA0000000110000000
2010 DATA1000110110110000
2020 DATA1001111001111000
2030 DATA1011111111111100
2040 DATA1010000000000100
2050 DATA1010111111110101
2060 DATA1110101111010111
2070 DATA1010101111010100
2080 DATA1000111111110000
2090 DATA1000011111100000
2100 DATA1110000000011111
2110 DATA1110011111011011
2120 DATA1110111111010001
2130 DATA1000001001011011
2140 DATA0000110110111011

2150 DATA0000111001101110

このようになります。

20行~220行が MAP

1010行 ~ 1160行が、前回やったスプライトの移動

1080行と、1170行 ~ 1240行が、壁"#"との当たり判定

 

1170行 ~ 1200行がなぜ4回も、VRAMから文字を取得しているかといいますと、

マイキャラであるスプライトが16x16ドットだからです。

4ヶ所調べないと、めり込んでしまうのです。

こちらに似たようなことが画像入りで書いてあります。よろしければどうぞ^^

www.nyaonyao21.com

 

 

 

1080 TX=X:TY=Yと、

1250 PUT SPRITE 0,(X ,Y),15,0の

位置にお気をつけください。

 

1080 TX=X:TY=Yは、カーソルキーの入力を取得して、X,Yの座標を変更する前

 

1250 PUT SPRITE 0,(X ,Y),15,0は、座標X,Yの計算がすべて終わった最後の方です。

 

まとめ

 

⬇︎を公式として使ってもOKです。

A$ = CHR$ ( VPEEK  &H1800+(X¥8)+(Y¥8)*32 )

機能: X,Y (スプライトの座標など) に値を入れると、

A$にその座標の文字が返ってきます。 

           

その返ってきた文字が、壁を表している文字だった場合、

キャラクターをそれ以上動かなくさせます。

 

 

VRAMのアドレスの内容を知っていると、実に色々なことができます!

ここができるとプログラムがとても面白くなってくるので、

追々説明していきたいと思います^^

(ちなみに文字の形を変えて、ブロックの絵にするのもVRAMにアクセスします。)

 

MSX実機が欲しい方はこちらでどうぞ。

通販ショップの駿河屋(MSX本体)

 

 

次回は、文字(今回は#でした)をブロックの絵に描き変えるというのをやりたい

と思います。

 

おまけ

 このプログラムですと、画面の下の方がスカスカになってしまいます。

PRINTがすべて終わると、改行がされてしまい

上の方が消えてしまうためです。

 

これを改善する方法もあります。

f:id:nyaonyaokun:20180918112928p:plain

 

WebMSXで実行


15 POKE &HF3B1,26
16 KEY1,CHR$(12)+"POKE&HF3B1,24"+CHR$(13)

 

230 LOCATE 0,21:PRINT"##########
######################"

240 LOCATE 0,22:PRINT"##########
######################"

250 LOCATE 0,23:PRINT"##########
######################"

 

これだけ追加してみてください。

プログラムをCTRL + STOP で止めたあとは、ちょっと挙動がおかしくなるので、

F1キーを押していただくと元に戻ると思います。

これは、15行でY座標を26行までと設定しています。

16行でF1キーに、画面を消して、y行を再び24行に戻すというのを設定しています。

 

よろしければ色々やってみてください^^

 

つづきのページはこちら

www.nyaonyao21.com

 

 

MSX MAGAZINE 永久保存版 [CD-ROM1枚、特製シール付き]
MSXアソシエーション
アスキー
売り上げランキング: 366,184
 

 

MSX MAGAZINE 永久保存版 2
MSX MAGAZINE 永久保存版 2
posted with amazlet at 18.09.04

アスキー
売り上げランキング: 694,835

 

MSX MAGAZINE永久保存版3
MSX MAGAZINE永久保存版3
posted with amazlet at 18.09.04

アスキー
売り上げランキング: 818,909
僕のはwin10じゃないので試していませんが。
ネットで調べてみてください;)
 
 
 

こちらの方が安いかもしれません^^

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

  


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

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