SmileBASIC

SmileBASIC講座


今回で最終回となります。

今までに紹介してきた技術をすべて組み合わせて、ゲームを作ってみたいと思います。
ミニゲームは過去にも作ってきましたが、今回はそれより発展させたゲームを作ります。

ゲーム作りを始める前に便利な機能について紹介します。

アニメーション表示機能

スプライトにはアニメーション機能があります。
この機能を使うとスプライトの移動や回転や拡大縮小などの様々な表示ができます。
アニメーションを行うには「SPANIM」という命令を使用します。SPANIM命令の書式は次のとおりです。

SPANIM 管理番号,"アニメ対象",時間,項目1[,項目2]…[,ループ]

「管理番号」はアニメーションさせるスプライトの管理番号です。
「アニメ対象」はアニメさせる機能を指定します。この機能はたくさんの種類が存在します。
「ループ」はアニメを繰り返す回数のことです。0で無限に繰り返します。
「時間」は表示させたい時間をフレーム数で指定します。
「項目」についてはアニメ対象の種類によって違いますので、実例を挙げて紹介します。

《移動のアニメーション》

たとえば、図のように「人」のキャラクターが左から右に向かって移動する表示したいとします。
キャラクターが終点に到着すると、開始点に戻って動きを繰り返します。
移動にかかる時間は120フレーム=2秒間とします。

時間 座標 時間 座標 無限に繰り返し
SPANIM 管理番号,"XY", 1, 64,120, -120, 336,120, 0

これをSPANIM命令に置き換えたものがこちらです。
アニメ対象を「"XY"」とすることで、移動するアニメーションを行います。
時間の項目をマイナスの値にすると途中の座標を補間しながら移動します。

《定義番号のアニメーション》

続けて、このように4つの画像を切り替えて表示をしたい場合です。
これで人のキャラクターが走っているように見えます。

時間 番号 時間 番号 時間 番号 時間 番号 時間 無限に繰り返し
SPANIM 管理番号,"I", 8, 2544, 8, 2545, 8, 2546, 8, 2547, 8, 0

これをSPANIM命令に置き換えたものがこちらです。
アニメ対象を「"I"」とすると、キャラクター定義用テンプレートの切り替えるアニメーションを行います。
画像1枚あたりの表示時間を8フレーム=約0.133秒としました。

以上の2つのアニメーションを合体させると、このようなプログラムになります。
実行して確認してみましょう。

スプライトの当たり判定

スプライト同士の重なり具合を調べるにはスプライトの衝突判定機能を使うと便利です。

こちらは衝突判定機能を実験するためのプログラムです。
まず、「SPCOL」という命令を使いスプライトの衝突判定機能を有効にします。
SPCOL命令の書式は次のとおりです。

SPCOL 管理番号 [,スケール対応]

「管理番号」はスプライトの管理番号です。
「スケール対応」はSPSCALEで拡大縮小した範囲を有効とするかを設定します。
「TRUE」の場合は有効、「FALSE」の場合は無効とします。

スプライトの衝突を検出するには「SPHITSP」関数を使います。
SPHITSP関数の主な書式は次のとおりです。

戻り値 = SPHITSP( 管理番号 [,先頭ID,末尾ID] )

「管理番号」は判定するスプライトの管理番号を指定します。
「先頭ID」「末尾ID」は判定する管理番号の範囲を指定しますが、今回は使用しません。
関数の戻り値には、その衝突したスプライトの管理番号が返されます。

プログラムを実行した結果です。
「人」と「リンゴ」がアニメーション機能で動きます。
赤い四角形は当たり判定の範囲を視覚化したものです。
四角形が重なると「衝突」と判定します。
画面左側の数値はSPHITSP関数の戻り値です。
この場合、「人」のスプライトの立場で衝突を判定しています。
衝突した場合には、「リンゴ」のスプライトの管理番号として「1」を表示します。
衝突していない場合には「-1」を表示します。

ゲームの作り方

ここからが本題の「ゲームの作り方」です。
この記事は初心者講座ですので、ゲームの規模も初心者向けにしたいと思います。

《ゲーム作りの難易度》

ゲームを作るには労力と時間が必要です。
たとえば、ミニゲームを完成させるのに1日を費やしたとします。
では、超大作ゲームを完成させるには何日必要でしょうか?
この「作ることの大変さ」をここでは「難易度」と呼ぶことにします。
理想としては、ゲームの規模に対して難易度は比例して欲しいのですが、実際には難易度は自分で思っているよりも上がってしまいます。
プログラムが巨大化・複雑化して、収拾がつかなくなり、最後には完成せずに終わってしまいます。

《サブルーチンの使い方》

難易度の上がりすぎを防ぐ方法の1つは「サブルーチン」を使うことです。
サブルーチンは処理ごとに切り分けたプログラムのことです。

サブルーチンを実行する仕組みです。
サブルーチンの内部で処理が終わると、元の処理の流れに戻ります。

たとえば、このようなプログラムがあったとします。
これを処理ごとに切り分けて、サブルーチンに置き換えていきます。

サブルーチンに置き換えた結果がこちらです。
サブルーチンの先頭には「@ラベル名」を書き、最後には「RETURN」を書きます。
サブルーチンは「GOSUB」という命令を使って呼び出します。
書式は「GOSUB @ラベル名」です。
この結果を見るとプログラムが無駄に増えただけに感じるかもしれません。
この方法はプログラムが長くなった時に意味を持ちます。
サブルーチンを使うと、プログラムを「部品」として扱いやすくなります。
部品の1つ1つをしっかり作ることで、プログラムが分かりやすくなり、ゲーム作りの難易度を抑えることができます。
なお、処理を切り分ける方法として、SmileBASICには「ユーザー命令/ユーザー関数(DEF)」という機能もあります。

ゲーム作りの開始

続いて、ゲームの画面やルールを決めましょう。

今回はこのようなゲームを作ります。
タイトルは「リンゴ地獄」と名付けました。
「プレイヤーキャラ」は左右に移動したり、ジャンプすることができます。
プレイヤーが「リンゴ」を取るとスコアが加算されます。
地面は右から左に流れていきます。
地面にはたまに穴が空いています。
プレイが進むにつれて穴の数は増えていきます。
プレイヤーが穴に落ちるとゲームオーバーです。
プレイ中の画面の他にタイトル画面やゲームオーバー画面も用意します。
ボタンは次のように割り振りました。

十字ボタン(左右のみ) 左右の移動。
Aボタン ジャンプ。Aボタンを押す時間が長いほど高くジャンプすることができます。
プログラムを作る

ゲームのプログラムを作ります。
プログラムは全体で130行くらいの長さになります。
ここでは、サブルーチンごとに内容を紹介します。

《メイン処理》

最初に実行するプログラムです。
各機能のサブルーチンを呼び出します。
それぞれのラベル名の意味は次のとおりです。

ラベル名 機能
@INIT 初期化のサブルーチン。
@TITLE タイトル画面のサブルーチン。
@MAIN メインループのサブルーチン。
@GOVER ゲームオーバー画面のサブルーチン。

「@INIT」は初期化を行うサブルーチンです。
変数の初期化を行います。

変数名 内容
SPTBL キャラクター定義テンプレートを格納する配列変数です。
添え字の0がプレイヤーキャラ用、1がリンゴ用です。
HISCORE ハイスコアです。ゲームを起動してからの最高得点を格納します。
スタート時は0点です。

《タイトル画面》

「@TITLE」はタイトル画面を表示するサブルーチンです。

「@TITLE」のサブルーチンを実行するとこうなります。
プログラムの行数を節約しているので、ものすごく地味なタイトルです。

《プレイ中の処理》

「@MAIN」はゲームプレイ中の処理のサブルーチンです。
ゲームオーバーになると変数ENDFLAGの値が1になり、ループを抜け出します。
登場する変数の意味は次のとおりです。

変数名 内容
LEVEL ゲームのレベル。0が一番簡単。99で最高難易度。
SPEED ループ1周あたりの画面スクロールする速度。今回は8に固定。
SCORE スコア。リンゴを1個取るたびに1つ増える。
ENDFLAG ループの終了フラグ。スタート時は0。1で終了。
CNT ループの回数。スタート時は0。1ループごとに1つ増える。
IN ID番号。0の場合はプレイヤー。1の場合はリンゴ。
G Y方向の速度。ジャンプ時の値はマイナス。落下時はプラス。

このように大量の変数が登場します。
重要な変数名は「A」とか「B」とかではなく、意味が伝わるように書いたほうがいいでしょう。

37行目~46行目はキャラクターの管理を行います。
ここではキャラクターを動かしたり、作成したり、削除をします。

キャラクターの種類を判別するために「ID番号」という情報を設定します。
ID番号は0番がプレイヤーキャラ、1番がリンゴです。
ID番号は「内部変数」の0番に格納します。
内部変数というのはユーザーが自由に使えるスプライト内の変数のことです。
「内部変数」の1番にはY方向の速度を格納します。
内部変数を書き込むには「SPVAR」命令を使います。
SPVAR命令の書式は次のとおりです。

SPVAR 管理番号,内部変数番号,数値

「管理番号」はスプライトの管理番号のことです。
「内部変数番号」には0~7の値が入ります。
「数値」は内部変数に登録する数値です。
そして、内部変数を読み込むには「SPVAR」関数を使います。
SPVAR関数の書式は次のとおりです。

戻り値=SPVAR( 管理番号,内部変数番号 )

「管理番号」と「内部変数番号」の意味はSPVAR命令と同じです。

33行目~36行目はプレイヤーを画面に追加する処理を行っています。
地面が描き終わらないと、プレイヤーは落下してしまいますので、ループが40週するまで登場を待っています。
47行目では地面を動かすためのサブルーチンを呼び出しています。

42行目は「ON GOSUB」命令を使って、サブルーチンを呼び出しています。
現時点では登場キャラクターは2種類だけですが、将来、種類が増えた場合には簡単にラベル名を追加することができます。

《ゲームオーバー画面》

「@GOVER」はゲームオーバー画面を表示するためのサブルーチンです。

「@GOVER」を実行すると、このような文字が表示されます。
プログラムの行数を節約しているので、地味な表示です。

《スプライトの作成》

「@SPMAKE」は新しくスプライトを作成するサブルーチンです。
変数NEWIDには作りたいキャラのID番号を格納しておきます。
変数X,Yには出現させたい座標を格納しておきます。

《地面の処理》

「@JIMEN」は地面を動かすためのサブルーチンです。
変数SPEEDが0の場合、スクロールを停止させます。
これはゲームオーバーになった時にプレイヤーを穴に落とすためです。
スクロールしたままだと地面にめり込んでしまいます。
75行目のIF文では地面に穴を空けるかどうかの判定を行っています。
地面の穴の情報は変数HOLEに格納します。
81行目~86行目は変数LEVELを増やし、リンゴの出現処理を行っています。

変数名 内容
HOLE 地面の穴の情報です。
値が0の場合は穴が空いていません。1~6の場合は穴が空いています。

実行時のイメージです。
穴の大きさは6文字ぶんに設定しています。
穴を空けている途中にはリンゴは出現しません。

《プレイヤーの移動》

「@MAN」はプレイヤーキャラを動かすサブルーチンです。
90~95行目はプレイヤーが穴に落ちるまでの処理です。
画面下に着いて、ENDFLAGが1になり、ゲームオーバーが確定します。

床面に対して当たり判定は座標(x-12,y+1)と座標(x+12,y+1)の2点で行っています。
たとえば、図のような位置にプレイヤーがいる場合、左側が接触しているため落下しません。

この状態だと落下します。

《リンゴの移動》

「@APPLE」はリンゴを移動させるためのサブルーチンです。

変数名 内容
HIT 当たり判定の結果。
値が0以上の場合は衝突している。-1の場合は衝突していない。

リンゴを8ドット左へ移動します。
ここではプレイヤーとの当たり判定も行っています。
リンゴがプレイヤーに衝突した場合、リンゴを画面外に移動させて、スコアを加算します。

《ボタンを待つ処理》

「@BTNWAIT」はAボタンが押されるまで待つサブルーチンです。
タイトル画面とゲームオーバー画面の表示時に呼び出しています。

以上でゲームのプログラムの解説はすべて終了です。
長いプログラムは理解するのは大変だと思います。
その場合には、サブルーチンを1つずつ理解していきましょう。
時間はかかりますが、そのうち全体像が理解できるようになります。

ここで作成したゲームは公開キー(NKFE3E73)で公開しています。
実機で遊んでみたい方は、ぜひダウンロードをしてみてください。

まとめ

今回新たに紹介した命令の一覧です。

  • SPANIM
  • SPVAR
  • GOSUB
  • ON GOSUB
  • RETURN

これらの命令の詳しい書式について知りたい場合にはSmileBASICの公式サイトにある「命令表」で調べてみましょう。

(おまけ)ゲームを改良する

今回紹介したゲームはまだまだ改良の余地があると思います。
思いつく点としては、次のようなものがあります。

  • 見た目を派手にする(背景を追加する)
  • 分かりやすくする(スコアの文字を大きくする)
  • キャラの種類を増やす(敵キャラを追加する)
  • 音を鳴らす(BGMと効果音を追加する)

例として改良してみた後のゲーム画面です。
ゲームの見た目を派手にすると楽しくなります。
一番の課題はゲームのバランスです。
ここでは敵キャラクター(白いお化け)を追加してみたのですが、実際に遊んでみると、ゲームが難しすぎてイライラしてしまいます。
何らかの方法でバランス調整を行って、ゲームをやさしくしないといけません。
このあたりの作業は「直す→遊ぶ→直す→遊ぶ……」の繰り返しなので、効率的な方法ではありません。
このプロセスの中にゲーム作りの面白さを見つけてみましょう。

以上

ページトップへ