Fighting Game Input Buffer Implementation in Unity
unknown
csharp
a year ago
7.4 kB
18
Indexable
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class FightingGameInputBuffer : MonoBehaviour
{
// Defines a special move with a name and its required input sequence.
[System.Serializable]
public class SpecialMove
{
public string moveName; // Name of the special move.
public List<string> inputSequence; // Input sequence to execute the move.
}
// UI components for displaying special move and input buffer.
public Text specialMoveText;
public Transform bufferDisplayParent;
public GameObject buttonImagePrefab;
// Duration for displaying a special move message.
public float specialMoveDisplayDuration = 2f;
private float specialMoveTimer = 0f;
// Sprites representing various input directions and actions.
public Sprite upSprite, downSprite, leftSprite, rightSprite;
public Sprite lightSprite, mediumSprite, heavySprite, specialSprite;
public Sprite upLeftSprite, upRightSprite, downLeftSprite, downRightSprite;
// Input buffer and configuration.
private List<string> buffer = new List<string>();
private float bufferStoreTime = 0.4f; // Maximum time an input remains in the buffer.
private int maxBufferSize = 10; // Maximum size of the input buffer.
private List<float> inputTimestamps = new List<float>(); // Timestamps for inputs.
// List of all defined special moves.
public List<SpecialMove> specialMoves = new List<SpecialMove>();
// Mappings of input strings to their corresponding sprites.
private Dictionary<string, Sprite> buttonSprites;
// Tracks the state of each input key.
private Dictionary<string, bool> keyStates = new Dictionary<string, bool>
{
{ "up", false }, { "down", false }, { "left", false }, { "right", false },
{ "upleft", false }, { "upright", false }, { "downleft", false }, { "downright", false },
{ "light", false }, { "medium", false }, { "heavy", false }, { "special", false }
};
// Initialize button sprite mappings.
void Start()
{
buttonSprites = new Dictionary<string, Sprite>
{
{ "up", upSprite }, { "down", downSprite }, { "left", leftSprite }, { "right", rightSprite },
{ "upleft", upLeftSprite }, { "upright", upRightSprite }, { "downleft", downLeftSprite }, { "downright", downRightSprite },
{ "light", lightSprite }, { "medium", mediumSprite }, { "heavy", heavySprite }, { "special", specialSprite }
};
}
// Main update loop to handle inputs, buffer management, and special move detection.
void Update()
{
// Handle individual directional and action inputs.
HandleInput("up", "Vertical", 1);
HandleInput("down", "Vertical", -1);
HandleInput("left", "Horizontal", -1);
HandleInput("right", "Horizontal", 1);
HandleInput("light", "LightAttack", 1);
HandleInput("medium", "MediumAttack", 1);
HandleInput("heavy", "HeavyAttack", 1);
HandleInput("special", "SpecialAttack", 1);
// Handle combined diagonal inputs.
HandleDiagonalInput("upleft", 1, -1);
HandleDiagonalInput("upright", 1, 1);
HandleDiagonalInput("downleft", -1, -1);
HandleDiagonalInput("downright", -1, 1);
// Remove expired inputs from the buffer.
CleanExpiredInputs();
// Check if any special moves are executed.
CheckSpecialMoves();
// Update the special move display timer.
if (specialMoveTimer > 0)
{
specialMoveTimer -= Time.deltaTime;
if (specialMoveTimer <= 0)
{
specialMoveText.text = ""; // Clear the display when timer expires.
}
}
}
// Tracks input states and adds valid inputs to the buffer.
void HandleInput(string button, string axisName, float expectedValue)
{
bool isButtonPressed = Input.GetAxisRaw(axisName) == expectedValue;
if (isButtonPressed && !keyStates[button])
{
keyStates[button] = true; // Mark input as pressed.
AddToBuffer(button); // Add to buffer.
}
else if (!isButtonPressed)
{
keyStates[button] = false; // Reset input state.
}
}
// Handles diagonal input detection by combining vertical and horizontal axes.
void HandleDiagonalInput(string button, float verticalExpectedValue, float horizontalExpectedValue)
{
bool isButtonPressed = Input.GetAxisRaw("Vertical") == verticalExpectedValue &&
Input.GetAxisRaw("Horizontal") == horizontalExpectedValue;
if (isButtonPressed && !keyStates[button])
{
keyStates[button] = true;
AddToBuffer(button); // Add diagonal input to buffer.
}
else if (!isButtonPressed)
{
keyStates[button] = false;
}
}
// Adds an input to the buffer and maintains buffer size.
void AddToBuffer(string input)
{
buffer.Add(input);
inputTimestamps.Add(Time.time); // Store timestamp.
// Remove the oldest input if buffer exceeds maximum size.
if (buffer.Count > maxBufferSize)
{
buffer.RemoveAt(0);
inputTimestamps.RemoveAt(0);
}
UpdateBufferDisplay(); // Update UI to reflect buffer.
}
// Removes inputs from the buffer that have expired.
void CleanExpiredInputs()
{
float currentTime = Time.time;
for (int i = buffer.Count - 1; i >= 0; i--)
{
if (currentTime - inputTimestamps[i] >= bufferStoreTime)
{
buffer.RemoveAt(i); // Remove expired input.
inputTimestamps.RemoveAt(i);
}
}
}
// Checks the buffer for valid special move sequences.
void CheckSpecialMoves()
{
foreach (var move in specialMoves)
{
// Compare the buffer's recent inputs with the special move's sequence.
if (buffer.Count >= move.inputSequence.Count &&
buffer.Skip(buffer.Count - move.inputSequence.Count).SequenceEqual(move.inputSequence))
{
// Display special move and clear the buffer.
specialMoveText.text = move.moveName + " Executed!";
specialMoveTimer = specialMoveDisplayDuration;
buffer.Clear();
inputTimestamps.Clear();
break;
}
}
}
// Updates the UI to display the current input buffer.
void UpdateBufferDisplay()
{
// Clear existing buffer display.
foreach (Transform child in bufferDisplayParent)
{
Destroy(child.gameObject);
}
// Instantiate UI elements for each input in the buffer.
foreach (var button in buffer)
{
if (buttonSprites.ContainsKey(button))
{
GameObject icon = Instantiate(buttonImagePrefab, bufferDisplayParent);
icon.GetComponent<Image>().sprite = buttonSprites[button];
}
}
}
}
Editor is loading...
Leave a Comment