【プチコン4講座】背景を表示してみよう
こんにちは。継続の錬金術士なおキーヌです。
ブログ毎日更新は211日目になります。
第3回「プレイヤーをコントロールしてみよう」にてボタンの仕組みとプレイヤーを8方向移動させることが出来ました。
今回は真っ黒なままでは味気ないですし、折角性能が素晴らしいSwitchなので背景を表示してしまいましょう。
自機が車ということで宇宙空間より地面を走っている方が自然に見えるのでまず地面を設置していきます。
それではプチコン4でSTG作りその第4回目始めましょう。
背景を表示する方法
ずっと背景が真っ黒っていうのもなんか味気ないわね。
そうか?俺は宇宙空間みたいで結構気に入ってるぞ。
そうだね。昔のゲームだと宇宙船だったり戦闘機だったりが多くて背景の描写を減らして少しでも容量をなくすために頑張っていたんだけど今はそんなこと考える必要もないし、そもそも自機が車だから地面があった方が自然だね。
キャラクターを表示する時はスプライトをつかったけど、まさか背景もスプライトを使うのか?
出来ない事も無いけど、プチコンにはテキストスクリーンっていう仕組みが用意されているんだ。名前は「テキスト」ってついてるけど主に背景に使う仕組みって今は覚えてもらってたら大丈夫だよ。早速使ってみようか。
TPRINT 0, CHR$(&HE8D8)
なんか左上にでたな。しかし文字が邪魔で見辛い……なんだこれ?
砂漠のマップチップだよ。これを画面全体に敷き詰めて砂漠を表現してみるよ。今度は下記のコードを試してみて。
TPUT 0, 10, 10, CHR$(&HE8D8)
あ、下の方に出てきたよ。これってもしかしてスプライトと同じで0は番号でその隣にあるのはX座標とY座標で、最後が何を表示するか。でしょ!?
大正解!順を追ってやっていると似たようなのが出てきた時に何をしているのか予測がつきやすくて良いでしょ。
でもX座標とY座標10なのにやけに下に方にいるよな。
リキくんも良い所突くね。そう、スプライトとの違いの1つとしてテキストスクリーンは基本16×16のサイズで動いていくんだ。
これをどうやって画面全体に敷き詰めればいいの?
ここでは「for」を使ったループを使用するよ。1つずつ右にズラして描写して一番右まできたら一番左に戻って1つ下にズレてまた右に1つずつ描写って感じで敷き詰めるんだ。早速コードを書くよ。
var I=0,J=0
for J=0 to 14
for I=0 to 24
TPUT 0, I, J, CHR$(&HE8D8)
next
next
おぉ、砂漠が画面全体に広がったぞ!すげぇ!どういう仕組みだこれ!?
なるほど!ループを入れ子にしてZ状に表示していくのね!
この方法だと1つの画像しか表示できないから、条件式を設けたりして別の画像を描写するってのもできるんだけど、正直凄く効率が悪いしめんどうくさいんだ。
確かにずっと砂漠しかないと面白みに欠けるわね。
マップエディタなんかがあったらそれを使ってマップを作って読み込むってのが楽なんだけど元々プチコン4にはその機能は入ってないんだ。
既にプチコン4のユーザーが誰か作っているかもしれないけどここは一旦自力でマップを作ってみるね。簡単なマップだからコードにしてみたよ。
DIM MAPDATA[] = [\
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,\
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\
]
なんだこれ!0がいっぱいあって……所々1があるな。
実はこれがマップの正体なんだ。
これがマップなの?ちょっと想像できないわね……
ちなみにこれは配列っていって変数は1つしか入れられないけど配列はたくさん入れることが出来るんだ。
親には名前を付けられるけどその中に入っているそれぞれの変数には名前は付けられないけど、連番になっているから指定すれば好きな所から値を取れるんだ。
ちょっとよくわからないわね……
実際にこの配列を使ってマップを表示してみようか。配列のアクセスの仕方もコードを見ればすぐわかるよ。
var I=0,J=0
DIM MAPDATA[] = [\
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,\
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\
]
for J=0 to 14
for I=0 to 24
if MAPDATA[I * (J+1)] == 0 then
TPUT 0, I, J, CHR$(&HE8D8)
elseif MAPDATA[I * (J+1)] == 1 then
TPUT 0, I, J, CHR$(&HE8D9)
endif
next
next
マップにてきとうに1を置いていったからSSとちょっと違うかもしれないけど同じような感じになっていたら成功だよ。
なんかさっぱりわからんぞ!トモカズ!説明してくれ!
1つずつ説明していくね。まず変数の宣言の仕方は1つずつやらなくてもこのIとJのようにカンマを区切れば一々「var」をか無くてもよくなるんだ。見通しは悪くなるけどね。
次にMAPDATA、つまり配列だね。この中に0と1がカンマ区切りでいっぱいならんでて、まるで二次元のマップのようにみえるけど
実はプログラム的には1次元になっているんだ。本当は途中で改行するとエラーが出るんだけどプチコン4では「\」を最後に入れると改行してもエラーがでなくなるんだ。
バックスラッシュ?俺には円マークにしか見えないが……
ブログだとそう見えちゃうけど内部的には同じなんだ。キーボードの¥を押すかJoyConで-ボタンを押して家マークの上にある逆スラッシュを押すと良いよ。
おぉ、本当だ!円マークを押したらスラッシュの逆向きのが出てきたぞ!
配列の話に戻ると、ちょっとマップデータでは配列の説明としては変に複雑になっちゃうからまた今度配列については説明するよ。今はこういう形で書いておけばマップとして使えるって思ってくれたらいいよ。
わかったわ。次のforを使っているループなんだけど、これってどういう意味になるの?
forは決まった数のループで使うんだ。最初に変数に0を入れているのは開始の時の数値で、toをはさんで右にある数字が最後の数字ってことさ。つまり最初のforは0~14の15回ループになるんだ。そしてループは入れ子になっているから、中のforが終わってからやっと外側のforの数値が1つプラスされていくんだよ。
なるほど!それならIが最後まで行ったらJが1つ追加されてY座標を1つ下に下げられるってわけね!よくできてるぅ!
このforの入れ子手法は二次元的な処理をしたいときによく使うよ。といっても今回作るゲームではこのマップ描写ぐらいしか使わないんだけどね。だから複雑に考えずにこうしたらマップを描写出来るって思っておけば大丈夫。計算も描写もなにもかもプチコン4がやってくれるからね。
後はこの配列の中身を見てるってのはなんとなくわかるんだけどさ、これはどうなってんだ?
配列にアクセスする時は例えばこれならMAPDATA[0]だと最初の0を取ることが出来てMAPDATA[1]なら次にある1が取れるって感じだね。カッコの中は連番の数字を指定しなきゃいけないんだけど、ここには計算式を入れられるんだ。
I * (J+1)ってなにしてんだこれ
横 かける 縦 の計算だよ。 でも0に何をかけても0になっちゃうから縦方向には+1をしておいて1回目の横ループが全部0にならないように補正してるんだ。こういう補正は結構プログラミングでよく使うから1個ずらしたいってときとかは使ってみると良いよ。
確かにそれなら0から最後まで数字がカウントできるわね。
横と縦は0~24と0~14までしかカウントしないけど、MAPDATA配列は折り返してはいるが実際は1つの横に長いデータで、個数で言うと25×15の360個のデータがあるから0から最後までカウントさせる必要があるんだ。
私はよくわかったけど、リキにはちょっと難易度が高いんじゃないかしら?
うぐぐ……
確かにちょっと難易度がぐっと上がった感じがあるね。やっていることは凄く単純なんだけどちょっと見た目と中身のズレが生じて理解し辛い部分なんだ。プログラミングを難しく感じる部分の1つでここで挫折してしまう人も少なくはないよ。そういう時はわからないから先に進むをやろうね。こんな複雑なことしてるのはココだけだし1回書いてしまえばあとはプログラムが勝手に動いてくれるし心配しないでも大丈夫だよ。
わ、わかった……悔しいが次に行こうぜ……
テキストスクリーンについて知ろう
テキストスクリーンについてちょっとお勉強しようか。といっても正直ボクもまだプチコン4に完全に慣れていないってのもあって分からないところも多いからわかる範囲で説明するよ。
テキストスクリーンって名前なんだからテキストも表示できるってことか?
そうだね。画像を使った文字を表示したり色々なことが出来るよ。それよりも重要な部分が描写するためのレイヤー構造なんだ。
レイヤー?
透明のシートが重なってるイメージをしてくれればいいかな。例えば今回TPUTの最初に0を指定したでしょ?あれがレイヤーの番号なんだ。
スプライトの場合は管理番号だったけど、テキストスクリーンの時はレイヤーの番号になるのね。
レイヤーは0~4の5枚あるんだけど実質使えるのは0~3の4枚だと思ってくれていいよ。そしてレイヤーの数値が少ないほど手前にあるんだ。
ということはレイヤー0に砂漠を全部表示したってことは……後ろにあるレイヤーはみえなくなってるってこと?
そう、だから一番背景にしたいなら3番レイヤーで描写するべきだね。もっと詳しく知りたい人は公式のリファレンスをみてね。
画面をスクロールするにはどうすればいいか
なぁトモカズ、ちょっと思ったんだけどよ
もしかして画面スクロールについてかい?
あぁ、その通りだ。このままだとシューティングって感じがしないもんな。俺の知ってるレトロゲーシューティングは常に背景が動いてたぜ。
スクロールはちょっと難易度が高いんだ。実はまだプチコン4になってからボクもやったことがないからまだ詳しい説明ができないんだけど……考え方は伝えることが出来るかな。
プチコン4はテキストスクリーンにおいてデフォルト状態だと画面に映っている部分までしか描写することはできないんだ。だから描写する範囲を広げて見えないところも描写してあげる必要があるんだよ。そして、テキストスクリーンの座標をループする度に左に動かしていけばスクロールの完成だよ。
スプライトなら画面外でも大丈夫だったよね?動かしたときは画面外にいけてもエラーでなかったし。
なるほど……マユミちゃんそれナイスアイデアだよ!
え?え?
背景は砂漠のマップチップだけにして、それ以外はスプライトにしてしまうって手もあるよ。プレイヤー以外のスプライトは常に左に動くようにして疑似的にスクロールしてるように見せるんだ。
そういうことね!トモくんの発想力凄い!
どっちにしろ障害物はスプライトにする予定だったからそっちの方が簡単でいいかもしれない。今回はそっちでいこうか。本当のスクロールはちょっと勉強したいから時間欲しいな。
トモカズでもわかってないものを俺たちがわかるはずもないもんな(笑)
シューティングゲーム作り講座第4回まとめ
- TPRINT
-
テキストスクリーン用のPRINT文と思ってくれていたら良いです。
-
ゲーム作りにはあまり使いません。主に確認用で使います。
- TPUT レイヤー番号, X座標, Y座標, チップ番号
-
レイヤー番号は0~3を指定して使います。4は基本的に使いません。
-
X座標とY座標に指定した位置にマップチップを描写します。ここで指定する値は常に16が掛け算された値になるので注意してください。
-
チップ番号は公式に一覧が載っていないので自力で探すしかありません。オンラインで一覧表示してくれるツールがあるので探してみてください。
- CHR$(n)
-
指定された文字コードから文字を返す。
-
主にマップチップを指定する時に使います。というかそれ以外今のところ知りません。
-
頭に「&H」を付けて4桁の16進数の数字を使って指定します。
-
例:CHR$(&HE8D9) とすると骨のある砂漠チップで CHR$(&HE8D8) だと砂漠だけのチップになります。下4桁の数値を16進数(0~Fの数値)を指定して何が表示されるか見てみるのも面白いかもしれません。表示される内容はF10もしくはスマイルツール2で確認できます。
-
探すの面倒なので出来れば公式で一覧表を作ってほしい所ですね……
- for 初期値 to ループ終了値 ~ next
-
値を決めたループです。無限ループにしたくないときに使います。
-
プログラミング言語には大体実装されている機能なのでforの使い方を検索すれば大体わかります。
トモカズくんが言ったように私自身がテキストスクリーンによるマップスクロールはまだやったことが無いので説明できません。
テキストスクリーンのレイヤーをずらして横に並べてスクロールさせ、画面外に行ったレイヤーを後ろに移動させて延々とループさせるというのはわかったのですが
まだ試していないのでとりあえずマユミちゃんの言った通りスプライトでの疑似スクロールで今回の講座を進めていきます。
スクロールについてはアクションゲーム講座を開いたときにでもやろうかと思います。
それまでには勉強しておかなきゃいけないですね。
次回は今までやったことのまとめでもやろうと思います。
それに加えて関数についての解説も開くのでお楽しみに!
それでは。