Added comments to everything
This commit is contained in:
@@ -1,38 +1,117 @@
|
||||
using UnityEngine; using Game; using Music; using Player;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class AnimationPlayer : MonoBehaviour
|
||||
{
|
||||
public enum AnimationState { Idle, Run, Jump, Walk };
|
||||
public AnimationState state;
|
||||
public bool backwards;
|
||||
public bool block = false;
|
||||
public AnimationClip clip;
|
||||
private Animator animator;
|
||||
|
||||
private void Start() // Plays the specified animation clip
|
||||
/// <summary>
|
||||
/// This class manages the player's animations, including setting animation states,
|
||||
/// handling directional changes, and triggering specific animations like punching.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class AnimationPlayer : MonoBehaviour
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
animator.Play(clip.name);
|
||||
}
|
||||
/// <summary>
|
||||
/// Represents the different animation states the player can be in.
|
||||
/// </summary>
|
||||
public enum AnimationState
|
||||
{
|
||||
/// <summary>
|
||||
/// The idle state, when the player is not moving.
|
||||
/// </summary>
|
||||
Idle,
|
||||
|
||||
private void LateUpdate() // Updates the animation state
|
||||
{
|
||||
animator.SetInteger("state", (int)state);
|
||||
transform.localScale = new Vector3(Mathf.Sign(backwards ? -1 : 1) * Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);
|
||||
animator.SetBool("block", block);
|
||||
}
|
||||
/// <summary>
|
||||
/// The running state, when the player is moving quickly.
|
||||
/// </summary>
|
||||
Run,
|
||||
|
||||
public void SetState(AnimationState state) // Sets the animation state
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
/// <summary>
|
||||
/// The jumping state, when the player is in the air.
|
||||
/// </summary>
|
||||
Jump,
|
||||
|
||||
public void Punch() // Triggers punch animation
|
||||
{
|
||||
animator.SetTrigger("punch");
|
||||
/// <summary>
|
||||
/// The walking state, when the player is moving slowly.
|
||||
/// </summary>
|
||||
Walk
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current animation state of the player.
|
||||
/// </summary>
|
||||
public AnimationState state;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the player is facing backwards.
|
||||
/// </summary>
|
||||
public bool backwards;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the player is currently blocking.
|
||||
/// </summary>
|
||||
public bool block = false;
|
||||
|
||||
/// <summary>
|
||||
/// The animation clip to play when the script starts.
|
||||
/// </summary>
|
||||
public AnimationClip clip;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the Animator component that controls the player's animations.
|
||||
/// </summary>
|
||||
private Animator animator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Animator component and plays the specified animation clip.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
|
||||
// Play the initial animation clip
|
||||
if (clip != null)
|
||||
{
|
||||
animator.Play(clip.name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the player's animation state and direction every frame.
|
||||
/// </summary>
|
||||
private void LateUpdate()
|
||||
{
|
||||
// Set the animation state in the Animator
|
||||
animator.SetInteger("state", (int)state);
|
||||
|
||||
// Adjust the player's scale to reflect their facing direction
|
||||
transform.localScale = new Vector3(
|
||||
Mathf.Sign(backwards ? -1 : 1) * Mathf.Abs(transform.localScale.x),
|
||||
transform.localScale.y,
|
||||
transform.localScale.z
|
||||
);
|
||||
|
||||
// Update the blocking state in the Animator
|
||||
animator.SetBool("block", block);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the player's animation state.
|
||||
/// </summary>
|
||||
/// <param name="state">The new animation state to set.</param>
|
||||
public void SetState(AnimationState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the punch animation.
|
||||
/// </summary>
|
||||
public void Punch()
|
||||
{
|
||||
animator.SetTrigger("punch");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,60 +1,109 @@
|
||||
using UnityEngine; using Game; using Music; using Player;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
public class Block : MonoBehaviour
|
||||
{
|
||||
public bool blocking = false;
|
||||
private InputActionAsset actions;
|
||||
private float blockPressTime = 0f;
|
||||
[SerializeField] private float parryThreshold = 0.2f; // Time for successful parry
|
||||
private bool isParrying = false;
|
||||
|
||||
private void Start()
|
||||
/// <summary>
|
||||
/// This class handles the player's ability to block and parry incoming attacks.
|
||||
/// Blocking reduces damage, while parrying reflects attacks if timed correctly.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
public class Block : MonoBehaviour
|
||||
{
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
/// <summary>
|
||||
/// Indicates whether the player is currently blocking.
|
||||
/// </summary>
|
||||
public bool blocking = false;
|
||||
|
||||
private void Update() // Player blocks when "block" is pressed
|
||||
{
|
||||
InputAction blockAction = actions.FindAction("Block");
|
||||
if (blockAction.ReadValue<float>() == 1f)
|
||||
/// <summary>
|
||||
/// The input actions associated with the player.
|
||||
/// </summary>
|
||||
private InputActionAsset actions;
|
||||
|
||||
/// <summary>
|
||||
/// The time when the block button was pressed.
|
||||
/// </summary>
|
||||
private float blockPressTime = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum time (in seconds) for a successful parry after pressing the block button.
|
||||
/// </summary>
|
||||
[SerializeField] private float parryThreshold = 0.2f;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the player is currently parrying.
|
||||
/// </summary>
|
||||
private bool isParrying = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the player's input actions.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
if (!blocking)
|
||||
{
|
||||
blockPressTime = Time.time; // Start parry timer
|
||||
}
|
||||
blocking = true;
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
else
|
||||
|
||||
/// <summary>
|
||||
/// Updates the player's blocking and parrying state every frame based on input.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (blocking) // Successful parry if blocked in time
|
||||
// Get the block action from the input system
|
||||
InputAction blockAction = actions.FindAction("Block");
|
||||
|
||||
// Check if the block button is being pressed
|
||||
if (blockAction.ReadValue<float>() == 1f)
|
||||
{
|
||||
float pressDuration = Time.time - blockPressTime;
|
||||
if (pressDuration <= parryThreshold)
|
||||
if (!blocking)
|
||||
{
|
||||
Parry();
|
||||
}
|
||||
else
|
||||
{
|
||||
isParrying = false;
|
||||
// Start the parry timer when the block button is first pressed
|
||||
blockPressTime = Time.time;
|
||||
}
|
||||
blocking = true;
|
||||
}
|
||||
blocking = false;
|
||||
else
|
||||
{
|
||||
// Handle the release of the block button
|
||||
if (blocking)
|
||||
{
|
||||
// Calculate how long the block button was held
|
||||
float pressDuration = Time.time - blockPressTime;
|
||||
|
||||
// If the button was released within the parry threshold, trigger a parry
|
||||
if (pressDuration <= parryThreshold)
|
||||
{
|
||||
Parry();
|
||||
}
|
||||
else
|
||||
{
|
||||
isParrying = false;
|
||||
}
|
||||
}
|
||||
blocking = false;
|
||||
}
|
||||
|
||||
// Update the blocking state in the animation system
|
||||
GetComponent<AnimationPlayer>().block = blocking;
|
||||
}
|
||||
GetComponent<AnimationPlayer>().block = blocking;
|
||||
}
|
||||
|
||||
private void Parry()
|
||||
{
|
||||
isParrying = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Activates the parry state, allowing the player to reflect attacks.
|
||||
/// </summary>
|
||||
private void Parry()
|
||||
{
|
||||
isParrying = true;
|
||||
}
|
||||
|
||||
public bool IsParrying()
|
||||
{
|
||||
return isParrying;
|
||||
/// <summary>
|
||||
/// Checks if the player is currently parrying.
|
||||
/// </summary>
|
||||
/// <returns>True if the player is parrying, false otherwise.</returns>
|
||||
public bool IsParrying()
|
||||
{
|
||||
return isParrying;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,22 @@ using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class handles the player's ability to take damage, die, and respawn.
|
||||
/// It also manages interactions like blocking, parrying, and dropping items when hit.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
[RequireComponent(typeof(RespawnOnTriggerEnter))]
|
||||
public class Damageable : MonoBehaviour
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The force applied to the player when hit.
|
||||
/// </summary>
|
||||
public float force = 50f; // Force applied when hit
|
||||
public float force = 50f;
|
||||
|
||||
/// <summary>
|
||||
/// The current accumulated damage of the player.
|
||||
@@ -26,15 +29,13 @@ namespace Player
|
||||
/// <summary>
|
||||
/// The maximum damage the player can take before dying.
|
||||
/// </summary>
|
||||
public float maxDamage = 1000f; // Set max health
|
||||
public float maxDamage = 1000f;
|
||||
|
||||
/// <summary>
|
||||
/// The number of lives the player has.
|
||||
/// </summary>
|
||||
public int lives = 0;
|
||||
|
||||
private Animator animator;
|
||||
|
||||
/// <summary>
|
||||
/// If true, applies damage to self for debugging purposes.
|
||||
/// </summary>
|
||||
@@ -61,7 +62,12 @@ namespace Player
|
||||
public event System.Action<GameObject> OnPlayerRespawn;
|
||||
|
||||
/// <summary>
|
||||
/// Unity Start method. Initializes the animator reference.
|
||||
/// Reference to the player's animator component.
|
||||
/// </summary>
|
||||
private Animator animator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the animator reference.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
@@ -69,7 +75,7 @@ namespace Player
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unity Update method. Handles debug self-damage if enabled.
|
||||
/// Handles debug self-damage if enabled.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
@@ -81,7 +87,7 @@ namespace Player
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unity OnTriggerEnter2D method. Applies damage when colliding with a punch hurtbox.
|
||||
/// Applies damage when colliding with a punch hurtbox.
|
||||
/// </summary>
|
||||
/// <param name="collision">The collider that entered the trigger.</param>
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
@@ -99,33 +105,40 @@ namespace Player
|
||||
/// <param name="damageSource">The GameObject causing the damage.</param>
|
||||
private void Damage(GameObject damageSource)
|
||||
{
|
||||
if (dying || damageSource.CompareTag("Hat")) return; // Exclude hat from taking damage
|
||||
// Prevent damage if the player is dying or the damage source is a hat
|
||||
if (dying || damageSource.CompareTag("Hat")) return;
|
||||
|
||||
float actualForce = damageSource.GetComponent<Damageable>().force;
|
||||
Block blockComponent = GetComponent<Block>();
|
||||
|
||||
GetComponentInChildren<UseItem>().DropItem(); // Drops hat if held
|
||||
// Drop the item if the player is holding one
|
||||
GetComponentInChildren<UseItem>().DropItem();
|
||||
|
||||
if (blockComponent != null && blockComponent.blocking)
|
||||
{
|
||||
if (blockComponent.IsParrying()) // Player receives damage if punching a parrying player
|
||||
if (blockComponent.IsParrying())
|
||||
{
|
||||
// Handle parry logic
|
||||
damageSource.GetComponent<Damageable>().SuccessfulParry(gameObject, actualForce);
|
||||
AudioManager.Instance.PlaySound("Parry");
|
||||
return;
|
||||
}
|
||||
else // Player does less damage if punching a blocking player
|
||||
else
|
||||
{
|
||||
// Reduce damage if the player is blocking
|
||||
AudioManager.Instance.PlaySound("Punch");
|
||||
actualForce /= 4;
|
||||
GetComponent<Rigidbody2D>().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce, ForceMode2D.Force);
|
||||
}
|
||||
}
|
||||
else // Player does full damage to a non-blocking player
|
||||
else
|
||||
{
|
||||
// Apply full damage if the player is not blocking
|
||||
AudioManager.Instance.PlaySound("Punch");
|
||||
GetComponent<Rigidbody2D>().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce * (1 + (damage / maxDamage) * 3), ForceMode2D.Force);
|
||||
}
|
||||
|
||||
// Update the player's damage and check if they should die
|
||||
damage += actualForce;
|
||||
damage = Mathf.Clamp(damage, 0f, maxDamage);
|
||||
if (damage >= maxDamage)
|
||||
@@ -140,10 +153,8 @@ namespace Player
|
||||
/// <param name="damage">The amount of damage to add.</param>
|
||||
public void Damage(float damage)
|
||||
{
|
||||
//if (GameManager.Instance.gameOver) return; // Prevent damage after game is over
|
||||
|
||||
this.damage += damage;
|
||||
if (damage >= maxDamage)
|
||||
if (this.damage >= maxDamage)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
@@ -171,13 +182,16 @@ namespace Player
|
||||
/// </summary>
|
||||
private void Die()
|
||||
{
|
||||
if (GameManager.Instance != null) //&& !GameManager.Instance.gameOver) // Prevent death after game is over
|
||||
if (GameManager.Instance != null)
|
||||
{
|
||||
// Drop the item if the player is holding one
|
||||
UseItem useItem = GetComponent<UseItem>();
|
||||
if (useItem != null)
|
||||
{
|
||||
useItem.DropItem(); // Ensure the player drops the item before the death animation
|
||||
useItem.DropItem();
|
||||
}
|
||||
|
||||
// Trigger the death animation and mark the player as dying
|
||||
animator.SetBool("die", true);
|
||||
dying = true;
|
||||
|
||||
@@ -203,15 +217,17 @@ namespace Player
|
||||
public void Respawn()
|
||||
{
|
||||
transform.position = GameManager.Instance.spawnPosition;
|
||||
|
||||
// Reset the player's velocity
|
||||
if (TryGetComponent<Rigidbody2D>(out var rb))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
rb.angularVelocity = 0f;
|
||||
}
|
||||
if (TryGetComponent<Damageable>(out var damageable))
|
||||
{
|
||||
damageable.ResetDamage();
|
||||
}
|
||||
|
||||
// Reset the player's damage
|
||||
ResetDamage();
|
||||
|
||||
OnPlayerRespawn?.Invoke(gameObject);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,89 +1,161 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine; using Game; using Music; using Player;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
public class PlayerCameraMovement : MonoBehaviour
|
||||
{
|
||||
private Vector3 start;
|
||||
private Vector3 target;
|
||||
public float weight;
|
||||
public float speed;
|
||||
private GameObject playerThatWon;
|
||||
public float lowerBound;
|
||||
public bool winScene = false;
|
||||
|
||||
public bool staticCamera = false;
|
||||
|
||||
private void Start()
|
||||
/// <summary>
|
||||
/// This class controls the movement of the camera to follow players during the game.
|
||||
/// It also handles special behavior for the camera in the win scene.
|
||||
/// </summary>
|
||||
public class PlayerCameraMovement : MonoBehaviour
|
||||
{
|
||||
start = transform.position;
|
||||
}
|
||||
/// <summary>
|
||||
/// The starting position of the camera.
|
||||
/// </summary>
|
||||
private Vector3 start;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (winScene) // If the game is over, the camera will follow the player that won
|
||||
/// <summary>
|
||||
/// The target position the camera should move toward.
|
||||
/// </summary>
|
||||
private Vector3 target;
|
||||
|
||||
/// <summary>
|
||||
/// The weight used to blend between the camera's starting position and the players' average position.
|
||||
/// </summary>
|
||||
public float weight;
|
||||
|
||||
/// <summary>
|
||||
/// The speed at which the camera moves toward the target position.
|
||||
/// </summary>
|
||||
public float speed;
|
||||
|
||||
/// <summary>
|
||||
/// The player who won the game, used to focus the camera in the win scene.
|
||||
/// </summary>
|
||||
private GameObject playerThatWon;
|
||||
|
||||
/// <summary>
|
||||
/// The lowest vertical position the camera can move to.
|
||||
/// </summary>
|
||||
public float lowerBound;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the camera is in the win scene mode.
|
||||
/// </summary>
|
||||
public bool winScene = false;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the camera should remain static and not follow players.
|
||||
/// </summary>
|
||||
public bool staticCamera = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the camera's starting position.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
if (playerThatWon == null || !playerThatWon.activeInHierarchy)
|
||||
start = transform.position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the camera's position every frame to follow players or focus on the winner.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
// If the game is over, focus the camera on the player that won
|
||||
if (winScene)
|
||||
{
|
||||
playerThatWon = FindWinner();
|
||||
if (playerThatWon == null || !playerThatWon.activeInHierarchy)
|
||||
{
|
||||
playerThatWon = FindWinner();
|
||||
}
|
||||
|
||||
if (playerThatWon != null)
|
||||
{
|
||||
// Move the camera toward the winning player's position
|
||||
target = playerThatWon.transform.position;
|
||||
transform.position = Vector3.Lerp(
|
||||
transform.position,
|
||||
new Vector3(target.x, target.y, target.z - 10),
|
||||
speed * 12 * Time.deltaTime
|
||||
);
|
||||
|
||||
// Ensure the camera does not go below the lower bound
|
||||
if (transform.position.y < lowerBound)
|
||||
{
|
||||
transform.position = new Vector3(transform.position.x, lowerBound, transform.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerThatWon != null)
|
||||
// Follow the players during the game
|
||||
List<GameObject> players = GameManager.players;
|
||||
if (players.Count == 0) return;
|
||||
|
||||
Vector3 playerAverage = Vector3.zero;
|
||||
int activePlayers = 0;
|
||||
|
||||
// Calculate the average position of all active players
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
target = playerThatWon.transform.position;
|
||||
transform.position = Vector3.Lerp(transform.position, new Vector3(target.x, target.y, target.z - 10), speed * 12 * Time.deltaTime);
|
||||
if (transform.position.y < lowerBound)
|
||||
if (player == null || !player.activeInHierarchy) continue;
|
||||
|
||||
Damageable damageable = player.GetComponent<Damageable>();
|
||||
if (damageable != null && damageable.dying) continue;
|
||||
|
||||
playerAverage += player.transform.position;
|
||||
activePlayers++;
|
||||
}
|
||||
|
||||
if (activePlayers == 0 || staticCamera) return;
|
||||
|
||||
playerAverage /= activePlayers;
|
||||
|
||||
// Blend between the starting position and the players' average position
|
||||
target = start * weight + playerAverage * (1 - weight);
|
||||
transform.position = Vector3.Lerp(
|
||||
transform.position,
|
||||
new Vector3(target.x, target.y, transform.position.z),
|
||||
speed * Time.deltaTime
|
||||
);
|
||||
|
||||
// Ensure the camera does not go below the lower bound
|
||||
if (transform.position.y < lowerBound)
|
||||
{
|
||||
transform.position = new Vector3(transform.position.x, lowerBound, transform.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates the win scene mode and focuses the camera on the winning player.
|
||||
/// </summary>
|
||||
/// <param name="player">The player who won the game.</param>
|
||||
public void WinScene(GameObject player)
|
||||
{
|
||||
winScene = true;
|
||||
playerThatWon = player;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the first active player in the game, used to determine the winner.
|
||||
/// </summary>
|
||||
/// <returns>The first active player GameObject, or null if no players are active.</returns>
|
||||
private GameObject FindWinner()
|
||||
{
|
||||
foreach (GameObject player in GameManager.players)
|
||||
{
|
||||
if (player != null && player.activeInHierarchy)
|
||||
{
|
||||
transform.position = new Vector3(transform.position.x, lowerBound, transform.position.z);
|
||||
return player;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// Moves the camera to follow the players
|
||||
List<GameObject> players = GameManager.players;
|
||||
if (players.Count == 0) return;
|
||||
Vector3 playerAverage = Vector3.zero;
|
||||
int activePlayers = 0;
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
if (player == null || !player.activeInHierarchy) continue;
|
||||
Damageable damageable = player.GetComponent<Damageable>();
|
||||
if (damageable != null && damageable.dying) continue;
|
||||
playerAverage += player.transform.position;
|
||||
activePlayers++;
|
||||
}
|
||||
|
||||
if (activePlayers == 0) return;
|
||||
if (staticCamera) return;
|
||||
|
||||
playerAverage /= activePlayers;
|
||||
|
||||
target = start * weight + playerAverage * (1 - weight);
|
||||
transform.position = Vector3.Lerp(transform.position, new Vector3(target.x, target.y, transform.position.z), speed * Time.deltaTime);
|
||||
if (transform.position.y < lowerBound)
|
||||
{
|
||||
transform.position = new Vector3(transform.position.x, lowerBound, transform.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
public void WinScene(GameObject player)
|
||||
{
|
||||
winScene = true;
|
||||
playerThatWon = player;
|
||||
}
|
||||
|
||||
private GameObject FindWinner() // Finds the player that won
|
||||
{
|
||||
foreach (GameObject player in GameManager.players)
|
||||
{
|
||||
if (player != null && player.activeInHierarchy)
|
||||
{
|
||||
return player;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,111 +1,198 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine; using Game; using Music; using Player;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
public class PlayerManager : MonoBehaviour
|
||||
{
|
||||
public static PlayerManager Instance;
|
||||
public List<PlayerJoinCard> cards;
|
||||
[SerializeField] private InputActionAsset playerActions;
|
||||
public List<Color> playerColors;
|
||||
public GameObject playerSelect;
|
||||
private bool gameStarted = false;
|
||||
|
||||
private void Awake()
|
||||
/// <summary>
|
||||
/// This class manages player-related functionality, such as joining, leaving, and assigning colors.
|
||||
/// It also handles starting the game once players have joined.
|
||||
/// </summary>
|
||||
public class PlayerManager : MonoBehaviour
|
||||
{
|
||||
Init();
|
||||
}
|
||||
/// <summary>
|
||||
/// The singleton instance of the <see cref="PlayerManager"/> class.
|
||||
/// </summary>
|
||||
public static PlayerManager Instance;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GetComponent<PlayerInputManager>().onPlayerJoined += OnPlayerJoined;
|
||||
GetComponent<PlayerInputManager>().onPlayerLeft += OnPlayerLeft;
|
||||
}
|
||||
/// <summary>
|
||||
/// A list of player join cards, which represent players in the UI.
|
||||
/// </summary>
|
||||
public List<PlayerJoinCard> cards;
|
||||
|
||||
private void OnPlayerJoined(PlayerInput playerInput) // Adds a player when they join
|
||||
{
|
||||
if (gameStarted)
|
||||
{
|
||||
Destroy(playerInput.gameObject);
|
||||
return;
|
||||
}
|
||||
print("Player joined");
|
||||
DontDestroyOnLoad(playerInput.gameObject);
|
||||
if (PlayerCardCreator.Instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PlayerJoinCard card = PlayerCardCreator.Instance.CreateCard();
|
||||
if (card == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
card.playerNumber = GameManager.players.Count + 1;
|
||||
cards.Add(card);
|
||||
if (GameManager.players == null)
|
||||
{
|
||||
GameManager.players = new List<GameObject>();
|
||||
}
|
||||
GameManager.players.Add(playerInput.gameObject);
|
||||
Colorize(GameManager.players.Count - 1);
|
||||
}
|
||||
/// <summary>
|
||||
/// The input actions used by players.
|
||||
/// </summary>
|
||||
[SerializeField] private InputActionAsset playerActions;
|
||||
|
||||
/// <summary>
|
||||
/// A list of colors assigned to players for identification.
|
||||
/// </summary>
|
||||
public List<Color> playerColors;
|
||||
|
||||
private void OnPlayerLeft(PlayerInput playerInput) // Removes the player if they leave
|
||||
{
|
||||
Destroy(playerInput.gameObject);
|
||||
GameManager.players.Remove(playerInput.gameObject);
|
||||
print("Player left");
|
||||
}
|
||||
/// <summary>
|
||||
/// The UI element used for player selection.
|
||||
/// </summary>
|
||||
public GameObject playerSelect;
|
||||
|
||||
private void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
/// <summary>
|
||||
/// Indicates whether the game has started.
|
||||
/// </summary>
|
||||
private bool gameStarted = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton instance of the <see cref="PlayerManager"/>.
|
||||
/// </summary>
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartGame() // Allows game to start after a player has joined
|
||||
{
|
||||
if (GameManager.players.Count == 0)
|
||||
/// <summary>
|
||||
/// Subscribes to player join and leave events.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
return;
|
||||
GetComponent<PlayerInputManager>().onPlayerJoined += OnPlayerJoined;
|
||||
GetComponent<PlayerInputManager>().onPlayerLeft += OnPlayerLeft;
|
||||
}
|
||||
gameStarted = true;
|
||||
HubManager.Instance.LoadScene(GameManager.map);
|
||||
}
|
||||
|
||||
private void Colorize(int index) // Pairs each player with a unique color
|
||||
{
|
||||
GameObject player = GameManager.players[index];
|
||||
Color color = playerColors[(GameManager.players.Count - 1) % playerColors.Count];
|
||||
float tint = Mathf.Floor((GameManager.players.Count - 1) / playerColors.Count);
|
||||
color = (color + color + Color.white * tint) / (tint + 2);
|
||||
GameManager.playerColors.Add(color);
|
||||
ApplyColor(player, color);
|
||||
ApplyColor(cards[GameManager.players.IndexOf(player)].playerPreview, color);
|
||||
}
|
||||
|
||||
private void ApplyColor(GameObject obj, Color color) // Applies a color to each player
|
||||
{
|
||||
if (obj.TryGetComponent<SpriteRenderer>(out _))
|
||||
/// <summary>
|
||||
/// Handles logic for when a player joins the game.
|
||||
/// </summary>
|
||||
/// <param name="playerInput">The <see cref="PlayerInput"/> of the player who joined.</param>
|
||||
private void OnPlayerJoined(PlayerInput playerInput)
|
||||
{
|
||||
obj.GetComponent<SpriteRenderer>().color = color;
|
||||
}
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
if (child.TryGetComponent<SpriteRenderer>(out _))
|
||||
// Prevent players from joining after the game has started
|
||||
if (gameStarted)
|
||||
{
|
||||
ApplyColor(child.gameObject, color);
|
||||
Destroy(playerInput.gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
print("Player joined");
|
||||
|
||||
// Ensure the player object persists across scenes
|
||||
DontDestroyOnLoad(playerInput.gameObject);
|
||||
|
||||
// Create a player join card for the new player
|
||||
if (PlayerCardCreator.Instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PlayerJoinCard card = PlayerCardCreator.Instance.CreateCard();
|
||||
if (card == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign a player number and add the card to the list
|
||||
card.playerNumber = GameManager.players.Count + 1;
|
||||
cards.Add(card);
|
||||
|
||||
// Initialize the player list in the GameManager if it doesn't exist
|
||||
if (GameManager.players == null)
|
||||
{
|
||||
GameManager.players = new List<GameObject>();
|
||||
}
|
||||
|
||||
// Add the player to the GameManager's player list and assign a color
|
||||
GameManager.players.Add(playerInput.gameObject);
|
||||
Colorize(GameManager.players.Count - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles logic for when a player leaves the game.
|
||||
/// </summary>
|
||||
/// <param name="playerInput">The <see cref="PlayerInput"/> of the player who left.</param>
|
||||
private void OnPlayerLeft(PlayerInput playerInput)
|
||||
{
|
||||
// Remove the player from the game and destroy their object
|
||||
Destroy(playerInput.gameObject);
|
||||
GameManager.players.Remove(playerInput.gameObject);
|
||||
print("Player left");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton instance of the <see cref="PlayerManager"/>.
|
||||
/// </summary>
|
||||
private void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the game if at least one player has joined.
|
||||
/// </summary>
|
||||
public void StartGame()
|
||||
{
|
||||
// Prevent starting the game if no players have joined
|
||||
if (GameManager.players.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gameStarted = true;
|
||||
|
||||
// Load the selected map
|
||||
HubManager.Instance.LoadScene(GameManager.map);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a unique color to a player and their associated UI elements.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the player in the player list.</param>
|
||||
private void Colorize(int index)
|
||||
{
|
||||
// Get the player object and assign a base color
|
||||
GameObject player = GameManager.players[index];
|
||||
Color color = playerColors[(GameManager.players.Count - 1) % playerColors.Count];
|
||||
|
||||
// Adjust the color tint based on the number of players
|
||||
float tint = Mathf.Floor((GameManager.players.Count - 1) / playerColors.Count);
|
||||
color = (color + color + Color.white * tint) / (tint + 2);
|
||||
|
||||
// Add the color to the GameManager's player color list
|
||||
GameManager.playerColors.Add(color);
|
||||
|
||||
// Apply the color to the player and their UI preview
|
||||
ApplyColor(player, color);
|
||||
ApplyColor(cards[GameManager.players.IndexOf(player)].playerPreview, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a color to a GameObject and its children.
|
||||
/// </summary>
|
||||
/// <param name="obj">The GameObject to colorize.</param>
|
||||
/// <param name="color">The color to apply.</param>
|
||||
private void ApplyColor(GameObject obj, Color color)
|
||||
{
|
||||
// Apply the color to the object's SpriteRenderer, if it has one
|
||||
if (obj.TryGetComponent<SpriteRenderer>(out _))
|
||||
{
|
||||
obj.GetComponent<SpriteRenderer>().color = color;
|
||||
}
|
||||
|
||||
// Recursively apply the color to all child objects
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
if (child.TryGetComponent<SpriteRenderer>(out _))
|
||||
{
|
||||
ApplyColor(child.gameObject, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
using System.Collections;
|
||||
using TMPro;
|
||||
using Unity.IO.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class handles the player's movement, including walking, jumping, and animations.
|
||||
/// It also manages input, physics, and interactions with the ground.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(BoxCollider2D))]
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
@@ -16,6 +19,7 @@ namespace Player
|
||||
[RequireComponent(typeof(Punch))]
|
||||
public class PlayerMovement : MonoBehaviour
|
||||
{
|
||||
// --- Public Fields ---
|
||||
|
||||
/// <summary>
|
||||
/// Layers considered as ground for the player.
|
||||
@@ -28,10 +32,11 @@ namespace Player
|
||||
/// </summary>
|
||||
public TextMeshProUGUI playerText;
|
||||
|
||||
[Header("Movement")]
|
||||
|
||||
/// <summary>
|
||||
/// Base walk speed of the player.
|
||||
/// </summary>
|
||||
[Header("Movement")]
|
||||
public float walkSpeed;
|
||||
|
||||
/// <summary>
|
||||
@@ -109,6 +114,8 @@ namespace Player
|
||||
/// </summary>
|
||||
public float groundCheckDistance;
|
||||
|
||||
// --- Private Fields ---
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the Rigidbody2D component.
|
||||
/// </summary>
|
||||
@@ -174,6 +181,8 @@ namespace Player
|
||||
/// </summary>
|
||||
private Vector3 positionLastFrame;
|
||||
|
||||
// --- Unity Methods ---
|
||||
|
||||
/// <summary>
|
||||
/// Initializes player components and sets up initial values.
|
||||
/// </summary>
|
||||
@@ -221,6 +230,8 @@ namespace Player
|
||||
Animate();
|
||||
}
|
||||
|
||||
// --- Movement Methods ---
|
||||
|
||||
/// <summary>
|
||||
/// Updates the player's animation state based on movement and grounded status.
|
||||
/// </summary>
|
||||
@@ -236,20 +247,10 @@ namespace Player
|
||||
animationPlayer.SetState(AnimationPlayer.AnimationState.Idle);
|
||||
}
|
||||
|
||||
if (true)
|
||||
{
|
||||
if (virtualAxisX < -0.01f)
|
||||
animationPlayer.backwards = true;
|
||||
else if (virtualAxisX > 0.01f)
|
||||
animationPlayer.backwards = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (body.linearVelocityX < -0.1f)
|
||||
animationPlayer.backwards = true;
|
||||
else if (body.linearVelocityX > 0.1f)
|
||||
animationPlayer.backwards = false;
|
||||
}
|
||||
if (virtualAxisX < -0.01f)
|
||||
animationPlayer.backwards = true;
|
||||
else if (virtualAxisX > 0.01f)
|
||||
animationPlayer.backwards = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -427,6 +428,5 @@ namespace Player
|
||||
{
|
||||
if (IsPhysicallyGrounded()) body.linearVelocity = Vector2.zero;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +1,108 @@
|
||||
using UnityEngine; using Game; using Music; using Player;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
[RequireComponent(typeof(AnimationPlayer))]
|
||||
public class Punch : MonoBehaviour
|
||||
{
|
||||
public bool cancelable = true;
|
||||
|
||||
[SerializeField] private BoxCollider2D hurtbox;
|
||||
|
||||
InputActionAsset actions;
|
||||
|
||||
private void Start()
|
||||
/// <summary>
|
||||
/// This class handles the punching mechanic for the player, including triggering animations,
|
||||
/// enabling and disabling the hurtbox, and managing player speed during a punch.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
[RequireComponent(typeof(AnimationPlayer))]
|
||||
public class Punch : MonoBehaviour
|
||||
{
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the player can cancel their punch action.
|
||||
/// </summary>
|
||||
public bool cancelable = true;
|
||||
|
||||
private void Update() // Executes punch when 'punch' is pressed
|
||||
{
|
||||
if (actions.FindAction("Punch").WasPressedThisFrame())
|
||||
/// <summary>
|
||||
/// The hurtbox used to detect collisions with other players or objects during a punch.
|
||||
/// </summary>
|
||||
[SerializeField] private BoxCollider2D hurtbox;
|
||||
|
||||
/// <summary>
|
||||
/// The input actions associated with the player.
|
||||
/// </summary>
|
||||
private InputActionAsset actions;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the player's input actions.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
if (!cancelable) return;
|
||||
ExecutePunch();
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for punch input every frame and executes the punch if the action is triggered.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
// Executes punch when the "Punch" action is pressed
|
||||
if (actions.FindAction("Punch").WasPressedThisFrame())
|
||||
{
|
||||
if (!cancelable) return; // Prevents punching if the action is not cancelable
|
||||
ExecutePunch();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the punch action, triggering the punch animation and slowing the player down.
|
||||
/// </summary>
|
||||
private void ExecutePunch()
|
||||
{
|
||||
// Trigger the punch animation
|
||||
GetComponent<AnimationPlayer>().Punch();
|
||||
|
||||
// Disable the ability to cancel the punch
|
||||
DisableCancellation();
|
||||
|
||||
// Temporarily reduce the player's movement speed during the punch
|
||||
GetComponent<PlayerMovement>().maxSpeedOverride = 1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the hurtbox, allowing the punch to interact with other objects.
|
||||
/// </summary>
|
||||
public void EnableHurtbox()
|
||||
{
|
||||
if (hurtbox != null) hurtbox.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the hurtbox, preventing the punch from interacting with other objects.
|
||||
/// </summary>
|
||||
public void DisableHurtbox()
|
||||
{
|
||||
if (hurtbox != null) hurtbox.enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the ability to cancel the punch action.
|
||||
/// </summary>
|
||||
public void DisableCancellation()
|
||||
{
|
||||
cancelable = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the ability to cancel the punch action.
|
||||
/// </summary>
|
||||
public void EnableCancellation()
|
||||
{
|
||||
cancelable = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the player's movement speed to its maximum value after the punch is complete.
|
||||
/// </summary>
|
||||
public void ReturnToMaxSpeed()
|
||||
{
|
||||
GetComponent<PlayerMovement>().maxSpeedOverride = GetComponent<PlayerMovement>().maxSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecutePunch() // Triggers punch animation
|
||||
{
|
||||
GetComponent<AnimationPlayer>().Punch();
|
||||
DisableCancellation();
|
||||
GetComponent<PlayerMovement>().maxSpeedOverride = 1f; // Slows player down when punching
|
||||
}
|
||||
|
||||
public void EnableHurtbox()
|
||||
{
|
||||
if (hurtbox != null) hurtbox.enabled = true;
|
||||
}
|
||||
|
||||
public void DisableHurtbox()
|
||||
{
|
||||
if (hurtbox != null) hurtbox.enabled = false;
|
||||
}
|
||||
|
||||
public void DisableCancellation()
|
||||
{
|
||||
cancelable = false;
|
||||
}
|
||||
|
||||
public void EnableCancellation()
|
||||
{
|
||||
cancelable = true;
|
||||
}
|
||||
|
||||
public void ReturnToMaxSpeed() // Resets player speed after punch
|
||||
{
|
||||
GetComponent<PlayerMovement>().maxSpeedOverride = GetComponent<PlayerMovement>().maxSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,73 @@
|
||||
using UnityEngine; using Game; using Music; using Player;
|
||||
using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
public class TeleportPlatform : MonoBehaviour
|
||||
{
|
||||
public Vector2 teleportPoint;
|
||||
public string teleportTag;
|
||||
public string playerTag = "Player";
|
||||
public bool isPlatform = true;
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
/// <summary>
|
||||
/// This class handles teleportation for platforms and players when they collide with the teleport trigger.
|
||||
/// It can teleport either the platform itself or a player to a specified location.
|
||||
/// </summary>
|
||||
public class TeleportPlatform : MonoBehaviour
|
||||
{
|
||||
if (!isPlatform)
|
||||
/// <summary>
|
||||
/// The position where the platform or player will be teleported.
|
||||
/// </summary>
|
||||
public Vector2 teleportPoint;
|
||||
|
||||
/// <summary>
|
||||
/// The tag used to identify objects (e.g., platforms) that can trigger teleportation.
|
||||
/// </summary>
|
||||
public string teleportTag;
|
||||
|
||||
/// <summary>
|
||||
/// The tag used to identify player objects.
|
||||
/// </summary>
|
||||
public string playerTag = "Player";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this script is handling a platform or a player.
|
||||
/// If true, it teleports players. If false, it teleports the platform itself.
|
||||
/// </summary>
|
||||
public bool isPlatform = true;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the teleportation logic when an object enters the trigger collider.
|
||||
/// </summary>
|
||||
/// <param name="collision">The collider of the object that entered the trigger.</param>
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
// Teleports the platform
|
||||
if (collision.CompareTag(teleportTag))
|
||||
if (!isPlatform)
|
||||
{
|
||||
transform.position = teleportPoint;
|
||||
if (TryGetComponent<Rigidbody2D>(out var rb))
|
||||
// Teleports the platform itself
|
||||
if (collision.CompareTag(teleportTag))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
// Move the platform to the teleport point
|
||||
transform.position = teleportPoint;
|
||||
|
||||
// Reset the platform's velocity if it has a Rigidbody2D component
|
||||
if (TryGetComponent<Rigidbody2D>(out var rb))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Teleports the player
|
||||
if (collision.CompareTag(playerTag))
|
||||
else
|
||||
{
|
||||
collision.transform.position = teleportPoint;
|
||||
if (collision.TryGetComponent<Rigidbody2D>(out var rb))
|
||||
// Teleports the player
|
||||
if (collision.CompareTag(playerTag))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
// Move the player to the teleport point
|
||||
collision.transform.position = teleportPoint;
|
||||
|
||||
// Reset the player's velocity if they have a Rigidbody2D component
|
||||
if (collision.TryGetComponent<Rigidbody2D>(out var rb))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,31 +3,70 @@ using UnityEngine;
|
||||
using Game;
|
||||
using Music;
|
||||
using Player;
|
||||
|
||||
namespace Player
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class allows a player to pick up, hold, and drop items during the game.
|
||||
/// It is primarily used for managing interactions with the "hat" in "keep-away" mode.
|
||||
/// </summary>
|
||||
public class UseItem : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The tag used to identify items that can be picked up.
|
||||
/// </summary>
|
||||
[SerializeField] private string itemTag;
|
||||
|
||||
/// <summary>
|
||||
/// The item currently being held by the player.
|
||||
/// </summary>
|
||||
private GameObject heldItem;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the player is currently holding an item.
|
||||
/// </summary>
|
||||
private bool isHoldingItem = false;
|
||||
|
||||
/// <summary>
|
||||
/// The time when the player started holding the item.
|
||||
/// </summary>
|
||||
private float holdStartTime;
|
||||
|
||||
/// <summary>
|
||||
/// The total time the player has held the item.
|
||||
/// </summary>
|
||||
public float holdTime;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the player's <see cref="Damageable"/> component.
|
||||
/// </summary>
|
||||
private Damageable damageable;
|
||||
|
||||
/// <summary>
|
||||
/// The position where the item will be held (e.g., above the player's head).
|
||||
/// </summary>
|
||||
[SerializeField] public Transform head;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the player's <see cref="Damageable"/> component.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
damageable = GetComponent<Damageable>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
/// <summary>
|
||||
/// Updates the player's state every frame.
|
||||
/// If the player is holding an item, it keeps the item positioned on their head
|
||||
/// and updates the hold time in "keep-away" mode.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (isHoldingItem)
|
||||
{
|
||||
// Keeps hat on the player's head
|
||||
// Keeps the item positioned on the player's head
|
||||
heldItem.transform.localPosition = Vector3.zero;
|
||||
|
||||
if (GameManager.gameMode == GameManager.GameMode.keepAway)
|
||||
{
|
||||
// Adds time to the player's leaderboard standing
|
||||
@@ -37,19 +76,30 @@ namespace Player
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollisionEnter2D(Collision2D collision) // Player automatically picks up hat when touching it
|
||||
/// <summary>
|
||||
/// Automatically picks up an item when the player collides with it.
|
||||
/// </summary>
|
||||
/// <param name="collision">The collision data from the item.</param>
|
||||
private void OnCollisionEnter2D(Collision2D collision)
|
||||
{
|
||||
// Check if the collided object is a "hat" and the player is not already holding an item
|
||||
if (collision.gameObject.CompareTag("Hat") && !isHoldingItem && !damageable.dying)
|
||||
{
|
||||
PickUpItem(collision.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void PickUpItem(GameObject item) // Player picks up hat and starts hold counter
|
||||
/// <summary>
|
||||
/// Allows the player to pick up an item and start the hold timer.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to pick up.</param>
|
||||
public void PickUpItem(GameObject item)
|
||||
{
|
||||
if (damageable.dying) return; // Prevent picking up items if the player is dying
|
||||
if (HatRespawn.canBePickedUp == false) return; // Prevent picking up items if they are not interactable
|
||||
// Prevent picking up items if the player is dying or the item is not interactable
|
||||
if (damageable.dying) return;
|
||||
if (HatRespawn.canBePickedUp == false) return;
|
||||
|
||||
// Set the item as the held item and update its state
|
||||
heldItem = item;
|
||||
isHoldingItem = true;
|
||||
holdStartTime = Time.time;
|
||||
@@ -59,31 +109,47 @@ namespace Player
|
||||
item.transform.parent = head;
|
||||
item.transform.localRotation = Quaternion.identity;
|
||||
item.transform.localPosition = Vector3.zero;
|
||||
//item.transform.GetChild(0).transform.localPosition = item.GetComponent<HatRespawn>().initialSubhatPosition;
|
||||
|
||||
// Initialize the player's hold time in the GameManager if not already set
|
||||
if (!GameManager.playerHoldTimes.ContainsKey(gameObject))
|
||||
{
|
||||
GameManager.playerHoldTimes[gameObject] = 0f;
|
||||
}
|
||||
|
||||
// Play the pickup sound and stop any ongoing hat movement
|
||||
AudioManager.Instance.PlaySound("Pickup Hat");
|
||||
GameManager.Instance.StopCoroutine("MoveHatToWinner");
|
||||
}
|
||||
|
||||
public void DropItem() // Player drops hat when hit
|
||||
/// <summary>
|
||||
/// Allows the player to drop the item they are holding.
|
||||
/// </summary>
|
||||
public void DropItem()
|
||||
{
|
||||
if (GameManager.Instance.gameOver) return; // Prevent dropping items if the game is over
|
||||
// Prevent dropping items if the game is over
|
||||
if (GameManager.Instance.gameOver) return;
|
||||
|
||||
if (isHoldingItem)
|
||||
{
|
||||
// Enable the item's collider and make it interactable after a short delay
|
||||
heldItem.GetComponent<Collider2D>().enabled = true;
|
||||
HatRespawn.canBePickedUp = false;
|
||||
StartCoroutine(WaitForInteractability());
|
||||
|
||||
// Make the item dynamic and apply random force and torque to it
|
||||
heldItem.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
|
||||
heldItem.GetComponent<Rigidbody2D>().AddForce(Vector2.up * Random.Range(10f, 30f) + Vector2.right * Random.Range(-10, 10), ForceMode2D.Impulse);
|
||||
heldItem.GetComponent<Rigidbody2D>().AddTorque(Random.Range(-1, 1), ForceMode2D.Impulse);
|
||||
|
||||
// Notify the item that it has been dropped
|
||||
heldItem.GetComponent<HatRespawn>().OnHatDropped();
|
||||
|
||||
// Detach the item from the player
|
||||
heldItem.transform.parent = GameManager.Instance.transform;
|
||||
heldItem = null;
|
||||
isHoldingItem = false;
|
||||
|
||||
// Remove the player's hold time from the GameManager
|
||||
if (GameManager.playerHoldTimes.ContainsKey(gameObject))
|
||||
{
|
||||
GameManager.playerHoldTimes.Remove(gameObject);
|
||||
@@ -91,15 +157,23 @@ namespace Player
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for a short delay before making the item interactable again.
|
||||
/// </summary>
|
||||
/// <returns>An IEnumerator for coroutine execution.</returns>
|
||||
private IEnumerator WaitForInteractability()
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
HatRespawn.canBePickedUp = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the player is currently holding an item.
|
||||
/// </summary>
|
||||
/// <returns>True if the player is holding an item, false otherwise.</returns>
|
||||
public bool IsHoldingItem()
|
||||
{
|
||||
return isHoldingItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user