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
エンジンはユーザーからのすべての入力を取得し、入力フォーカス(input focus)を取得したゲームオブジェクト(game object)内にある、on_input() 関数を実装したスクリプトコンポーネント(script component)と GUI スクリプトコンポーネントにアクション(action)として配信します。このマニュアルでは、入力を取得するための入力バインディング(input binding)の設定方法と、入力に反応するコードの作成方法を説明します。
入力システムは、シンプルで強力な概念をいくつか組み合わせており、ゲームに合った方法で入力を管理できます。

入力バインディングはプロジェクト全体に適用されるテーブルです。デバイスからの入力をスクリプトコンポーネントや GUI スクリプトに配信する前に、名前を付けた アクション へどう変換するかを指定できます。新しい入力バインディングファイルを作成するには、Assets ビュー内の場所を 右クリック し、New... ▸ Input Binding を選択します。エンジンが新しいファイルを使うようにするには、game.project の Game Binding 項目を変更します。

すべての新規プロジェクトテンプレートでは、デフォルトの入力バインディングファイルが自動的に作成されるため、通常は新しいバインディングファイルを作成する必要はありません。デフォルトのファイル名は game.input_binding で、プロジェクトのルートにある input フォルダーにあります。ファイルを ダブルクリック してエディターで開きます。

新しいバインディングを作成するには、該当するトリガーの種類のセクションの下部にある + ボタンをクリックします。各項目には2つのフィールドがあります。
A ボタンをアクション jump にバインドできます。ただし、残念ながらタッチ入力には他の入力と同じアクション名を付けられないという既知のバグがあります。デバイスに対応した5種類の入力トリガー(input trigger)を作成できます。
上記の5種類のトリガーに加えて、Defold は Android と iOS のネイティブアプリケーションで加速度計の入力もサポートしています。game.project ファイルの Input セクションで Use Accelerometer チェックボックスをオンにします。
function on_input(self, action_id, action)
if action.acc_x and action.acc_y and action.acc_z then
-- react to accelerometer data
end
end
スクリプトコンポーネントや GUI スクリプトで入力アクションを受信するには、コンポーネントを持つゲームオブジェクトに acquire_input_focus メッセージを送信します。
-- tell the current game object (".") to acquire input focus
msg.post(".", "acquire_input_focus")
このメッセージは、ゲームオブジェクト内の入力を受け取れるコンポーネント(スクリプトコンポーネント、GUI コンポーネント、コレクションプロキシ(collection proxy))を 入力スタック に追加するようエンジンに指示します。ゲームオブジェクトのコンポーネントは入力スタックの上に置かれ、最後に追加されたコンポーネントがスタックの一番上になります。ゲームオブジェクトに入力を受け取れるコンポーネントが複数ある場合は、すべてがスタックに追加される点に注意してください。

すでに入力フォーカスを取得しているゲームオブジェクトが再度フォーカスを取得すると、そのコンポーネントがスタックの一番上に移動します。
入力アクションは、入力スタックの順序に従って上から下へ配信されます。

スタック上にあり、on_input() 関数を持つコンポーネントでは、そのフレーム内の入力アクションごとに1回、次の引数を指定してその関数が呼び出されます。
selfaction_idnil になります。名前のないこれらのアクションは、action.source で区別します。actionpressed であったかなど、アクションに関する有用なデータを含むテーブルです。利用可能なアクションのフィールドについて詳しくは、on_input() を参照してください。function on_input(self, action_id, action)
if action_id == hash("left") and action.pressed then
-- move left
local pos = go.get_position()
pos.x = pos.x - 100
go.set_position(pos)
elseif action_id == hash("right") and action.pressed then
-- move right
local pos = go.get_position()
pos.x = pos.x + 100
go.set_position(pos)
end
end
action.source は、アクション名とは独立して入力デバイスの種類を識別します。スクリプトと GUI スクリプトの両方の on_input() コールバックで利用でき、次のハッシュのいずれかです。
action.source |
入力の種類 |
|---|---|
hash("keyboard") |
Key Triggers からの個々のキー入力。 |
hash("text") |
Text Triggers からのテキストと未確定テキストの入力。物理キーボードから入力したテキストも含みます。 |
hash("mouse") |
物理マウスのボタン、ホイール入力、ポインター移動。 |
hash("touch") |
タッチ入力。タッチから模擬したマウスクリックとポインター移動も含みます。 |
hash("gamepad") |
ゲームパッド入力。生の入力と接続イベントも含みます。 |
hash("accelerometer") |
加速度センサーのサンプル。 |
action.source は文字列ではなく、hash("touch") のようなハッシュと比較します。たとえば、マウスの左ボタンのアクションは、物理マウスからもタップからも発生します。入力元を使うと、最初の押下時から区別できます。マウスクリックとタッチの区別を参照してください。
複数のデバイスが名前付きのアクションを共有すると、それぞれの入力が組み合わされることがあります。入力元はキーボード、テキスト、マウス、タッチの順に処理し、そのアクションに最後に寄与した入力元を報告します。キーとマウスボタンのリリースでは、同じフレームでほかの入力が寄与しない限り、直前の入力元を保持します。ゲームパッドのアクションは、コントローラーごとに独立しています。各バインディングを個別に処理する必要がある場合は、別々のアクション名を使います。
ポインター移動と加速度センサーのサンプルにはアクション名がないため、どちらも action_id == nil を使います。それぞれ別のコールバックで届きます。ポインター移動には座標と、マウスまたはタッチの入力元があり、加速度センサーのサンプルには acc_x、acc_y、acc_z と加速度センサーの入力元があります。同じフレームで両方が発生しても、各コールバックを独立して消費できます。加速度センサーのサンプルは、値が変化していなくても届きます。
以下の例は、名前のないこれらのアクションを処理します。ポインター移動を受け取るには少なくとも1つの Mouse Trigger を設定し、加速度センサーのサンプルを受け取るには対応デバイスで Use Accelerometer を有効にします。
function init(self)
msg.post(".", "acquire_input_focus")
end
function on_input(self, action_id, action)
if action_id == nil then
if action.source == hash("mouse") or action.source == hash("touch") then
print("Pointer position:", action.x, action.y)
elseif action.source == hash("accelerometer") then
print("Acceleration:", action.acc_x, action.acc_y, action.acc_z)
end
end
end
コレクションプロキシを通じて動的に読み込まれる各ゲームワールド(game world)は、それぞれ独自の入力スタックを持ちます。配信されるアクションが読み込まれたワールドの入力スタックに届くには、プロキシコンポーネントがメインワールドの入力スタック上にある必要があります。読み込まれたワールドのスタック上のすべてのコンポーネントを処理してから、メインスタックの下への配信を続けます。

コレクションプロキシコンポーネントを持つゲームオブジェクトに acquire_input_focus を送信し忘れるのは、よくある間違いです。この手順を省略すると、読み込まれたワールドの入力スタック上のどのコンポーネントにも入力が届きません。
入力アクションの受信を停止するには、ゲームオブジェクトに release_input_focus メッセージを送信します。このメッセージは、そのゲームオブジェクトのコンポーネントを入力スタックから取り除きます。
-- tell the current game object (".") to release input focus.
msg.post(".", "release_input_focus")
コンポーネントの on_input() では、アクションをスタックの下へさらに渡すかどうかを制御できます。
on_input() が false を返す場合や、戻り値を省略した場合(この場合は nil が返され、Lua では偽の値として扱われます)、入力アクションは入力スタック上の次のコンポーネントに渡されます。on_input() が true を返す場合、入力は消費されます。入力スタックの下にあるコンポーネントは、その入力を受け取りません。これは すべての 入力スタックに適用される点に注意してください。プロキシで読み込まれたワールドのスタック上のコンポーネントが入力を消費し、メインスタック上のコンポーネントに入力が届かないようにすることもできます。
入力の消費は、ゲームのさまざまな部分の間で入力の受信先を切り替えるシンプルで強力な方法で、多くの場面で役立ちます。たとえば、一時的にゲーム内で入力を受け取る唯一の部分となるポップアップメニューが必要な場合です。

ポーズメニューは最初は非表示(無効)になっており、プレイヤーが HUD の PAUSE 項目に触れると有効になります。
function on_input(self, action_id, action)
if action_id == hash("mouse_press") and action.pressed then
-- Did the player press PAUSE?
local pausenode = gui.get_node("pause")
if gui.pick_node(pausenode, action.x, action.y) then
-- Tell the pause menu to take over.
msg.post("pause_menu", "show")
end
end
end

ポーズメニューの GUI は入力フォーカスを取得して入力を消費し、ポップアップメニューに関係するもの以外の入力を受け付けなくします。
function on_message(self, message_id, message, sender)
if message_id == hash("show") then
-- Show the pause menu.
local node = gui.get_node("pause_menu")
gui.set_enabled(node, true)
-- Acquire input.
msg.post(".", "acquire_input_focus")
end
end
function on_input(self, action_id, action)
if action_id == hash("mouse_press") and action.pressed then
-- do things...
local resumenode = gui.get_node("resume")
if gui.pick_node(resumenode, action.x, action.y) then
-- Hide the pause menu
local node = gui.get_node("pause_menu")
gui.set_enabled(node, false)
-- Release input.
msg.post(".", "release_input_focus")
end
end
-- Consume all input. Anything below us on the input stack
-- will never see input until we release input focus.
return true
end