ゲーム中にアイテムを入手したときにそれをストックしておく場所があって、それを自分の好きな場面で使えるようにすると、ゲーム戦略が立てられるようになるので面白さが格段に増すと思います。
今回はそのようなアイテムをストックしておけるアイテムボックスのプログラムをつくっていきます。
この記事を読んでいただくと、アクションゲームでアイテムボックスにアイテムを格納する・取り出すプログラミングの方法が分かります。
なお、この記事で使用しているスプライト(キャラクター・背景・オブジェクト・音声など)はすべてパブリックドメインの無料の素材をダウンロードして使用しています。
完成品
この章の内容をご自身のScratch環境に反映すれば、同じ動きを再現することができます。
完成した動き
アイテムボックスに4つのケース、アイテムは5個用意しています。
アイテムに触れるとそのアイテムがケースに移動します。
ケースに空きがある場合、最大4個までアイテムを格納することができます。
ケースには左から1~4の番号を割り当てていて、キーボードの該当する番号を押すとその番号のケースに入っているアイテムを取り出すことができます。
一度取り出したアイテムは消費してしまうので消えたことにしています。
使用したスプライト
スプライトは「キャラ1」「地面1」「天気1」「ボックス」「アイテム」の5つです。
アクションゲーム用の背景・キャラクター・アイテム等の画像や音声は、パブリックドメインである「スーパーパワーアセットパック(CC0)のprehistoric-platformer」を使っています。
「キャラ1・地面1・天気1」スプライトについては、こちらの記事の「使用したスプライト」の章で詳しく説明していますので参照してください。↓↓↓
【Scratch 3.0】アクションゲーム ジャンプと地面にめり込まないように着地する方法(Tips)
【ボックスのスプライト】
「ボックス」スプライトの画像は、スーパーパワーアセットパックの「prehistoric-platformer\hud」フォルダ内にある「inventory-left.png」「inventory-middle.png」「inventory-right.png」「inventory-case.png」の4つのファイルをコスチュームにアップロードして使用しています。
※プログラムや説明の中で『ケース』と呼んでいるのは下の図で一番下にある画像のことです。ボックスと使い分けて呼んでいます。
【アイテムのスプライト】
「アイテム」スプライトの画像は、スーパーパワーアセットパックの「prehistoric-platformer\items」フォルダ内にある「8.png」「14.png」「20.png」「21.png」「26.png」ファイルをコスチュームにアップロードして使用しています。
完成したスクリプト
完成したスクリプトの全体です。
内容をアイテムボックスに関するものに絞るため、各スプライトのスクリプトから背景スクロールや一部のアニメーションなど、説明に必須でないブロックは削除しています。そのため、以前の記事に比べてプログラムの量が少なくなっているところがあります。
【キャラ1のスクリプト】
「キャラ1」のスクリプトは、以前の記事と同じ内容なのでこちらの記事を参照してください。↓↓↓
【Scratch 3.0】アクションゲーム ジャンプしながら移動する方法(Tips)
【地面1のスクリプト】
※前回の内容と同じです。
【天気1のスクリプト】
※前回の内容と同じです。
【ボックスのスクリプト】
- ケース数:このスプライトのみ
- ケース番号:このスプライトのみ
- X:このスプライトのみ
- Y:このスプライトのみ
- ケースin:すべてのスプライト用
- ケースx:すべてのスプライト用
- ケースy:すべてのスプライト用
【アイテムのスクリプト】
- クローン名:このスプライトのみ
- i:このスプライトのみ
スクリプトの作り方
ここからはプログラムを作っていく中でポイントとなる部分を説明します。
ポイント①:アイテムを入れるケースの座標をリストに入れる
まず、アイテムを入れるためのボックスとケースを配置します。
【ボックスのスプライト】の項で示していますが、ケースとその背景画像(ボックス部分)はすべて同一のスプライトの中にあってコスチュームの部分で複数の画像を持っています。
そのため、ケースを複数配置する場合はクローンを作成する必要があります。
汎用的な定義ブロックをつくって、ケースもその背景部分もすべて1つの定義ブロックで作れるようにしました。
この定義ブロック(名称:ケースのクローン作成)は、2つの引数を与える必要があり、1つは「繰り返し回数(数値)」、もう1つは「コスチューム名(文字列)」です。
コスチューム名が「ケース」だった場合に、定義ブロック内の「もし~なら」部分が実行されます。
「ケース番号」変数が1のとき、リスト「ケースx」と「ケースy」の要素番号1番にそれぞれx座標とy座標が格納されます。その後、「ケース番号」変数が1つずつ増えながら合計4回繰り返しています。
リスト「ケースx」と「ケースy」の実行結果を見ると下の図のようになります。
ケース1~4の中心座標が、リストの1番目~4番目に格納されます。
格納された座標は、ゲットしたアイテムの移動先に指定したり、ケースからアイテムを取り出した後に残りのアイテムを左詰めに並べ替えるときに使います。
ポイント②:アイテムクローン1つ1つに自分の名前を覚えさせておく
クローンはただ複数つくっただけでは、1つ1つのクローンを区別できません。
今回はクローンを識別したいので「このスプライトのみ」でつくった「クローン名」変数を使って、それを実現します。
ここでも「定義ブロック(名称:アイテムクローン作成)」を使っています。引数は1つ(アイテム名:文字列)与える必要があります。
「自分自身のクローンを作る」ブロックの手前で「クローン名」変数の値を設定してからクローンをつくることで、各クローンが別々の値を持つようになります。
このブロックが実行されると、各クローンが持っている「クローン名」変数の値はコスチューム名と一致したものになります(下図参照)。
ポイント①とポイント②を組み合わせることで、どのクローンがどのケースに入っているかを特定することができるようになります。
ポイント③:主人公が触れたらケースに移動する
主人公がアイテムに触れたかどうかを調べるには、各クローンのプログラム内で自分が触られたかどうかをチェックし続ける必要があります。そのため「クローンされたとき」ブロックの下に「ずっと」ブロックをつなげて行います。
クローンに何かをさせたいときは「クローンされたとき」ブロックの下でないと実現できません。「緑の旗でスタート」ブロックの下は、スプライトそのもの(実体)に対してのプログラムを作成する場所であって、そこにつないだブロックはクローン全体に影響を与えます。さらに個別のクローンに何かさせたいときは「このスプライトのみ」で作った変数を利用します。
各クローンが定義ブロック(名称:アイテムを取得)を実行し続けています。この定義ブロックには引数を1つ(アイテム名)を与える必要があります。
チェックの内容は、「キャラ1」スプライトに触れていて、かつ「クローン名」と「アイテム名」が一致した場合に条件が成立して「ケースに入れる」定義ブロックが実行される内容になっています。
ポイント②で説明したように「クローン名」変数には、クローンされたアイテム画像ごとに「にく・おの・ほね・ブーメラン・貝がら」とそれぞれ別々の名前が格納されている状態です。
たとえば、主人公が「おの」の画像に触れたとしましょう。このとき「アイテムを取得(おの)」ブロックだけのチェックは成立しますが、それ以外では成立しません。つまり、「おの」の画像だけが「ケースに入れる」対象になるということです。
つぎに「ケースに入れる」定義ブロックの中身を確認します。
「ケースin」リストが登場しますが、最初は中身が空っぽ(長さ=0)の状態です。
「ケースin」リストの長さが「ボックスのケース数(初期値=4)」よりも小さかったら実行するという条件になっています。
「ボックスのケース数(初期値=4)回繰り返す」ブロックの中身に移ります。
「もし(ケースinの長さ)=(ボックスのケース数-i)なら」ブロックの条件が成立すると、ケースの左から順に見てまだアイテムが入っていない場所を探して、そのケースの中心座標に移動させます。
最後に「ケースin」リストに「クローン名(=アイテム名)」を追加します。
この定義ブロック(名称:ケースに入れる)は、ケースからアイテムを取りのぞいた後に改めてアイテムを追加する場合にも使うことができます。
「もし~なら」の条件が成立するときの「ケースinの長さ」「変数iの値」「格納されるリストの要素番号」「格納されるクローン名」の関係を表で表すと次のようになります。
ケースinの長さ | 変数iの値 | 格納されるリストの要素番号 |
0 | 4 | 1 |
1 | 3 | 2 |
2 | 2 | 3 |
3 | 1 | 4 |
4 | – | – |
これらのスクリプトの実行結果は下の図のように、主人公がアイテム画像に触れた順番にケースの左から画像が配置され、同時に「ケースin」リストには要素番号1番から順番にクローン名(=アイテム名)が入ります。
ポイント④:指定されたケース番号からアイテムを取り出す
ケースからアイテムを取り出す(今回は削除)ときにはキーボードの「1」「2」「3」「4」キーを使います。
この番号キーはケースの左から順番に対応していて、どの位置のアイテムを取り出すかを指定することができます。
いずれかの番号キーを押すと、「アイテムを取り出す」定義ブロックが実行されます。この定義ブロックは引数を1つ(要素番号:数値)必要とします。
「もし(クローン名=ケースinの(要素番号)番目なら」ブロックが成立すると、「ケースin」リストから指定した番号の要素を削除し、該当したクローン(アイテム画像)も削除します。
この条件は、「ケースin」リストの指定した要素番号に入っているアイテム名と一致した名前を持っているクローンに対して成立します。
なお、リスト全般に言えることですが、途中の番号の要素を削除すると自動的に前詰めして常にスキマができないように調整してくれます。(スタックなのでこれは当然だと思われる)
そのため、ケースに入れた画像も常にリストの状態と合わせておく必要があるので、最後にケースに入れがアイテム画像を左詰めに並べ替える処理(「ケースを整理する」定義ブロック)を行います。この部分はポイント⑤で説明します。
ダミーのコスチュームが必要なことが発覚!
ちょっとここで事件があったので触れておきます。
今回「アイテム」スプライトのコスチュームにあえて「ダミー」画像を追加して、わざわざそのクローンも作るようにしています。このダミー画像は何も描かれていないのでクローンを作っても画面上には何も表示されません。
最初はこれを作らない状態で動かしていたのですが、ケースに入れたアイテムを1つしか消していないのにリストから2つ分消えてしまう(場合がある)現象に悩まされていて、たどり着いた解決策がダミー画像を追加する方法でした。
指定したアイテム画像はケースから削除されるのですが、リストからは2つ分消えてしまうのでもう1つの画像はケース内に残ったまま消せなくなってしまいます。
まったく原因が分からないのですが、仕様なのか?スタックのバグだったりするのか?今のところお手上げ状態です。
なので、必ずダミーのコスチュームが必要、というのが現状です。
ポイント⑤:アイテムが取り出されたらケース内を左詰めで並べ替える
アイテムをケースから取り出した後にケース内のアイテムを左詰めで並べ替えます。
「ケースin」リストの中は自動的に前詰めになるので、アイテム画像もそれに合わせる形で整頓する必要があります。
つまり、リストを正としてアイテム画像の方を並べ替えるわけです。
削除後の「ケースin」リストの長さ分だけ繰り返し処理を行います。
移動先の座標はもともと「ケースx」リストと「ケースy」リストに入っているのでそれを使って座標を移動させればOKです。
ここまでのポイントを押さえれば、アクションゲームでアイテムボックスにアイテムを格納する・取り出すためのスクリプトを完成させることができると思います。
失敗しやすいポイント
ポイント④の最後の方で説明しましたが、「ダミー」コスチューム画像を使わなかった場合どうなるかを試してみましょう。
「ケースin」リストが一度に2つ削除されるタイミングがあるのが分かると思います。こうなるとケースに入ったアイテム画像に不具合が発生します。この原因が不明。。。
応用編
今回応用編は特にありません。
まとめ
さいごに、今回の記事で説明した『アクションゲームでアイテムボックスにアイテムを格納する・取り出すプログラミング』のポイントをまとめます。
- ポイント①:アイテムを入れるケースの座標をリストに入れる
- ポイント②:アイテムクローン1つ1つに自分の名前を覚えさせておく(変数を「このスプライトのみ」でつくる)
- ポイント③:主人公が触れたらケースに移動する(リストに入った座標を利用する)
- ポイント④:指定されたケース番号からアイテムを取り出す
- ポイント⑤:アイテムが取り出されたらケース内を左詰めで並べ替える(リストは自動的に前詰めになる)
今回紹介したアイテムボックスは、アイテムを好きな順番で取得でき、好きな順番で取り出すことができるようになっているので、わりと汎用的に使えるロジックではないかと思います。
取り出したアイテムをどのように使うかは、それぞれのアイテム画像の特性ごとに考える必要があるので、またの機会にチャレンジしてみたいと思います。
どうでしたか?上手く再現できたでしょうか?
他にも役に立つTips(ティップス)記事をたくさん書いてますので、ぜひ見てみてください。(記事のタイトルに「Tips」と書いていたり「Tips」タグを貼ってあります)