307 lines
11 KiB
C#
307 lines
11 KiB
C#
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace BulletHellTemplate
|
|
{
|
|
/// <summary>
|
|
/// Handles skill activation for PC using keyboard and mouse inputs.
|
|
/// Manages skill activation, aiming, cooldowns, and prevents skill spamming by enforcing a delay between skill uses.
|
|
/// </summary>
|
|
public class PCSkillController : MonoBehaviour
|
|
{
|
|
[Tooltip("Mappings for each skill's keyboard and mouse buttons")]
|
|
public List<SkillKeyMapping> skillKeyMappings;
|
|
|
|
[Tooltip("Delay before allowing the next skill to be used to prevent spamming.")]
|
|
public float delayToNextSkill = 0.3f;
|
|
|
|
private bool[] isSkillActive; // Tracks whether a skill is being held
|
|
private bool[] isOnCooldown; // Tracks whether a skill is on cooldown
|
|
private float[] cooldownTime; // Initial cooldown times per skill
|
|
private float[] currentCooldown; // Current cooldowns per skill
|
|
private CharacterEntity characterEntity; // Reference to the character entity
|
|
|
|
private bool canUseSkill = true; // Flag to determine if a new skill can be used
|
|
|
|
private void Awake()
|
|
{
|
|
int skillCount = skillKeyMappings.Count;
|
|
isSkillActive = new bool[skillCount];
|
|
isOnCooldown = new bool[skillCount];
|
|
cooldownTime = new float[skillCount];
|
|
currentCooldown = new float[skillCount];
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
characterEntity = UIGameplay.Singleton.GetCharacterEntity();
|
|
if (characterEntity == null)
|
|
{
|
|
Debug.LogError("CharacterEntity is not assigned or missing.");
|
|
}
|
|
|
|
for (int i = 0; i < skillKeyMappings.Count; i++)
|
|
{
|
|
int skillIndex = skillKeyMappings[i].skillIndex;
|
|
cooldownTime[i] = characterEntity.GetSkillCooldown(skillIndex);
|
|
currentCooldown[i] = 0f;
|
|
isOnCooldown[i] = false;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (characterEntity == null) return;
|
|
|
|
for (int i = 0; i < skillKeyMappings.Count; i++)
|
|
{
|
|
UpdateSkillCooldown(i);
|
|
CheckInputForSkill(i);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up the character entity and initializes skill cooldown data.
|
|
/// </summary>
|
|
/// <param name="entity">The character entity to associate with this controller.</param>
|
|
public void Setup(CharacterEntity entity)
|
|
{
|
|
characterEntity = entity;
|
|
|
|
for (int i = 0; i < skillKeyMappings.Count; i++)
|
|
{
|
|
int skillIndex = skillKeyMappings[i].skillIndex;
|
|
cooldownTime[i] = characterEntity.GetSkillCooldown(skillIndex);
|
|
currentCooldown[i] = 0f;
|
|
isOnCooldown[i] = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the current cooldown for a specified skill.
|
|
/// </summary>
|
|
/// <param name="skillIndex">The skill index to query.</param>
|
|
/// <returns>The current cooldown time remaining for the skill.</returns>
|
|
public float GetCurrentCooldown(int skillIndex)
|
|
{
|
|
int mappingIndex = skillKeyMappings.FindIndex(mapping => mapping.skillIndex == skillIndex);
|
|
if (mappingIndex >= 0)
|
|
{
|
|
return currentCooldown[mappingIndex];
|
|
}
|
|
else
|
|
{
|
|
return 0f;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the initial cooldown time for a specified skill.
|
|
/// </summary>
|
|
/// <param name="skillIndex">The skill index to query.</param>
|
|
/// <returns>The initial cooldown time of the skill.</returns>
|
|
public float GetCooldownTime(int skillIndex)
|
|
{
|
|
int mappingIndex = skillKeyMappings.FindIndex(mapping => mapping.skillIndex == skillIndex);
|
|
if (mappingIndex >= 0)
|
|
{
|
|
return cooldownTime[mappingIndex];
|
|
}
|
|
else
|
|
{
|
|
return 0f;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks input for skill activation, holding, and release events.
|
|
/// </summary>
|
|
private void CheckInputForSkill(int index)
|
|
{
|
|
if (GameplayManager.Singleton != null && GameplayManager.Singleton.IsPaused())
|
|
return;
|
|
|
|
SkillKeyMapping skillMapping = skillKeyMappings[index];
|
|
|
|
foreach (Key key in skillMapping.keyboardKeys)
|
|
{
|
|
if (key == Key.None) continue;
|
|
|
|
if (Keyboard.current[key].wasPressedThisFrame)
|
|
ActivateSkill(index);
|
|
else if (Keyboard.current[key].isPressed)
|
|
UpdateSkillAim(index);
|
|
else if (Keyboard.current[key].wasReleasedThisFrame)
|
|
ReleaseSkill(index);
|
|
}
|
|
|
|
foreach (MouseButton mouseButton in skillMapping.mouseButtons)
|
|
{
|
|
if (IsMouseButtonPressed(mouseButton))
|
|
ActivateSkill(index);
|
|
else if (IsMouseButtonHeld(mouseButton))
|
|
UpdateSkillAim(index);
|
|
else if (IsMouseButtonReleased(mouseButton))
|
|
ReleaseSkill(index);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Activates the skill if not on cooldown, if a skill can be used, and enables directional aiming.
|
|
/// </summary>
|
|
private void ActivateSkill(int index)
|
|
{
|
|
if (!isSkillActive[index] && !isOnCooldown[index] && canUseSkill)
|
|
{
|
|
int skillIndex = skillKeyMappings[index].skillIndex;
|
|
if (characterEntity.GetSkillData(skillIndex).manaCost > characterEntity.GetCurrentMP())
|
|
{
|
|
characterEntity.DisplayMPInsufficientMessage("Not enough MP to use skill");
|
|
UIGameplay.Singleton.DisplayMPInsufficientMessage("Not enough MP to use skill");
|
|
return;
|
|
}
|
|
|
|
isSkillActive[index] = true;
|
|
characterEntity.SetDirectionalAimActive(true, index,true); // Enable directional aiming
|
|
canUseSkill = false; // Prevent other skills from being activated immediately
|
|
StartCoroutine(SkillDelay()); // Start the delay coroutine
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Coroutine to handle the delay before allowing the next skill to be used.
|
|
/// </summary>
|
|
private IEnumerator SkillDelay()
|
|
{
|
|
yield return new WaitForSeconds(delayToNextSkill);
|
|
canUseSkill = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the aiming direction while a skill is being held.
|
|
/// </summary>
|
|
private void UpdateSkillAim(int index)
|
|
{
|
|
if (isSkillActive[index])
|
|
{
|
|
Vector2 direction = GetMouseDirection();
|
|
characterEntity.UpdateDirectionalAim(direction, index);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Releases the skill, triggers its use, starts cooldown, and disables directional aiming.
|
|
/// </summary>
|
|
private void ReleaseSkill(int index)
|
|
{
|
|
if (isSkillActive[index])
|
|
{
|
|
Vector2 direction = GetMouseDirection();
|
|
int skillMappingIndex = skillKeyMappings[index].skillIndex;
|
|
|
|
characterEntity.UseSkill(skillMappingIndex, direction);
|
|
StartCooldown(index);
|
|
|
|
isSkillActive[index] = false;
|
|
characterEntity.SetDirectionalAimActive(false, index, true); // Disable directional aiming
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the cooldown for a specific skill, adjusting for any cooldown reduction.
|
|
/// </summary>
|
|
private void StartCooldown(int index)
|
|
{
|
|
isOnCooldown[index] = true;
|
|
float cooldownReduction = characterEntity.GetCurrentCooldownReduction() / 100f;
|
|
currentCooldown[index] = cooldownTime[index] * (1 - cooldownReduction);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the cooldown timer for a specific skill.
|
|
/// </summary>
|
|
private void UpdateSkillCooldown(int index)
|
|
{
|
|
if (GameplayManager.Singleton != null && GameplayManager.Singleton.IsPaused())
|
|
return;
|
|
|
|
if (isOnCooldown[index])
|
|
{
|
|
currentCooldown[index] -= Time.deltaTime;
|
|
|
|
if (currentCooldown[index] <= 0f)
|
|
{
|
|
currentCooldown[index] = 0f;
|
|
isOnCooldown[index] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the aiming direction based on the mouse position.
|
|
/// </summary>
|
|
private Vector2 GetMouseDirection()
|
|
{
|
|
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
|
|
Plane plane = new Plane(Vector3.up, characterEntity.transform.position);
|
|
if (plane.Raycast(ray, out float distance))
|
|
{
|
|
Vector3 point = ray.GetPoint(distance);
|
|
Vector3 direction = point - characterEntity.transform.position;
|
|
return new Vector2(direction.x, direction.z).normalized;
|
|
}
|
|
return Vector2.zero;
|
|
}
|
|
|
|
private bool IsMouseButtonPressed(MouseButton mouseButton)
|
|
{
|
|
return mouseButton switch
|
|
{
|
|
MouseButton.Left => Mouse.current.leftButton.wasPressedThisFrame,
|
|
MouseButton.Right => Mouse.current.rightButton.wasPressedThisFrame,
|
|
MouseButton.Middle => Mouse.current.middleButton.wasPressedThisFrame,
|
|
_ => false,
|
|
};
|
|
}
|
|
|
|
private bool IsMouseButtonHeld(MouseButton mouseButton)
|
|
{
|
|
return mouseButton switch
|
|
{
|
|
MouseButton.Left => Mouse.current.leftButton.isPressed,
|
|
MouseButton.Right => Mouse.current.rightButton.isPressed,
|
|
MouseButton.Middle => Mouse.current.middleButton.isPressed,
|
|
_ => false,
|
|
};
|
|
}
|
|
|
|
private bool IsMouseButtonReleased(MouseButton mouseButton)
|
|
{
|
|
return mouseButton switch
|
|
{
|
|
MouseButton.Left => Mouse.current.leftButton.wasReleasedThisFrame,
|
|
MouseButton.Right => Mouse.current.rightButton.wasReleasedThisFrame,
|
|
MouseButton.Middle => Mouse.current.middleButton.wasReleasedThisFrame,
|
|
_ => false,
|
|
};
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class SkillKeyMapping
|
|
{
|
|
public int skillIndex;
|
|
public List<Key> keyboardKeys = new List<Key> { Key.None };
|
|
public List<MouseButton> mouseButtons = new List<MouseButton>();
|
|
}
|
|
|
|
public enum MouseButton
|
|
{
|
|
Left,
|
|
Right,
|
|
Middle
|
|
}
|
|
}
|