diff --git a/Assets/Scripts/CameraOperator.cs b/Assets/Scripts/CameraOperator.cs index 55b600e..58bd32a 100644 --- a/Assets/Scripts/CameraOperator.cs +++ b/Assets/Scripts/CameraOperator.cs @@ -20,7 +20,9 @@ public class CameraOperator : MonoBehaviour players.Remove(id); } - // Update is called once per frame + /// + /// Rotates the camera to point at the center between the players. + /// void LateUpdate() { if (players.Count < 1) diff --git a/Assets/Scripts/Managers/AVEffectsManager.cs b/Assets/Scripts/Managers/AVEffectsManager.cs index 45b2ad9..f671aa7 100644 --- a/Assets/Scripts/Managers/AVEffectsManager.cs +++ b/Assets/Scripts/Managers/AVEffectsManager.cs @@ -30,8 +30,12 @@ namespace Managers void Start() { - centralAudioSource = audioLibrary.audios.First(a => a.tag == "music").audioSource; - centralAudioSource.Play(); + if(audioLibrary == null){ + return; + } + centralAudioSource = audioLibrary.audios.First(a => a.tag == "music")?.audioSource; + if(centralAudioSource != null) + centralAudioSource.Play(); } } diff --git a/Assets/Scripts/Managers/GameManager.cs b/Assets/Scripts/Managers/GameManager.cs index 8a45237..7d1c0d6 100644 --- a/Assets/Scripts/Managers/GameManager.cs +++ b/Assets/Scripts/Managers/GameManager.cs @@ -23,8 +23,6 @@ public enum Scenes namespace Managers { - // public enum GameState { Starting, Match, End, Paused } - /// /// Starts up the game and it's managers. /// Provides methods for loading additional scenes and triggering custom events when loaded. @@ -88,7 +86,7 @@ namespace Managers } /// - /// Instantiates the managers needed to use the main menu. + /// Instantiates the managers needed to play the game. /// void InstantiateBaseManagers() { @@ -148,6 +146,9 @@ namespace Managers } } + /// + /// Starts the camera, for showing an image before the main menu is loaded. + /// void ShowStartScreen() { startCamera.SetActive(true); @@ -169,8 +170,8 @@ namespace Managers } /// - /// Initiates a local battle by giving relavant information to the match manager - /// and starting the match managers appropriate process. + /// Initiates a local battle by giving relavant information to the responsible managers + /// and starting their appropriate processes. /// /// Scene id of the chosen arena. public IEnumerator SetupLocalMatchFromMainMenu() @@ -246,6 +247,10 @@ namespace Managers } + /// + /// Custom delegate which can be executed after scene load. + /// + /// Data of the loaded scene public delegate void CustomOnSceneLoaded(SceneLoadEventArgs args); public class SceneLoadEventArgs : EventArgs diff --git a/Assets/Scripts/Managers/MatchManager.cs b/Assets/Scripts/Managers/MatchManager.cs index 341cb36..3441a86 100644 --- a/Assets/Scripts/Managers/MatchManager.cs +++ b/Assets/Scripts/Managers/MatchManager.cs @@ -7,9 +7,6 @@ using PrimeTween; using UnityEditor; using UnityEngine; using GameLogic; -using Unity.VisualScripting; -using System.Xml; -using System.Collections; using System.Threading.Tasks; namespace Managers @@ -24,7 +21,6 @@ namespace Managers private static string arenaAssetsPath = "Assets/ScriptedAssets/Arenas"; private static string ruleAssetsPath = "Assets/ScriptedAssets/Rules"; - private bool needsStartConfirmation = false; public event Action OnStartPressed; /// /// Globally accessible member to use manager with. @@ -132,6 +128,9 @@ namespace Managers } } + /// + /// Creates statistics for the players participating in the match. + /// public void SetupMatchPlayerStatistics() { matchPlayerStatistics.Clear(); @@ -190,6 +189,11 @@ namespace Managers matchState = MatchState.CharacterSelect; } + /// + /// Announcement of who won. + /// TODO: Also restarts the match right now, no matter what. + /// + /// Result data of the completed match. async public void AnnounceWinner(MatchResult mr) { UIManager.G.announcments.QueueAnnounceText($"{mr.Winner.playerName}" + @@ -205,6 +209,10 @@ namespace Managers RestartMatch(); } + /// + /// Starts the match anew. + /// Resetting player positions and statistics. + /// public void RestartMatch() { ResetMatchCharacters(); @@ -212,6 +220,10 @@ namespace Managers matchState = MatchState.Match; } + /// + /// Initializes the match, waits for match begin + /// confirmation by the players and counts down to start. + /// async public void StartMatch() { foreach (Player p in matchPlayers) diff --git a/Assets/Scripts/MatchLogic.cs b/Assets/Scripts/MatchLogic.cs index d64010b..b7bdeff 100644 --- a/Assets/Scripts/MatchLogic.cs +++ b/Assets/Scripts/MatchLogic.cs @@ -1,16 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; -using Managers; -using TMPro; using UnityEditor; -using UnityEngine.InputSystem; namespace GameLogic { + /// + /// Updates and checks a matches rules according to the state of the match. + /// public static class MatchLogic { public static MatchRule currentRule; + + /// + /// Update match conditions and check for match conclusion. + /// + /// Affected player + /// Update to the matches conditions + /// Dictionary of the players in the match and their current stats + /// public static MatchResult UpdateMatchResult(Player p, MatchConditionUpdate args, Dictionary mps) { switch (args.Condition) diff --git a/Assets/Scripts/NimbleZoneDetection.cs b/Assets/Scripts/NimbleZoneDetection.cs index 372f207..6544df5 100644 --- a/Assets/Scripts/NimbleZoneDetection.cs +++ b/Assets/Scripts/NimbleZoneDetection.cs @@ -27,6 +27,7 @@ public class NimbleZoneDetection : MonoBehaviour private Zone zone = Zone.NimbleZone; // Ripple properties + // These influence the shader on the nimble zone [SerializeField] private float rippleFrequency = 3f; [SerializeField] @@ -39,10 +40,10 @@ public class NimbleZoneDetection : MonoBehaviour private float rippleDuration = 1f; [SerializeField] private float impactVelocityModifier = 1f; - [SerializeField] + [SerializeField, Tooltip("Minimum ripple effect intensity.")] [Range(0, 1)] private float minImpact = 0.2f; - [SerializeField] + [SerializeField, Tooltip("Velocity which makes the highest/most intense ripples.")] private float maxVelocity = 45f; private int maxRippleAmount = 5; private MeshRenderer meshRenderer; @@ -55,19 +56,37 @@ public class NimbleZoneDetection : MonoBehaviour ResetRippleShaderProperties(); } + /// + /// Array of the available gravities. + /// private Func[] gravityFunctions = { DownGravity, NoGravity, InwardsGravity, OutwardsGravity }; + /// + /// Function which returns a gravity zero vector. + /// private static Func NoGravity = new(transform => new Vector3()); + /// + /// Function which returns a gravity vector downwards, depending + /// on the parent transforms rotation. + /// The parenting transform for a ship is the arena it's in. + /// private static Func DownGravity = new(transform => transform.parent.rotation * Vector3.down * gravityFactor); - // TODO: This is too specific maybe? + /// + /// Function which returns a gravity vector towards the center of the parenting transform. + /// The parenting transform for a ship is the arena it's in. + /// private static Func InwardsGravity = new(transform => (transform.position - transform.parent.position).normalized * -gravityFactor); + /// + /// Function which returns a gravity vector outwards from the center of the parenting transform. + /// The parenting transform for a ship is the arena it's in. + /// private static Func OutwardsGravity = new Func(transform => (transform.position - transform.parent.position).normalized * gravityFactor); @@ -113,12 +132,24 @@ public class NimbleZoneDetection : MonoBehaviour material.SetFloat("_ShaderTime", Time.timeSinceLevelLoad); } - private float ImpactVelocityEffect(float duration, float velocity) + /// + /// Calculates the effect which a given velocity has on a ripple property. + /// + /// Initial value of the ripple property + /// Velocity of the impact + /// + private float ImpactVelocityEffect(float initial, float velocity) { return math.max(math.smoothstep(0, maxVelocity, velocity), minImpact) - * impactVelocityModifier * duration; + * impactVelocityModifier * initial; } + /// + /// Spawns ripples on the shader of the nimble zone. + /// Up to 5 parallel ripples. + /// + /// + /// private void SpawnRipple(Collider collider, bool isOutwardsRipple) { Rigidbody body = collider.attachedRigidbody; @@ -174,6 +205,9 @@ public class NimbleZoneDetection : MonoBehaviour } } + /// + /// Resets the ripple shaders exposed properties to 0 + /// private void ResetRippleShaderProperties() { Vector4[] rippleOrigins = new Vector4[maxRippleAmount]; diff --git a/Assets/Scripts/PlayingFieldDetection.cs b/Assets/Scripts/PlayingFieldDetection.cs index e7a8aba..b88e32b 100644 --- a/Assets/Scripts/PlayingFieldDetection.cs +++ b/Assets/Scripts/PlayingFieldDetection.cs @@ -6,6 +6,11 @@ using UnityEngine; public class PlayingFieldDetection : MonoBehaviour { private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Updates the match conditions, when a ship leaves the playing field. + /// + /// private void OnTriggerExit(Collider collider) { if (collider.tag == "Ship") diff --git a/Assets/Scripts/Ship.cs b/Assets/Scripts/Ship.cs index 5fffa5f..113583c 100644 --- a/Assets/Scripts/Ship.cs +++ b/Assets/Scripts/Ship.cs @@ -87,6 +87,9 @@ public class Ship : MonoBehaviour UpdateTackleResponse(isCriticalTackle); } + /// + /// Movement logic and simulation of the ship. + /// void UpdateMovement() { @@ -144,9 +147,14 @@ public class Ship : MonoBehaviour Color.black); } + /// + /// Calculates a vector to mitigate the ship drifting when it's changing direction. + /// + /// Current velocity of the ship + /// Zone which the ship is in + /// Vector3 DriftDampeningAcceleration(Vector3 currentVelocity, Zone zone) { - // TODO: add in ifs for ignoring small deviations Vector3 antiDriftVelocity; float antiDriftFactor; // Cancel out inertia/drifting @@ -170,6 +178,12 @@ public class Ship : MonoBehaviour return antiDriftVelocity * props.antiDriftAmount * antiDriftFactor; } + /// + /// Calculates drag on the ship depending on it's velocity and inhabited zone. + /// + /// Velocity of the ship + /// Zone which the ship is in + /// Vector3 DragDecceleration(Vector3 currentVelocity, Zone zone) { Vector3 drag = new Vector3(); @@ -190,11 +204,23 @@ public class Ship : MonoBehaviour return drag; } + /// + /// Is the boost input pressed and boosting possible? + /// + /// Boosting state bool IsBoosting() { return state.boostInput > 0 && canBoost; } + /// + /// Applies boost to an acceleration vector. + /// This includes increasing acceleration and mitigating + /// the gravity. + /// + /// Current acceleration vector + /// Gravity vector which is in force + /// Vector3 BoostAcceleration(Vector3 acceleration, Vector3 currentGravity) { if (IsBoosting()) @@ -205,39 +231,44 @@ public class Ship : MonoBehaviour return acceleration; } + /// + /// Logic which depletes boost capacity when boost conditions are met. + /// + /// Time delta of the current frame void BoostStateUpdate(float deltaTime) { boostUI.UpdateFill(Math.Min(state.boostCapacity / props.maxBoostCapacity, 1)); if (IsBoosting() && state.thrustInput != 0) { - // Debug.Log("Boost Kapazität wird verbraucht: " + boostCapacity); state.boostCapacity -= deltaTime; } if (canBoost && zone == Zone.OutsideZone) { - // Debug.Log("Boost Kapazität wird passiv verbraucht: " + boostCapacity); state.boostCapacity -= deltaTime * props.outsideBoostRate; } if (state.boostCapacity <= 0) { canBoost = false; - // Debug.Log("Boost aufgebraucht"); } - // TODO this will be spam abused + if ((state.boostInput <= 0 || state.thrustInput == 0 || !canBoost) && zone == Zone.NimbleZone && state.boostCapacity <= props.maxBoostCapacity) { - // Debug.Log("Boost wird aufgeladen: " + boostCapacity); state.boostCapacity += deltaTime; } + // When your boost capacity is still critical, you can't start boosting immediately again. + // TODO: This is not tested well enough with players. if (canBoost == false && state.boostCapacity >= props.minBoostCapacity) { canBoost = true; - // Debug.Log("Boost verfügbar"); } } + /// + /// Logic which sets the isTackled state. + /// + /// Use true to process a tackle hit void UpdateTackleResponse(bool gotTackled = false) { if (gotTackled && !isTackled) @@ -256,6 +287,13 @@ public class Ship : MonoBehaviour } } + /// + /// Called by the collision regions which detect tackling. + /// Adds resulting forces to the ship and intiates the tackle + /// response. + /// + /// Kind of the tackle. Depends on collision region. + /// Object which has collided with the collision region. void StartTackleResponse(TackleKind tackleKind, Collider collider) { float tacklePowerFactor = props.criticalTacklePowerFactor; diff --git a/Assets/Scripts/ShipState.cs b/Assets/Scripts/ShipState.cs index 2045263..781746c 100644 --- a/Assets/Scripts/ShipState.cs +++ b/Assets/Scripts/ShipState.cs @@ -2,6 +2,9 @@ using UnityEngine; namespace ShipHandling { + /// + /// Variables for the ship which can also be under the players control. + /// public class ShipState { public float thrustInput = 0; diff --git a/Assets/Scripts/TackleDetection.cs b/Assets/Scripts/TackleDetection.cs index 79eb9cf..880c94d 100644 --- a/Assets/Scripts/TackleDetection.cs +++ b/Assets/Scripts/TackleDetection.cs @@ -1,10 +1,18 @@ using UnityEngine; using UnityEngine.Events; +/// +/// Used on vulnerable trigger zones for ships. +/// public class TackleDetection : MonoBehaviour { [SerializeField] private TackleKind tackleKind; public UnityEvent TackleResponse; + + /// + /// Invokes the fitting tackle response on trigger entered. + /// + /// void OnTriggerEnter(Collider collider) { if (collider.tag != "Spike" && collider.tag != "Bumper") diff --git a/Assets/Scripts/UI/Announcments.cs b/Assets/Scripts/UI/Announcments.cs index eefdc97..cfcceab 100644 --- a/Assets/Scripts/UI/Announcments.cs +++ b/Assets/Scripts/UI/Announcments.cs @@ -1,10 +1,12 @@ using System; -using System.Collections; using System.Collections.Generic; using TMPro; -using Unity.VisualScripting; using UnityEngine; +/// +/// Provides methods for displaying text on a text mesh pro. +/// Features a queue for messages which dissapear after a set time. +/// public class Announcments : MonoBehaviour { [SerializeField] TextMeshProUGUI announcementText; @@ -12,7 +14,10 @@ public class Announcments : MonoBehaviour public Queue> announcementQueue = new Queue>(); private bool workingOnQueue = false; private float remainingTime; - + + /// + /// Update the message queue. + /// void Update() { if (!workingOnQueue && announcementQueue.Count != 0) @@ -38,20 +43,10 @@ public class Announcments : MonoBehaviour } } - public void AnnounceText(string text, float time) - { - announcementText.text = text; - announcementText.enabled = true; - remainingTime = time; - enabled = true; - } - - public void QueueAnnounceText(string text, float time) - { - announcementQueue.Enqueue(new Tuple(text, time)); - enabled = true; - } - + /// + /// Shows the text without time limit. + /// + /// Text to be shown. public void AnnounceText(string text) { announcementText.text = text; @@ -60,6 +55,33 @@ public class Announcments : MonoBehaviour enabled = false; } + /// + /// Set the announcement text for a certain time. + /// + /// + /// Time in seconds + private void AnnounceText(string text, float time) + { + announcementText.text = text; + announcementText.enabled = true; + remainingTime = time; + enabled = true; + } + + /// + /// Add an announcement to the queue. + /// + /// Text to be shown. + /// Time of the announcement in seconds. + public void QueueAnnounceText(string text, float time) + { + announcementQueue.Enqueue(new Tuple(text, time)); + enabled = true; + } + + /// + /// Stop the announcement and clear the queue. + /// public void StopAnnouncement() { announcementQueue.Clear(); diff --git a/Assets/Scripts/UI/BoostCapacityUI.cs b/Assets/Scripts/UI/BoostCapacityUI.cs index 3b0cb21..04ddeca 100644 --- a/Assets/Scripts/UI/BoostCapacityUI.cs +++ b/Assets/Scripts/UI/BoostCapacityUI.cs @@ -1,8 +1,10 @@ using TMPro; -using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; +/// +/// HUD element which displays a ships remaining boost capacity. +/// public class BoostCapacityUI : MonoBehaviour { public Color goodColor = Color.green; @@ -12,6 +14,11 @@ public class BoostCapacityUI : MonoBehaviour [SerializeField] private TextMeshProUGUI hint; private float minBoostRatio = 0.3f; + /// + /// Ratio of capacity to max capacity under which the + /// boost capacity is considered critically low. + /// + /// public void SetMinBoostRatio(float minBoostRatio) { this.minBoostRatio = minBoostRatio; @@ -22,6 +29,10 @@ public class BoostCapacityUI : MonoBehaviour hint.SetText($"Boost Capacity \n {p.playerName} \n {p.character.shipName}"); } + /// + /// Updates the color and fill of the capacity meter. + /// + /// Fill percentage public void UpdateFill(float fill) { fillImage.fillAmount = fill; diff --git a/Assets/Scripts/UI/HUD.cs b/Assets/Scripts/UI/HUD.cs index 93eaec8..ca1133e 100644 --- a/Assets/Scripts/UI/HUD.cs +++ b/Assets/Scripts/UI/HUD.cs @@ -1,13 +1,17 @@ -using System.Collections; -using System.Collections.Generic; -using Unity.VisualScripting; using UnityEngine; +/// +/// Colleciton class for referencing and controlling HUD elements. +/// public class HUD : MonoBehaviour { public BoostCapacityUI[] boostCapacities; public JoinPrompt[] joinPrompts; + /// + /// Start a join prompt. + /// + /// Player to which the prompt belongs public void StartJoinPrompt(Player player) { foreach (JoinPrompt jp in joinPrompts) diff --git a/Assets/SlimUI/Modern Menu 1/Scripts/Managers/SlimUIMainMenu.cs b/Assets/SlimUI/Modern Menu 1/Scripts/Managers/SlimUIMainMenu.cs index cf93277..43894e9 100644 --- a/Assets/SlimUI/Modern Menu 1/Scripts/Managers/SlimUIMainMenu.cs +++ b/Assets/SlimUI/Modern Menu 1/Scripts/Managers/SlimUIMainMenu.cs @@ -89,10 +89,6 @@ namespace SlimUI.ModernMenu [Tooltip("The GameObject holding the Audio Source component for the SWOOSH SOUND when switching to the Settings Screen")] public AudioSource swooshSound; - // [Header("Options")] - // public bool flyCameraLoadTransition = true; - - void Start() { GM = GameManager.G; @@ -212,11 +208,11 @@ namespace SlimUI.ModernMenu } /// - /// Loads the Gameplay UI and unloads the Main Menu once thats loaded. + /// Loads the Gameplay UI and after that unloads the Main Menu. /// Also Initiates the setup of the local match once the Gameplay UI is /// loaded. /// - /// + /// IEnumerator for async statemachine private IEnumerator SwitchToIngameUI() { AsyncOperation o = SceneManager.LoadSceneAsync((int)Scenes.GameplayUserInterface, diff --git a/README.md b/README.md new file mode 100644 index 0000000..61b45ac --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +When using this repo a game can be started from the Unity Editor, +by starting the GameManagement scene from the Assets/Scenes folder. +The GameManager is a sort of bootloader, which sets up all the +other managers and orchestrates the match start process. + +Once the main menu is loaded, the only real option is to start a +local 2v2 match. +I use SlimUI, as the main menu for now, it is a store asset. +Starting this match (using the button in SlimUI) sets off the async scene loading, +transition to the arena camera and match setup in the GameManager. + +The GameManager provides a method which invokes an event once a +specific scene has been loaded. +Here I'm using that to trigger the camera transition once the arena scene was loaded. + +After the camera transition the InGameUI scene is loaded and when the UI is there, +the match setup process in the GameManager is started. + +To look into this process see: +Assets\SlimUI\Modern Menu 1\Scripts\Managers\SlimUIMainMenu Line 162 onwards +Assets\Scripts\Managers\GameManager Line 176 onwards + +Also noteworthy is the Ship Movement logic in which I change the flying behavior and gravity +for the ship depending which zone it is in +and the shader for the ripple effect of the inner/green/nimble zone, which is an older simple +ripple shader converted to URP (in code not shader graph), featuring up to 5 simulateously animated ripples. \ No newline at end of file