メニューとセーブデータ2024年11月02日くいなちゃん「プログラミング言語Kuin」の基本機能を学ぶ、実行環境がexe用のチュートリアル4です。今回は横視点のアクションゲームを作ってみます。今回は画像を使ったゲームを作ります。完成画面は図1-1の通りです。完成画面まずは前回と同様、スニペットから「mainとdrawコントロール」のコードを挿入してください(図1-2)。kui_action1.knこの状態で、ひとまず適当なフォルダにソースコードを保存しましょう。空のフォルダを作成し、その中に「main.kn」など、好きな名前で保存してください。Kuinのソースコード名には、小文字アルファベット、数字、「_」の記号が使え、拡張子は「.kn」です。先頭の文字には数字が使えません。1.2画像の用意それではゲームで使う画像を用意します。図1-3の「resフォルダを開く」をクリックし、resフォルダを開いてください。先ほど保存した.knファイルの場所に「res」という名前のフォルダが作られ、それが開かれたと思います。「res」フォルダを開くKuinでは、プログラム上で読み込むファイルは基本的にこの「res」フォルダの中に入れます。ここに入れておくと、リリースビルド時に「res」フォルダは暗号化されて1つのファイルにまとまります。今回読み込ませる画像は自分で描いてもいいですが、今回はKuinに付属しているフリー素材を使いましょう。「samples/free_resources/」に入っているファイルのうち、「dot_back_side.png」「dot_kuina_chan.png」「dot_map_chips_side.png」「map_sample_side.txt」の4つを「res」フォルダの中にコピーしてください(図1-4)。画像の用意これで画像をプログラムから呼び出せるようになりました。2背景の表示まずは背景画像を読み込んで表示してみましょう。図2-1のプログラムを追加します。kui_action2.kn3行目の「draw@Tex」は、画像を格納できるクラスです。8行目の「draw@makeTex」関数で、先ほど配置した「res/dot_back_side.png」の画像ファイルを読み込み、変数「@texBack」に代入しています。「draw@makeTex」関数の括弧内は、読み込む画像のファイルパスです。12行目の「@texBack.drawScale」関数で、「@texBack」に格納されている画像を描画しています。この「.drawScale」は「draw@Tex」クラスの中にある関数です。「.drawScale」は画像を引き伸ばして描画する関数で、括弧内はそれぞれ「転送先の座標X」「座標Y」「幅」「高さ」「転送元の座標X」「座標Y」「幅」「高さ」「色」です(図2-2)。色として指定している「draw@white」は白色を意味し、「0xFFFFFFFF」と書くことと同じです。白色を指定すると画像はそのまま描画されますが、黒色に近づけると画像は暗く描画されます。9行目の「draw@sampler」関数は、画像を引き伸ばしたときの補間方法を設定する関数で、「%point」を指定すると補間されず、「%linear」を指定すると補間されて見た目がなめらかになります。今回はドットがはっきりした見た目にしたいため、補間なしの%pointにしています。実行すると図2-3のようになります。背景の描画3キャラクターの表示それではキャラクターの表示に着手しますが、その前にキャラクターの座標を扱うクラスを作成しましょう。今回はマップと衝突したときに物理挙動を実現させたいため、Kuinに用意されている便利なクラス「game@Rect」を継承して利用します。「継承」とは、既存のクラスに変数や関数を追加して新しいクラスを作成することです(図3-1)。kui_action3.kn1~3行目で@Playerクラスを作成しています。括弧内に「game@Rect」と書いていますが、このように括弧内に既存のクラス名を書くことで、そのクラスの中身を引き継いでクラスを作ることができます。game@Rectクラスは、「x」「y」などの座標を入れる変数を持っています。2行目でクラスに追加している「toRight」変数の型は「bool」になっていますが、bool型とは真偽を格納する型です。プログラム上では、真は「true」と書き、偽は「false」と書きます。「toRight」変数にはキャラクターが右を向いているかどうかを格納する予定で、右を向いているなら「true」、左を向いているなら「false」を入れます。8~9行目で、プレイヤー用の画像を入れる変数「@texPlayer」と、先ほど作成した@Playerクラス型の変数「@player」を作り、15~21行目でそれぞれの中身を設定しています。26行目で、プレイヤーの座標「@player.x」「@player.y」の位置にキャラクターを描画しています。プレイヤーの座標がちょうど画像の中心になるように描画したいので、キャラクターの幅と高さの半分である64.0を引き算しています(図3-2)。実行すると図3-3のようになります。プレイヤーの描画4キャラクターの移動キャラクターの移動処理を追加します(図4-1)。kui_action4.kn27行目~34行目で、右や左キーが押されたときに、プレイヤーの速度を表す「@player.veloX」変数を増減させ、プレイヤーが向いている方向も設定しています。35行目の「@player.move(0.0)」は、プレイヤーの位置に速度を加算して移動させる関数です。括弧内に0.0より大きい値を入れると、速度がその値を超えないように自動調整されます。今回は最大速度を縦と横とで別々に設定したいため、自動調整されないように0.0を渡しています。36行目の書き換えにより、キャラクターをアニメーションさせています。0.0)」の部分は、プレイヤーが右向きなら128.0、左向きなら0.0になります。C)」と書くと、AがtrueならB、AがfalseならCを返します。36行目の「pattern[~]」の部分は、23行目で作成した「配列」の変数にアクセスしています。「配列」とは変数を複数個並べたようなもので、例えば23行目のように変数の型を「[]float」とすると、floatの値を複数個並べたものが格納できます。配列の値を読み書きするときは、「変数名[要素番号]」と書きます。128.0]」を代入していますが、このときpattern[0]と書くと0.0、pattern[1]と書くと64.0、pattern[2]と書くと0.0、pattern[3]と書くと128.0の値が取得できます。23行目の変数は、他の変数とは違って関数の中で作成していますが、こうすると関数が呼び出されたときに作成されて、関数を抜けるときに破棄される変数になります。このような関数内の変数を「ローカル変数」といい、関数外の変数を「グローバル変数」といいます。グローバル変数にアクセスするときには変数名の先頭に「@」を付ける必要があります。36行目の「draw@cnt()」は、プログラムの起動から何フレーム経ったかを返す関数です。4」で「0、1、2、3、0、1、2、3、0、...」と繰り返すパターンが生み出されます。これにより歩行アニメーションを描画しています。実行すると図4-2のようになります。次はマップの描画です。図5-1のプログラムを追加します。kui_action5.kn10~11行目で、マップ用のテクスチャとマップデータを入れる変数を作成し、18~19行目で実際に読みこんで格納しています。11行目にあるgame@Mapクラスは、2Dマップを簡単に扱うための機能を持っています。19行目の「game@makeMap」は、決められた書式で書かれたマップデータを読み込む関数です。括弧内は順に「マップデータのファイルパス」「マップチップの幅」「マップチップの高さ」です。マップチップの幅と高さは、マップとキャラクターの衝突判定をするときに使われます。41~48行目でマップを描画しています。for」で0から14まで数え上げながら繰り返しています。このfor文にはyと書いていますが、こうするとfor文の中でyを変数のようにアクセスすることができ、数え上げている最中の値を取得できます。for」でxを0から25まで数え上げながら繰り返しています。従ってこの中では、yの値が初めは0でxの値が「0、1、2、...、25」となった後、yが1でxが「0、...、25」、yが2でxが「0、...、25」と進み、yが14でxが25になるまで繰り返される流れになります。43~46行目ではこれらのxとyに対して各マップチップを描画し、マップ全体を描画しています。43行目では@mapに入っているマップデータから、(x,y)の座標にあるマップチップを取得し、変数chipに入れています。このint型とは、整数を入れる型です。chipが0未満のときは「空気」を想定しているため何も描画せず、0以上のときにchipに応じた画像を45行目で描画しています。float」と書くと、整数であるxの値が小数であるfloat型に変換されて計算されます。Kuinでは、int型の値は「5」のように書き、float型の値は「5.0」のように書かなければならないなど、型を厳密に区別しています。異なる型でやりとりする必要があるときには「$」演算子などを使って変換してください。実行すると図5-2のようになります。マップの描画map_sample_side.txtの中身をテキストエディタで開いてみると、図5-3のようになっています。map_sample_side.txt書式は、カンマと改行区切りで順に「1行(横)のマップチップの数」「1列(縦)のマップチップの数」と書き、以後マップチップの値を羅列します。今回は横に26個、縦に15個並んでいます。このような書式で書くとgame@makeMap関数で読み込めるようになります。最後に、プレイヤーのジャンプと衝突判定を実装します。while」の中身のみを変更しますので、その部分だけを抜粋します(図6-1)。kui_action6.kn11~13行目はジャンプ処理です。11行目の「&」は日本語の「かつ」に相当するものもので、このif文の条件は「Aボタンが押された時間が1フレーム以上で、かつAボタンが押された時間が6フレーム以下で、かつプレイヤーが接地していたらジャンプ」といった内容です。接地する直前にボタンを押したときにもジャンプできるように、やや複雑な条件にしています。12行目で上方向の速度を設定してジャンプしています。14行目は下向きに速度を加算していますが、これは重力です。18~19行目はプレイヤーとマップとの衝突判定を行っています。衝突判定は、「move」「衝突判定の各関数」「update」の順で行います。衝突判定の各関数を呼ぶと衝突結果のデータが蓄積され、update関数で位置や速度に反映される流れです。18行目のgame@hitMapRectは、game@Mapとgame@Rectの衝突判定を行う関数で、括弧内は順に「game@Mapの値」「game@Rectの値」「マップチップ情報を返す関数」「衝突すると呼び出される関数」です。ここではマップチップ情報を返す関数に、21~40行目で作っているgetChipInfo関数を渡していて、この中でマップチップの形状や摩擦や空気抵抗などの情報を返しています。21行目のgetChipInfo関数は呼び出されるときに、括弧内のchipとinfoにそれぞれ「マップチップの種類」と「情報格納用の変数」が送られてきます。chipの値を元に、infoに情報を格納する流れです。22行目の「switch」は、括弧内の値に応じて分岐を行う命令で、値が合致した「case」の処理に飛びます。2」に合致するためそこからプログラムを実行して、31行目の別のcaseに達した段階でswitch文を抜けて39行目に飛びます。10」のように範囲指定もできます。-1」とは、intの最小値以上-1以下の範囲を表します。あとはinfoに入れる値ですが、info.shapeはマップチップの形状、info.solidFrictionは固体の摩擦係数、info.repulsionは触れたときの反発係数、info.fluidFrictionは空気抵抗となっています。設定すると自動的に衝突時の物理挙動が計算されます。実行すると図6-2のようになります。以上で、横視点アクションゲームの完成です。重力を無くすと、上視点のゲームも作れます。次回は、メニューの作り方やセーブデータの扱い方について説明します。メニューとセーブデータ前へ目次ホームへ次へ1730493397jaf。