Merge branch 'main' into Dylan
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
[RequireComponent(typeof(RespawnOnTriggerEnter))]
|
||||
public class Damageable : MonoBehaviour
|
||||
{
|
||||
public float force = 50f;
|
||||
public float damage = 0f;
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (collision.gameObject.CompareTag("Punch Hurtbox"))
|
||||
{
|
||||
if (GetComponent<Block>().blocking)
|
||||
{
|
||||
collision.gameObject.GetComponent<Damageable>().Damage(gameObject);
|
||||
return;
|
||||
}
|
||||
Damage(collision.transform.parent.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Recoil(GameObject damageSource)
|
||||
{
|
||||
GetComponent<Rigidbody2D>().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up) * damage, ForceMode2D.Force);
|
||||
//damageSource.transform.localScale *= 1.1f;
|
||||
}
|
||||
|
||||
public void Damage(GameObject source)
|
||||
{
|
||||
damage += force;
|
||||
Recoil(source);
|
||||
}
|
||||
|
||||
public void ResetDamage()
|
||||
{
|
||||
damage = 0f;
|
||||
//transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
8
Assets/Scripts/Game.meta
Normal file
8
Assets/Scripts/Game.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb25285062358bf41aa26cc8ca26b120
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
24
Assets/Scripts/Game/CreatePlayerJoinCards.cs
Normal file
24
Assets/Scripts/Game/CreatePlayerJoinCards.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class PlayerCardCreator : MonoBehaviour
|
||||
{
|
||||
public static PlayerCardCreator Instance;
|
||||
|
||||
public GameObject playerJoinCardPrefab;
|
||||
|
||||
private void Awake() // Ensures only one instance of PlayerCardCreator exists
|
||||
{
|
||||
if (Instance == null) Instance = this;
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerJoinCard CreateCard() // Creates a player join card
|
||||
{
|
||||
GameObject card = Instantiate(playerJoinCardPrefab, transform);
|
||||
return card.GetComponent<PlayerJoinCard>();
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/CreatePlayerJoinCards.cs.meta
Normal file
2
Assets/Scripts/Game/CreatePlayerJoinCards.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4faf59678eb534fabab364215e093fa0
|
||||
14
Assets/Scripts/Game/EventSystemizer.cs
Normal file
14
Assets/Scripts/Game/EventSystemizer.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
public class EventSystemizer : MonoBehaviour
|
||||
{
|
||||
private void Update() // Ensures only one instance of EventSystem exists
|
||||
{
|
||||
foreach (EventSystem system in FindObjectsByType<EventSystem>(FindObjectsSortMode.None))
|
||||
{
|
||||
if (system == GetComponent<EventSystem>()) continue;
|
||||
Destroy(system.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/EventSystemizer.cs.meta
Normal file
2
Assets/Scripts/Game/EventSystemizer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 305a0eb0ddc9f88438e978efa8dd6f69
|
||||
54
Assets/Scripts/Game/FallPlatform.cs
Normal file
54
Assets/Scripts/Game/FallPlatform.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
public class FallPlatform : MonoBehaviour
|
||||
{
|
||||
public float fallDelay = 2f; // Delay before the platform falls
|
||||
public float resetDelay = 4f; // Delay before the platform resets
|
||||
|
||||
bool falling;
|
||||
Rigidbody2D rb;
|
||||
Vector3 defposition;
|
||||
|
||||
void Start()
|
||||
{
|
||||
defposition = transform.parent.position;
|
||||
rb = transform.parent.GetComponent<Rigidbody2D>();
|
||||
}
|
||||
private void OnTriggerEnter2D(Collider2D collision) // Makes platform fall when player or another platform touch it
|
||||
{
|
||||
try
|
||||
{
|
||||
if (collision.transform.childCount != 0 && !falling && (collision.gameObject.CompareTag("Player") || collision.transform.GetChild(0).TryGetComponent(out FallPlatform _)))
|
||||
{
|
||||
StartCoroutine(FallAfterDelay());
|
||||
}
|
||||
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError("Error in FallPlatform: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator FallAfterDelay() // Sets platform to fall and respawn
|
||||
{
|
||||
falling = true;
|
||||
yield return new WaitForSeconds(fallDelay);
|
||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
||||
yield return new WaitForSeconds(resetDelay);
|
||||
transform.parent.GetComponent<Animator>().SetTrigger("respawn");
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
Respawn();
|
||||
}
|
||||
|
||||
//only resets the object script is attached to, need to fix so platform will reset with fall trigger object
|
||||
// Use transform.parent to get the object it's attatched to
|
||||
private void Respawn() // Resets the platform position
|
||||
{
|
||||
falling = false;
|
||||
rb.bodyType = RigidbodyType2D.Static;
|
||||
transform.parent.position = defposition;
|
||||
transform.parent.rotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/FallPlatform.cs.meta
Normal file
2
Assets/Scripts/Game/FallPlatform.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d315bad368a8a247a5df8ac6b2f3ec1
|
||||
259
Assets/Scripts/Game/GameManager.cs
Normal file
259
Assets/Scripts/Game/GameManager.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class GameManager : MonoBehaviour
|
||||
{
|
||||
public static GameManager Instance { get; private set; }
|
||||
public float time = 180f;
|
||||
public delegate void GameEvent();
|
||||
public event GameEvent StartGameEvent;
|
||||
public event GameEvent EndGameEvent;
|
||||
public static List<GameObject> players = new List<GameObject>();
|
||||
public static List<Color> playerColors = new List<Color>();
|
||||
public float offset = 1f;
|
||||
public static bool music = true;
|
||||
public bool gameOver = false;
|
||||
public GameTimer gameTimer;
|
||||
public static Dictionary<GameObject, float> playerHoldTimes = new Dictionary<GameObject, float>();
|
||||
public static GameMode gameMode = GameMode.freeForAll; // loads a default gamemode as a safety net
|
||||
public static string map = "Platformer With Headroom"; // loads a default map as a safety net
|
||||
public Vector2 spawnPosition;
|
||||
public Vector2 obstacleCourseSpawnPosition;
|
||||
public List<Vector2> hatSpawnPositions = new List<Vector2>();
|
||||
public Canvas LeaderboardCanvas;
|
||||
public Canvas TimerCanvas;
|
||||
public GameObject hatObject;
|
||||
public enum GameMode
|
||||
{
|
||||
freeForAll,
|
||||
keepAway,
|
||||
obstacleCourse
|
||||
}
|
||||
|
||||
private void Awake() // Ensures only one instance of GameManager exists
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start() // Starts the game and music
|
||||
{
|
||||
MusicManager.Instance.StartPlaylist();
|
||||
StartGame();
|
||||
}
|
||||
|
||||
private void Update() // Continuously updates player hold times
|
||||
{
|
||||
if (gameOver) return;
|
||||
|
||||
if (gameMode == GameMode.keepAway)
|
||||
{
|
||||
foreach (var player in players)
|
||||
{
|
||||
float holdTime = GetPlayerHoldTime(player);
|
||||
UpdatePlayerHoldTime(player, holdTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetPlayerHoldTime(GameObject player)
|
||||
{
|
||||
UseItem useItem = player.GetComponent<UseItem>();
|
||||
if (useItem != null)
|
||||
{
|
||||
return useItem.holdTime;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public void StartGame() // Sets up the proper gamemode
|
||||
{
|
||||
GameManager.playerHoldTimes.Clear();
|
||||
if (GameManager.players.Count == 0) return;
|
||||
|
||||
StartGameEvent?.Invoke();
|
||||
print("Starting game with mode: " + gameMode + " and map: " + map);
|
||||
if (gameMode == GameMode.freeForAll) // Sets up the game for free for all mode
|
||||
{
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
player.transform.position = spawnPosition + (offset * players.IndexOf(player) * Vector2.right);
|
||||
player.GetComponent<Damageable>().lives = 5;
|
||||
}
|
||||
}
|
||||
if (gameMode == GameMode.keepAway) // Sets up the game for keep away mode
|
||||
{
|
||||
gameTimer.startTime = time;
|
||||
gameTimer.StartTimer();
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
player.transform.position = spawnPosition + (offset * players.IndexOf(player) * Vector2.right);
|
||||
player.GetComponent<Damageable>().lives = 0;
|
||||
}
|
||||
}
|
||||
if (gameMode == GameMode.obstacleCourse) // Sets up the game for obstacle course mode
|
||||
{
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
player.transform.position = spawnPosition;
|
||||
player.GetComponent<Damageable>().lives = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayerDied(Damageable player) // Handles player deaths for the respective gamemode
|
||||
{
|
||||
UseItem useItem = player.GetComponent<UseItem>(); // Drop the item the player is holding
|
||||
if (useItem != null)
|
||||
{
|
||||
if (gameOver == false)
|
||||
{
|
||||
useItem.DropItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
return; // Prevents winner from dropping the item if the game is over
|
||||
}
|
||||
}
|
||||
|
||||
if (gameMode == GameMode.freeForAll) // Respawns player if they have lives left
|
||||
{
|
||||
player.lives--;
|
||||
if (player.lives <= 0 && !gameOver)
|
||||
{
|
||||
player.gameObject.SetActive(false);
|
||||
if (AlivePlayers().Count <= 1)
|
||||
{
|
||||
GameOver(); // Winner is called when only one player is left
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RespawnPlayer(player.gameObject);
|
||||
}
|
||||
}
|
||||
if (gameMode == GameMode.keepAway) // Always respawns player regardless of lives
|
||||
{
|
||||
RespawnPlayer(player.gameObject);
|
||||
}
|
||||
if (gameMode == GameMode.obstacleCourse)
|
||||
{
|
||||
RespawnPlayer(player.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void RespawnPlayer(GameObject player) // Respawns player at the spawn point and resets health
|
||||
{
|
||||
RespawnOnTriggerEnter respawnScript = player.GetComponent<RespawnOnTriggerEnter>();
|
||||
if (respawnScript != null)
|
||||
{
|
||||
player.transform.position = respawnScript.spawnPoint;
|
||||
player.GetComponent<Damageable>().ResetDamage();
|
||||
player.GetComponent<Damageable>().Respawn();
|
||||
}
|
||||
}
|
||||
|
||||
public void GameOver() // Ends game and displays winner
|
||||
{
|
||||
gameOver = true;
|
||||
EndGameEvent?.Invoke();
|
||||
LeaderboardCanvas.gameObject.SetActive(false);
|
||||
TimerCanvas.gameObject.SetActive(false);
|
||||
|
||||
if (gameMode == GameMode.freeForAll) // Last player alive wins
|
||||
{
|
||||
GameObject winner = AlivePlayers()[0];
|
||||
print(winner.name + " is the winner");
|
||||
FindFirstObjectByType<PlayerCameraMovement>().WinScene(winner);
|
||||
WinScreen.Instance.ShowWinScreen(players.IndexOf(winner) + 1);
|
||||
FindFirstObjectByType<LifeDisplayManager>().HideLifeDisplay();
|
||||
}
|
||||
if (gameMode == GameMode.keepAway) // Player with the most time holding the hat wins
|
||||
{
|
||||
GameObject winner = null;
|
||||
float maxHoldTime = -1f;
|
||||
foreach (var player in GameManager.playerHoldTimes)
|
||||
{
|
||||
if (player.Value > maxHoldTime)
|
||||
{
|
||||
maxHoldTime = player.Value;
|
||||
winner = player.Key;
|
||||
}
|
||||
}
|
||||
if (winner != null)
|
||||
{
|
||||
print(winner.name + " is the winner with " + maxHoldTime + " seconds!");
|
||||
FindFirstObjectByType<PlayerCameraMovement>().WinScene(winner);
|
||||
WinScreen.Instance.ShowWinScreen(players.IndexOf(winner) + 1);
|
||||
FindFirstObjectByType<LifeDisplayManager>().HideLifeDisplay();
|
||||
StartCoroutine(MoveHatToWinner(winner));
|
||||
hatObject.SetActive(true);
|
||||
hatObject.GetComponent<Collider2D>().enabled = true;
|
||||
hatObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
|
||||
}
|
||||
}
|
||||
if (gameMode == GameMode.obstacleCourse) // Player who reached the end first wins
|
||||
{
|
||||
GameObject winner = ObstacleCourse.playerWon;
|
||||
|
||||
print(winner.name + " is the winner!");
|
||||
FindFirstObjectByType<PlayerCameraMovement>().WinScene(winner);
|
||||
WinScreen.Instance.ShowWinScreen(players.IndexOf(winner) + 1);
|
||||
FindFirstObjectByType<LifeDisplayManager>().HideLifeDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator MoveHatToWinner(GameObject winner)
|
||||
{
|
||||
while (!winner.GetComponent<UseItem>().IsHoldingItem())
|
||||
{
|
||||
hatObject.transform.position = winner.transform.position + Vector3.up * 3/2;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<GameObject> AlivePlayers() // Returns a list of all players that are alive
|
||||
{
|
||||
List<GameObject> alivePlayers = new();
|
||||
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
if (player.activeInHierarchy) alivePlayers.Add(player);
|
||||
}
|
||||
|
||||
return alivePlayers;
|
||||
}
|
||||
|
||||
public void UpdatePlayerHoldTime(GameObject player, float holdTime) // Updates the player's hold time and leaderboard
|
||||
{
|
||||
bool shouldSort = false;
|
||||
|
||||
if (playerHoldTimes.ContainsKey(player))
|
||||
{
|
||||
if (holdTime > playerHoldTimes[player])
|
||||
{
|
||||
shouldSort = true;
|
||||
}
|
||||
playerHoldTimes[player] = holdTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
playerHoldTimes.Add(player, holdTime);
|
||||
shouldSort = true;
|
||||
}
|
||||
LeaderboardManager.Instance.UpdatePlayerHoldTimeText(player, holdTime);
|
||||
if (shouldSort)
|
||||
{
|
||||
LeaderboardManager.Instance.UpdateLeaderboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/GameManager.cs.meta
Normal file
2
Assets/Scripts/Game/GameManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6e4006937b044c9ab3de25a7ab68162
|
||||
23
Assets/Scripts/Game/GameManagerHelper.cs
Normal file
23
Assets/Scripts/Game/GameManagerHelper.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteAlways]
|
||||
public class GameManagerHelper : MonoBehaviour
|
||||
{
|
||||
public bool addHatPosition;
|
||||
public bool addSpawnPosition;
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (addHatPosition)
|
||||
{
|
||||
addHatPosition = false;
|
||||
GetComponent<GameManager>().hatSpawnPositions.Add(GameObject.Find("HELPER").transform.position);
|
||||
}
|
||||
if (addSpawnPosition)
|
||||
{
|
||||
addSpawnPosition = false;
|
||||
GetComponent<GameManager>().spawnPosition = GameObject.Find("HELPER").transform.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/GameManagerHelper.cs.meta
Normal file
2
Assets/Scripts/Game/GameManagerHelper.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c35a13ba94b04f19a6ee30e6fe34327
|
||||
58
Assets/Scripts/Game/GameTimer.cs
Normal file
58
Assets/Scripts/Game/GameTimer.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class GameTimer : MonoBehaviour
|
||||
{
|
||||
public float startTime = 180f;
|
||||
private float timeRemaining;
|
||||
private bool timerRunning = false;
|
||||
|
||||
public Text timerText;
|
||||
[SerializeField] private TextMeshProUGUI timer;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
timeRemaining = startTime;
|
||||
timer.text = "3:00.00";
|
||||
UpdateTimerDisplay();
|
||||
}
|
||||
|
||||
private void Update() // Updates the timer to show the time remaining
|
||||
{
|
||||
if (timerRunning)
|
||||
{
|
||||
timeRemaining -= Time.deltaTime;
|
||||
|
||||
if (timeRemaining <= 0)
|
||||
{
|
||||
timeRemaining = 0;
|
||||
timerRunning = false;
|
||||
OnTimerEnd();
|
||||
}
|
||||
|
||||
UpdateTimerDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartTimer() // Starts the timer
|
||||
{
|
||||
if (!timerRunning)
|
||||
{
|
||||
timeRemaining = startTime;
|
||||
timerRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTimerDisplay() // Formats and sets the time remaining
|
||||
{
|
||||
int minutes = Mathf.FloorToInt(timeRemaining / 60);
|
||||
int seconds = Mathf.FloorToInt(timeRemaining % 60);
|
||||
timer.text = string.Format("{0}:{1:D2}", minutes, seconds);
|
||||
}
|
||||
|
||||
private void OnTimerEnd() // Ends the game when the time runs out
|
||||
{
|
||||
GameManager.Instance.GameOver();
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/GameTimer.cs.meta
Normal file
2
Assets/Scripts/Game/GameTimer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 012d92d911650b340a4561288484ac28
|
||||
55
Assets/Scripts/Game/HatRespawn.cs
Normal file
55
Assets/Scripts/Game/HatRespawn.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class HatRespawn : MonoBehaviour
|
||||
{
|
||||
private float lastInteractionTime;
|
||||
public const float respawnTime = 10f;
|
||||
private bool isDropped;
|
||||
|
||||
public static bool canBePickedUp = true; // Flag to check if the hat can be picked up
|
||||
|
||||
void Start()
|
||||
{
|
||||
lastInteractionTime = Time.time;
|
||||
isDropped = false;
|
||||
transform.position = GameManager.Instance.hatSpawnPositions[Random.Range(0, GameManager.Instance.hatSpawnPositions.Count - 1)];
|
||||
}
|
||||
|
||||
void Update() // Checks if the hat has been inactive for too long
|
||||
{
|
||||
if (isDropped && Time.time - lastInteractionTime > respawnTime)
|
||||
{
|
||||
RespawnHat();
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D collision) // Respawns the hat if it falls out of bounds
|
||||
{
|
||||
if (collision.gameObject.CompareTag("Platformer Hazard"))
|
||||
{
|
||||
RespawnHat();
|
||||
}
|
||||
}
|
||||
|
||||
public void Interact() // Updates the player interaction time
|
||||
{
|
||||
lastInteractionTime = Time.time;
|
||||
isDropped = false;
|
||||
}
|
||||
|
||||
public void OnHatDropped() // Resets the timer when the hat is dropped
|
||||
{
|
||||
lastInteractionTime = Time.time;
|
||||
isDropped = true;
|
||||
}
|
||||
|
||||
private void RespawnHat() // Respawns the hat at the designated spawn position
|
||||
{
|
||||
transform.position = GameManager.Instance.hatSpawnPositions[Random.Range(0, GameManager.Instance.hatSpawnPositions.Count - 1)];
|
||||
GetComponent<Rigidbody2D>().linearVelocity = Vector2.zero;
|
||||
GetComponent<Rigidbody2D>().angularVelocity = 0f;
|
||||
transform.rotation = Quaternion.identity;
|
||||
lastInteractionTime = Time.time; // Reset the timer after respawning
|
||||
isDropped = false;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/HatRespawn.cs.meta
Normal file
2
Assets/Scripts/Game/HatRespawn.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1803a208ca94f44a189bf03342859d36
|
||||
55
Assets/Scripts/Game/HealthBarManager.cs
Normal file
55
Assets/Scripts/Game/HealthBarManager.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class HealthBarManager : MonoBehaviour
|
||||
{
|
||||
public GameObject healthBarPrefab;
|
||||
private Dictionary<GameObject, GameObject> playerHealthBars = new Dictionary<GameObject, GameObject>();
|
||||
|
||||
void Start()
|
||||
{
|
||||
GameManager.Instance.StartGameEvent += OnGameStart;
|
||||
GameManager.Instance.EndGameEvent += OnGameEnd;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
GameManager.Instance.StartGameEvent -= OnGameStart;
|
||||
GameManager.Instance.EndGameEvent -= OnGameEnd;
|
||||
}
|
||||
|
||||
void Update() // Updates position of health bars to follow each player
|
||||
{
|
||||
foreach (var kvp in playerHealthBars)
|
||||
{
|
||||
GameObject player = kvp.Key;
|
||||
if (player == null) continue;
|
||||
|
||||
GameObject healthBar = kvp.Value;
|
||||
healthBar.transform.SetPositionAndRotation(new Vector3(player.transform.position.x, player.transform.position.y + 1.5f, player.transform.position.z), Quaternion.identity);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGameStart() // Creates health bars for each player
|
||||
{
|
||||
foreach (GameObject player in GameManager.players)
|
||||
{
|
||||
if (!playerHealthBars.ContainsKey(player))
|
||||
{
|
||||
GameObject healthBar = Instantiate(healthBarPrefab);
|
||||
healthBar.transform.localScale *= 1.5f;
|
||||
healthBar.GetComponent<TerribleHealthBarScript>().SetPlayer(player);
|
||||
playerHealthBars[player] = healthBar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGameEnd() // Destroys the health bars when the game ends
|
||||
{
|
||||
foreach (var kvp in playerHealthBars)
|
||||
{
|
||||
Destroy(kvp.Value);
|
||||
}
|
||||
playerHealthBars.Clear();
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/HealthBarManager.cs.meta
Normal file
2
Assets/Scripts/Game/HealthBarManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a80b536f823e50142b142b4e0b64ea97
|
||||
22
Assets/Scripts/Game/InfiniteScroll.cs
Normal file
22
Assets/Scripts/Game/InfiniteScroll.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class InfiniteScroll : MonoBehaviour
|
||||
{
|
||||
public float speed;
|
||||
public float start;
|
||||
public float end;
|
||||
|
||||
private void Update() // Moves the background
|
||||
{
|
||||
if (transform.position.x > end)
|
||||
{
|
||||
transform.position = new Vector3(start, transform.position.y, transform.position.z);
|
||||
}
|
||||
else if (transform.position.x < start)
|
||||
{
|
||||
transform.position = new Vector3(end, transform.position.y, transform.position.z);
|
||||
}
|
||||
|
||||
transform.position += speed * Time.deltaTime * Vector3.right;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/InfiniteScroll.cs.meta
Normal file
2
Assets/Scripts/Game/InfiniteScroll.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0e4599228c7142f9a5d65ab96f9fdc3
|
||||
88
Assets/Scripts/Game/LeaderboardManager.cs
Normal file
88
Assets/Scripts/Game/LeaderboardManager.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class LeaderboardManager : MonoBehaviour
|
||||
{
|
||||
public static LeaderboardManager Instance { get; private set; }
|
||||
|
||||
[SerializeField] private GameObject playersParent;
|
||||
[SerializeField] private GameObject playerPrefab;
|
||||
[SerializeField] private GameObject leaderboardIconPrefab;
|
||||
|
||||
private Dictionary<GameObject, GameObject> playerIcons = new Dictionary<GameObject, GameObject>();
|
||||
|
||||
private void Awake() // Ensures only one instance of LeaderboardManager exists
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitializeLeaderboard();
|
||||
}
|
||||
|
||||
private void InitializeLeaderboard() // Creates the leaderboard icons for each player
|
||||
{
|
||||
RectTransform parentRectTransform = playersParent.GetComponent<RectTransform>();
|
||||
parentRectTransform.anchoredPosition = new Vector2(-10f, 10f);
|
||||
|
||||
foreach (GameObject player in GameManager.players)
|
||||
{
|
||||
Transform parent = Instantiate(playerPrefab, playersParent.transform).transform;
|
||||
GameObject leaderboardIcon = Instantiate(leaderboardIconPrefab, parent);
|
||||
leaderboardIcon.GetComponentInChildren<Image>().color = GameManager.playerColors[GameManager.players.IndexOf(player)];
|
||||
playerIcons[player] = parent.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateLeaderboard()
|
||||
{
|
||||
List<KeyValuePair<GameObject, float>> sortedList = new List<KeyValuePair<GameObject, float>>(GameManager.playerHoldTimes);
|
||||
sortedList.Sort((pair1, pair2) => pair2.Value.CompareTo(pair1.Value));
|
||||
|
||||
for (int i = 0; i < sortedList.Count; i++)
|
||||
{
|
||||
var player = sortedList[i];
|
||||
playerIcons[player.Key].transform.SetSiblingIndex(i);
|
||||
|
||||
// Update the number text
|
||||
TextMeshProUGUI[] textComponents = playerIcons[player.Key].GetComponentsInChildren<TextMeshProUGUI>();
|
||||
foreach (var textComponent in textComponents)
|
||||
{
|
||||
if (textComponent.name == "Position Text")
|
||||
{
|
||||
textComponent.text = "#" + (i + 1).ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePlayerHoldTimeText(GameObject player, float holdTime)
|
||||
{
|
||||
if (playerIcons.ContainsKey(player))
|
||||
{
|
||||
TextMeshProUGUI[] textComponents = playerIcons[player].GetComponentsInChildren<TextMeshProUGUI>();
|
||||
foreach (var textComponent in textComponents)
|
||||
{
|
||||
if (textComponent.name == "Text (TMP)")
|
||||
{
|
||||
int minutes = Mathf.FloorToInt(holdTime / 60F);
|
||||
int seconds = Mathf.FloorToInt(holdTime % 60F);
|
||||
textComponent.text = string.Format("{0:0}:{1:00}", minutes, seconds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
2
Assets/Scripts/Game/LeaderboardManager.cs.meta
Normal file
2
Assets/Scripts/Game/LeaderboardManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94998096868b2f543ae7fcd946cc4f14
|
||||
46
Assets/Scripts/Game/LifeDisplayManager.cs
Normal file
46
Assets/Scripts/Game/LifeDisplayManager.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class LifeDisplayManager : MonoBehaviour
|
||||
{
|
||||
public GameObject players;
|
||||
public GameObject playerPrefab;
|
||||
public GameObject lifePrefab;
|
||||
public Dictionary<Damageable, List<GameObject>> lifeDisplays = new Dictionary<Damageable, List<GameObject>>();
|
||||
|
||||
private void Start() // Creates life icons for each player
|
||||
{
|
||||
if (GameManager.gameMode == GameManager.GameMode.freeForAll)
|
||||
{
|
||||
foreach (GameObject player in GameManager.players)
|
||||
{
|
||||
Transform parent = Instantiate(playerPrefab, players.transform).transform;
|
||||
List<GameObject> lives = new List<GameObject>();
|
||||
for (int i = 0; i < player.GetComponent<Damageable>().lives; i++)
|
||||
{
|
||||
GameObject life = Instantiate(lifePrefab, parent);
|
||||
life.transform.Find("LIFE").GetComponent<Image>().color = GameManager.playerColors[GameManager.players.IndexOf(player)];
|
||||
lives.Add(life);
|
||||
}
|
||||
lifeDisplays.Add(player.GetComponent<Damageable>(), lives);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update() // Updates the lives displayed based on player lives
|
||||
{
|
||||
foreach (Damageable damageable in lifeDisplays.Keys)
|
||||
{
|
||||
foreach (GameObject life in lifeDisplays[damageable])
|
||||
{
|
||||
life.SetActive(lifeDisplays[damageable].IndexOf(life) < damageable.lives);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HideLifeDisplay() // Hides life display
|
||||
{
|
||||
players.SetActive(false);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/LifeDisplayManager.cs.meta
Normal file
2
Assets/Scripts/Game/LifeDisplayManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e87378682ef9471d82043136357cc02
|
||||
18
Assets/Scripts/Game/MapSelect.cs
Normal file
18
Assets/Scripts/Game/MapSelect.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class MapSelect : MonoBehaviour
|
||||
{
|
||||
private ToggleGroup maps;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
maps = GetComponent<ToggleGroup>();
|
||||
}
|
||||
|
||||
void Update() // Sets the map based on the selected toggle
|
||||
{
|
||||
Toggle toggle = maps.GetFirstActiveToggle();
|
||||
GameManager.map = toggle.name;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/MapSelect.cs.meta
Normal file
2
Assets/Scripts/Game/MapSelect.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 200b7ae572458463f97cb3b2fb349152
|
||||
29
Assets/Scripts/Game/ModeSelect.cs
Normal file
29
Assets/Scripts/Game/ModeSelect.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class ModeSelect : MonoBehaviour
|
||||
{
|
||||
private ToggleGroup maps;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
maps = GetComponent<ToggleGroup>();
|
||||
}
|
||||
|
||||
void Update() // Updates the game mode based on the selected toggle
|
||||
{
|
||||
Toggle toggle = maps.GetFirstActiveToggle();
|
||||
if (toggle.name == "Free-For-All")
|
||||
{
|
||||
GameManager.gameMode = GameManager.GameMode.freeForAll;
|
||||
}
|
||||
else if (toggle.name == "Keep-Away")
|
||||
{
|
||||
GameManager.gameMode = GameManager.GameMode.keepAway;
|
||||
}
|
||||
else if (toggle.name == "Obstacle Course")
|
||||
{
|
||||
GameManager.gameMode = GameManager.GameMode.obstacleCourse;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/ModeSelect.cs.meta
Normal file
2
Assets/Scripts/Game/ModeSelect.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 234cf5c6ddbad406d9c687f76819ad6a
|
||||
30
Assets/Scripts/Game/MovingPlatform.cs
Normal file
30
Assets/Scripts/Game/MovingPlatform.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class MovingPlatform : MonoBehaviour
|
||||
{
|
||||
public Transform platform;
|
||||
public int startPoint;
|
||||
public Transform[] points;
|
||||
public float speed;
|
||||
private int i;
|
||||
|
||||
void Start() // Sets the initial position of the platform
|
||||
{
|
||||
transform.position = points[startPoint].position;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// If the platform is close to the target point, it starts moving to the next one
|
||||
if (Vector2.Distance(transform.position, points[i].position) < 0.02f)
|
||||
{
|
||||
i++;
|
||||
if (i == points.Length)
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
// Moves the platform towards the next point
|
||||
transform.position = Vector2.MoveTowards(transform.position, points[i].position, speed * Time.deltaTime);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/MovingPlatform.cs.meta
Normal file
2
Assets/Scripts/Game/MovingPlatform.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15a2da7226a2f054b9f96b2769e449e2
|
||||
26
Assets/Scripts/Game/ObjectVisibility.cs
Normal file
26
Assets/Scripts/Game/ObjectVisibility.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class ObjectVisibility : MonoBehaviour
|
||||
{
|
||||
void Start()
|
||||
{
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
private void UpdateVisibility() // Sets object visible if playing keep away mode
|
||||
{
|
||||
if (GameManager.gameMode == GameManager.GameMode.keepAway)
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/ObjectVisibility.cs.meta
Normal file
2
Assets/Scripts/Game/ObjectVisibility.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34a52816a1c62984ea622bbf50849c68
|
||||
14
Assets/Scripts/Game/PlayerJoinCard.cs
Normal file
14
Assets/Scripts/Game/PlayerJoinCard.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerJoinCard : MonoBehaviour
|
||||
{
|
||||
public GameObject playerPreview;
|
||||
public int playerNumber;
|
||||
public TextMeshProUGUI playerNumberText;
|
||||
|
||||
void Start() // Sets player number
|
||||
{
|
||||
playerNumberText.text = playerNumber.ToString();
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/PlayerJoinCard.cs.meta
Normal file
2
Assets/Scripts/Game/PlayerJoinCard.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d858973e2b6054f4281e30a4db77c8fe
|
||||
@@ -6,7 +6,7 @@ public class RespawnOnTriggerEnter : MonoBehaviour
|
||||
public bool spawnPointIsInitialPosition = false;
|
||||
public string respawnTag;
|
||||
|
||||
private void Start()
|
||||
private void Start() // Set the spawn point to the initial maps spawn point
|
||||
{
|
||||
if (spawnPointIsInitialPosition)
|
||||
{
|
||||
@@ -18,15 +18,10 @@ public class RespawnOnTriggerEnter : MonoBehaviour
|
||||
{
|
||||
if (other.CompareTag(respawnTag))
|
||||
{
|
||||
transform.position = spawnPoint;
|
||||
if (TryGetComponent<Rigidbody2D>(out var rb))
|
||||
if (TryGetComponent(out Damageable damageable))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
}
|
||||
if (TryGetComponent<Damageable>(out var damageable))
|
||||
{
|
||||
damageable.ResetDamage();
|
||||
damageable.Damage(9999f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Assets/Scripts/Game/TerribleHealthBarScript.cs
Normal file
80
Assets/Scripts/Game/TerribleHealthBarScript.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class TerribleHealthBarScript : MonoBehaviour
|
||||
{
|
||||
public Color fullHealthColor;
|
||||
public Color fullDeathColor;
|
||||
public Color subtractionColor;
|
||||
public GameObject healthVisual;
|
||||
public GameObject actualHealthVisual;
|
||||
public GameObject deathVisual;
|
||||
public float smoothSpeed = 0.1f;
|
||||
public TextMeshProUGUI text;
|
||||
private Damageable healthScript;
|
||||
|
||||
private Vector3 initialScale;
|
||||
private Vector3 initialPosition;
|
||||
private Vector3 targetScale;
|
||||
private Vector3 targetPosition;
|
||||
private Color targetActualColor;
|
||||
|
||||
public GameObject player;
|
||||
|
||||
void Start()
|
||||
{
|
||||
InitializePlayer(player);
|
||||
}
|
||||
|
||||
void Update() // Updates each player's health bar to display their current health
|
||||
{
|
||||
if (player == null || healthScript == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float healthRatio = (healthScript.maxDamage - healthScript.damage) / healthScript.maxDamage;
|
||||
|
||||
targetActualColor = Color.Lerp(fullDeathColor, fullHealthColor, healthRatio);
|
||||
targetScale = new Vector3(Mathf.Lerp(0, 1, healthRatio) * initialScale.x, healthVisual.transform.localScale.y, healthVisual.transform.localScale.z);
|
||||
targetPosition = new Vector3(Mathf.Lerp(-0.5f, 0, healthRatio), healthVisual.transform.localPosition.y, healthVisual.transform.localPosition.z);
|
||||
text.text = (healthScript.maxDamage - healthScript.damage).ToString() + "/" + healthScript.maxDamage.ToString();
|
||||
actualHealthVisual.transform.localScale = targetScale;
|
||||
actualHealthVisual.transform.localPosition = targetPosition;
|
||||
healthVisual.transform.localScale = Vector3.Lerp(healthVisual.transform.localScale, targetScale, smoothSpeed);
|
||||
healthVisual.transform.localPosition = Vector3.Lerp(healthVisual.transform.localPosition, targetPosition, smoothSpeed);
|
||||
actualHealthVisual.GetComponent<SpriteRenderer>().color = Color.Lerp(actualHealthVisual.GetComponent<SpriteRenderer>().color, targetActualColor, smoothSpeed);
|
||||
deathVisual.GetComponent<SpriteRenderer>().color = Color.Lerp(deathVisual.GetComponent<SpriteRenderer>().color, targetActualColor * 0.5f, smoothSpeed);
|
||||
healthVisual.GetComponent<SpriteRenderer>().color = subtractionColor;
|
||||
}
|
||||
|
||||
public void SetPlayer(GameObject player)
|
||||
{
|
||||
InitializePlayer(player);
|
||||
}
|
||||
|
||||
private void InitializePlayer(GameObject player) // Adds a health bar for each player
|
||||
{
|
||||
this.player = player;
|
||||
if (this.player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
healthScript = player.GetComponent<Damageable>();
|
||||
if (healthScript == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize() // Sets up the health bars
|
||||
{
|
||||
initialScale = healthVisual.transform.localScale;
|
||||
initialPosition = healthVisual.transform.position;
|
||||
targetScale = initialScale;
|
||||
targetPosition = initialPosition;
|
||||
targetActualColor = actualHealthVisual.GetComponent<SpriteRenderer>().color;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/TerribleHealthBarScript.cs.meta
Normal file
2
Assets/Scripts/Game/TerribleHealthBarScript.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c83fdf078a8b34ef7bb2829a58c1a545
|
||||
35
Assets/Scripts/Game/WinScreen.cs
Normal file
35
Assets/Scripts/Game/WinScreen.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
public class WinScreen : MonoBehaviour
|
||||
{
|
||||
public static WinScreen Instance;
|
||||
public List<TextMeshProUGUI> playerTexts;
|
||||
|
||||
private void Awake() // Ensures only one instance of WinScreen exists
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowWinScreen(int player) // Triggers the win screen to appear
|
||||
{
|
||||
foreach (TextMeshProUGUI playerText in playerTexts)
|
||||
{
|
||||
playerText.text = "Player " + player;
|
||||
if (playerText.color != Color.black)
|
||||
{
|
||||
playerText.color = GameManager.playerColors[player - 1];
|
||||
}
|
||||
}
|
||||
|
||||
GetComponent<Animator>().SetTrigger("win");
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/WinScreen.cs.meta
Normal file
2
Assets/Scripts/Game/WinScreen.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a15ab2e7ce7b04e19ae259be17276f08
|
||||
8
Assets/Scripts/Music.meta
Normal file
8
Assets/Scripts/Music.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5d30ab9d20fa416dbd26b382141fe1d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Scripts/Music/._MusicManager.cs
Normal file
BIN
Assets/Scripts/Music/._MusicManager.cs
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._MusicManager.cs.meta
Normal file
BIN
Assets/Scripts/Music/._MusicManager.cs.meta
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._MusicTrack.cs
Normal file
BIN
Assets/Scripts/Music/._MusicTrack.cs
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._MusicTrack.cs.meta
Normal file
BIN
Assets/Scripts/Music/._MusicTrack.cs.meta
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._TrackLayer.cs
Normal file
BIN
Assets/Scripts/Music/._TrackLayer.cs
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._TrackLayer.cs.meta
Normal file
BIN
Assets/Scripts/Music/._TrackLayer.cs.meta
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._TrackManager.cs
Normal file
BIN
Assets/Scripts/Music/._TrackManager.cs
Normal file
Binary file not shown.
BIN
Assets/Scripts/Music/._TrackManager.cs.meta
Normal file
BIN
Assets/Scripts/Music/._TrackManager.cs.meta
Normal file
Binary file not shown.
117
Assets/Scripts/Music/MusicManager.cs
Normal file
117
Assets/Scripts/Music/MusicManager.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions.Must;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class MusicManager : MonoBehaviour
|
||||
{
|
||||
public static MusicManager Instance;
|
||||
public List<Playlist> playlists;
|
||||
private Dictionary<string, Playlist> sceneToPlaylist = new Dictionary<string, Playlist>();
|
||||
public GameObject songPrefab;
|
||||
|
||||
private void Awake() // Creates only one MusicManager instance at a time
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
|
||||
foreach (Playlist playlist in playlists)
|
||||
{
|
||||
foreach (string scene in playlist.trackScenes)
|
||||
{
|
||||
sceneToPlaylist.Add(scene, playlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StartPlaylist() // Starts music playlist for each scene
|
||||
{
|
||||
if (GetActiveSceneNotTitleScreen() == "Player Select") return;
|
||||
StopAllCoroutines();
|
||||
foreach (Transform child in transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
try
|
||||
{
|
||||
StartCoroutine(PlayPlaylist(sceneToPlaylist[GetActiveSceneNotTitleScreen()]));
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
|
||||
print("No playlist found for this scene: " + GetActiveSceneNotTitleScreen());
|
||||
}
|
||||
}
|
||||
|
||||
public void StartPlaylist(string scene) // Sets music for Title Screen
|
||||
{
|
||||
if (GetActiveSceneNotTitleScreen() == "Player Select") return;
|
||||
StopAllCoroutines();
|
||||
foreach (Transform child in transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
StartCoroutine(PlayPlaylist(sceneToPlaylist[scene]));
|
||||
}
|
||||
|
||||
private IEnumerator PlayPlaylist(Playlist playlist)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Shuffles the playlist
|
||||
List<AudioClip> randomized = new List<AudioClip>(playlist.songs);
|
||||
for (int i = 0; i < randomized.Count; i++)
|
||||
{
|
||||
AudioClip temp = randomized[i];
|
||||
int randomIndex = Random.Range(i, randomized.Count);
|
||||
randomized[i] = randomized[randomIndex];
|
||||
randomized[randomIndex] = temp;
|
||||
}
|
||||
|
||||
// Starts the music in the playlist
|
||||
foreach (AudioClip song in randomized)
|
||||
{
|
||||
AudioSource songInstance = Instantiate(songPrefab, transform).GetComponent<AudioSource>();
|
||||
songInstance.clip = song;
|
||||
songInstance.volume = playlist.volume;
|
||||
songInstance.Play();
|
||||
if (playlist.shuffleTime > 0f)
|
||||
{
|
||||
yield return new WaitForSeconds(playlist.shuffleTime);
|
||||
float time = 0f;
|
||||
while (time < 5f)
|
||||
{
|
||||
songInstance.volume = playlist.volume * (1 - time / 5f);
|
||||
time += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new WaitForSeconds(song.length);
|
||||
}
|
||||
Destroy(songInstance.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetActiveSceneNotTitleScreen() // Finds the scene name besides Title Screen
|
||||
{
|
||||
for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++)
|
||||
{
|
||||
if (SceneManager.GetSceneAt(sceneIndex).name != "Title Screen")
|
||||
{
|
||||
return SceneManager.GetSceneAt(sceneIndex).name;
|
||||
}
|
||||
}
|
||||
return "Title Screen";
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Music/MusicManager.cs.meta
Normal file
11
Assets/Scripts/Music/MusicManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f701561e8549d464b9530bb56c6bfeb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -50
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
14
Assets/Scripts/Music/Playlist.cs
Normal file
14
Assets/Scripts/Music/Playlist.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
[System.Serializable]
|
||||
public class Playlist
|
||||
{
|
||||
public string trackName;
|
||||
public List<string> trackScenes;
|
||||
public List<AudioClip> songs;
|
||||
public float shuffleTime;
|
||||
public float volume;
|
||||
}
|
||||
11
Assets/Scripts/Music/Playlist.cs.meta
Normal file
11
Assets/Scripts/Music/Playlist.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7217d9ffc9dfd0c42bd093ee6d9c5db1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
Assets/Scripts/Music/TrackLayer.cs
Normal file
16
Assets/Scripts/Music/TrackLayer.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
[System.Serializable]
|
||||
public class TrackLayer
|
||||
{
|
||||
public string layerName;
|
||||
public AudioClip layerTrack;
|
||||
public enum EnableTrigger { Scene, Magnetism, Goal, Button, Toggle, Movement, ConstantForce, EndOfLevel, ElectromagneticPulse, Collectible };
|
||||
public EnableTrigger enableTrigger = EnableTrigger.Scene;
|
||||
|
||||
public List<string> layerScenes;
|
||||
public string triggerName;
|
||||
}
|
||||
11
Assets/Scripts/Music/TrackLayer.cs.meta
Normal file
11
Assets/Scripts/Music/TrackLayer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a0b53b66b1b30143a043e7df151c454
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
366
Assets/Scripts/Music/TrackManager.cs
Normal file
366
Assets/Scripts/Music/TrackManager.cs
Normal file
@@ -0,0 +1,366 @@
|
||||
#if NO
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class TrackManager : MonoBehaviour
|
||||
{
|
||||
public Playlist musicTrack;
|
||||
public GameObject layerPrefab;
|
||||
|
||||
private List<TrackLayer> persistentLayers = new List<TrackLayer>();
|
||||
|
||||
private Scene currentScene;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (!GameManager.music)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
foreach (var layer in musicTrack.trackLayers)
|
||||
{
|
||||
if (layer.enableTrigger != TrackLayer.EnableTrigger.Scene)
|
||||
{
|
||||
persistentLayers.Add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
currentScene = GetActiveSceneNotStatistics();
|
||||
InitializeLayers();
|
||||
UpdateLayers(musicTrack.trackLayers);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
CheckForRestartability();
|
||||
|
||||
if (currentScene != GetActiveSceneNotStatistics())
|
||||
{
|
||||
currentScene = GetActiveSceneNotStatistics();
|
||||
UpdateLayers(musicTrack.trackLayers);
|
||||
}
|
||||
|
||||
if (persistentLayers.Count != 0) UpdateLayers(persistentLayers);
|
||||
}
|
||||
|
||||
private void InitializeLayers()
|
||||
{
|
||||
foreach (TrackLayer layer in musicTrack.trackLayers)
|
||||
{
|
||||
AudioSource layerSource = Instantiate(layerPrefab, transform).GetComponent<AudioSource>();
|
||||
layerSource.gameObject.name = layer.layerName;
|
||||
layerSource.clip = layer.layerTrack;
|
||||
layerSource.volume = 0;
|
||||
|
||||
try
|
||||
{
|
||||
layerSource.outputAudioMixerGroup = musicTrack.defaultMixer.FindMatchingGroups("Master/" + layer.layerName)[0];
|
||||
}
|
||||
catch
|
||||
{
|
||||
layerSource.outputAudioMixerGroup = musicTrack.defaultMixer.FindMatchingGroups("Master")[0];
|
||||
}
|
||||
|
||||
layerSource.Play();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLayers(List<TrackLayer> layers)
|
||||
{
|
||||
if (StatisticsManager.PlayerPrefs.GetInt("settingMusic") == 1)
|
||||
{
|
||||
foreach (TrackLayer layer in layers)
|
||||
{
|
||||
DisableLayer(layer);
|
||||
|
||||
if (layer.enableTrigger == TrackLayer.EnableTrigger.Magnetism)
|
||||
{
|
||||
GameObject player = GameObject.Find(layer.triggerName);
|
||||
try
|
||||
{
|
||||
if (player != null && (player.GetComponent<PlayerMovement>().magnetized/* || FindFirstObjectByType<LevelEnd>().ending*/))
|
||||
{
|
||||
if (layer.layerScenes.Count == 0)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
print(e.ToString());
|
||||
}
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.Movement)
|
||||
{
|
||||
GameObject player = GameObject.Find(layer.triggerName);
|
||||
try
|
||||
{
|
||||
if (player != null && player.GetComponent<Rigidbody2D>().linearVelocity.magnitude >= 0.1f)
|
||||
{
|
||||
if (layer.layerScenes.Count == 0)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
print(e.ToString());
|
||||
}
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.ConstantForce)
|
||||
{
|
||||
GameObject player = GameObject.Find(layer.triggerName);
|
||||
try
|
||||
{
|
||||
if (player != null && player.GetComponent<ConstantForce2D>().force.magnitude >= 0.1f)
|
||||
{
|
||||
if (layer.layerScenes.Count == 0)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
print(e.ToString());
|
||||
}
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.Toggle)
|
||||
{
|
||||
GameObject toggle = GameObject.Find(layer.triggerName);
|
||||
try
|
||||
{
|
||||
if (toggle != null && toggle.GetComponent<ToggleBehavior>().state == ToggleBehavior.ToggleState.active)
|
||||
{
|
||||
if (layer.layerScenes.Count == 0)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
print(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.Button)
|
||||
{
|
||||
GameObject button = GameObject.Find(layer.triggerName);
|
||||
try
|
||||
{
|
||||
if (button != null && button.GetComponent<ButtonBehavior>().state == ButtonBehavior.ButtonState.pressed)
|
||||
{
|
||||
if (layer.layerScenes.Count == 0)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
print(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.Goal)
|
||||
{
|
||||
GameObject goal = GameObject.Find(layer.triggerName);
|
||||
try
|
||||
{
|
||||
if (goal != null && goal.GetComponent<Goal>().isActivated)
|
||||
{
|
||||
if (layer.layerScenes.Count == 0)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
print(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.EndOfLevel)
|
||||
{
|
||||
if (FindFirstObjectByType<LevelEnd>().ending)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.ElectromagneticPulse)
|
||||
{
|
||||
if (Camera.main.GetComponent<CameraFollow>().playTheTrack)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
}
|
||||
}
|
||||
else if (layer.enableTrigger == TrackLayer.EnableTrigger.Collectible)
|
||||
{
|
||||
if (FindFirstObjectByType<Collectible>().playTheTrack)
|
||||
{
|
||||
EnableLayer(layer, "collectibleEnabled");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string scene in layer.layerScenes)
|
||||
{
|
||||
if (scene == currentScene.name)
|
||||
{
|
||||
EnableLayer(layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForRestartability()
|
||||
{
|
||||
bool restart = false;
|
||||
|
||||
for (int i = 0; i < transform.childCount; i++)
|
||||
{
|
||||
AudioSource child = transform.GetChild(i).GetComponent<AudioSource>();
|
||||
if (child != null)
|
||||
{
|
||||
if (!child.isPlaying)
|
||||
{
|
||||
restart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!restart) return;
|
||||
|
||||
for (int i = 0; i < transform.childCount; i++)
|
||||
{
|
||||
AudioSource child = transform.GetChild(i).GetComponent<AudioSource>();
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
child.Stop();
|
||||
child.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableLayer(TrackLayer layer, string parameter = "enabled")
|
||||
{
|
||||
transform.Find(layer.layerName).GetComponent<Animator>().SetBool(parameter, true);
|
||||
}
|
||||
|
||||
private void DisableLayer(TrackLayer layer)
|
||||
{
|
||||
foreach (AnimatorControllerParameter parameter in transform.Find(layer.layerName).GetComponent<Animator>().parameters)
|
||||
{
|
||||
transform.Find(layer.layerName).GetComponent<Animator>().SetBool(parameter.name, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Scene GetActiveSceneNotStatistics()
|
||||
{
|
||||
for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++)
|
||||
{
|
||||
if (SceneManager.GetSceneAt(sceneIndex).name != "Statistics Manager Scene")
|
||||
{
|
||||
return SceneManager.GetSceneAt(sceneIndex);
|
||||
}
|
||||
}
|
||||
return SceneManager.GetSceneByBuildIndex(0);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
StartCoroutine(DestroyTrack());
|
||||
}
|
||||
|
||||
public IEnumerator DestroyTrack()
|
||||
{
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
Assets/Scripts/Music/TrackManager.cs.meta
Normal file
11
Assets/Scripts/Music/TrackManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f4092644348346419647bf86cb02003
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Player.meta
Normal file
8
Assets/Scripts/Player.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9544c3283a37464f88c711b2bcd2f17
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,33 +3,32 @@ using UnityEngine;
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class AnimationPlayer : MonoBehaviour
|
||||
{
|
||||
public enum AnimationState { Idle, Run, Jump };
|
||||
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()
|
||||
private void Start() // Plays the specified animation clip
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
animator.Play(clip.name);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
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);
|
||||
}
|
||||
|
||||
public void SetState(AnimationState state)
|
||||
public void SetState(AnimationState state) // Sets the animation state
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void Punch()
|
||||
public void Punch() // Triggers punch animation
|
||||
{
|
||||
animator.SetTrigger("punch");
|
||||
}
|
||||
57
Assets/Scripts/Player/Block.cs
Normal file
57
Assets/Scripts/Player/Block.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
[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()
|
||||
{
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
|
||||
private void Update() // Player blocks when "block" is pressed
|
||||
{
|
||||
InputAction blockAction = actions.FindAction("Block");
|
||||
if (blockAction.ReadValue<float>() == 1f)
|
||||
{
|
||||
if (!blocking)
|
||||
{
|
||||
blockPressTime = Time.time; // Start parry timer
|
||||
}
|
||||
blocking = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (blocking) // Successful parry if blocked in time
|
||||
{
|
||||
float pressDuration = Time.time - blockPressTime;
|
||||
if (pressDuration <= parryThreshold)
|
||||
{
|
||||
Parry();
|
||||
}
|
||||
else
|
||||
{
|
||||
isParrying = false;
|
||||
}
|
||||
}
|
||||
blocking = false;
|
||||
}
|
||||
GetComponent<AnimationPlayer>().block = blocking;
|
||||
}
|
||||
|
||||
private void Parry()
|
||||
{
|
||||
isParrying = true;
|
||||
}
|
||||
|
||||
public bool IsParrying()
|
||||
{
|
||||
return isParrying;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Player/Block.cs.meta
Normal file
2
Assets/Scripts/Player/Block.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8c9288561905664eade3f6b2634fc6d
|
||||
136
Assets/Scripts/Player/Damageable.cs
Normal file
136
Assets/Scripts/Player/Damageable.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
[RequireComponent(typeof(RespawnOnTriggerEnter))]
|
||||
public class Damageable : MonoBehaviour
|
||||
{
|
||||
public float force = 50f; // Force applied when hit
|
||||
public float damage = 0f;
|
||||
public float maxDamage = 1000f; // Set max health
|
||||
public int lives = 0;
|
||||
private Animator animator;
|
||||
public bool damageSelfDebug = false;
|
||||
public bool dying = false;
|
||||
public event System.Action<GameObject> OnPlayerPunched;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (damageSelfDebug)
|
||||
{
|
||||
damageSelfDebug = false;
|
||||
Damage(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D collision) // Calls Damage method when player is hit
|
||||
{
|
||||
if (collision.gameObject.CompareTag("Punch Hurtbox"))
|
||||
{
|
||||
Damage(collision.transform.parent.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Damage(GameObject damageSource) // Damages player
|
||||
{
|
||||
if (dying || damageSource.CompareTag("Hat")) return; // Exclude hat from taking damage
|
||||
|
||||
float actualForce = damageSource.GetComponent<Damageable>().force;
|
||||
Block blockComponent = GetComponent<Block>();
|
||||
|
||||
GetComponentInChildren<UseItem>().DropItem(); // Drops hat if held
|
||||
|
||||
if (blockComponent != null && blockComponent.blocking)
|
||||
{
|
||||
if (blockComponent.IsParrying()) // Player receives damage if punching a parrying player
|
||||
{
|
||||
damageSource.GetComponent<Damageable>().SuccessfulParry(gameObject, actualForce);
|
||||
return;
|
||||
}
|
||||
else // Player does less damage if punching a blocking player
|
||||
{
|
||||
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
|
||||
{
|
||||
GetComponent<Rigidbody2D>().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * actualForce * (1 + (damage / maxDamage) * 3), ForceMode2D.Force);
|
||||
}
|
||||
damage += actualForce;
|
||||
damage = Mathf.Clamp(damage, 0f, maxDamage);
|
||||
if (damage >= maxDamage)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
public void Damage(float damage) // Adds damage to player when hit
|
||||
{
|
||||
if (GameManager.Instance.gameOver) return; // Prevent damage after game is over
|
||||
|
||||
this.damage += damage;
|
||||
if (damage >= maxDamage)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
private void SuccessfulParry(GameObject damageSource, float force)
|
||||
{
|
||||
GetComponent<Rigidbody2D>().AddForce(((transform.position - damageSource.transform.position).normalized + Vector3.up * 2) * force, ForceMode2D.Force);
|
||||
damage += force;
|
||||
damage = Mathf.Clamp(damage, 0f, maxDamage);
|
||||
if (damage >= maxDamage)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
private void Die() // Triggers death animation and sets player to dying state
|
||||
{
|
||||
if (GameManager.Instance != null && !GameManager.Instance.gameOver) // Prevent death after game is over
|
||||
{
|
||||
UseItem useItem = GetComponent<UseItem>();
|
||||
if (useItem != null)
|
||||
{
|
||||
useItem.DropItem(); // Ensure the player drops the item before the death animation
|
||||
}
|
||||
animator.SetBool("die", true);
|
||||
dying = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleDeath() // Removes player from dying state after respawn
|
||||
{
|
||||
GameManager.Instance.PlayerDied(this);
|
||||
animator.SetBool("die", false);
|
||||
dying = false;
|
||||
}
|
||||
|
||||
public void Respawn() // Respawns player to the spawnPosition and resets damage/health bar
|
||||
{
|
||||
transform.position = GameManager.Instance.spawnPosition;
|
||||
if (TryGetComponent<Rigidbody2D>(out var rb))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
rb.angularVelocity = 0f;
|
||||
}
|
||||
if (TryGetComponent<Damageable>(out var damageable))
|
||||
{
|
||||
damageable.ResetDamage();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetDamage()
|
||||
{
|
||||
damage = 0f;
|
||||
}
|
||||
}
|
||||
86
Assets/Scripts/Player/PlayerCameraMovement.cs
Normal file
86
Assets/Scripts/Player/PlayerCameraMovement.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
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()
|
||||
{
|
||||
start = transform.position;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (winScene) // If the game is over, the camera will follow the player that won
|
||||
{
|
||||
if (playerThatWon == null || !playerThatWon.activeInHierarchy)
|
||||
{
|
||||
playerThatWon = FindWinner();
|
||||
}
|
||||
|
||||
if (playerThatWon != null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
transform.position = new Vector3(transform.position.x, lowerBound, transform.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
97
Assets/Scripts/Player/PlayerManager.cs
Normal file
97
Assets/Scripts/Player/PlayerManager.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
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()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GetComponent<PlayerInputManager>().onPlayerJoined += OnPlayerJoined;
|
||||
GetComponent<PlayerInputManager>().onPlayerLeft += OnPlayerLeft;
|
||||
}
|
||||
|
||||
private void OnPlayerJoined(PlayerInput playerInput) // Adds a player when they join
|
||||
{
|
||||
if (gameStarted)
|
||||
{
|
||||
Destroy(playerInput.gameObject);
|
||||
return;
|
||||
}
|
||||
Debug.Log("Player joined");
|
||||
DontDestroyOnLoad(playerInput.gameObject);
|
||||
PlayerJoinCard card = PlayerCardCreator.Instance.CreateCard();
|
||||
card.playerNumber = GameManager.players.Count + 1;
|
||||
cards.Add(card);
|
||||
GameManager.players.Add(playerInput.gameObject);
|
||||
Colorize(GameManager.players.Count - 1);
|
||||
}
|
||||
|
||||
|
||||
private void OnPlayerLeft(PlayerInput playerInput) // Removes the player if they leave
|
||||
{
|
||||
Destroy(playerInput.gameObject);
|
||||
GameManager.players.Remove(playerInput.gameObject);
|
||||
Debug.Log("Player left");
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartGame() // Allows game to start after a player has joined
|
||||
{
|
||||
if (GameManager.players.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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 _))
|
||||
{
|
||||
obj.GetComponent<SpriteRenderer>().color = color;
|
||||
}
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
if (child.TryGetComponent<SpriteRenderer>(out _))
|
||||
{
|
||||
ApplyColor(child.gameObject, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections;
|
||||
using TMPro;
|
||||
using Unity.IO.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(BoxCollider2D))]
|
||||
@@ -18,19 +18,20 @@ public class PlayerMovement : MonoBehaviour
|
||||
|
||||
[Header("Movement")]
|
||||
public float walkSpeed;
|
||||
public float walkSpeedFactor = 1f;
|
||||
public float maxSpeed = 5f;
|
||||
public float slowdownMultiplier = 10f;
|
||||
public float walkSpeedFactor = 1f; // Sets walk speed
|
||||
public float maxSpeed = 5f; // Sets max speed
|
||||
public float maxSpeedOverride;
|
||||
public float slowdownMultiplier = 10f; // Sets slow walk speed
|
||||
public float virtualAxisX;
|
||||
public float virtualButtonJump;
|
||||
public float virtualButtonJumpLastFrame;
|
||||
public float turnaroundMultiplier = 2;
|
||||
public float turnaroundMultiplier = 2; // Sets speed when turning around
|
||||
public float walkSmooth;
|
||||
public float secondsToFullSpeed;
|
||||
public float jumpSpeed;
|
||||
public float coyoteTime;
|
||||
public float jumpLenience;
|
||||
public float timeUnableToBeDeclaredNotJumping = 0.1f;
|
||||
public float timeUnableToBeDeclaredNotJumping = 0.1f; // Jump threshold
|
||||
public float groundCheckDistance;
|
||||
|
||||
private Rigidbody2D body;
|
||||
@@ -38,22 +39,20 @@ public class PlayerMovement : MonoBehaviour
|
||||
private PlayerInput input;
|
||||
private AnimationPlayer animationPlayer;
|
||||
private Punch punch;
|
||||
private Damageable damageable;
|
||||
|
||||
private bool jumpInputStillValid = false;
|
||||
private float lastTimeJumpPressed;
|
||||
|
||||
private bool canBeDeclaredNotJumping = true;
|
||||
|
||||
private bool jumpPhysics;
|
||||
|
||||
private bool jumping;
|
||||
|
||||
private float lastTimeJumpPressed;
|
||||
private float lastTimeOnGround;
|
||||
|
||||
private Vector3 positionLastFrame;
|
||||
|
||||
void Start()
|
||||
void Start() // Sets up player components
|
||||
{
|
||||
maxSpeedOverride = maxSpeed;
|
||||
GetComponent<RespawnOnTriggerEnter>().spawnPoint = transform.position;
|
||||
|
||||
body = GetComponent<Rigidbody2D>();
|
||||
@@ -61,12 +60,16 @@ public class PlayerMovement : MonoBehaviour
|
||||
input = GetComponent<PlayerInput>();
|
||||
animationPlayer = GetComponent<AnimationPlayer>();
|
||||
punch = GetComponent<Punch>();
|
||||
damageable = GetComponent<Damageable>();
|
||||
|
||||
playerText.text = input.playerIndex.ToString();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
private void Update() // Updates player movement
|
||||
{
|
||||
if (GameManager.Instance != null && GameManager.Instance.gameOver) maxSpeed = 1f;
|
||||
if (damageable.dying) return;
|
||||
|
||||
Jump();
|
||||
|
||||
UpdateVirtualAxis();
|
||||
@@ -81,19 +84,19 @@ public class PlayerMovement : MonoBehaviour
|
||||
Land();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
private void LateUpdate()
|
||||
{
|
||||
Animate();
|
||||
}
|
||||
|
||||
private void Animate()
|
||||
private void Animate() // Sets player animation
|
||||
{
|
||||
if (!IsPhysicallyGrounded())
|
||||
animationPlayer.SetState(AnimationPlayer.AnimationState.Jump);
|
||||
else
|
||||
{
|
||||
if (Mathf.Abs(body.linearVelocityX) >= 0.1f)
|
||||
animationPlayer.SetState(AnimationPlayer.AnimationState.Run);
|
||||
if (Mathf.Abs(body.linearVelocityX) >= 0.05f)
|
||||
animationPlayer.SetState(GameManager.Instance.gameOver ? AnimationPlayer.AnimationState.Walk : AnimationPlayer.AnimationState.Run);
|
||||
else
|
||||
animationPlayer.SetState(AnimationPlayer.AnimationState.Idle);
|
||||
}
|
||||
@@ -104,7 +107,7 @@ public class PlayerMovement : MonoBehaviour
|
||||
animationPlayer.backwards = false;
|
||||
}
|
||||
|
||||
private void Land()
|
||||
private void Land() // Stops jumping when player lands
|
||||
{
|
||||
if (body.linearVelocity.y >= 0f) return;
|
||||
|
||||
@@ -117,10 +120,8 @@ public class PlayerMovement : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private void Jump()
|
||||
private void Jump() // Player jumps when 'jump' is pressed
|
||||
{
|
||||
//if (!punch.cancelable) return;
|
||||
|
||||
if (virtualButtonJumpLastFrame == 1f)
|
||||
{
|
||||
jumpInputStillValid = true;
|
||||
@@ -138,12 +139,19 @@ public class PlayerMovement : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private void JumpPhysics()
|
||||
private void JumpPhysics() // Applies jump physics
|
||||
{
|
||||
if (jumpPhysics)
|
||||
{
|
||||
if (body.linearVelocity.y < 0 || !IsPhysicallyGrounded()) body.linearVelocity = new Vector2(body.linearVelocity.x, 0);
|
||||
body.AddForce(Vector2.up * jumpSpeed, ForceMode2D.Impulse);
|
||||
if (!GetComponent<Block>().blocking)
|
||||
{
|
||||
if (body.linearVelocity.y < 0 || !IsPhysicallyGrounded()) body.linearVelocity = new Vector2(body.linearVelocity.x, 0);
|
||||
body.AddForce(Vector2.up * jumpSpeed, ForceMode2D.Impulse);
|
||||
if (Mathf.Abs(body.linearVelocityX) > maxSpeed)
|
||||
{
|
||||
body.linearVelocity = new Vector2(Mathf.Sign(body.linearVelocityX) * maxSpeed, body.linearVelocity.y);
|
||||
}
|
||||
}
|
||||
jumpPhysics = false;
|
||||
}
|
||||
|
||||
@@ -151,22 +159,26 @@ public class PlayerMovement : MonoBehaviour
|
||||
body.AddForce(Vector2.down * jumpSpeed);
|
||||
}
|
||||
|
||||
private IEnumerator NotJumpingDelay()
|
||||
private IEnumerator NotJumpingDelay() // Sets jump threshold
|
||||
{
|
||||
canBeDeclaredNotJumping = false;
|
||||
yield return new WaitUntil(() => !IsBasicallyGrounded());
|
||||
canBeDeclaredNotJumping = true;
|
||||
}
|
||||
|
||||
private void HorizontalMovement()
|
||||
private void HorizontalMovement() // Sets player horizontal movement
|
||||
{
|
||||
//if (!punch.cancelable) return;
|
||||
float temporaryMax = IsPhysicallyGrounded() ? maxSpeedOverride : Mathf.Infinity;
|
||||
float temporarySlowdown = IsPhysicallyGrounded() ? slowdownMultiplier : 1;
|
||||
|
||||
body.AddForce(new Vector2(virtualAxisX * walkSpeed * walkSpeedFactor, 0), ForceMode2D.Force);
|
||||
|
||||
if (Mathf.Abs(body.linearVelocityX) >= maxSpeed)
|
||||
if (!GetComponent<Block>().blocking && (Mathf.Abs(body.linearVelocityX) <= maxSpeed || Mathf.Sign(body.linearVelocityX) != Mathf.Sign(virtualAxisX)))
|
||||
{
|
||||
body.AddForce(new Vector2(-Mathf.Sign(body.linearVelocityX) * (Mathf.Abs(body.linearVelocityX) - maxSpeed) * slowdownMultiplier, 0));
|
||||
body.AddForce(new Vector2(virtualAxisX * walkSpeed * walkSpeedFactor, 0), ForceMode2D.Force);
|
||||
}
|
||||
|
||||
if (Mathf.Abs(body.linearVelocityX) >= temporaryMax)
|
||||
{
|
||||
body.AddForce(new Vector2(-Mathf.Sign(body.linearVelocityX) * (Mathf.Abs(body.linearVelocityX) - temporaryMax) * temporarySlowdown, 0));
|
||||
}
|
||||
|
||||
if (transform.position == positionLastFrame && (input.actions.FindAction("Move").ReadValue<Vector2>().x == 0))
|
||||
@@ -174,10 +186,15 @@ public class PlayerMovement : MonoBehaviour
|
||||
virtualAxisX = 0;
|
||||
}
|
||||
|
||||
if (GetComponent<Block>().blocking)
|
||||
{
|
||||
body.AddForce(new Vector2(-body.linearVelocityX * 0.8f, 0), ForceMode2D.Force);
|
||||
}
|
||||
|
||||
positionLastFrame = transform.position;
|
||||
}
|
||||
|
||||
private void UpdateVirtualAxis()
|
||||
private void UpdateVirtualAxis() // Updates virtual axis
|
||||
{
|
||||
virtualButtonJump = input.actions.FindAction("Action").ReadValue<float>();
|
||||
virtualButtonJumpLastFrame = input.actions.FindAction("Action").WasPressedThisFrame() ? 1 : 0;
|
||||
@@ -186,7 +203,7 @@ public class PlayerMovement : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
public bool IsBasicallyGrounded()
|
||||
public bool IsBasicallyGrounded() // Checks if player is on land within a threshold
|
||||
{
|
||||
if (IsPhysicallyGrounded())
|
||||
{
|
||||
@@ -201,7 +218,7 @@ public class PlayerMovement : MonoBehaviour
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsPhysicallyGrounded()
|
||||
public bool IsPhysicallyGrounded() // Checks if player is on land
|
||||
{
|
||||
RaycastHit2D leftCheck = Physics2D.Raycast(GetPointInBoxCollider(collide, -1, -1), Vector2.down, groundCheckDistance, ground);
|
||||
RaycastHit2D rightCheck = Physics2D.Raycast(GetPointInBoxCollider(collide, 1, -1), Vector2.down, groundCheckDistance, ground);
|
||||
@@ -215,7 +232,7 @@ public class PlayerMovement : MonoBehaviour
|
||||
return false;
|
||||
}
|
||||
|
||||
public Vector2 GetPointInBoxCollider(BoxCollider2D boxCollider2D, float horizontal, float vertical)
|
||||
public Vector2 GetPointInBoxCollider(BoxCollider2D boxCollider2D, float horizontal, float vertical)
|
||||
{
|
||||
return new Vector2
|
||||
(
|
||||
@@ -224,7 +241,7 @@ public class PlayerMovement : MonoBehaviour
|
||||
);
|
||||
}
|
||||
|
||||
public void StopVelocity()
|
||||
public void StopVelocity() // Stops inertia when landed
|
||||
{
|
||||
if (IsPhysicallyGrounded()) body.linearVelocity = Vector2.zero;
|
||||
}
|
||||
59
Assets/Scripts/Player/Punch.cs
Normal file
59
Assets/Scripts/Player/Punch.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
[RequireComponent(typeof(AnimationPlayer))]
|
||||
public class Punch : MonoBehaviour
|
||||
{
|
||||
public bool cancelable = true;
|
||||
|
||||
[SerializeField] private BoxCollider2D hurtbox;
|
||||
|
||||
InputActionAsset actions;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
|
||||
private void Update() // Executes punch when 'punch' is pressed
|
||||
{
|
||||
if (actions.FindAction("Punch").WasPressedThisFrame())
|
||||
{
|
||||
if (!cancelable) return;
|
||||
ExecutePunch();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
37
Assets/Scripts/Player/TeleportPlatform.cs
Normal file
37
Assets/Scripts/Player/TeleportPlatform.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class TeleportPlatform : MonoBehaviour
|
||||
{
|
||||
public Vector2 teleportPoint;
|
||||
public string teleportTag;
|
||||
public string playerTag = "Player";
|
||||
public bool isPlatform = true;
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (!isPlatform)
|
||||
{
|
||||
// Teleports the platform
|
||||
if (collision.CompareTag(teleportTag))
|
||||
{
|
||||
transform.position = teleportPoint;
|
||||
if (TryGetComponent<Rigidbody2D>(out var rb))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Teleports the player
|
||||
if (collision.CompareTag(playerTag))
|
||||
{
|
||||
collision.transform.position = teleportPoint;
|
||||
if (collision.TryGetComponent<Rigidbody2D>(out var rb))
|
||||
{
|
||||
rb.linearVelocity = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Player/TeleportPlatform.cs.meta
Normal file
2
Assets/Scripts/Player/TeleportPlatform.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 182a9e619d36aeb4592fb532d3c9db55
|
||||
97
Assets/Scripts/Player/UseItem.cs
Normal file
97
Assets/Scripts/Player/UseItem.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
public class UseItem : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string itemTag;
|
||||
private GameObject heldItem;
|
||||
private bool isHoldingItem = false;
|
||||
private float holdStartTime;
|
||||
public float holdTime;
|
||||
private Damageable damageable;
|
||||
|
||||
[SerializeField] public Transform head;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
damageable = GetComponent<Damageable>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (isHoldingItem)
|
||||
{
|
||||
// Keeps hat on the player's head
|
||||
heldItem.transform.localPosition = Vector3.zero;
|
||||
if (GameManager.gameMode == GameManager.GameMode.keepAway)
|
||||
{
|
||||
// Adds time to the player's leaderboard standing
|
||||
holdTime += Time.deltaTime;
|
||||
GameManager.Instance.UpdatePlayerHoldTime(gameObject, holdTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollisionEnter2D(Collision2D collision) // Player automatically picks up hat when touching it
|
||||
{
|
||||
if (collision.gameObject.CompareTag("Hat") && !isHoldingItem && !damageable.dying)
|
||||
{
|
||||
PickUpItem(collision.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void PickUpItem(GameObject item) // Player picks up hat and starts hold counter
|
||||
{
|
||||
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
|
||||
|
||||
heldItem = item;
|
||||
isHoldingItem = true;
|
||||
holdStartTime = Time.time;
|
||||
item.GetComponent<Collider2D>().enabled = false;
|
||||
item.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Static;
|
||||
item.GetComponent<HatRespawn>().Interact();
|
||||
item.transform.parent = head;
|
||||
item.transform.localRotation = Quaternion.identity;
|
||||
item.transform.localPosition = Vector3.zero;
|
||||
if (!GameManager.playerHoldTimes.ContainsKey(gameObject))
|
||||
{
|
||||
GameManager.playerHoldTimes[gameObject] = 0f;
|
||||
}
|
||||
GameManager.Instance.StopCoroutine("MoveHatToWinner");
|
||||
}
|
||||
|
||||
public void DropItem() // Player drops hat when hit
|
||||
{
|
||||
if (GameManager.Instance.gameOver) return; // Prevent dropping items if the game is over
|
||||
|
||||
if (isHoldingItem)
|
||||
{
|
||||
heldItem.GetComponent<Collider2D>().enabled = true;
|
||||
HatRespawn.canBePickedUp = false;
|
||||
StartCoroutine(WaitForInteractability());
|
||||
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(-5, 5), ForceMode2D.Impulse);
|
||||
heldItem.GetComponent<HatRespawn>().OnHatDropped();
|
||||
heldItem.transform.parent = GameManager.Instance.transform;
|
||||
heldItem = null;
|
||||
isHoldingItem = false;
|
||||
if (GameManager.playerHoldTimes.ContainsKey(gameObject))
|
||||
{
|
||||
GameManager.playerHoldTimes.Remove(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator WaitForInteractability()
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
HatRespawn.canBePickedUp = true;
|
||||
}
|
||||
|
||||
public bool IsHoldingItem()
|
||||
{
|
||||
return isHoldingItem;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Player/UseItem.cs.meta
Normal file
2
Assets/Scripts/Player/UseItem.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 861b3bde023ca7f48a72c48ef9ee25d2
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerCameraMovement : MonoBehaviour
|
||||
{
|
||||
private Vector3 start;
|
||||
private Vector3 target;
|
||||
public float weight;
|
||||
public float speed;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
start = transform.position;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
List<GameObject> players = PlayerManager.Instance.players;
|
||||
|
||||
if (players.Count == 0) return;
|
||||
|
||||
Vector3 playerAverage = Vector3.zero;
|
||||
foreach (GameObject player in players)
|
||||
{
|
||||
playerAverage += player.transform.position;
|
||||
}
|
||||
playerAverage /= players.Count;
|
||||
|
||||
target = start * weight + playerAverage * (1 - weight);
|
||||
transform.position = Vector3.Lerp(transform.position, target, speed * Time.deltaTime);
|
||||
transform.position = new Vector3(transform.position.x, transform.position.y, -10);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework.Constraints;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class PlayerManager : MonoBehaviour
|
||||
{
|
||||
public static PlayerManager Instance;
|
||||
|
||||
public List<GameObject> players;
|
||||
[SerializeField] private InputActionAsset playerActions;
|
||||
|
||||
private Vector2 spawnPosition;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GetComponent<PlayerInputManager>().onPlayerJoined += OnPlayerJoined;
|
||||
GetComponent<PlayerInputManager>().onPlayerLeft += OnPlayerLeft;
|
||||
}
|
||||
|
||||
private void OnPlayerJoined(PlayerInput playerInput)
|
||||
{
|
||||
playerInput.transform.position = spawnPosition;
|
||||
players.Add(playerInput.gameObject);
|
||||
print("Player joined");
|
||||
}
|
||||
|
||||
private void OnPlayerLeft(PlayerInput playerInput)
|
||||
{
|
||||
Destroy(playerInput.gameObject);
|
||||
players.Remove(playerInput.gameObject);
|
||||
print("Player left");
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
print("A PlayerManager already exists.");
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
|
||||
spawnPosition = transform.position;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
[RequireComponent(typeof(PlayerMovement))]
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
[RequireComponent(typeof(AnimationPlayer))]
|
||||
public class Punch : MonoBehaviour
|
||||
{
|
||||
public bool cancelable = true;
|
||||
|
||||
[SerializeField] private BoxCollider2D hurtbox;
|
||||
|
||||
InputActionAsset actions;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
actions = GetComponent<PlayerInput>().actions;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (actions.FindAction("Punch").ReadValue<float>() == 1f)
|
||||
{
|
||||
//if (!cancelable) return;
|
||||
GetComponent<AnimationPlayer>().Punch();
|
||||
DisableCancellation();
|
||||
}
|
||||
}
|
||||
|
||||
public void EnableHurtbox()
|
||||
{
|
||||
hurtbox.enabled = true;
|
||||
}
|
||||
|
||||
public void DisableHurtbox()
|
||||
{
|
||||
hurtbox.enabled = false;
|
||||
}
|
||||
|
||||
public void DisableCancellation()
|
||||
{
|
||||
cancelable = false;
|
||||
}
|
||||
|
||||
public void EnableCancellation()
|
||||
{
|
||||
cancelable = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user