Defoldで簡単なゲームを作ってみる
今回はDefoldと呼ばれるゲームエンジンを使用して簡単なゲームを作るまでの操作方法を説明していきたいと思います。
Defoldに関しては詳細な内容の資料は公式のチュートリアルが大半ですが、基本的なことは他のサイトなどにたくさん書かれているので、そちらの参考資料などを載せながら説明していきます。
環境
準備
インストールに関してはとても簡単でした。私は下のURLの記事を参考にダウンロードしてそのまま使えたので説明は省きます。
またこのURLの記事を執筆した方が、ほかのdefoldに関しての内容を目次形式で記事としてまとめてくれているのでそれを参考にするととても分かりやすいと思います。
目次ページのURLを以下に示します。私がこの記事を執筆している(2022/6/26)時点では目次の内容が初級の”関数を使う”までしか進められていないので、ここで説明されていないことを重点的に説明しながらゲームを作成していきたいと思います。
defoldを使ったことがない方は以下の3つは最低限読んでおくことをお勧めします。
そして今回使用する画像などは全てパブリックドメインと呼ばれるライセンス表記など気にせず自由に使える画像を使います。
ライセンスなどの知識がない方は使用する前にパブリック・ドメインやCC0などと調べると良いでしょう。
私が気に入っているものを貼っておくので参考にしてください。各サイトからダウンロードできます。
- 注意:ネットの画像を使用する際はライセンスなどに注意して使用しましょう。本記事を参考にした場合に起こった問題は全て個人の責任になるため、筆者は一切の責任を負いかねます。
ゲーム作成
今回は主人公を操作して自動生成するコインを集めるゲームを作っていきたいと思います。
最初なのでダウンロードしたDefoldエディタを起動しましょう。
起動したらNEW PROJECTからEmpty projectを選択して右下のCreate New Projectでプロジェクトを作成します。保存する名前とディレクトリの変更も下部で出来るので適宜変更してください。
主人公の表示
まずは主人公のキャラクターを表示していきましょう。キャラクターを参考記事では静止画像として読み込んでいたので、まずはコマ送りのアニメーション形式で読み込ませていくところまで進めて行きましょう。
使用するキャラクターなどの画像をプロジェクトのフォルダにコピーしていきます。
私の場合はプロジェクトのファイル直下にassetsフォルダを作成して中身に先ほど説明したURLからダウンロードしたパブリックドメイン系の画像を解凍してそのまま入れました。今回使用していくのはRocky Roadsです。記事と同じ方法で進めて行きたい場合はこちらを使ってください。
コピーした後のエディタではこのような構造で表示されます。
主人公として使おうと思っているslime.pngと言う画像を見てみると姿勢を変えた画像が一枚にまとまっているのがわかります。このような画像をコマ送りのアニメーションとして使用したい場合はTile Sourceと呼ばれる要素を使用します。
そして、今回作成するものは全てmainフォルダ内に作っていくのでmainファイルにカーソルを合わせて右クリックでTile Sourceを選択してファイルを作成します。
名前は無難にmeと設定しておきましょう。
作成されたme.tilesourceを選択すると画面右側にOutlineが表示されますので画像に従って操作してください。
これでTile Sourceに画像が適用されます。
そうすると下の画像のように中央に開かれた画像が出ます。
しかし、拡大されすぎて少ししか映っていません。。。
このようなときはエディタ内で”F”キーを押すとある程度見える感じに補正してくれます。
私の場合はこんな感じに自動で移動してくれます。
それでも少し見切れていますが。。。あとは自分の好みに見え方を少し調節する感じです。
開かれた画像を見てみると、少し見ずらいですが線が引かれてマス目状に画像が分割されていることがわかります。
私の場合はすでに自動で一枚づつの大きさを認識して適切なサイズに設定されています。
Tile Source内のプロパティを見てみると下の画像のようになっています。
使っている画像全体の幅が80で、高さが32です。
その中で横5枚、縦2枚分の画像で分けたいので幅16、高さ16の画像(Tile)が一枚分になります。
80 / 5 = 16 (幅)
32 / 2 = 16 (高さ)
そしてプロパティ内のTile WidthとTile Heightがそれぞれ16になっているので私の場合は今回編集する必要がありませんが、各自の環境や使っている画像で変わってくるので、プロパティ内のこの2箇所を自身で計算して入力してください。
全体の幅と高さをそれぞれ分割したい数で割れば数値がでてきます。
Extruede Bordersに関しては公式のリファレンスを見てもいまいち理解できなかったため、初期値の2から変えていません。
それ以外は今後使うものもありますが、まだ触らなくて大丈夫です。
そしたら次にOutline内のanimを編集していきます。
これは分割した画像をアニメーションとして使用する時に開始するTileと終了するTileを決めます。そのほかにもPlaybackでアニメーションの再生方法やFPS設定もできます。
今回のようなTileが2段になっている場合一段目の一番左から”1”として右に数えていき、折り返して2段目の左から数えて行きます。
そのためStart Tileは1、End Tileは7となります。8~10は何もないので不要になります。
そしてPlaybackをLoop ForwardにすることによってLoopで繰り返し再生とForwardでStart Tileから順に進んでいくようになります。Backはその逆になります
FPSは10程度にしておくと分かりやすくなります。
次にゲームオブジェクトに紐づけていくので左側で画面でmainフォルダにGame Objectファイルを追加していきます。
Game Objectファイルにもmeと名付けておきます。
ここから先は静止画像の適応とほぼ同じ作業になります。
右側の画面でGame ObjectにSpriteコンポーネントを追加していきます。
追加したSpriteのプロパティを変更していきます。
これで、先ほど作成したTile sourceとアニメーションの設定であるanimを適用しました。
あとは画面に表示するための設定を操作します。
先ほど作成したGame Objectファイルが候補に挙がっているので選択しましょう。
そうすると画面中央にキャラクターが表示されます。(下記画像はFキーで調節後)
今回使用している画像がとても小さく、このままだと見えにくいのでスケールを大きくします。
今回は10倍程度にしておくとちょうど良いでしょう。
Collection内のGame Objectに対してスケールの設定ができます。
XとYを変更しましたが、今回はZを変更しないようにしましょう。
赤と緑の線が引かれていてキャラクターで隠れていますが、2つの線が交差している点がゲーム画面の左下に当たります。分かりやすいように画面中央寄りに設定していきます。
赤枠で囲んだ2箇所どちらかをドラッグすることで自由に移動できます。
画面サイズはデフォルトだと960x640なのでメモリを見てはみ出さない程度にしておきましょう。
画面サイズの確認方法は以下の画像を参考にしてください。必須ではないのでスキップしても大丈夫です
移動出来たら(Ctrl + Shift + B)でゲームが実行されます。
実行されると表示されるスライムが動き出すことが確認できます。
今回は一枚の画像にアニメーションが挿入されているものを使用したため、Tile Sourceという要素を使用しました。
しかし、アニメーションが複数枚に分かれている場合はAtlasと呼ばれる要素を使用して複数画像を一まとまりに扱いコマ送りの画像を設定することもできます。
こちらの説明は省きますが、リファレンスや最初のチュートリアル内容をよく見るとわかると思います。
説明自体はチュートリアル内ではされていないので、リファレンスか自分でファイルを見て理解してください。
これでキャラクターの表示までは出来ました。
主人公を移動させる
表示させたキャラクターをマウスに追従させていきます。
キーボードの入力を元に何かを動作させる方法は以下のURLで詳しく説明されているので省いて、マウスの位置を使用したキャラクター移動を実装していきます。
キーボードよりも実装は簡単になっていますので進めて行きます。
Scriptファイルを作成するとデフォルトでそれぞれのタイミングで呼ばれる関数が記述されています。
今回使用するのはinitとon_input関数のみですので、以下に示すプログラムのみに書き変えてください。
init関数 Scriptが適用されているGame Objectが画面に生成されるときに一度呼び出される
on_input関数 入力系イベントが発生したときに呼び出される
内容はプログラムにコメントとして記述しておきます。
function init(self) go.set_position(vmath.vector3(480, 320, 0)) --ゲームオブジェクトを画面中央に移動 msg.post(".", "acquire_input_focus") --on_input関数でマウス屋キーボードなどの状態を取得するためのお約束 end function on_input(self, action_id, action) go.set_position(vmath.vector3(action.x, action.y, 0)) --actionでマウスの画面上位置を取得してゲームオブジェクトの位置を上書き end
今の状態だとScriptを用意しただけなので、適用したいGame Objectに割り当てていきます。
これで適用されました。
me.goに適用するとmain.collection内にあるme.goにも変更が適用されます。
逆にmain.collection内のme.goにScriptの割り当てをしてもme.goが変更されるのでどちらからでも問題ありません。
ここまでの作業が出来たら(Ctrl + Shift + B)で実行します。先ほど実行してそのままウィンドウが残っているのであればエディタ内で(Ctrl + R)でホットリロードがされます。
起動されるとマウスにキャラクターが追従されると思います。
簡単ですが、これでキャラ移動が可能になりました。
コインの自動生成
次に新たなゲームオブジェクトとしてコインが必要です、主人公の表示で行った手順と重複するため、説明は省きます。
主人公の表示と同じ手順でRocky Roads内のcoin.pngを使ったGame Objectを作成した後の作業をこちらで説明します。
試したい方は各自の環境で作成してください。
ファイル構造は以下のようになりました。
コインのTail Sourceにおけるanimのプロパティ例
ここからは、コインの自動生成をするための操作をしていきます。
まずは生成用のScriptを作成します。
Scriptの中身は以下のように書き換えます。
local genTime = 0.4 --コインの生成時間間隔 local min_y = 60 --生成場所y軸の最低値 local max_y = 600 --生成場所y軸の最高値 local min_x = 60 --生成場所x軸の最低値 local max_x = 900 --生成場所x軸の最高値 function init(self) self.timer = genTime math.randomseed(0) end function update(self, dt) self.timer = self.timer - dt if self.timer <= 0 then --生成時間隔の確認 self.timer = genTime local p = go.get_position() p.y = vmath.lerp(math.random(), min_y, max_y) --y座標のランダム生成 p.x = vmath.lerp(math.random(), min_x, max_x) --xpcall座標のランダム生成 local component = "#coint_factory" --コンポーネントの取得 factory.create(component, p) --コンポーネントの生成 end end
FactoryとScriptで同じ名前にするのがいけなかったのか、自動的にScriptの名前の後ろに1がついていますが問題ないのでそのまま続けます。
これで実行すると自動でコインが生成されます。
見てみるとコインが小さいのとスライムの手前にコインが来ていることがわかります。
これらを改善していきます。
プロパティを以下のように変えると改善されます。
スケールが大きくなっているのとスライムの後ろにコインが来ることがわかります。
赤枠内のZプロパティを0.8にすることによってスライムよりも後ろのレイヤーで表示されるようになります。
スライムのプロパティでは1になっているのでそれよりも後ろになるようです。
これでコインの自動生成が可能になりました。
しかし、このままだと時間がたつにつれてエラーが出始めます。
スプライトの生成量には限度があるようです。
これらを改善するのと今後のゲーム性を持たせるために一定時間で消失するように設定していきますが、これは次の項で同時に説明します。
当たり判定
主人公であるスライムとコインに当たり判定を与えていきます。
これでスライムには当たり判定を持たせることができました。
コイン(coin.go)にも当たり判定を同じ手順で付けていきます。
同じ手順なので説明は省略しますが、一点だけ注意があります。
コインの場合はプロパティのGroupとMaskを主人公の時と逆にする必要があります。
これで二つの当たり判定の範囲は決定出来ました。
次に当たり判定を受けて実行するプログラムを記述します。
今回はコインのみの状態を変えたいので、コインに新たなScriptを適用します。
前の項で説明したように、一定時間で消失させたいのでその実装も行います。
中身を以下に書き変えます。
local delTime = 2 --消失する時間 function init(self) self.time = delTime end function update(self, dt) self.time = self.time - dt if self.time <= 0 then go.delete() --自身のgame objectを削除する end end function on_message(self, message_id, message, sender) if message_id == hash("collision_response") then --当たり判定を取る if message.group == hash("me") then --当たった相手のグループが”me”かの判定 msg.post("main#main", "add_score", {amount = 1}) --スコアボードへの通知 go.delete() --当たったら削除 end end end
これで実行すると、コインが一定時間で無限に生成されて、スライムがコインに触れると消さるようになります。また、一定時間触れられなかったコインは削除されます。
この時点だと以下のようなエラーが出ることがありますが、この後実装するスコアボードのためのコードが含まれているので無視してください。
該当箇所が以下になります。
msg.post("main#main", "add_score", {amount = 1}) --スコアボードへの通知
スコアボード
いくつコインを取得できたか確認するボードを作っていきます。
中身を以下に書き変えます。
プログラムはチュートリアルの中からとってきました。
function init(self) self.score = 0 self.score_node = gui.get_node("score") end local function scale_down(self, node) local s = 1.0 gui.animate(node, gui.PROP_SCALE, vmath.vector4(s, s, s, 0), gui.EASING_OUT, 0.05) end function on_message(self, message_id, message, sender) if message_id == hash("add_score") then local s = 1.2 self.score = self.score + message.amount gui.set_text(self.score_node, tostring(self.score)) gui.animate(self.score_node, gui.PROP_SCALE, vmath.vector4(s, s, s, 0), gui.EASING_OUT, 0.1, 0.0, scale_down) end end
これで起動するとスコアボードが出てきます。
あとはバックグラウンド用のアトラスを用意してゲームオブジェクトとスプライトを紐づけてコレクションに適用すれば一枚のバックグラウンド画像を背景として設定できます。
画像は好きな画像を使って行ください。
その時のコレクションにおけるZ軸は0近くにしておくことをお勧めします。
背景なので一番下に表示されることが重要です。
まとめ
とても長くなってしまいましたがDefoldの基本的な使い方はある程度身についたと思います。 プログラムよりもUIでの操作が多いため、容量をつかむと簡単に感じます。 もう少しプログラムに力を入れるといろいろなことができると思いますが、今回はここまでにしたいと思います。
コメント
コメントを投稿