├── Patterns ├── ChainOfResponsibility │ ├── Handlers │ │ ├── CutsceneInputHandler.cs │ │ ├── DialogInputHandler.cs │ │ ├── GameplayInputHandler.cs │ │ └── UIInputHandler.cs │ ├── InputData.cs │ ├── InputHandler.cs │ ├── InputManager.cs │ ├── InputState.cs │ └── README.md ├── StatePattern │ ├── IOnboardingState.cs │ ├── OnboardingManager.cs │ ├── README.md │ ├── StateMachine.cs │ └── States │ │ ├── CombatTutorialState.cs │ │ ├── InventoryTutorialState.cs │ │ └── MovementTutorialState.cs └── StrategyPattern │ ├── Character.cs │ ├── IAttackStrategy.cs │ ├── README.md │ └── Strategies │ ├── AreaAttackStrategy.cs │ ├── MeleeAttackStrategy.cs │ └── RangedAttackStrategy.cs ├── README.md └── docs ├── .gitignore ├── .nojekyll ├── CNAME ├── README.md ├── _sidebar.md ├── ads.txt ├── assets └── favicon │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── safari-pinned-tab.svg │ └── site.webmanifest ├── audio └── basic-audio-play.md ├── basics ├── euler-angles.md ├── monobehaviour.md ├── quaternion.md ├── transform.md └── vector3.md ├── design-patterns ├── chain-of-responsibility-pattern.md ├── command-pattern.md ├── factory-pattern.md ├── object-pooling-pattern.md ├── observer-pattern.md ├── singleton.md ├── state-pattern.md └── strategy-pattern.md ├── index.html ├── input ├── keyboard.md ├── mouse.md └── touch.md ├── movement-rotation ├── move-object.md └── rotate-object.md ├── package.json ├── physics ├── ignore-collision.md └── raycast.md ├── practical-use-cases ├── check-if-object-is-on-the-ground.md ├── get-the-transform-of-a-body-bone.md ├── load-next-scene.md └── make-object-look-at-the-camera.md ├── scripting ├── asyncawait.md ├── coroutines.md ├── custom-editor-scripts.md ├── event-systems.md └── scriptable-objects.md ├── scripts └── generate-docs.ts ├── shortcuts ├── hierarchy-management.md ├── layout.md ├── scene-view-editing.md └── scene-view-navigation.md ├── tbd-to-be-documented ├── input.md └── scripting.md ├── tsconfig.json └── ui ├── button.md └── slider.md /Patterns/ChainOfResponsibility/Handlers/CutsceneInputHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class CutsceneInputHandler : InputHandler 4 | { 5 | private void Awake() 6 | { 7 | handledStates = new[] { InputState.Cutscene }; 8 | } 9 | 10 | protected override void ProcessInput(InputData input) 11 | { 12 | if (input.IsProcessed) return; 13 | 14 | // Only allow skipping cutscene with interact button 15 | if (input.InteractPressed) 16 | { 17 | Debug.Log("Skip Cutscene"); 18 | } 19 | 20 | input.IsProcessed = true; 21 | } 22 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/Handlers/DialogInputHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class DialogInputHandler : InputHandler 4 | { 5 | private void Awake() 6 | { 7 | handledStates = new[] { InputState.Dialog }; 8 | } 9 | 10 | protected override void ProcessInput(InputData input) 11 | { 12 | if (input.IsProcessed) return; 13 | 14 | // Handle dialog choices 15 | if (input.Movement != Vector2.zero) 16 | { 17 | Debug.Log("Dialog Choice: " + input.Movement); 18 | } 19 | 20 | // Handle advancing dialog 21 | if (input.InteractPressed) 22 | { 23 | Debug.Log("Advance Dialog"); 24 | } 25 | 26 | input.IsProcessed = true; 27 | } 28 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/Handlers/GameplayInputHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class GameplayInputHandler : InputHandler 4 | { 5 | private void Awake() 6 | { 7 | handledStates = new[] { InputState.Gameplay }; 8 | } 9 | 10 | protected override void ProcessInput(InputData input) 11 | { 12 | if (input.IsProcessed) return; 13 | 14 | // Handle movement 15 | if (input.Movement != Vector2.zero) 16 | { 17 | Debug.Log("Movement: " + input.Movement); 18 | } 19 | 20 | // Handle jump 21 | if (input.JumpPressed) 22 | { 23 | Debug.Log("Jump"); 24 | } 25 | 26 | // Handle interaction 27 | if (input.InteractPressed) 28 | { 29 | Debug.Log("Interact"); 30 | } 31 | 32 | input.IsProcessed = true; 33 | } 34 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/Handlers/UIInputHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class UIInputHandler : InputHandler 4 | { 5 | private void Awake() 6 | { 7 | handledStates = new[] { InputState.UI }; 8 | } 9 | 10 | protected override void ProcessInput(InputData input) 11 | { 12 | if (input.IsProcessed) return; 13 | 14 | // Handle UI navigation 15 | if (input.Movement != Vector2.zero) 16 | { 17 | Debug.Log("UI Navigation: " + input.Movement); 18 | } 19 | 20 | // Handle UI selection 21 | if (input.InteractPressed) 22 | { 23 | Debug.Log("UI Selection"); 24 | } 25 | 26 | input.IsProcessed = true; 27 | } 28 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/InputData.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class InputData 4 | { 5 | public Vector2 Movement { get; private set; } 6 | public bool JumpPressed { get; private set; } 7 | public bool InteractPressed { get; private set; } 8 | public bool IsProcessed { get; set; } 9 | 10 | public InputData(Vector2 movement, bool jumpPressed, bool interactPressed) 11 | { 12 | Movement = movement; 13 | JumpPressed = jumpPressed; 14 | InteractPressed = interactPressed; 15 | IsProcessed = false; 16 | } 17 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/InputHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public abstract class InputHandler : MonoBehaviour 4 | { 5 | protected InputHandler nextHandler; 6 | protected InputState[] handledStates; 7 | protected InputState currentState; 8 | 9 | public void SetNextHandler(InputHandler handler) 10 | { 11 | nextHandler = handler; 12 | } 13 | 14 | public virtual bool HandleInput(InputData input) 15 | { 16 | if (CanHandleState(currentState)) 17 | { 18 | ProcessInput(input); 19 | return true; 20 | } 21 | 22 | return nextHandler != null && nextHandler.HandleInput(input); 23 | } 24 | 25 | protected abstract void ProcessInput(InputData input); 26 | 27 | protected bool CanHandleState(InputState state) 28 | { 29 | foreach (var handledState in handledStates) 30 | { 31 | if (state == handledState) return true; 32 | } 33 | return false; 34 | } 35 | 36 | public void SetState(InputState newState) 37 | { 38 | currentState = newState; 39 | } 40 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/InputManager.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class InputManager : MonoBehaviour 4 | { 5 | private GameplayInputHandler gameplayHandler; 6 | private UIInputHandler uiHandler; 7 | private CutsceneInputHandler cutsceneHandler; 8 | private DialogInputHandler dialogHandler; 9 | 10 | private InputState currentState = InputState.Gameplay; 11 | 12 | void Start() 13 | { 14 | // Initialize handlers 15 | gameplayHandler = gameObject.AddComponent(); 16 | uiHandler = gameObject.AddComponent(); 17 | cutsceneHandler = gameObject.AddComponent(); 18 | dialogHandler = gameObject.AddComponent(); 19 | 20 | // Set up the chain 21 | gameplayHandler.SetNextHandler(uiHandler); 22 | uiHandler.SetNextHandler(cutsceneHandler); 23 | cutsceneHandler.SetNextHandler(dialogHandler); 24 | 25 | // Set initial state 26 | SetGameState(InputState.Gameplay); 27 | } 28 | 29 | void Update() 30 | { 31 | // Gather input 32 | Vector2 movement = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); 33 | bool jumpPressed = Input.GetButtonDown("Jump"); 34 | bool interactPressed = Input.GetButtonDown("Interact"); 35 | 36 | // Create input data 37 | var inputData = new InputData(movement, jumpPressed, interactPressed); 38 | 39 | // Process input through chain 40 | gameplayHandler.HandleInput(inputData); 41 | } 42 | 43 | public void SetGameState(InputState newState) 44 | { 45 | currentState = newState; 46 | 47 | // Update all handlers with new state 48 | gameplayHandler.SetState(newState); 49 | uiHandler.SetState(newState); 50 | cutsceneHandler.SetState(newState); 51 | dialogHandler.SetState(newState); 52 | } 53 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/InputState.cs: -------------------------------------------------------------------------------- 1 | public enum InputState 2 | { 3 | Gameplay, 4 | UI, 5 | Cutscene, 6 | Dialog 7 | } -------------------------------------------------------------------------------- /Patterns/ChainOfResponsibility/README.md: -------------------------------------------------------------------------------- 1 | # Chain of Responsibility Pattern Example 2 | 3 | A Unity example demonstrating the Chain of Responsibility pattern with a game input handling system. 4 | 5 | ## Overview 6 | 7 | The Chain of Responsibility pattern manages input handling across different game states (gameplay, UI, cutscenes, dialog). Each handler processes input based on the current game state, ensuring inputs are handled appropriately in each context. 8 | 9 | ## Implementation 10 | 11 | - [`InputState.cs`](InputState.cs): Defines the possible game states 12 | - [`InputData.cs`](InputData.cs): Contains all input information (movement, buttons) 13 | - [`InputHandler.cs`](InputHandler.cs): Base handler class with chain logic 14 | - Game States: 15 | - [`GameplayInputHandler.cs`](Handlers/GameplayInputHandler.cs): Handles player movement and actions 16 | - [`UIInputHandler.cs`](Handlers/UIInputHandler.cs): Handles UI navigation and selection 17 | - [`CutsceneInputHandler.cs`](Handlers/CutsceneInputHandler.cs): Handles cutscene controls 18 | - [`DialogInputHandler.cs`](Handlers/DialogInputHandler.cs): Handles dialog system input 19 | - [`InputManager.cs`](InputManager.cs): Sets up the chain and manages game states 20 | 21 | ## Usage 22 | 23 | ```csharp 24 | // Setup is automatic - just add to a GameObject 25 | InputManager manager = gameObject.AddComponent(); 26 | 27 | // Change states as needed 28 | manager.SetGameState(InputState.Dialog); // When entering dialog 29 | manager.SetGameState(InputState.Gameplay); // When returning to gameplay 30 | ``` 31 | 32 | ## Benefits 33 | 34 | - Clean separation of input handling by game state 35 | - Easy to add new input states and handlers 36 | - Prevents input conflicts between states 37 | - Centralized input management 38 | -------------------------------------------------------------------------------- /Patterns/StatePattern/IOnboardingState.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityCheatSheet.Patterns.StatePattern 4 | { 5 | public interface IState 6 | { 7 | void Enter(); 8 | void Update(); 9 | void Exit(); 10 | } 11 | } -------------------------------------------------------------------------------- /Patterns/StatePattern/OnboardingManager.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace UnityCheatSheet.Patterns.StatePattern 6 | { 7 | public class OnboardingManager : MonoBehaviour 8 | { 9 | private StateMachine stateMachine; 10 | private Dictionary directionsTriedMap = new Dictionary(); 11 | private bool onboardingComplete = false; 12 | 13 | private void Start() 14 | { 15 | InitializeDirectionsMap(); 16 | stateMachine = gameObject.AddComponent(); 17 | } 18 | 19 | private void InitializeDirectionsMap() 20 | { 21 | directionsTriedMap["up"] = false; 22 | directionsTriedMap["down"] = false; 23 | directionsTriedMap["left"] = false; 24 | directionsTriedMap["right"] = false; 25 | } 26 | 27 | public void SetDirectionTried(string direction, bool tried) 28 | { 29 | if (directionsTriedMap.ContainsKey(direction)) 30 | { 31 | directionsTriedMap[direction] = tried; 32 | } 33 | } 34 | 35 | public bool HasTriedAllDirections() 36 | { 37 | return directionsTriedMap.All(kvp => kvp.Value); 38 | } 39 | 40 | public void CompleteOnboarding() 41 | { 42 | onboardingComplete = true; 43 | Debug.Log("Onboarding completed! The player is ready to start the game."); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Patterns/StatePattern/README.md: -------------------------------------------------------------------------------- 1 | # State Pattern Example 2 | 3 | A Unity example demonstrating the State Pattern with a game onboarding system. 4 | 5 | ## Overview 6 | 7 | The State Pattern allows an object to alter its behavior when its internal state changes. In this example, we use it to manage different states of a game onboarding system, where each state represents a different tutorial phase. 8 | 9 | ## Implementation 10 | 11 | - [`IState.cs`](IState.cs): Base interface for all states 12 | - [`StateMachine.cs`](StateMachine.cs): Manages state transitions 13 | - [`OnboardingManager.cs`](OnboardingManager.cs): Handles onboarding logic 14 | - States: 15 | - [`MovementTutorialState.cs`](States/MovementTutorialState.cs): Teaches basic movement 16 | - [`CombatTutorialState.cs`](States/CombatTutorialState.cs): Teaches combat mechanics 17 | - [`InventoryTutorialState.cs`](States/InventoryTutorialState.cs): Teaches inventory usage 18 | 19 | ## Usage 20 | 21 | ```csharp 22 | // Setup is automatic - just add to a GameObject 23 | OnboardingManager manager = gameObject.AddComponent(); 24 | 25 | // States will transition automatically as player completes each tutorial phase 26 | // You can also manually transition if needed: 27 | manager.ChangeState(new CombatTutorialState()); 28 | ``` 29 | 30 | ## Benefits 31 | 32 | - Clean separation of tutorial phases 33 | - Easy to add new tutorial states 34 | - Clear state transitions 35 | - Centralized tutorial management 36 | ``` -------------------------------------------------------------------------------- /Patterns/StatePattern/StateMachine.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityCheatSheet.Patterns.StatePattern 4 | { 5 | public class StateMachine : MonoBehaviour 6 | { 7 | private IState currentState; 8 | 9 | private void Start() 10 | { 11 | // Start with the first state in your sequence 12 | ChangeState(new States.MovementTutorialState(this)); 13 | } 14 | 15 | private void Update() 16 | { 17 | if (currentState != null) 18 | { 19 | currentState.Update(); 20 | } 21 | } 22 | 23 | public void ChangeState(IState newState) 24 | { 25 | if (currentState != null) 26 | { 27 | currentState.Exit(); 28 | } 29 | 30 | currentState = newState; 31 | currentState.Enter(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Patterns/StatePattern/States/CombatTutorialState.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityCheatSheet.Patterns.StatePattern.States 5 | { 6 | public class CombatTutorialState : IState 7 | { 8 | private readonly OnboardingManager manager; 9 | private bool attackPerformed = false; 10 | private bool blockPerformed = false; 11 | 12 | public CombatTutorialState(OnboardingManager manager) 13 | { 14 | this.manager = manager; 15 | } 16 | 17 | public void Enter() 18 | { 19 | Debug.Log("Welcome to combat training! Press Left Mouse Button to attack, Right Mouse Button to block."); 20 | } 21 | 22 | public void Update() 23 | { 24 | if (Input.GetMouseButtonDown(0) && !attackPerformed) 25 | { 26 | attackPerformed = true; 27 | Debug.Log("Excellent attack!"); 28 | } 29 | 30 | if (Input.GetMouseButtonDown(1) && !blockPerformed) 31 | { 32 | blockPerformed = true; 33 | Debug.Log("Perfect block!"); 34 | } 35 | 36 | if (attackPerformed && blockPerformed) 37 | { 38 | manager.StartCoroutine(TransitionToNextState()); 39 | } 40 | } 41 | 42 | public void Exit() 43 | { 44 | Debug.Log("Combat tutorial completed!"); 45 | } 46 | 47 | private IEnumerator TransitionToNextState() 48 | { 49 | yield return new WaitForSeconds(2f); 50 | manager.ChangeState(new InventoryTutorialState(manager)); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Patterns/StatePattern/States/InventoryTutorialState.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityCheatSheet.Patterns.StatePattern.States 5 | { 6 | public class InventoryTutorialState : IState 7 | { 8 | private readonly OnboardingManager manager; 9 | private bool inventoryOpened = false; 10 | private bool itemSelected = false; 11 | 12 | public InventoryTutorialState(OnboardingManager manager) 13 | { 14 | this.manager = manager; 15 | } 16 | 17 | public void Enter() 18 | { 19 | Debug.Log("Let's learn about inventory management! Press 'I' to open inventory."); 20 | } 21 | 22 | public void Update() 23 | { 24 | if (Input.GetKeyDown(KeyCode.I)) 25 | { 26 | inventoryOpened = true; 27 | Debug.Log("Inventory opened! Try selecting the Health Potion."); 28 | } 29 | 30 | // Simulated item selection (press Space to simulate selecting the item) 31 | if (inventoryOpened && Input.GetKeyDown(KeyCode.Space)) 32 | { 33 | itemSelected = true; 34 | Debug.Log("Perfect! You've completed the basic tutorials!"); 35 | manager.StartCoroutine(CompleteOnboarding()); 36 | } 37 | } 38 | 39 | public void Exit() 40 | { 41 | Debug.Log("Inventory tutorial completed!"); 42 | } 43 | 44 | private IEnumerator CompleteOnboarding() 45 | { 46 | yield return new WaitForSeconds(3f); 47 | manager.CompleteOnboarding(); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Patterns/StatePattern/States/MovementTutorialState.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityCheatSheet.Patterns.StatePattern.States 5 | { 6 | public class MovementTutorialState : IState 7 | { 8 | private readonly OnboardingManager manager; 9 | private bool movementCompleted = false; 10 | 11 | public MovementTutorialState(OnboardingManager manager) 12 | { 13 | this.manager = manager; 14 | } 15 | 16 | public void Enter() 17 | { 18 | Debug.Log("Welcome to the movement tutorial! Use WASD or arrow keys to move."); 19 | } 20 | 21 | public void Update() 22 | { 23 | if (Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.UpArrow)) 24 | { 25 | manager.SetDirectionTried("up", true); 26 | Debug.Log("Moved up!"); 27 | } 28 | if (Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.DownArrow)) 29 | { 30 | manager.SetDirectionTried("down", true); 31 | Debug.Log("Moved down!"); 32 | } 33 | if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow)) 34 | { 35 | manager.SetDirectionTried("left", true); 36 | Debug.Log("Moved left!"); 37 | } 38 | if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow)) 39 | { 40 | manager.SetDirectionTried("right", true); 41 | Debug.Log("Moved right!"); 42 | } 43 | 44 | if (manager.HasTriedAllDirections() && !movementCompleted) 45 | { 46 | movementCompleted = true; 47 | Debug.Log("Great job! You've mastered movement."); 48 | manager.StartCoroutine(TransitionToNextState()); 49 | } 50 | } 51 | 52 | public void Exit() 53 | { 54 | Debug.Log("Movement tutorial completed!"); 55 | } 56 | 57 | private IEnumerator TransitionToNextState() 58 | { 59 | yield return new WaitForSeconds(2f); 60 | manager.ChangeState(new CombatTutorialState(manager)); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Patterns/StrategyPattern/Character.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityCheatSheet.Patterns.StrategyPattern.Strategies; 3 | 4 | namespace UnityCheatSheet.Patterns.StrategyPattern 5 | { 6 | public class Character : MonoBehaviour 7 | { 8 | private IAttackStrategy attackStrategy; 9 | public Transform target; 10 | 11 | private void Start() 12 | { 13 | // Default to melee attack 14 | SetAttackStrategy(new MeleeAttackStrategy()); 15 | } 16 | 17 | public void SetAttackStrategy(IAttackStrategy strategy) 18 | { 19 | attackStrategy = strategy; 20 | Debug.Log($"Changed to {strategy.GetType().Name} - Range: {strategy.GetRange()}, Damage: {strategy.GetDamage()}"); 21 | } 22 | 23 | public void PerformAttack() 24 | { 25 | if (attackStrategy != null && target != null) 26 | { 27 | attackStrategy.Attack(transform, target); 28 | } 29 | else 30 | { 31 | Debug.LogWarning("Cannot attack: Missing strategy or target"); 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Patterns/StrategyPattern/IAttackStrategy.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityCheatSheet.Patterns.StrategyPattern 4 | { 5 | public interface IAttackStrategy 6 | { 7 | void Attack(Transform attacker, Transform target); 8 | float GetDamage(); 9 | float GetRange(); 10 | } 11 | } -------------------------------------------------------------------------------- /Patterns/StrategyPattern/README.md: -------------------------------------------------------------------------------- 1 | # Strategy Pattern Example 2 | 3 | A Unity example demonstrating the Strategy Pattern with a combat system. 4 | 5 | ## Overview 6 | 7 | The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. In this example, we use it to implement different attack strategies that a character can switch between during gameplay. 8 | 9 | ## Implementation 10 | 11 | - [`IAttackStrategy.cs`](IAttackStrategy.cs): Base interface for all attack strategies 12 | - [`Character.cs`](Character.cs): Context class that uses the strategies 13 | - Strategies: 14 | - [`MeleeAttackStrategy.cs`](Strategies/MeleeAttackStrategy.cs): Close-range attack 15 | - [`RangedAttackStrategy.cs`](Strategies/RangedAttackStrategy.cs): Long-range attack 16 | - [`AreaAttackStrategy.cs`](Strategies/AreaAttackStrategy.cs): Area-of-effect attack 17 | 18 | ## Usage 19 | 20 | ```csharp 21 | // Add Character component to a GameObject 22 | Character character = gameObject.AddComponent(); 23 | 24 | // Switch between different attack strategies 25 | character.SetAttackStrategy(new MeleeAttackStrategy()); 26 | character.SetAttackStrategy(new RangedAttackStrategy()); 27 | character.SetAttackStrategy(new AreaAttackStrategy()); 28 | 29 | // Perform attack with current strategy 30 | character.PerformAttack(); 31 | ``` 32 | 33 | ## Benefits 34 | 35 | - Easy to add new attack strategies 36 | - Switch strategies at runtime 37 | - Clean separation of attack algorithms 38 | - Encapsulated attack behavior -------------------------------------------------------------------------------- /Patterns/StrategyPattern/Strategies/AreaAttackStrategy.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityCheatSheet.Patterns.StrategyPattern.Strategies 4 | { 5 | public class AreaAttackStrategy : IAttackStrategy 6 | { 7 | private readonly float damage = 10f; 8 | private readonly float range = 5f; 9 | 10 | public void Attack(Transform attacker, Transform target) 11 | { 12 | Debug.Log($"Performing area attack at {attacker.position} with radius {range}!"); 13 | Debug.Log($"All enemies within range take {damage} damage!"); 14 | } 15 | 16 | public float GetDamage() => damage; 17 | public float GetRange() => range; 18 | } 19 | } -------------------------------------------------------------------------------- /Patterns/StrategyPattern/Strategies/MeleeAttackStrategy.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityCheatSheet.Patterns.StrategyPattern.Strategies 4 | { 5 | public class MeleeAttackStrategy : IAttackStrategy 6 | { 7 | private readonly float damage = 20f; 8 | private readonly float range = 2f; 9 | 10 | public void Attack(Transform attacker, Transform target) 11 | { 12 | if (Vector3.Distance(attacker.position, target.position) <= range) 13 | { 14 | Debug.Log($"Performing melee attack for {damage} damage!"); 15 | } 16 | else 17 | { 18 | Debug.Log("Target is too far for melee attack"); 19 | } 20 | } 21 | 22 | public float GetDamage() => damage; 23 | public float GetRange() => range; 24 | } 25 | } -------------------------------------------------------------------------------- /Patterns/StrategyPattern/Strategies/RangedAttackStrategy.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityCheatSheet.Patterns.StrategyPattern.Strategies 4 | { 5 | public class RangedAttackStrategy : IAttackStrategy 6 | { 7 | private readonly float damage = 15f; 8 | private readonly float range = 10f; 9 | 10 | public void Attack(Transform attacker, Transform target) 11 | { 12 | if (Vector3.Distance(attacker.position, target.position) <= range) 13 | { 14 | Vector3 direction = (target.position - attacker.position).normalized; 15 | Debug.Log($"Firing projectile in direction {direction} for {damage} damage!"); 16 | } 17 | else 18 | { 19 | Debug.Log("Target is out of range for ranged attack"); 20 | } 21 | } 22 | 23 | public float GetDamage() => damage; 24 | public float GetRange() => range; 25 | } 26 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Cheat Sheet 2 | 3 | ## Table of Contents 4 | 5 | - [Basics](#basics) 6 | - [MonoBehaviour](#monobehaviour) 7 | - [Transform](#transform) 8 | - [Vector3](#vector3) 9 | - [Quaternion](#quaternion) 10 | - [Euler Angles](#euler-angles) 11 | - [Movement & Rotation](#movement--rotation) 12 | - [Move Object](#move-object) 13 | - [Transform.Translate()](#transformtranslate) 14 | - [Vector3.MoveTowards()](#vector3movetowards) 15 | - [Vector3.Lerp()](#vector3lerp) 16 | - [Vector3.SmoothDamp()](#vector3smoothdamp) 17 | - [Rotate Object](#rotate-object) 18 | - [Transform.rotation](#transformrotation) 19 | - [Transform.eulerAngles](#transformeulerangles) 20 | - [Transform.Rotate()](#transformrotate) 21 | - [Transform.RotateAround()](#transformrotatearound) 22 | - [Transform.LookAt()](#transformlookat) 23 | - [Quaternion.LookRotation()](#quaternionlookrotation) 24 | - [Quaternion.FromToRotation()](#quaternionfromtorotation) 25 | - [Quaternion.ToAngleAxis()](#quaterniontoangleaxis) 26 | - [Physics](#physics) 27 | - [Raycast](#raycast) 28 | - [Ignore Collision](#ignorecollision) 29 | - [Input](#input) 30 | - [Keyboard](#keyboard) 31 | - [Mouse](#mouse) 32 | - [Touch](#touch) 33 | - [UI](#ui) 34 | - [Button](#button) 35 | - [Slider](#slider) 36 | - [Audio](#audio) 37 | - [Basic Audio Play](#basic-audio-play) 38 | - [Scripting](#scripting) 39 | - [Coroutines](#coroutines) 40 | - [Async/Await](#asyncawait) 41 | - [Basic Structure](#basic-structure) 42 | - [Loading Resources](#loading-resources) 43 | - [Web Requests](#web-requests) 44 | - [Scene Loading](#scene-loading) 45 | - [Parallel Operations](#parallel-operations) 46 | - [Timeout Handling](#timeout-handling) 47 | - [Best Practices](#best-practices) 48 | - [Event Systems](#event-systems) 49 | - [Scriptable Objects](#scriptable-objects) 50 | - [Custom Editor Scripts](#custom-editor-scripts) 51 | - [Design Patterns](#design-patterns) 52 | - [Singleton](#singleton) 53 | - [Factory Pattern](#factory-pattern) 54 | - [Observer Pattern](#observer-pattern) 55 | - [Command Pattern](#command-pattern) 56 | - [State Pattern](#state-pattern) 57 | - [Basic Example](#basic-example) 58 | - [Detailed Example - Game Onboarding System](#detailed-example---game-onboarding-system) 59 | - [Strategy Pattern](#strategy-pattern) 60 | - [Basic Example](#basic-example-1) 61 | - [Detailed Example - Combat System](#detailed-example---combat-system) 62 | - [Object Pooling Pattern](#object-pooling-pattern) 63 | - [Chain of Responsibility Pattern](#chain-of-responsibility-pattern) 64 | - [Basic Example](#basic-example-2) 65 | - [Detailed Example - Input Handling System](#detailed-example---input-handling-system) 66 | - [Shortcuts](#shortcuts) 67 | - [Scene View Editing](#scene-view-editing) 68 | - [Scene View Navigation](#scene-view-navigation) 69 | - [Hierarchy Management](#hierarchy-management) 70 | - [Layout](#layout) 71 | - [Practical Use Cases](#practical-use-cases) 72 | - [Check if object is on the ground](#check-if-object-is-on-the-ground) 73 | - [Get the transform of a Body Bone](#get-the-transform-of-a-body-bone) 74 | - [Make object look at the camera](#make-object-look-at-the-camera) 75 | - [Load next scene](#load-next-scene) 76 | - [TBD (To Be Documented)](#tbd-to-be-documented) 77 | - [Input](#input-1) 78 | - [Scripting](#scripting-1) 79 | 80 | ## Basics 81 | 82 | ### [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html) 83 | [MonoBehaviour Life Cycle Flow Chart](https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg) 84 | ```csharp 85 | // MonoBehaviour is the base class from which every Unity script derives. 86 | // Offers some life cycle functions that are easier for you to develop your game. 87 | 88 | // Some of the most frequently used ones are as follows; 89 | Awake() 90 | Start() 91 | Update() 92 | FixedUpdate() 93 | LateUpdate() 94 | OnGUI() 95 | OnEnable() 96 | OnDisable() 97 | ``` 98 | 99 | ### [Transform](https://docs.unity3d.com/ScriptReference/Transform.html) 100 | ```csharp 101 | // Transform is a fundamental component in Unity that every GameObject has. 102 | // It defines the object's Position, Rotation, and Scale in the game world. 103 | 104 | // Access the transform component 105 | Transform transform = gameObject.transform; 106 | 107 | // Position: Vector3 representing world space coordinates (x, y, z) 108 | transform.position = new Vector3(0, 2, 0); // Set absolute position 109 | transform.localPosition = Vector3.zero; // Position relative to parent 110 | 111 | // Rotation: Can be set using Euler angles (degrees) or Quaternions 112 | transform.rotation = Quaternion.identity; // No rotation 113 | transform.eulerAngles = new Vector3(0, 90, 0); // Rotate 90 degrees around Y axis 114 | transform.localRotation = Quaternion.identity; // Rotation relative to parent 115 | 116 | // Scale: Vector3 representing scale on each axis 117 | transform.localScale = Vector3.one; // Normal scale (1, 1, 1) 118 | transform.localScale = new Vector3(2, 2, 2); // Double size on all axes 119 | 120 | // Parent-Child Relationships 121 | transform.parent = anotherObject.transform; // Set parent 122 | transform.SetParent(null); // Remove parent (make root) 123 | ``` 124 | 125 | ### [Vector3](https://docs.unity3d.com/ScriptReference/Vector3.html) 126 | ```csharp 127 | // Vector3 is representation of 3D vectors and points 128 | // It's used to represent 3D positions,considering x,y & z axis. 129 | 130 | Vector3 v = new Vector3(0f, 0f, 0f); 131 | ``` 132 | 133 | ### [Quaternion](https://docs.unity3d.com/ScriptReference/Quaternion.html) 134 | ```csharp 135 | // A Quaternion stores the rotation of the Transform in world space. 136 | // Quaternions are based on complex numbers and don't suffer from gimbal lock. 137 | // Unity internally uses Quaternions to represent all rotations. 138 | // You almost never access or modify individual Quaternion components (x,y,z,w); 139 | 140 | // A rotation 30 degrees around the y-axis 141 | Quaternion rotation = Quaternion.Euler(0, 30, 0); 142 | ``` 143 | 144 | ### Euler Angles 145 | ```csharp 146 | // Euler angles are "degree angles" like 90, 180, 45, 30 degrees. 147 | // Quaternions differ from Euler angles in that they represent a point on a Unit Sphere (the radius is 1 unit). 148 | 149 | // Create a quaternion that represents 30 degrees about X, 10 degrees about Y 150 | Quaternion rotation = Quaternion.Euler(30, 10, 0); 151 | 152 | // Using a Vector 153 | Vector3 EulerRotation = new Vector3(30, 10, 0); 154 | Quaternion rotation = Quaternion.Euler(EulerRotation); 155 | 156 | // Convert a transform's Quaternion angles to Euler angles 157 | Quaternion quaternionAngles = transform.rotation; 158 | Vector3 eulerAngles = quaternionAngles.eulerAngles; 159 | ``` 160 | 161 | ## Movement & Rotation 162 | 163 | ### Move Object 164 | #### Transform.Translate() 165 | ```csharp 166 | // Moves the transform in the direction and distance of translation. 167 | public void Translate(Vector3 translation); 168 | public void Translate(Vector3 translation, Space relativeTo = Space.Self); 169 | 170 | transform.Translate(Vector3.right * movementSpeed); 171 | ``` 172 | 173 | #### Vector3.MoveTowards() 174 | ```csharp 175 | // Calculate a position between the points specified by current and target 176 | // Moving no farther than the distance specified by maxDistanceDelta 177 | public static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta); 178 | 179 | Vector3 targetPosition; 180 | transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime); 181 | ``` 182 | 183 | #### Vector3.Lerp() 184 | ```csharp 185 | // Linearly interpolates between two points. Results in a smooth transition. 186 | public static Vector3 Lerp(Vector3 startValue, Vector3 endValue, float interpolationRatio); 187 | 188 | Vector3 targetPosition; 189 | float t = 0; 190 | t += Time.deltaTime * speed; 191 | transform.position = Vector3.Lerp(transform.position, targetPosition, t); 192 | ``` 193 | 194 | #### Vector3.SmoothDamp() 195 | ```csharp 196 | // Gradually changes a vector towards a desired goal over time. 197 | // The vector is smoothed by some spring-damper like function, which will never overshoot. 198 | // The most common use is for smoothing a follow camera. 199 | public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed = Mathf.Infinity, float deltaTime = Time.deltaTime); 200 | 201 | float smoothTime = 1f; 202 | Vector3 velocity; 203 | Vector3 targetPosition = target.TransformPoint(new Vector3(0, 5, -10)); 204 | // Smoothly move the camera towards that target position 205 | transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, smoothTime); 206 | ``` 207 | 208 | ### Rotate Object 209 | #### Transform.rotation 210 | ```csharp 211 | // A Quaternion stores the rotation of the Transform in world space. 212 | // Quaternions are based on complex numbers and don't suffer from gimbal lock. 213 | // Unity internally uses Quaternions to represent all rotations. 214 | 215 | transform.rotation = new Quaternion(rotx, roty, rotz, rotw); 216 | ``` 217 | 218 | #### Transform.eulerAngles 219 | ```csharp 220 | // Transform.eulerAngles represents rotation in world space. 221 | // It is important to understand that although you are providing X, Y, and Z rotation values to describe your rotation 222 | // those values are not stored in the rotation. Instead, the X, Y & Z values are converted to the Quaternion's internal format. 223 | 224 | transform.eulerAngles = Vector3(rotx, roty, rotz); 225 | ``` 226 | 227 | #### Transform.Rotate() 228 | ```csharp 229 | // Applies rotation around all the given axes. 230 | public void Rotate(Vector3 eulers, Space relativeTo = Space.Self); 231 | public void Rotate(float xAngle, float yAngle, float zAngle, Space relativeTo = Space.Self); 232 | 233 | transform.Rotate(rotx, roty, rotz); 234 | ``` 235 | 236 | #### Transform.RotateAround() 237 | ```csharp 238 | // Rotates the transform about axis passing through point in world coordinates by angle degrees. 239 | public void RotateAround(Vector3 point, Vector3 axis, float angle); 240 | 241 | // Spin the object around the target at 20 degrees/second. 242 | Transform target; 243 | transform.RotateAround(target.position, Vector3.up, 20 * Time.deltaTime); 244 | ``` 245 | 246 | #### Transform.LookAt() 247 | ```csharp 248 | // Points the positive 'Z' (forward) side of an object at a position in world space. 249 | public void LookAt(Transform target); 250 | public void LookAt(Transform target, Vector3 worldUp = Vector3.up); 251 | 252 | // Rotate the object's forward vector to point at the target Transform. 253 | Transform target; 254 | transform.LookAt(target); 255 | 256 | // Same as above, but setting the worldUp parameter to Vector3.left in this example turns the object on its side. 257 | transform.LookAt(target, Vector3.left); 258 | ``` 259 | 260 | #### Quaternion.LookRotation() 261 | ```csharp 262 | // Creates a rotation with the specified forward and upwards directions. 263 | public static Quaternion LookRotation(Vector3 forward, Vector3 upwards = Vector3.up); 264 | 265 | // The following code rotates the object towards a target object. 266 | Vector3 direction = target.position - transform.position; 267 | Quaternion rotation = Quaternion.LookRotation(direction); 268 | transform.rotation = rotation; 269 | ``` 270 | 271 | #### Quaternion.FromToRotation() 272 | ```csharp 273 | // Creates a rotation (a Quaternion) which rotates from fromDirection to toDirection. 274 | public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection); 275 | 276 | // Sets the rotation so that the transform's y-axis goes along the z-axis. 277 | transform.rotation = Quaternion.FromToRotation(Vector3.up, transform.forward); 278 | ``` 279 | 280 | #### Quaternion.ToAngleAxis() 281 | ```csharp 282 | // Converts a rotation to angle-axis representation (angles in degrees). 283 | // In other words, extracts the angle as well as the axis that this quaternion represents. 284 | public void ToAngleAxis(out float angle, out Vector3 axis); 285 | 286 | // Extracts the angle - axis rotation from the transform rotation 287 | float angle = 0.0f; 288 | Vector3 axis = Vector3.zero; 289 | transform.rotation.ToAngleAxis(out angle, out axis); 290 | ``` 291 | 292 | ## Physics 293 | ### Raycast 294 | 295 | ```csharp 296 | void FixedUpdate() { 297 | // Bit shift the index of the layer (8) to get a bit mask 298 | int layerMask = 1 << 8; 299 | 300 | // This would cast rays only against colliders in layer 8. 301 | // But instead we want to collide against everything except layer 8. The ~ operator does this, it inverts a bitmask. 302 | layerMask = ~layerMask; 303 | 304 | RaycastHit hit; 305 | // Does the ray intersect any objects excluding the player layer 306 | if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity, layerMask)) { 307 | Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.yellow); 308 | Debug.Log("Did Hit"); 309 | } 310 | } 311 | ``` 312 | 313 | ### Ignore Collision 314 | ```csharp 315 | // Makes the collision detection system ignore all collisions between collider1 and collider2. 316 | public static void IgnoreCollision(Collider collider1, Collider collider2, bool ignore = true); 317 | 318 | // Here we're disabling the collision detection between the colliders of ally and bullet objects. 319 | Transform bullet; 320 | Transform ally; 321 | Physics.IgnoreCollision(bullet.GetComponent(), ally.GetComponent()); 322 | ``` 323 | 324 | ## Input 325 | 326 | ### Keyboard 327 | 328 | ```csharp 329 | // Returns true during the frame the user starts pressing down the key 330 | if (Input.GetKeyDown(KeyCode.Space)) { 331 | Debug.Log("Space key was pressed"); 332 | } 333 | 334 | // Jump is also set to space in Input Manager 335 | if (Input.GetButtonDown("Jump")) { 336 | Debug.Log("Do something"); 337 | } 338 | ``` 339 | 340 | ### Mouse 341 | 342 | ```csharp 343 | if (Input.GetAxis("Mouse X") < 0) { 344 | Debug.Log("Mouse moved left"); 345 | } 346 | 347 | if (Input.GetAxis("Mouse Y") > 0) { 348 | Debug.Log("Mouse moved up"); 349 | } 350 | 351 | if (Input.GetMouseButtonDown(0)) { 352 | Debug.Log("Pressed primary button."); 353 | } 354 | 355 | if (Input.GetMouseButtonDown(1)) { 356 | Debug.Log("Pressed secondary button."); 357 | } 358 | 359 | if (Input.GetMouseButtonDown(2)) { 360 | Debug.Log("Pressed middle click."); 361 | } 362 | ``` 363 | 364 | ### Touch 365 | ```csharp 366 | if (Input.touchCount > 0) { 367 | touch = Input.GetTouch(0); 368 | 369 | if (touch.phase == TouchPhase.Began) { 370 | Debug.Log("Touch began"); 371 | } 372 | 373 | if (touch.phase == TouchPhase.Moved) { 374 | Debug.Log("Touch moves"); 375 | } 376 | 377 | if (touch.phase == TouchPhase.Ended) { 378 | Debug.Log("Touch ended"); 379 | } 380 | } 381 | ``` 382 | 383 | ## UI 384 | 385 | ### Button 386 | 387 | ```csharp 388 | // Button is used to handle user clicks and interactions. 389 | // Attach this script to a Button component to respond to button clicks. 390 | 391 | using UnityEngine.UI; 392 | 393 | Button myButton = GetComponent