この記事では、Unityの新しい入力システム「Input System」を活用して、ゼルダの伝説の回転斬りのような「溜め攻撃」アクションを実装する方法を解説します。
Input Systemには長押しを検知する「Hold Interaction」もありますが、今回はあえてそれを使わず、ボタン入力の基本的なイベントである「押した瞬間 (started)」と「離した瞬間 (canceled)」の時刻差を利用するアプローチを紹介します。
従来のUpdate関 数内で毎フレーム入力を監視する方法と比較して、Input Systemのイベント駆動型アプローチは、コードがシンプルになり、特に機能追加や変更に対する保守性が向上するメリットが期待できます。
この記事の内容
- 溜め攻撃の実装:Input System (Press) vs Update vs Hold Interaction
- Input SystemのインストールとInput Actionsアセットの作成
- Input Actions:左クリック(攻撃ボタン)アクションの定義
- スクリプト連携:PlayerInputとイベント処理スクリプト
- 溜め時間の計算ロジック:startedとcanceledの活用
- 中間演出の実装:コルーチンでInput Systemの弱点を補う
- まとめ:Pressイベント方式のメリット・デメリットと使い分け
溜め攻撃の実装:Input System (Press) vs Update vs Hold Interaction
溜め攻撃を実装する方法はいくつか考えられます。それぞれの特徴を見てみましょう。
- 従来の
Update関数による実装:Update()内で毎フレーム入力をチェックし、ボタンが押されている時間を計測します。- 仕組みは直感的ですが、入力の種類や条件分岐が増えるとコードが複雑化しがちです。
- Input System の
Hold Interactionを使う実装:- Input ActionsアセットでInteractionを「Hold」に設定し、指定時間(Hold Time)長押しされると
performedイベントが発生します。 - 設定は簡単ですが、後述す るように「短押し(通常攻撃)」と「長押し(溜め攻撃)」を同じボタンで使い分けたい場合に、実装がやや複雑になることがあります。
- Input ActionsアセットでInteractionを「Hold」に設定し、指定時間(Hold Time)長押しされると
- Input System の
Pressイベント (started/canceled) を使う実装(本記事のアプローチ):- ボタンが押された瞬間(
started)と離された瞬間(canceled)のイベントを利用し、その間の時間を計測します。 - イベント駆動でコードが整理されやすく、短押し・長押しの判定や溜め中の処理を柔軟に実装できます。
- ボタンが押された瞬間(
Q. なぜHold InteractionではなくPressイベント (started/canceled) を使うのか?
Hold Interactionは指定時間長押しされたことを検知するのに便利ですが、「同じボタンで短押し(通常攻撃)と長押し(溜め攻撃)を使い分けたい」場合や、「溜めている最中に演出を入れたい」場合には、少し扱いにくい側面があります。
- 短押しと長押しの両立: Hold Interactionでは、長押しが成立して
performedが呼ばれる前に、短押し時の処理(通常攻撃など)をボタンを押した直後に実行させたい場合、工夫が必要です。例えば、「押した瞬間(started)に通常攻撃を出し、Holdが成立したらキャンセルする」といった制御や、別途短押し用のアクションを用意するなど、実装が複雑になりがちです。 - 押下開始タイミングの活用: ボタンを押した瞬間にキャラクターが構えモーションに入ったり、溜めエフェクトを開始したりといった処理を即座に行いたい場合、Hold Interactionだけではタイミングを計りにくいことがあります。
- 溜め中の制御: 溜めゲージを表示したり、一定時間ごとに溜めレベルが上がる演出を入れたりする場合、最終的に
performedイベントが発生するまで待つ必要があるHold Interactionでは、溜めている途中の細かな制御がしづらいです。
一方、本記事で紹介する**Pressイベント (started/canceled) を利用する方法**では、
- ボタンを押した瞬間の
startedイベントと、離した瞬間のcanceledイベントの時刻差を計測することで、押下時間を正確に把握できます。 - これにより、「一定時間未満なら通常攻撃、一定時間以上なら溜め攻撃」といった判定を
canceledイベント内で簡単に行えます。 startedイベント発生時に溜め動作やエフェクトを開始し、canceledイベントで攻撃を発動、という流れを自然に実装できます。- (後述するコルーチンなどを組み合わせれば)溜めている最中の演出や状態変化も柔軟に組み込めます。
このように、短押し/長押しの判定や、溜め中の演出・状態管理を柔軟に行いたい場合には、started/canceledイベントを利用するアプローチが適していると言えます。
Input SystemのインストールとInput Actionsアセットの作成
まず、プロジェクトにInput Systemパッケージを導入し、入力を定義するInput Actionsアセットを作成します。
Input Systemパッケ ージのインストール
Unityエディタのメニューから操作します。

- Window > Package Manager を開きます。
- 左上のドロップダウンメニューで「Packages: Unity Registry」を選択します。
- リストから「Input System」を探し、「Install」ボタンをクリックします。
- インストール中にプロジェクト設定の変更を促すダイアログが出たら、「Yes」を選択してエディタを再起動します。
Input Actionsアセットファイルの作成
次に、入力アクションを定義するためのアセットファイルを作成します。

- Projectウィンドウで右クリックし、Create > Input Actions を選択します。
- 作成されたアセットファイル(例:
PlayerInputActions.inputactions)に分かりやすい名前を付けます。 - 作成したアセットファイルを選択し、Inspectorウィンドウで「Generate C# Class」にチェックを入れ、「Apply」ボタンを押します。

「Generate C# Class」にチェックを入れることで、このInput Actionsアセットに対応するC#クラスが自動生成され、スクリプトから入力イベントを扱いやすくなります。
Input Actions:左クリック(攻撃ボタン)アクションの定義
作成したInput Actionsアセットファイル(例: PlayerInputActions.inputactions)をダブルクリックして編集ウィンドウを開き、溜め攻撃に使用するアクションを定義します。

- Action Maps 列の「+」ボタンをクリックし、新しいAction Mapを作成します(例:
Gameplay)。Action Mapは関連するアクションをまとめるグループです。 - Actions 列の「+」ボタンをクリックし、新しいActionを作成します(例:
AttackLeft)。これが具体的な入力操作に対応します。 - 作成した
AttackLeftActionを選択し、右側のPropertiesパネルで以下を設定します。- Action Type: 「Button」を選択します。これは、押す/離すの単純な入力に適しています。
AttackLeftActionの下にある<No Binding>を選択 し、Propertiesパネルで以下を設定します。これが具体的な入力デバイスのボタンとの紐付け(Binding)です。- Path: プルダウンメニューから「Mouse」>「Left Button」を選択します。(ゲームパッドのボタンなどもここで設定可能)
- 編集が終わったら、ウィンドウ上部の「Save Asset」ボタンをクリックして変更を保存します。
これで、「マウスの左クリック」がAttackLeftという名前のアクションとして、スクリプトからイベントとして受け取れるようになりました。
スクリプト連携:PlayerInputとイベント処理スクリプト
定義したInput Actionsを実際にゲーム内で機能させるために、スクリプトとの連携を設定します。
-
シーン内に空のGameObjectを作成し、分かりやすい名前(例:
InputManager)を付けます。 -
作成した
InputManagerGameObjectに「Player Input」コンポーネントを追加します。 -
Player Inputコンポーネントの「Actions」フィールドに、先ほど作成したInput Actionsアセット(例:
PlayerInputActions.inputactions)をドラッグ&ドロップで設定します。 -
以下のC#スクリプト(例:
InputManager.cs)を作成し、InputManagerGameObjectにアタッチします。
using UnityEngine;
using UnityEngine.InputSystem;
// PlayerInputコンポーネントが必須であることを示す
[RequireComponent(typeof(PlayerInput))]
public class InputManager : MonoBehaviour
{
// ボタンが押され始めた時刻を記録する変数
private float buttonPressStartTime;
// 溜め攻撃と判定する時間のしきい値(例: 1秒)
private const float specialAttackThreshold = 1.0f;
// PlayerInputコンポーネントから呼び出されるメソッド
// メソッド名はInput Actionsで定義したアクション名(例: AttackLeft)に
// "On" を付けたものにするか、後述のようにInspectorで手動設定する
public void OnAttackLeft(InputAction.CallbackContext context)
{
// ボタンが押された瞬間 (started) の処理
if (context.started)
{
Debug.Log("Attack button pressed (started)");
// 押下開始時刻を記録
buttonPressStartTime = Time.time;
// ここで構えモーションや溜めエフェクト開始などの処理を入れることも可能
}
// ボタンが離された瞬間 (canceled) の処理
else if (context.canceled)
{
Debug.Log("Attack button released (canceled)");
// 押されていた時間を計算
float pressDuration = Time.time - buttonPressStartTime;
Debug.Log($"Press duration: {pressDuration} seconds");
// 押下時間がしきい値を超えていたら溜め攻撃
if (pressDuration > specialAttackThreshold)
{
PerformSpecialAttack(); // 溜め攻撃実行メソッド呼び出し
}
// しきい値未満なら通常攻撃
else
{
PerformNormalAttack(); // 通常攻撃実行メソッド呼び出し
}
}
// context.performed は Button タイプでは started とほぼ同じタイミングで呼ばれることが多い
// Hold Interaction を使わない場合、主に started と canceled を使う
}
// 通常攻撃を実行する処理(中身は仮)
private void PerformNormalAttack()
{
Debug.Log("Perform Normal Attack!");
// ここに実際の通常攻撃ロジックを記述
}
// 溜め攻撃を実行する処理(中身は仮)
private void PerformSpecialAttack()
{
Debug.Log("Perform Special Attack!");
// ここに実際の溜め攻撃ロジックを記述
}
}
-
InputManagerGameObjectを選択し、InspectorウィンドウでPlayer Inputコンポーネントの「Behavior」を「Invoke Unity Events」に設定します。 -
「Events」セクションが展開されるので、設定したAction Map名(例:
Gameplay)を開き、その中のアクション名(例:Attack Left)に対応するイベント欄の「+」ボタンをクリックします。 -
イベント欄に
InputManagerGameObject自体をドラッグ&ドロップし、右側のドロップダウンメニューから「InputManager」>「OnAttackLeft (InputAction.CallbackContext)」を選択します。(スクリプトのメソッド名がOn[アクション名]であれば自動で認識されることもあります)
これで、マウスの左ボタンがクリックされる(押される、または離される)たびに、InputManager.csスクリプト内のOnAttackLeftメソッドが呼び出されるようになります。このイベント駆動の仕組みにより、Update関数を使うことなく入力処理を実現できます。
溜め時間の計算ロジック:startedとcanceledの活用
前述のスクリプト (InputManager.cs) 内の OnAttackLeft メソッドで行っている溜め時間の計算ロジックを詳しく見てみましょう。
- 押下開始 (
context.started):- マウスの左ボタンが押された瞬間にこのブロックが実行されます。