2Dに特化した軽量ゲームエンジンDefoldでゲームを作る(前編)

defold-logo

 

 「Defold」とは、「キャンディークラッシュ」の制作会社「King」が独自に開発したゲームエンジンです。Defoldでは、コードの修正後すぐに実行して確認できるため、ビルドする時間をほぼ待つ必要がないので非常に快適です。なお、開発に利用できる言語は「Lua」となっています。

 

 

本記事でできること

・Defoldを使ったサンプルゲームが作れる(基本的には公式サイトのチュートリアルに従って実装していきます)

 

 本記事では地面のスクロールとキャラクターのジャンプ機能までを実装していきます。

 

 

1.新規プロジェクトの準備

 公式サイト(http://www.defold.com/)にアクセスして「Get Defold now」からサインアップします。

defold-tutorial-1-1

 

 ログインが完了すると「Getting Started Tutorial」というページが開きますので、該当するOSのエディターをダウンロードしておきましょう。

defold-tutorial-1-2

 

 同ページをスクロールしていくと、STEP1からSTEP9までのチュートリアルが記述されているので、「STEP 1 – INSTALLATION AND SETUP」から順番に説明していきます。

 最初に、左メニューに表示されている「+ADD PROJECT」から新しくプロジェクトを作成します。

defold-tutorial-1-3

 

 プロジェクトの作成が完了したらダウンロードしておいたエディターを起動しましょう。

defold-tutorial-1-4

 

 エディタが起動したら「Open Project」を選択して先ほど作成したプロジェクトを開きましょう。

defold-tutorial-1-5

 

 私は「My runner」という名前のプロジェクトを作成していたので、下図の様にリストで表示されています。「My runner」を選択後、「Next」ボタンで次へ進みましょう。

defold-tutorial-1-6

 

 Defoldではソースコード管理をGITで行っており、「New branch」ボタンからブランチを作るよう促されます。ブランチの名前はなんでも良いですが「master」にするのが普通で、チュートリアルページでも「master」にすることを勧めているようでした。「master」ブランチが作成できたら「Finish」ボタンで完了します。

defold-tutorial-1-7

 

 ちなみに、「branches」フォルダ内を確認するとGITで管理されていることが分かります。

defold-tutorial-1-10

 

 準備ができたので「Build And Launch」からゲーム実行しましょう。

defold-tutorial-1-8

 

 Defoldのロゴが表示されていれば成功です!

defold-tutorial-1-9

 

 

2.スクロールする地面を作成する

2.1 Defoldのロゴを削除

 先ほど実行したゲームには、Defoldのロゴが表示されていたので削除しておきます。「Project Explorer」ウィンドウから「main.collection」をダブルクリックして開きます。「Outline」ウィンドウに「go」というゲームオブジェクトがあるので右クリックして削除を選択します。忘れてはいけないのが変更を保存することです(File>Save(ショートカット:Ctrl+S))。保存を忘れて反映されないと勘違いしてしまうことがあるので注意して下さい。

defold-tutorial-2-1

 

 もう一度「Build And Launch」するとロゴが消えているはずです。

defold-tutorial-2-2

 

2.2 地面を表示

 画像をプロジェクトで利用するためには、1つの大きな画像としていくつかの画像を管理する「Atlas File」を利用します。これを利用することでパフォーマンスの向上を図ることができます。詳細についてはこちら(2D graphics documentation)で記述されています。下図では、「level.atlas」という名前のatlasファイルを「Project Explorer」上のmainフォルダを右クリックして「New>Atlas File」から作成しました。

 必要な素材は用意されているので「Download asset package」からダウンロードしましょう。

defold-tutorial-2-3

 

 アセットのダウンロードができたら「ground01.png」と「ground02.png」を「main/images」にドラッグアンドドロップします。

defold-tutorial-2-4

 

 「level.atlas」にドラッグアンドドロップした画像を追加します。「Outline」ウィンドウのAtlasを右クリックして「Add Images」をクリックするとウィンドウが開くので、「ground01.png」と「ground02.png」を選択しましょう(まとめて選択できます)。

defold-tutorial-2-5

 

 次は、Atlasに追加した画像を使うために「Collection File」を作成しましょう。「Collection File」は、このファイル自体がゲーム上で表示され使われるという訳ではなく、「Collection File」に追加した「ゲームオブジェクト」や「Collection File(異なるCollection Fileを含めることが可能)」が使われることになります。様々な「ゲームオブジェクト」を追加することができるので、プレハブやブループリントがより複雑になったものと考えて良さそうです。Defoldはゲーム起動時に「main.collection」を読み込むようになっているので、何らかの処理を実行させたい「ゲームオブジェクト」があれば「main.collection」に追加しましょう。

 

 今回は、「main.collection」に「ground.collection」を追加して地面を表示させてみます。下図では、「ground.collection」を「Project Explorer」上のmainフォルダを右クリックして「New>Collection File」から作成しました。「ground.collection」を開き、「Outline」ウィンドウの「Collection」を右クリックして「Add Game Object」から「go(ゲームオブジェクト)」を追加しましょう。

defold-tutorial-2-6

 

 「go」を右クリックして「Add Component」を選択するとウィンドウが開くので「Sprite」を追加しましょう。「go」はコピペできるのでスケールを0.6に設定してから複製します。ゲームオブジェクトのx座標は下図のように設定しておきます(Spriteの座標ではありません)。

defold-tutorial-2-7

 

 Spriteのプロパティを設定して地面の画像を表示しましょう。「Image」に先ほど作成したlevel.atlasを設定すると、「Default Animation」に「ground01」あるいは「ground02」が選択できるようになります。

defold-tutorial-2-8

 

 「ground.collection」が完成したので「main.collection」の「Outline」から追加しましょう。「Outline」上で右クリックして「Add Collection From File」から「ground.collection」を選択します。表示された「ground.collection」は、初期位置がおかしいのでプロパティのPosition(x軸を114、y軸を0に設定)を修正しておきましょう。

defold-tutorial-2-10

 

 「Project>Build  And Launch」からゲームを実行すると地面が表示されました。

defold-tutorial-2-11

 

2.3 地面を動かす

 ここからはいよいよLuaを使ってスクリプトの実装を行っていきます。スクリプトを追加するためには、「Project Explorer」のmainフォルダ上で右クリックして「New>Script File」を選択します(ファイル名はground.scriptとしました)。次に「ground.collection」を開き、「Controller」という名前のゲームオブジェクトを作って「ground.script」を追加しておきます。スクリプトの追加ができたら、ground.script」をダブルクリックで開きます。

defold-tutorial-2-12

 

 新規のスクリプトにはデフォルトで関数が実装されていますが、ここで利用する関数は「init」と「update」のみですので、その他の関数については消去してしまって問題ありません。スクリプトに書き込む内容は下記となります。

local pieces = { "ground0", "ground1", "ground2", "ground3", "ground4", "ground5", "ground6" }

function init(self)
    self.speed = 6
end

function update(self, dt)
    for i, p in ipairs(pieces) do 
        local pos = go.get_position(p)
        
        if pos.x <= -228 then 
            pos.x = 1368 + (pos.x + 228)
        end
        pos.x = pos.x - self.speed
        go.set_position(pos, p)
    end
end

 

 利用しているAPIとしては「go.get_position」と「go.set_position」で、これによりゲームオブジェクトの座標取得と設定が行えています。ゲームオブジェクトには多くのAPIが存在しているので、詳細についてはドキュメントを参照して下さい。また、上記で実行している処理は非常に単純で、ゲームオブジェクトが左に移動していき画面外になっていたら、強制的に右端に移動させるというものです。スクロールスピードについてはお好みの値に変更して下さい。
※正常に動作しない時は、ゲームオブジェクトの名前が異なっていたり、前章で地面の座標設定時にゲームオブジェクトの座標ではなくSpriteの座標を設定してしまっていることが考えられます。

 

 

3.操作可能なキャラクターを作成する

3.1 キャラクターアセットをインポート

 本章では地面を歩くことができるキャラクターを作成します。キャラクターのアセットは「getting-started-assets>hero-images」にあるので全てインポートします。新しくキャラクター用の「hero.atlas」という名前のatlasファイルを作成し、インポートした画像ファイルを追加しましょう。

defold-tutorial-3-1

 

 ゲーム作成においてアニメーションは非常に重要ですが、通常アニメーションは外部のソフトウェアを利用して作成することが多いと思います。Defoldでは、なんらかのソフトウェアで作成したアニメーションをスプライトシートとしてエクスポートして、それらをフリップブックアニメーションとして利用することができるようです。公式的にサポートしているアニメーション方法は前述の「Flip-book animation」と「Spine animation」のみでした(詳細についてはドキュメント参照)。今回のサンプルアセットには「Spine」が使われています。

 

 キャラクター画像の取り込みが完了したので、次はSpineの設定をしていきます。「Project Explorer」の「hero(新規に作成しました)」フォルダ上で「New>Spine Scene File」を選択します。このSpine Scene Fileにアニメーションに関連するデータを設定します。「spine_json」には「getting-started-assets>hero.json(インポートする)」を設定、「atlas」には「hero.atlas」を設定して保存すれば完了です。

defold-tutorial-3-2

 

3.2 キャラクター作成

 アニメーションデータの設定が完了したのでキャラクター用のゲームオブジェクトを作成します。作成したゲームオブジェクトを開き、「Outline」ウィンドウ内の右クリックメニューから「Add Component」で「Collision Object(当たり判定に使います)」と「Spine Model(アニメーションの再生に使います)」を追加しましょう。まず、「Collision Object」を右クリックして「Add Shape」ウィンドウから「Box」と「Speher」を追加します。配置場所に関しては下図を参考にしてみて下さい。

defold-tutorial-3-3

 

 「Collision Object」の設定は下記の通りです。ここで最も重要なのは「Group」と「Mask」プロパティです。用途としては、Groupで自分の衝突判定グループを設定し、Maskで衝突判定グループを指定して特定のグループのみに衝突判定を実行させます。従って下記の設定により、キャラクターは「geometry」グループとのみ衝突判定が発生することになります。

defold-tutorial-3-4

 

 最後に、アニメーションの設定を「Spine Model」で行っておきましょう。

defold-tutorial-3-5

 

3.3 キーボード入力を設定

 キャラクターをキーボード入力によって制御するためには、「Input Binding File」を設定する必要があります。ファイル自体はプロジェクトを作成するとデフォルトで作られているので「input/game.input_binding」を開きましょう。設定項目は下記の通りで、「スペースキー」を「jump」というアクションに関連付けています。タッチの方は検証してはいませんがスマホ用の入力トリガーでしょう。

defold-tutorial-3-6

 

3.4 キャラクタースクリプトの作成

 最後にキャラクターを制御するためのスクリプト(hero>hero.script)を作ります。実装する主な処理は下記の通りです。

・キャラクターに重力を与える

・地面の上を歩かせる

・プレイヤーの入力を受け取ってジャンプさせる

-- gravity pulling the player down in pixel units/sˆ2
local gravity = -20

-- take-off speed when jumping in pixel units/s
local jump_takeoff_speed = 900

function init(self)
    -- this tells the engine to send input to on_input() in this script
    msg.post(".", "acquire_input_focus")

    -- save the starting position
    self.position = go.get_position()

    -- keep track of movement vector and if there is ground contact
    self.velocity = vmath.vector3(0, 0, 0)
    self.ground_contact = false
end

function final(self)
    -- Return input focus when the object is deleted
    msg.post(".", "release_input_focus")
end

function update(self, dt)
    local gravity = vmath.vector3(0, gravity, 0)

    if not self.ground_contact then
        -- Apply gravity if there's no ground contact
        self.velocity = self.velocity + gravity
    end

    -- apply velocity to the player character
    go.set_position(go.get_position() + self.velocity * dt)

    -- reset volatile state
    self.correction = vmath.vector3()
    self.ground_contact = false
end

local function handle_geometry_contact(self, normal, distance)
    -- project the correction vector onto the contact normal
    -- (the correction vector is the 0-vector for the first contact point)
    local proj = vmath.dot(self.correction, normal)
    -- calculate the compensation we need to make for this contact point
    local comp = (distance - proj) * normal
    -- add it to the correction vector
    self.correction = self.correction + comp
    -- apply the compensation to the player character
    go.set_position(go.get_position() + comp)
    -- check if the normal points enough up to consider the player standing on the ground
    -- (0.7 is roughly equal to 45 degrees deviation from pure vertical direction)
    if normal.y > 0.7 then
        self.ground_contact = true
    end
    -- project the velocity onto the normal
    proj = vmath.dot(self.velocity, normal)
    -- if the projection is negative, it means that some of the velocity points towards the contact point
    if proj < 0 then
        -- remove that component in that case
        self.velocity = self.velocity - proj * normal
    end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("contact_point_response") then
        -- check if we received a contact point message. One message for each contact point
        if message.group == hash("geometry") then
            handle_geometry_contact(self, message.normal, message.distance)
        end
    end
end

local function jump(self)
    -- only allow jump from ground
    if self.ground_contact then
        -- set take-off speed
        self.velocity.y = jump_takeoff_speed
    end
end

local function abort_jump(self)
    -- cut the jump short if we are still going up
    if self.velocity.y > 0 then
        -- scale down the upwards speed
        self.velocity.y = self.velocity.y * 0.5
    end
end

function on_input(self, action_id, action)
    if action_id == hash("jump") or action_id == hash("touch") then
        if action.pressed then
            jump(self)
        elseif action.released then
            abort_jump(self)
        end
    end
end

 

 コードが長いため難しそうに見えてしまうのですが、理解し難い部分は「handle_geometry_contact」関数ぐらいです。この関数は、次章にて設定する地面の当たり判定部分と衝突した時にだけ実行されます。やっていることとしては、地面を突き抜けないようにキャラクターの座標を地面の上に設定していると考えて問題ないと思います。衝突判定時に通知される関数は利用できる引数が決まっているので、ドキュメントを参照するとより理解がしやすくなるかもしれません。

 

 作成したscriptはキャラクターのゲームオブジェクトに追加します。

defold-tutorial-3-7

 

3.5 地面の当たり判定

 スクリプト内で利用している「geometry」に対応する「Collision Object」を「ground.collection」に作ります。作成の方法は3.2章と同じで、「Box Shape」を下図のように配置します。設定時は、「Collision Object」の「Type」、「Group」、「Mask」プロパティを間違えないように注意して下さい。

defold-tutorial-3-8

 

 

4. コレクションを整理する

4.1 levelコレクションの作成

 これまでは「ground.collection」を直接「main.collection」に追加していましたが、これをやめて新しく「level.collection」を「main.collection」に追加します。コレクション内にコレクションを追加することもできるので、下図のように「ground.collection」と「hero」を「level.collection」に追加しましょう(座標に関しては適当に変更して下さい)。※Collectionの名前には「level」と付けておきます

defold-tutorial-4-1

 

4.2 動作確認

 地面の上をキャラクターが歩いているはずです。もちろんジャンプもできます!

defold-tutorial-4-2

 

defold-tutorial-4-3

 

 

5.まとめ

 今回は基本的な動作のみを実装しました。次回はキャラクターのアニメーションをジャンプによって変更したり、トゲ付きの足場を用意して衝突するとゲームオーバになるといったように、もう少しゲーム性を出すための実装を行っていきます。