Manuals
Manuals




This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English

Flash ユーザーのための Defold

このガイドでは、Flash ゲーム開発者向けの代替ツールとして Defold を紹介します。Flash のゲーム開発で使われる主要な概念の一部を取り上げ、それに対応する Defold のツールと方法を説明します。

はじめに

Flash の主な利点には、使い始めやすく、参入のハードルが低いことがありました。初めて使うユーザーでも短期間で使い方を学び、限られた時間で基本的なゲームを作成できました。Defold もゲームデザイン専用のツール群によって同様の利点を提供するとともに、上級開発者が高度な要件に対応する高度なソリューションを作成できるようにしています(たとえば、既定のレンダースクリプト(render script)を編集できます)。

Flash のゲームは ActionScript(最新バージョンは 3.0)でプログラミングしますが、Defold のスクリプトは Lua で記述します。このガイドでは、Lua と Actionscript 3.0 の詳しい比較は扱いません。Defold マニュアルには Defold での Lua プログラミングの入門説明があり、オンラインで無料公開されている、とても役立つ Programming in Lua(第1版)も紹介しています。

Jesse Warden の記事には Actionscript と Lua の基本的な比較があり、入門に役立つでしょう。ただし、Defold と Flash の構造には、言語の水準で見える違いよりも深い違いがあります。Actionscript と Flash は、クラスと継承を備えた従来の意味でのオブジェクト指向です。Defold にはクラスも継承もありません。Defold には、視覚や音声による表現、振る舞い、データを含められる ゲームオブジェクト(game object) という概念があります。ゲームオブジェクトの操作は、Defold API が提供する関数で行います。さらに、Defold ではオブジェクト間の通信に メッセージ(message) を使うことを推奨しています。メッセージはメソッド呼び出しよりも高水準の仕組みであり、メソッド呼び出しとして使うことを想定していません。これらは重要な違いで、慣れるまでには時間がかかりますが、このガイドでは詳しく扱いません。

代わりに、このガイドでは Flash によるゲーム開発の主要な概念の一部を取り上げ、それに最も近い Defold の概念を説明します。共通点、違い、よくある落とし穴を紹介し、Flash から Defold への移行を円滑に始められるようにします。

ムービークリップとゲームオブジェクト

ムービークリップ(movie clip)は、Flash のゲーム開発における主要な構成要素です。ムービークリップは、それぞれ独自のタイムラインを持つシンボルです。Defold でこれに最も近い概念はゲームオブジェクトです。

ゲームオブジェクトとムービークリップ

Flash のムービークリップとは異なり、Defold のゲームオブジェクトにはタイムラインがありません。代わりに、ゲームオブジェクトは複数のコンポーネント(component)で構成されます。コンポーネントには、スプライト(sprite)、サウンド(sound)、スクリプトなど、多くの種類があります(利用できるコンポーネントの詳細については、基本構成要素のドキュメントと関連記事を参照してください)。下のスクリーンショットのゲームオブジェクトは、スプライトとスクリプトで構成されています。スクリプトコンポーネントは、ゲームオブジェクトのライフサイクル全体を通じて、その振る舞いと見た目を制御するために使います。

スクリプトコンポーネント

ムービークリップには別のムービークリップを含められますが、ゲームオブジェクトには別のゲームオブジェクトを含めることはできません。ただし、ゲームオブジェクトを別のゲームオブジェクトの子にすることはでき、一緒に移動、拡大縮小、回転できる階層を作成できます。

Flash—ムービークリップを手動で作成する

Flash では、ライブラリからタイムラインへドラッグすることで、ムービークリップのインスタンスをシーンに手動で追加できます。下のスクリーンショットでは、各 Flash ロゴが logo ムービークリップのインスタンスになっています。

手動で作成したムービークリップ

Defold—ゲームオブジェクトを手動で作成する

前述のとおり、Defold にはタイムラインという概念がありません。代わりに、ゲームオブジェクトはコレクション(collection)で整理します。コレクションは、ゲームオブジェクトや別のコレクションを保持するコンテナー(またはプレハブ)です。最も基本的な構成では、1つのコレクションだけでゲームを作れます。ただし、Defold のゲームでは複数のコレクションを使うことがより一般的です。これらを、起動時に読み込まれるブートストラップコレクション(bootstrap collection)の main に手動で追加するか、コレクションプロキシ(collection proxy)を通じて動的に読み込みます。このように「レベル」や「画面」を読み込む概念に直接対応するものは Flash にはありません。

下の例では、main コレクションに logo ゲームオブジェクト(左側の Assets ブラウザーウィンドウに表示)のインスタンスが3つ含まれています(右側の Outline ウィンドウに一覧表示)。

手動で作成したゲームオブジェクト

Flash—手動で作成したムービークリップを参照する

Flash で手動作成したムービークリップを参照するには、手動で定義したインスタンス名を使う必要があります。

Flash のインスタンス名

Defold—ゲームオブジェクトの識別子

Defold では、すべてのゲームオブジェクトとコンポーネントをアドレスで参照します。ほとんどの場合、単純な名前や省略形だけで十分です。たとえば、次のように指定します。

  • "." は現在のゲームオブジェクトを指定します。
  • "#" は現在のコンポーネント(スクリプト)を指定します。
  • "logo" は識別子が logo のゲームオブジェクトを指定します。
  • "#script" は現在のゲームオブジェクトにある、識別子が script のコンポーネントを指定します。
  • "logo#script" は識別子が logo のゲームオブジェクトにある、識別子が script のコンポーネントを指定します。

手動で配置したゲームオブジェクトのアドレスは、割り当てられた Id プロパティ(property)によって決まります(スクリーンショットの右下を参照)。識別子は、現在作業しているコレクションファイル内で一意である必要があります。エディターが識別子を自動的に設定しますが、作成したゲームオブジェクトのインスタンスごとに変更できます。

ゲームオブジェクトの識別子

ゲームオブジェクトの識別子は、そのスクリプトコンポーネントで print(go.get_id()) を実行すると確認できます。これにより、現在のゲームオブジェクトの識別子がコンソールに出力されます。

アドレス指定(addressing)のモデルと、メッセージによる通信であるメッセージパッシング(message passing)は、Defold のゲーム開発における主要な概念です。アドレス指定のマニュアルメッセージパッシングのマニュアルで、これらを詳しく説明しています。

Flash—ムービークリップを動的に作成する

Flash でムービークリップを動的に作成するには、まず ActionScript Linkage を設定する必要があります。

ActionScript Linkage の設定

これによりクラス(この場合は Logo)が作成され、そのクラスの新しいインスタンスを作成できるようになります。Logo クラスのインスタンスを Stage に追加するには、次のように記述できます。

var logo:Logo = new Logo();
addChild(logo);

Defold—ファクトリーを使ってゲームオブジェクトを作成する

Defold では、 ファクトリー(factory) を使ってゲームオブジェクトを動的に生成します。ファクトリーは、特定のゲームオブジェクトのコピーを生成するためのコンポーネントです。この例では、logo ゲームオブジェクトをプロトタイプ(prototype)とするファクトリーを作成しています。

ロゴのファクトリー

ファクトリーは、ほかのすべてのコンポーネントと同じく、使用前にゲームオブジェクトに追加する必要がある点に注意してください。この例では、ファクトリーコンポーネントを保持するために、factories というゲームオブジェクトを作成しています。

ファクトリーコンポーネント

logo ゲームオブジェクトのインスタンスを生成するには、次の関数を呼び出します。

local logo_id = factory.create("factories#logo_factory")

URL は factory.create() の必須パラメーターです。さらに、位置、回転、プロパティ、スケールを設定する任意のパラメーターも追加できます。ファクトリーコンポーネントの詳細については、ファクトリーのマニュアルを参照してください。factory.create() を呼び出すと、作成されたゲームオブジェクトの識別子が返される点にも注目してください。この識別子は、後で参照できるようにテーブル(Lua で配列に相当するもの)に保存できます。

Flash—ステージ

Flash では、Timeline(下のスクリーンショットの上部)と Stage(Timeline の下に表示)を使い慣れているでしょう。

タイムラインとステージ

前述のムービークリップの節で説明したように、Stage は基本的に Flash ゲームの最上位のコンテナーで、プロジェクトをエクスポートするたびに作成されます。Stage は既定で、MainTimeline という子を1つ持ちます。プロジェクト内で生成される各ムービークリップには独自のタイムラインがあり、ほかのシンボル(ムービークリップも含む)のコンテナーとして使えます。

Defold—コレクション

Flash の Stage に相当する Defold の概念はコレクションです。エンジンの起動時に、コレクションファイルの内容に基づいて新しいゲームワールド(game world)が作成されます。既定ではこのファイルの名前は main.collection ですが、各 Defold プロジェクトのルートにある game.project 設定ファイルから、起動時に読み込むコレクションを変更できます。

game.project

コレクションは、ゲームオブジェクトや別のコレクションをエディター内で整理するためのコンテナーです。コレクションファクトリー(collection factory)を使うと、スクリプトを通じてランタイムにコレクションの内容を生成することもできます。これは通常のゲームオブジェクトのファクトリーと同じように動作します。たとえば、敵の集団や、特定の配置パターンで収集用のコインを生成する場合に役立ちます。下のスクリーンショットでは、logos コレクションのインスタンスを2つ、main コレクションに手動で配置しています。

コレクション

まったく新しいゲームワールドを読み込みたい場合もあります。コレクションプロキシコンポーネントを使うと、コレクションファイルの内容に基づいて新しいゲームワールドを作成できます。これは、新しいゲームレベル、ミニゲーム、カットシーンなどを読み込む場面で役立ちます。

Flash—タイムライン

Flash のタイムラインは、主にアニメーションに使います。さまざまなフレーム単位の手法や、シェイプトゥイーン、モーショントゥイーンを利用します。プロジェクト全体の FPS(1秒あたりのフレーム数)設定によって、1フレームを表示する時間が決まります。上級ユーザーは、ゲーム全体の FPS に加え、個々のムービークリップの FPS も変更できます。

シェイプトゥイーンでは、2つの状態の間でベクターグラフィックスを補間できます。下に示す、四角形を三角形に変形するシェイプトゥイーンの例のように、主に単純な形状や用途に限って役立ちます。

タイムライン

モーショントゥイーンでは、サイズ、位置、回転など、オブジェクトのさまざまなプロパティをアニメーション化できます。下の例では、一覧にあるすべてのプロパティを変更しています。

モーショントゥイーン

Defold—プロパティアニメーション

Defold はベクターグラフィックスではなくピクセル画像を扱うため、シェイプトゥイーンに相当する機能はありません。ただし、モーショントゥイーンには、プロパティアニメーション(property animation)という強力な対応機能があります。これは、スクリプトで go.animate() 関数を使って実行します。go.animate() 関数は、多くのイージング関数(独自のものも含む)のいずれかを使い、プロパティ(色、スケール、回転、位置など)を開始値から目的の終了値まで補間します。Flash では高度なイージング関数をユーザーが実装する必要がありましたが、Defold には多くのイージング関数がエンジンに組み込まれています。

Flash ではタイムライン上のグラフィックスのキーフレームを使ってアニメーションを作成します。一方、Defold でグラフィックスをアニメーション化する主な方法の1つは、インポートした連続画像を切り替えるフリップブックアニメーション(flipbook animation)です。アニメーションは、アトラス(atlas)と呼ばれるゲームオブジェクトのコンポーネントで整理します。この例では、ゲームキャラクター用のアトラスに、run というアニメーションシーケンスがあります。これは一連の png ファイルで構成されています。

フリップブック

Flash—深度インデックス

Flash では、表示リストによって表示する内容と順序が決まります。Stage などのコンテナー内でのオブジェクトの順序は、インデックスで管理します。addChild() メソッドでコンテナーに追加したオブジェクトは、自動的にインデックスの最上位に配置されます。インデックスは0から始まり、オブジェクトを追加するたびに増加します。下のスクリーンショットでは、logo ムービークリップのインスタンスを3つ生成しています。

深度インデックス

logo インスタンスの横にある数字は、表示リスト内の位置を示しています。ムービークリップの x/y 位置を処理するコードを除くと、上の例は次のように生成できます。

var logo1:Logo = new Logo();
var logo2:Logo = new Logo();
var logo3:Logo = new Logo();

addChild(logo1);
addChild(logo2);
addChild(logo3);

オブジェクトが別のオブジェクトより手前に表示されるか、奥に表示されるかは、表示リストのインデックス内での相対的な位置で決まります。たとえば、2つのオブジェクトのインデックス位置を入れ替えると、その仕組みがよく分かります。

swapChildren(logo2,logo3);

結果は次のようになります(インデックス位置も更新されています)。

深度インデックス

Defold—z 位置

Defold のゲームオブジェクトの位置は、x、y、z の3つの変数からなるベクトルで表します。z 位置は、ゲームオブジェクトの深度を決定します。既定のレンダースクリプトで使用できる z 位置の範囲は、-1から1です。

z 位置が-1から1の範囲外にあるゲームオブジェクトはレンダリングされないため、表示されません。これは Defold を使い始めた開発者がよく陥る落とし穴です。表示されるはずのゲームオブジェクトが見えない場合は、この点を覚えておくと役立ちます。

Flash のエディターでは深度インデックスは間接的に示され、Bring ForwardSend Backward といったコマンドで変更しますが、Defold ではエディターでオブジェクトの z 位置を直接設定できます。下のスクリーンショットでは、z 位置が0.2の logo3 が最前面に表示されています。ほかのゲームオブジェクトの z 位置は0.0と0.1です。

z 順序

1つ以上のコレクションに入れ子になっているゲームオブジェクトの z 位置は、そのオブジェクト自身の z 位置と、すべての親の z 位置によって決まる点に注意してください。たとえば、上の logo ゲームオブジェクトを logos コレクションに配置し、そのコレクションを main に配置したとします(下のスクリーンショットを参照)。logos コレクションの z 位置が0.9であれば、その中に含まれるゲームオブジェクトの z 位置は0.9、1.0、1.1になります。そのため、logo3 は z 位置が1より大きく、レンダリングされません。

z 順序

ゲームオブジェクトの z 位置は、もちろんスクリプトで変更することもできます。次のコードがゲームオブジェクトのスクリプトコンポーネント内にあるとします。

local pos = go.get_position()
pos.z  = 0.5
go.set_position(pos)

Flash の hitTestObjecthitTestPoint による衝突判定

Flash の基本的な衝突判定は、hitTestObject() メソッドで行います。この例では、bulletbullseye という2つのムービークリップを使います。これらを下のスクリーンショットに示します。Flash エディターでシンボルを選択すると青いバウンディングボックスが表示されます。hitTestObject() メソッドの結果は、このバウンディングボックスによって決まります。

ヒットテスト

hitTestObject() による衝突判定は、次のように行います。

bullet.hitTestObject(bullseye);

この場合、バウンディングボックスの使用は適切ではありません。下の状況でもヒットしたと判定されてしまうためです。

バウンディングボックスによるヒットテスト

hitTestObject() の代わりに使えるのが、hitTestPoint() メソッドです。このメソッドには shapeFlag パラメーターがあり、バウンディングボックスではなくオブジェクトの実際のピクセルを対象にヒットテストを実行できます。hitTestPoint() による衝突判定は、次のように行えます。

bullseye.hitTestPoint(bullet.x, bullet.y, true);

この行は、弾の x と y の位置(この例では左上)を、的の形状に対して判定します。hitTestPoint() は点と形状を判定するため、どの点を調べるか(あるいは複数の点を調べるか)が重要な検討事項です。

Defold—コリジョンオブジェクト

Defold には、衝突を検出し、スクリプトでそれに応答できる物理エンジンが含まれています。Defold の衝突判定は、ゲームオブジェクトにコリジョンオブジェクト(collision object)コンポーネントを割り当てるところから始めます。下のスクリーンショットでは、bullet ゲームオブジェクトにコリジョンオブジェクトを追加しています。コリジョンオブジェクトは、赤い半透明のボックスで示されています(エディター内でのみ表示されます)。

コリジョンオブジェクト

Defold には Box2D 物理エンジンの改変版が含まれており、現実に近い衝突を自動でシミュレートできます。このガイドでは、Flash の衝突判定に最も近いキネマティックコリジョンオブジェクト(kinematic collision object)を使うことを前提とします。動的コリジョンオブジェクト(dynamic collision object)の詳細については、Defold の物理マニュアルを参照してください。

コリジョンオブジェクトには、次のプロパティがあります。

コリジョンオブジェクトのプロパティ

弾のグラフィックスに最も適しているため、ボックス形状を使っています。的には、2D 衝突で使うもう1つの形状である球を使います。種類を Kinematic に設定すると、組み込みの物理エンジンに代わってスクリプトが衝突を解決します(ほかの種類の詳細については、物理マニュアルを参照してください)。Group プロパティはオブジェクトが所属するコリジョングループ(collision group)を、Mask プロパティは衝突を判定する相手のコリジョングループを決定します。現在の設定では、bullettarget とだけ衝突します。設定を次のように変更したとします。

コリジョングループとマスク

これで、弾は的とほかの弾に衝突するようになります。参考として、的のコリジョンオブジェクトは次のように設定しています。

弾のコリジョンオブジェクト

Group プロパティを target に、Maskbullet に設定している点に注目してください。

Flash では、スクリプトから明示的に呼び出したときだけ衝突判定を行います。Defold では、コリジョンオブジェクトが有効である限り、バックグラウンドで衝突判定が継続的に行われます。衝突が発生すると、ゲームオブジェクトのすべてのコンポーネント(特に関係するのはスクリプトコンポーネント)にメッセージが送信されます。これらは collision_responsecontact_point_response メッセージで、目的に合わせて衝突を解決するために必要な情報がすべて含まれています。

Defold の衝突判定の利点は、Flash より高度で、わずかな設定だけで比較的複雑な形状間の衝突を検出できることです。衝突判定は自動で行われるため、異なるコリジョングループ内のさまざまなオブジェクトをループで処理して、ヒットテストを明示的に実行する必要はありません。主な欠点は、Flash の shapeFlag に相当する機能がないことです。ただし、ほとんどの用途では、基本的なボックス形状と球形状の組み合わせで十分です。より複雑な場合には、カスタム形状も使用できます

Flash—イベント処理

イベントオブジェクトと、それに関連付けられたリスナーは、さまざまなイベント(マウスクリック、ボタン押下、クリップの読み込みなど)を検出し、それに応じたアクションを実行するために使います。扱えるイベントには多くの種類があります。

Defold—コールバック関数とメッセージ通信

Defold で Flash のイベント処理システムに相当する仕組みは、いくつかの要素で構成されています。まず、各スクリプトコンポーネントには、特定のイベントを検出する次のコールバック関数が用意されています。

init
スクリプトコンポーネントが初期化されるときに呼び出されます。Flash のコンストラクター関数に相当します。
final
スクリプトコンポーネントが破棄されるとき(生成したゲームオブジェクトが削除される場合など)に呼び出されます。
update
毎フレーム呼び出されます。Flash の enterFrame に相当します。
on_message
スクリプトコンポーネントがメッセージを受信したときに呼び出されます。
on_input
入力フォーカス(input focus)を持つゲームオブジェクトに、ユーザー入力(マウスやキーボードなど)が送信されたときに呼び出されます。入力フォーカスがあると、そのオブジェクトはすべての入力を受信し、それに応答できます。
on_reload
スクリプトコンポーネントが再読み込みされたときに呼び出されます。

上記のコールバック関数はすべて任意で、使わない場合は削除できます。入力の設定方法については、入力のマニュアルを参照してください。コレクションプロキシを使う場合には、よくある落とし穴があります。詳しくは、入力のマニュアルのこちらの節を参照してください。

衝突判定の節で説明したとおり、衝突イベントは、関係するゲームオブジェクトにメッセージを送信することで処理します。それぞれのスクリプトコンポーネントは、on_message コールバック関数でメッセージを受信します。

Flash—ボタンシンボル

Flash は、ボタン専用のシンボルの種類を使います。ボタンは、clickbuttonDown などの専用のイベントハンドラーメソッドを使い、ユーザーの操作を検出するとアクションを実行します。ボタンシンボルの「Hit」セクションにあるボタンのグラフィックスの形状によって、ボタンのヒット領域が決まります。

ボタン

Defold—GUI シーンとスクリプト

Defold には組み込みのボタンコンポーネントがなく、Flash のボタンのように、特定のゲームオブジェクトの形状に対するクリックを簡単に検出することもできません。最も一般的な解決方法は、GUI コンポーネントを使うことです。その理由の1つは、Defold の GUI コンポーネントの位置が、ゲーム内のカメラ(使用している場合)の影響を受けないことです。GUI API には、クリックやタッチイベントなどのユーザー入力が GUI 要素の範囲内にあるかどうかを検出する関数も含まれています。

デバッグ

Flash では、デバッグ時に trace() コマンドが役立ちます。Defold でこれに相当するのは print() で、trace() と同じように使います。

print("Hello world!"")

1つの print() 関数で複数の変数を出力できます。

print(score, health, ammo)

テーブルを扱うときに便利な pprint() 関数(整形出力)もあります。この関数は、入れ子になったテーブルも含め、テーブルの内容を出力します。次のスクリプトを見てみましょう。

factions = {"red", "green", "blue"}
world = {name = "Terra", teams = factions}
pprint(world)

この例では、テーブル(world)の中にテーブル(factions)が入れ子になっています。通常の print() コマンドを使うと、テーブルの一意の識別子が出力されますが、実際の内容は出力されません。

DEBUG:SCRIPT: table: 0x7ff95de63ce0

上記のように pprint() 関数を使うと、より分かりやすい結果が得られます。

DEBUG:SCRIPT:
{
  name = Terra,
  teams = {
    1 = red,
    2 = green,
    3 = blue,
  }
}

ゲームで衝突判定を使っている場合は、次のメッセージを送信すると、物理デバッグの有効・無効を切り替えられます。

msg.post("@system:", "toggle_physics_debug")

物理デバッグは、プロジェクト設定でも有効にできます。物理デバッグを有効にする前のプロジェクトは、次のように表示されます。

デバッグ無効

物理デバッグを有効にすると、ゲームオブジェクトに追加したコリジョンオブジェクトが表示されます。

デバッグ有効

衝突が発生すると、関連するコリジョンオブジェクトが明るく表示されます。さらに、衝突ベクトルも表示されます。

衝突

最後に、CPU とメモリの使用量を監視する方法については、プロファイラーのドキュメントを参照してください。高度なデバッグ手法の詳細については、Defold マニュアルのデバッグの節を参照してください。

次に読む資料

質問がある場合や行き詰まった場合は、Defold フォーラムで助けを求めることをお勧めします。