6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Unity C# 格闘ゲームのコマンド入力判定

Last updated at Posted at 2021-03-31

DEMO

※1
Build.hoge.unitywebのdataなどが重いので、
Wi-Fi接続またはLAN接続のPCで確認ください。

※2
判定部分とは実質無関係ですが、
OnGUI()を画面表示に使用しており、かつ、
OnGUI()の関連処理で文字列処理を多用しています。
そのため上記処理が起因のGCのスパイクが発生します。

※3
時間精度の引き下げが行なわれる事があるようなので、
処理時間がミリ秒の精度に丸められることがあります。
同処理が施されたブラウザでは処理時間が正確に計測出来ません。

Firefoxであれば、
Firefoxの設定エディターにて、自己責任の上、
privacy.reduceTimerPrecisionをfalseにすれば、
処理時間の丸めなしにはできないようですが、
処理時間の丸めの精度は変更できるようです。

はじめに

Unityの存在を先日知り、
Unity及びC#のお勉強も兼ねて、
波動拳の入力受付をしてみよう、
という思いに何故か至りました。

Unity及びC#を今回初めて触る、
オブジェクト指向恐怖症のIT業界外の人間で、
html,css,JavaScriptやPythonを、
休日等に少々触る程度の素人ですので、
本内容に間違いや勘違いが見受けられるかもしれません。

カプコン社のストリートファイター等の技名を使用していますが、
あのコマンドね、と認識が伝わりやすいだろう、という意図です。

解説前書

冒頭のDEMOから以下処理を削除した波動拳(強)のみの入力判定で、
冒頭のDEMOから以下処理を削除した入力判定の中核部分のコードになります。

・波動拳(強)以外の技の削除
・溜め時間取得用処理の削除
・同時押し判定緩和用処理の削除
・本解説に不要なinput処理の削除
・本解説に不要な処理時間低減施策削除
・Inspectorへのデバッグ表示用処理削除
・GameViewへのデバッグ表示関連処理削除

※Consoleに入力判定の成否を出力

一口解説

詳細はコードを見て貰うものとして、
全体のざっくりした流れは以下です。

・各種enum設定
・技のコマンドのクラスとそのList …①
・十字キーとパンチキックの状態取得用のクラス
・キー履歴保持のクラスとそのList
・void Start()
 ・技のコマンドのListの反転 …②
 ・キー履歴保持のためのインスタンス生成
 ・フレームレートの設定
・void Update()
 ・今フレームのキーの状態をキー履歴保持のListに追記
 (ある程度の量になったら古い履歴情報から順次削除)
  ・foreach
   ・foreach
    ・技のコマンドのひとつひとつを順次判定処理 …③
    (波動拳は下⇒右下⇒右⇒Pなので4回判定)
    (foreach1回目はP  の判定)
    (foreach2回目は右 の判定)
    (foreach3回目は右下の判定)
    (foreach4回目は下 の判定)

①技のコマンドのList

    private List<List<MoveCommand>> MoveCommandList = new List<List<MoveCommand>>()
    {
        new List<MoveCommand>()
        {
            // 波動拳                    状態は押している         キーは左   次の入力は 6フレーム以内 次の入力同時押し不可NextFrame判定
            new MoveCommand { DoFinger = Finger.Hold,    InputKey = Key.J2, NextTime =  6,            SlipTime = 1 },
            // 波動拳                    状態は押している         キーは左下 次の入力は 6フレーム以内 次の入力同時押し不可NextFrame判定
            new MoveCommand { DoFinger = Finger.Hold,    InputKey = Key.J3, NextTime =  6,            SlipTime = 1 },
            // 波動拳                    状態は押している         キーは右   次の入力は 7フレーム以内 次の入力同時押し可能ThisFrame判定
            new MoveCommand { DoFinger = Finger.Hold,    InputKey = Key.J6, NextTime =  7,            SlipTime = 0 },
            // 波動拳                    状態は押した             キーはP    最後なので 0に必ずする   最後なので 0に必ずする
            new MoveCommand { DoFinger = Finger.Pressed, InputKey = Key.HP, NextTime =  0,            SlipTime = 0 },
        },
    };

以下の条件をListに設定。

1つ目の入力:
キーの下 を押している、
次の入力は6フレーム以内、
次の入力の判定とは同一フレーム不可。

2つ目の入力:
キーの右下を押している、
次の入力は6フレーム以内、
次の入力の判定とは同一フレーム不可。

3つ目の入力:
キーの右 を押している、
次の入力は7フレーム以内、
次の入力の判定とは同一フレーム可能(右とPの同時押しOK)

4つ目の入力:
キーのP を押した。

②技のコマンドのListの反転

        foreach (List<MoveCommand> MoveCommandData in MoveCommandList) MoveCommandData.Reverse();

波動拳は下⇒右下⇒右⇒Pだが、
処理順はP⇒右⇒右下⇒下の順序で判定を行なうため反転。

③技のコマンドのひとつひとつを順次判定処理

        foreach (List<MoveCommand> MoveCommandData in MoveCommandList)
        {
            // 中略
            foreach (MoveCommand record in MoveCommandData)
            {
                // 中略
                InputGetKeyTinyHistoryDataRow = record.DoFinger switch
                {
                    Finger.Hold    => InputGetKeyTinyHistoryList.FindLast(row => ((StaticFrameCount - StaticNextTime) <= row.FrameCount) && (row.FrameCount <= (StaticFrameCount - StaticSlipTime)) && ((row.Hold    & StaticInputKey) == StaticInputKey)),
                    Finger.Pressed => InputGetKeyTinyHistoryList.FindLast(row => ((StaticFrameCount - StaticNextTime) <= row.FrameCount) && (row.FrameCount <= (StaticFrameCount - StaticSlipTime)) && ((row.Pressed & StaticInputKey) == StaticInputKey)),
                    _ => null
                };
                // 中略
            }
            // 中略
        }

キー履歴保持のList内に条件に合うキーが存在するかを判定。
以下の全ての条件判定が成立していれば波動拳入力受付承認。

波動拳のみなので、
外側のforeachは1回のみ。

内側のforeachの1回目:
現在のフレームに、
Pを"押した"、
という条件に合うキーが存在するか判定。

内側のforeachの2回目:
(P の成立フレーム-7)から
(P の成立フレーム-0)の間で、
右 を"押している"、
という条件に合うキーが存在するか判定。

内側のforeachの3回目:
(右 の成立フレーム-6)から
(右 の成立フレーム-1)の間で、
右下を"押している"、
という条件に合うキーが存在するか判定。

内側のforeachの4回目:
(右下の成立フレーム-6)から
(右下の成立フレーム-1)の間で、
下 を"押している"、
という条件に合うキーが存在するか判定。

備考情報

Debug.Logに関する備忘録。
Debug.Logは結構重いようで、
環境によって違うかもしれませんが、
1回で0.1msとか持っていかれるので、
処理時間計測時は使用しない方がよいです。

WebGLのBuildに関する備忘録。
WebGLのBuildすると日本語が表示されません。
等幅フォントを使用したいので、
NotoSansMonoCJKjp-Bold.otfを、
Assets/Resourcesに配置して表示しています。

動作方法

Unityを触られている人なら不要とは思いますが、念の為。

Unity Hub での工程

Unity Hub でプロジェクトを新規作成。2D(または3D)で作成。
※1 Unityのバージョンは[Unity 2020.3.33f1]や[Unity 2021.3.0f1]以降であれば大丈夫かと...
※2 プロジェクト名と保存先はお任せします。
 ↓
{ Unity 起動 }
 ↓

Unityでの工程

GameObject⇒Create Empty
InspectorウインドウでAdd Component⇒New script⇒Nameをscriptにして⇒Create and Add
ProjectウインドウのAssetsに追加されたscriptをダブルクリック。
 ↓
{ Visual Studio Community 起動 }
 ↓

Visual Studio Community での工程

冒頭のリンク先のコード、または、
中段のリンク先のコード、どちらかをコピペ。
エンコードをUnicode(UTF-8シグネチャ付き)の形式に変更してscript.csを上書き保存。
Visual Studio Community を終了。
 ↓
{ Unity をアクティブウインドウにする }
 ↓

Unityでの工程

File⇒Save
File⇒Exit
 ↓
{ Unity Hub をアクティブウインドウにする }
 ↓

Unity Hub での工程

上記で作成したプロジェクトをクリックしてUnityを再度起動。
 ↓
{ Unity 起動 }
 ↓

Unityでの工程

( HierarchyウインドウのGameObjectをクリック )
( Consoleウインドウをクリックした後 )
Edit⇒Play

再度起動理由

Unityを再起動しないと、
当方の環境での話なのかもしれませんが、
Input Manager で同時押しのキー取得できない、とか、
Input Manager の動作が何故かもっさりしたり、とか、
Input Manager が正常に動作をしてくれません。

References

Unity 初心者入門講座

Unity

Unity Profiler

Unity Font

Noto CJK fonts

C#

Local Web Server

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?