Skip to content

Instantly share code, notes, and snippets.

@feo52
Created May 30, 2021 04:00
Show Gist options
  • Save feo52/5d45238d0c02136c6343e7e64f39ff07 to your computer and use it in GitHub Desktop.
Save feo52/5d45238d0c02136c6343e7e64f39ff07 to your computer and use it in GitHub Desktop.
Hadoken Code HP
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;
public class script : MonoBehaviour
{
/// <summary>指の状態</summary>
private enum Finger
{
Zero = 0,
/// <summary>押している</summary>
Hold,
/// <summary>押した</summary>
Pressed,
}
/// <summary>キーの指定</summary>
[Flags]
private enum Key
{
Zero = 0,
/// <summary>十字キー左下方向</summary>
J1 = 0x00000001,
/// <summary>十字キー↓方向</summary>
J2 = 0x00000002,
/// <summary>十字キー右下方向</summary>
J3 = 0x00000004,
/// <summary>十字キー←方向</summary>
J4 = 0x00000010,
/// <summary>十字キー真ん中</summary>
J5 = 0x00000020,
/// <summary>十字キー→方向</summary>
J6 = 0x00000040,
/// <summary>十字キー左上方向</summary>
J7 = 0x00000100,
/// <summary>十字キー↑方向</summary>
J8 = 0x00000200,
/// <summary>十字キー右上方向</summary>
J9 = 0x00000400,
/// <summary>弱パンチ(ライトパンチ)</summary>
LP = 0x00010000,
/// <summary>中パンチ(ミドルパンチ)</summary>
MP = 0x00020000,
/// <summary>強パンチ(ハードパンチ)</summary>
HP = 0x00040000,
/// <summary>弱キック(ライトキック)</summary>
LK = 0x00100000,
/// <summary>中キック(ミドルキック)</summary>
MK = 0x00200000,
/// <summary>強キック(ハードキック)</summary>
HK = 0x00400000,
}
/// <summary>技のコマンド保持用</summary>
private class MoveCommand
{
/// <summary>入力コマンドキー(enum Finger)</summary>
public Finger DoFinger;
/// <summary>入力コマンドキー(enum Key)</summary>
public Key InputKey;
/// <summary>次のコマンドキー受付猶予時間(最終コマンドは必ず0にすること)</summary>
public int NextTime;
/// <summary>次のコマンドキー同時押し可否(最終コマンドは必ず0にすること)0はThisFrame判定 1はNextFrame判定</summary>
public int SlipTime;
}
/// <summary>GC Alloc 対策用</summary>
private static Key StaticInputKey;
private static int StaticNextTime;
private static int StaticSlipTime;
private static int StaticFrameCount;
/// <summary>技のコマンドリスト(二次元リスト)</summary>
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 },
},
};
/// <summary>
/// InputGetKeyData追加処理。
/// Update()を毎フレームにてキー情報の更新のために1回呼ぶ。
/// </summary>
///
/// Update()メソッド
/// 毎フレームにてキー情報の更新
///
/// 下記プロパティに各種状態を保持(読み取り専用)
/// 設定される数値は enum Key 参照
/// Hold = Input.GetKey
/// Pressed = Input.GetKeyDown
///
private class InputGetKeyDataForMoveCommand
{
public Key Hold { get; private set; } = Key.Zero;
public Key Pressed { get; private set; } = Key.Zero;
public void Update()
{
//十字キーの状態を取得
float x = Input.GetAxisRaw("Horizontal");
float y = Input.GetAxisRaw("Vertical");
int joyStick = 5;
joyStick += (int)x;
joyStick += (int)y * 3;
//十字キーおよびパンチキックの"押している"状態を変数に設定
Hold = Key.Zero;
if (joyStick == 1) Hold |= Key.J1;
if (joyStick == 2) Hold |= Key.J2;
if (joyStick == 3) Hold |= Key.J3;
if (joyStick == 4) Hold |= Key.J4;
if (joyStick == 5) Hold |= Key.J5;
if (joyStick == 6) Hold |= Key.J6;
if (joyStick == 7) Hold |= Key.J7;
if (joyStick == 8) Hold |= Key.J8;
if (joyStick == 9) Hold |= Key.J9;
if (Input.GetKey(KeyCode.I)) Hold |= Key.LP;
if (Input.GetKey(KeyCode.O)) Hold |= Key.MP;
if (Input.GetKey(KeyCode.P)) Hold |= Key.HP;
if (Input.GetKey(KeyCode.J)) Hold |= Key.LK;
if (Input.GetKey(KeyCode.K)) Hold |= Key.MK;
if (Input.GetKey(KeyCode.L)) Hold |= Key.HK;
//パンチキックの"押した"状態を変数に設定
Pressed = Key.Zero;
if (Input.GetKeyDown(KeyCode.I)) Pressed |= Key.LP;
if (Input.GetKeyDown(KeyCode.O)) Pressed |= Key.MP;
if (Input.GetKeyDown(KeyCode.P)) Pressed |= Key.HP;
if (Input.GetKeyDown(KeyCode.J)) Pressed |= Key.LK;
if (Input.GetKeyDown(KeyCode.K)) Pressed |= Key.MK;
if (Input.GetKeyDown(KeyCode.L)) Pressed |= Key.HK;
}
}
/// <summary>InputGetKeyData追加処理用</summary>
private InputGetKeyDataForMoveCommand InputGetKeyData = new InputGetKeyDataForMoveCommand();
/// <summary>
/// InputGetKeyDataの履歴保持用(極小版)
/// </summary>
/// 以下を保持。
/// 何フレーム目の情報か
/// どのキーを押しているか
/// どのキーを押したか
private class InputGetKeyTinyHistory
{
public int FrameCount;
public Key Hold;
public Key Pressed;
}
/// <summary>InputGetKeyDataの履歴保持最大フレーム数</summary>
private static readonly int InputGetKeyDataHistoryMax = 150;
/// <summary>InputGetKeyDataの履歴保持用(極小版)</summary>
private List<InputGetKeyTinyHistory> InputGetKeyTinyHistoryList = new List<InputGetKeyTinyHistory>(InputGetKeyDataHistoryMax);
private InputGetKeyTinyHistory[] InputGetKeyTinyHistoryData = new InputGetKeyTinyHistory[InputGetKeyDataHistoryMax];
private InputGetKeyTinyHistory InputGetKeyTinyHistoryDataRow = null;
/// <summary>処理時間計測用のストップウォッチ</summary>
private System.Diagnostics.Stopwatch DebugStopwatch1 = new System.Diagnostics.Stopwatch();
private System.Diagnostics.Stopwatch DebugStopwatch2 = new System.Diagnostics.Stopwatch();
private System.Diagnostics.Stopwatch DebugStopwatch3 = new System.Diagnostics.Stopwatch();
void Start()
{
// 技のコマンドリストの順序を反転
// 波動拳は下⇒右下⇒右⇒Pだが、
// 処理順はP⇒右⇒右下⇒下の順序で判定を行なうため反転。
foreach (List<MoveCommand> MoveCommandData in MoveCommandList) MoveCommandData.Reverse();
// InputGetKeyDataの履歴保持用のインスタンス作成
for (int i = 0; i < InputGetKeyDataHistoryMax; ++i)
{
InputGetKeyTinyHistoryData[i] = new InputGetKeyTinyHistory();
}
// フレームレートの設定
Application.targetFrameRate = 60;
}
void Update()
{
// GC Alloc 等確認用プロファイラースタート
Profiler.BeginSample("check_GC_Alloc");
// 処理時間計測用のストップウォッチスタート
DebugStopwatch1.Restart();
DebugStopwatch1.Start();
// InputGetKeyData追加処理更新
InputGetKeyData.Update();
// InputGetKeyDataの履歴保持用に今回のフレームのキー情報を取得
int i = Time.frameCount % InputGetKeyDataHistoryMax;
InputGetKeyTinyHistoryData[i].FrameCount = Time.frameCount;
InputGetKeyTinyHistoryData[i].Hold = InputGetKeyData.Hold;
InputGetKeyTinyHistoryData[i].Pressed = InputGetKeyData.Pressed;
// InputGetKeyDataの履歴保持用Listが最大数以上の場合には先頭から順次削除
while (InputGetKeyTinyHistoryList.Count >= InputGetKeyDataHistoryMax) InputGetKeyTinyHistoryList.RemoveAt(0);
// InputGetKeyDataの履歴保持用Listの末尾に今回のフレームのキー情報を追加
InputGetKeyTinyHistoryList.Add(InputGetKeyTinyHistoryData[i]);
// 技のコマンドリストを順次判定処理
// 本コードは波動拳だけなので1回転のみ
foreach (List<MoveCommand> MoveCommandData in MoveCommandList)
{
bool allow = false;
int index = 0;
StaticFrameCount = Time.frameCount;
// 処理時間計測用のストップウォッチスタート
DebugStopwatch2.Restart();
DebugStopwatch2.Start();
// 技のコマンドのひとつひとつを順次判定処理
// 波動拳は下⇒右下⇒右⇒Pなので4回転
// foreach1回目はP  の判定
// foreach2回目は右 の判定
// foreach3回目は右下の判定
// foreach4回目は下 の判定
foreach (MoveCommand record in MoveCommandData)
{
// GC Alloc 対策
StaticInputKey = record.InputKey;
StaticNextTime = record.NextTime;
StaticSlipTime = record.SlipTime;
// 処理時間計測用のストップウォッチスタート
DebugStopwatch3.Restart();
DebugStopwatch3.Start();
// 技のコマンドのひとつひとつを順次判定処理
// 波動拳は下⇒右下⇒右⇒Pなので4回判定
// foreach1回目はP  の判定
// foreach2回目は右 の判定
// foreach3回目は右下の判定
// foreach4回目は下 の判定
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
};
// 抽出データが存在する場合
if (InputGetKeyTinyHistoryDataRow != null)
{
//次の判定用に判定用のStaticFrameCountを更新。allowを1にする。
StaticFrameCount = InputGetKeyTinyHistoryDataRow.FrameCount;
allow = true;
}
// 抽出データが存在しない場合は波動拳コマンド入力受付否認。
else
{
allow = false;
break;
}
index++;
// 処理時間計測用のストップウォッチストップ
if (DebugStopwatch3.IsRunning) DebugStopwatch3.Stop();
}
// 処理時間計測用のストップウォッチストップ
if (DebugStopwatch2.IsRunning) DebugStopwatch2.Stop();
// コマンド入力受付承認?
if (allow)
{
// Consoleデバック表示
Debug.Log($"{Time.frameCount}fr [判定所要時間]{DebugStopwatch2.ElapsedTicks,6:D}ticks, [受付承認技名]波動拳");
}
else if (index > 0)
{
// Consoleデバック表示
Debug.Log($"{Time.frameCount}fr [判定所要時間]{DebugStopwatch2.ElapsedTicks,6:D}ticks, [受付否認技名]波動拳");
}
}
// 処理時間計測用のストップウォッチストップ
if (DebugStopwatch1.IsRunning) DebugStopwatch1.Stop();
// GC Alloc 等確認用プロファイラーストップ
Profiler.EndSample();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment