Sunday, 21 November 2021

Unity Implementing Finite State Pattern (FSM)

 State patterns are very useful when organized.   The theory behind is grouping every behavior in separated  classes and making those classes loosely coupled to the main algorithm

all game object behaviors will be grouped into some classes  and can be maintained by a main Finite State Machine Manager class

State patterns can be implemented with "Observation" systems

in our example, there is a player  moving to the target point  and we will have 3 different states for player

1. Idle state

2. Search State

3. Found state

In our example, there is a cube and a plain  when you click anywhere on-screen player moves to this point and stops

when the game starts Player is at IdleState (there must be an initial state for FSM to work)

so SearchState when you clicked somewhere on-screen

and FoundState when cube reached finish position

 To set up this example create an empty scene and add a plane and add a cube 

and add an EmptyGameObject => Namethis TargetAssigner and add "TargetAssigner" component to EmptyGameObject

and Add "PlayerStateManager" to Cube Object





=> Start by Creating Our IState Interface

  public interface IState
{
// start executing state
    void Enter();
// update in state
    void Tick();
//fixed Update in state
    void FixedTick();
// exiting current sate
    void Exit();
}
 
=> And Base StateMachine Class "StateMachineBase"

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class StateMachineBase : MonoBehaviour
{
    public IState CurrentState { get; private set; }
    public IState _previousState;
    bool _inTransition = false;
    public void ChangeState(IState newState)
    {
        if (CurrentState == newState || _inTransition)
            return;
        ChangeStateRoutine(newState);

    }
    public void RevertState()
    {
        if (_previousState != null)
            ChangeState(_previousState);
    }
    void ChangeStateRoutine(IState newState)
    {
        _inTransition = true;
        if (CurrentState != null)
            CurrentState.Exit();
        if (_previousState != null)
            _previousState = CurrentState;
        CurrentState = newState;
        CurrentState.Enter();
        _inTransition = false;
    }
    private void Update()
    {
        if (CurrentState != null && !_inTransition)
            CurrentState.Tick();
    }
    private void FixedUpdate()
    {
        if (CurrentState != null && !_inTransition)
            CurrentState.FixedTick();
    }

}

 
  
*** Those two classes can be used in any project as the main construction for FSM


=> For assigning Cube target there is our assigner (this is only for assigning target)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TargetAssigner : MonoBehaviour
{
    // delegate for moving player towards point
    public Action<Vector3> MoveCommand = delegate { };


    #region Fields
    Ray ray;
    RaycastHit hit;
    #endregion

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
                MoveCommand.Invoke(hit.point);
               
            }
        }
    }

    private void OnDrawGizmos()
    {
        // to see target gizmo
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(this.hit.point, 1F);
    }
}

=> Player State Manager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[RequireComponent(typeof(Rigidbody))]
public class PlayerStateManager : StateMachineBase
{
    #region Unity Fields
  
 
    [SerializeField]
    TargetAssigner target;
    [SerializeField]
    public  float RotateSpeed;
    [SerializeField]
    public float MoveSpeed;

    #endregion
    #region Public States
    public IdleState IdleState { get; private set; }
    public SearchState SearchState { get; private set; }
    public FoundState FoundState { get; private set; }
    #endregion
    public Vector3 TargetPosition { get;  set; }
    #region Fields
    Material stateMaterial;
    Rigidbody rbd;
    #endregion
    private void Awake()
    {
        rbd = this.GetComponent&ltRigidbody>();
        stateMaterial = this.GetComponent<MeshRenderer>().material;
        IdleState = new IdleState(this, stateMaterial, target);
        SearchState = new SearchState(this, stateMaterial, rbd);
        FoundState = new FoundState(this,stateMaterial,target);
    }
    private void Start()
    {
        ChangeState(IdleState);
    }





}


=> Idle State

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IdleState : IState
{
    PlayerStateManager _playerSM;
    TargetAssigner _targetAssigner;
    Material _material;
    Color _stateColor=Color.yellow;

    public  IdleState(PlayerStateManager playerSM, Material material,TargetAssigner targetAssigner)
    {

        this._playerSM = playerSM;
        this._material = material;
        this._targetAssigner = targetAssigner;
    }

    public void Enter()
    {
        Debug.Log("Idle State Enter");
        _material.color = _stateColor;
        _targetAssigner.MoveCommand += OnNewTargetAcuired;
    }

    public void Exit()
    {
        _targetAssigner.MoveCommand -= OnNewTargetAcuired;
    }

    public void FixedTick()
    {
        
    }

    public void Tick()
    {
        //
        Debug.Log("Idle State Tick");
    }

    void OnNewTargetAcuired(Vector3 newPosition)
    {

        _playerSM.TargetPosition = newPosition;
        _playerSM.ChangeState(_playerSM.SearchState);
    }
    

    // Start is called before the first frame update

}

=> Searcing State

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SearchState : IState
{
    PlayerStateManager _playerSM;
    Rigidbody _rbd;
    Material _material;
    Color _stateColor = Color.red;
    public SearchState(PlayerStateManager playerStateMan,Material material,Rigidbody rb)
    {
        _rbd = rb;
        _material = material;
        _playerSM = playerStateMan;
    }
    public void Enter()
    {
        Debug.Log($"STATE CHANE - Search");
        _material.color = _stateColor;
    }

    public void Exit()
    {
       
    }

    public void FixedTick()
    {
        float distanceFromtarget = Vector3.Distance(_playerSM.TargetPosition, _rbd.position);
        if (distanceFromtarget &lt .8F)
        {
            _playerSM.ChangeState(_playerSM.FoundState);
        }
        else
        {
            RotateTowardsTarget();
            MoveTowerdsTarget();
        }
    }
    void RotateTowardsTarget()
    {
        Quaternion lookrotation = Quaternion.LookRotation(_playerSM.TargetPosition - _rbd.position);
        lookrotation = Quaternion.Slerp(_rbd.rotation, lookrotation, _playerSM.RotateSpeed * Time.deltaTime);
        _rbd.MoveRotation(lookrotation);
    }
    void MoveTowerdsTarget()
    {
//        Vector3 moveoffset = _playerSM.transform.forward * _playerSM.MoveSpeed;
        _rbd.MovePosition(Vector3.Lerp(_playerSM.transform.position, _playerSM.TargetPosition,_playerSM.MoveSpeed));
    }

    public void Tick()
    {
   
    }
}

=> Found State

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FoundState : IState
{

    PlayerStateManager _playerStateManager;
    Color foundColor = Color.green;
    Material _material;
    TargetAssigner _targetassigned;
    public FoundState(PlayerStateManager playerStateManager, Material material, TargetAssigner targetassigned)
    {
        this._playerStateManager = playerStateManager;
        this._material = material;
        this._targetassigned = targetassigned;
    }
    public void Enter()
    {

        Debug.Log("Player is at found state");
        _material.color = foundColor;
        _targetassigned.MoveCommand += NewMoveCommand;
    }
    public void Exit()
    {
        _targetassigned.MoveCommand -= NewMoveCommand;
    }

    private void NewMoveCommand(Vector3 obj)
    {
        _playerStateManager.TargetPosition = obj;
        _playerStateManager.ChangeState(_playerStateManager.SearchState);
    }
    public void FixedTick()
    {
    }

    public void Tick()
    {
    
    }
}

Sunday, 7 November 2021

Unity Implementing Singleton

  Creating singleton objects can be very useful but you should  use it with some caution  first of all you need to make sure only one object is created in scene  and make sure it's needed for all scenes like audio/level changing exc

And Second important thing is don't make it a GOD mode class  and don't put everything in singleton classes

it will make your project more and more coupled and when it gets bigger you won't be able to manage it

there are several ways to create a singleton class but we will use it with a generic type so you can reuse it in any kind of project you like ;

Example is a simple level changing manager system like "GameManager"  when level completed loads the next level  and on next level loads next level again you dont have to  add this object in every level of the game



First of All our Generic "SingletonCreator" class ;


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SingletonCreator<T> : MonoBehaviour where T:MonoBehaviour{

    private static T _instance;
    public static T instance
    {
        get
        {
         
            return _instance;
        }
        set
        {
            _instance = value;
        }
    }
    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
        }
        _instance = this.GetComponent<T>();
        DontDestroyOnLoad(_instance);
    }

}

And Our  GameManager Looks like this; (Don't forget to add this "MonoBehaviour" class to scene or you may get null exceptions)


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : SingletonCreator<GameManager>;
{
    public int LevelIndex = 0;
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("object created");
        
    }



    public void LoadnextLevel()
    {
        LevelIndex += 1;
        SceneManager.LoadScene(LevelIndex);
    }

    public int NextLevelIndex()
    {
        Debug.Log($"LevelIndex Current Value : {LevelIndex}");
        LevelIndex++;
        return LevelIndex;
    }

    
}

As you se GameManager,AudioManager exc can be easily made singleton you may implement this aproach for different game objects 

To call Any GameManager Method  wrote a Single ButtonClick script  this script calls 

GameManager And Loads Scene



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ButtonClick : MonoBehaviour
{
    [SerializeField]
    Text buttonText;
    public void LoadNextScene()
    {
        GameManager.instance.LoadnextLevel();
    }

    public void IncreaseLevelText()
    {
        buttonText.text = GameManager.instance.NextLevelIndex().ToString();
    }
}

when you click button loads Nextlevel from GameManager.instance and second method increases levelIndex just for test out you may add a button on scene and bind this "ButtonClick" script and call NextLevel or IncreaseLevelText methods

Feel free to ask me any question you like

Happy Coding :)

Unity Implementint Object Pool

  Object pooling is a great way to  optimize your game and avoid memory leak you should implement this method on games in which you instantiate and destroy a lot of game objects this  approach  creates a game object pool and  does not destroy this object  only disables it and calls the same object when needed

it's a very modular reusable system in any kind of game


First of All Create A folder for Pooler like "ObjPooler" and ad those scripts

"CreateGameObjects" Script;


 
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

    public class CreateGameObjects : MonoBehaviour
    {
        public Transform Parent;
        
        [SerializeField]
        public List&ltPool> gameObjectList;
        private PoolDictionary poolDic;
        [SerializeField]
        private List&ltGameObject> gmSelectedGameObjects;
        private Transform destinatinTransform;private static CreateGameObjects _instance;
        public static CreateGameObjects Instance { get { return _instance; } }
        void Awake()
        {
        // Makes object singleton so you can reach easily
        if (_instance != null && _instance != this)
        {
            Destroy(this.gameObject);
        }
        else
        {
            _instance = this;
        }
        StartPooling();
        }
        public void StartPooling()
        {
            destinatinTransform = this.GetComponent&ltTransform>();
            poolDic = GetComponent&ltPoolDictionary>();
            poolDic.ResetPool();
            poolDic.setPool(gameObjectList, Parent);
        }

        public GameObject CreateGameObject(string TagName, Vector3 pos, Transform parent)
        {
            return poolDic.SpawnFromPool(TagName, pos, parent);
        }
        public GameObject InstantiateObject(string TagName, Vector3 pos)
        {
            Pool item = gameObjectList.Where(x => x.tag == TagName).FirstOrDefault();
            if (item != null)
            {
                return Instantiate(item.prefab, pos, Quaternion.identity);
            }
            return null;

        }

        public int AddOnScreenSelectedGameObject(GameObject gmObj)
        {
            gmSelectedGameObjects.Add(gmObj);
            return gmSelectedGameObjects.IndexOf(gmObj); // last insterted index
        }
        public void RemoveOnScreenSelectedGameObject()
        {
            gmSelectedGameObjects.Clear();

        }


    }

 

"Pool" Script


    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;
    }

 
"PoolDictionary" Script;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


    public class PoolDictionary : MonoBehaviour
    {
        //game objects queue
        [HideInInspector]
        public Dictionary&ltstring, Queue&ltGameObject>> poolDictionary;

        private List&ltPool> _pool;
        public void ResetPool()
        {
            _pool = new List&ltPool>();

        }
        // starts objectpool
        public void setPool(List&ltPool> pool, Transform parent)
        {
            _pool = pool;
            poolDictionary = new Dictionary&ltstring, Queue&ltGameObject>>();
            foreach (Pool item in _pool)
            {
                Queue&ltGameObject> objectPool = new Queue&ltGameObject>();
                for (int i = 0; i &lt item.size; i++)
                {
                    GameObject gmObj = Instantiate(item.prefab);
                    gmObj.SetActive(false);
                    //  gmObj.transform.SetParent(parent);
                    objectPool.Enqueue(gmObj);
                }
                poolDictionary.Add(item.tag, objectPool);
            }

        }
        private void activateAllChildren(GameObject gm)
        {
            gm.SetActive(true);
            for (int j = 0; j &lt gm.transform.childCount; j++)
            {
                gm.transform.GetChild(j).gameObject.SetActive(true);
            }

        }

        // calls object from pool
        public GameObject SpawnFromPool(string tag, Vector3 position, Transform parent)
        {
            if (!poolDictionary.ContainsKey(tag))
            {
                Debug.Log("Obj tag is not Found:" + tag);
                return null;
            }
            GameObject spawnObj = poolDictionary[tag].Dequeue();
            //makes selected gameobject active
            activateAllChildren(spawnObj);
            if (parent != null)
            {
                spawnObj.transform.SetParent(parent);
            }
            else
            {
                //  transform.SetParent(parent);
            }
            spawnObj.transform.position = position;
            spawnObj.transform.rotation = Quaternion.identity;

            poolDictionary[tag].Enqueue(spawnObj);
            return spawnObj;


        }



    }

you can implement those classes in any kind of project always the same to showcase an example I have created a player  and you can shoot with "space" button

Here is my "PlayerShooter" Script;

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShooter : MonoBehaviour
{
    [SerializeField]
    Transform shootingPoint;

    GameObject currentGameObj;
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
           currentGameObj= CreateGameObjects.Instance.CreateGameObject("Bullet", this.transform.position, null);
            currentGameObj.transform.position = shootingPoint.transform.position;
        }
    }
}

  


 And to Shoot Bullets here is my "BulletScript";

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletScript : MonoBehaviour
{
    
    void Update()
    {
        // speed can be a serializefield its for demostration.
        this.transform.position += Vector3.forward * 30F * Time.fixedDeltaTime;
    }
    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log("Bullet Collision");
        this.gameObject.SetActive(false);
    }
}

   

 and to start pooling you have to add Pool object to scene




 as You see There is a Bullet object  prefab it's a sphere  with nothing fancy only a collider and rigid body added with all axes constraint  as you see there is a very simple scene   you  need to add "PlayerShooter" Script to the player and "BulletScript" to Bullet and set Bullet tag"Bullet" 
you may set bullet pool size any count you like based on your game needs and you can add any kind of object  to the pool system





 So that's all for now if you have difficulties with implementation please mail me I can send you the whole project or don't hesitate to ask questions :)

happy coding :)









Monday, 1 November 2021

Unity Implementing Observer Pattern

Observer pattern is very useful when you need some event trigered actions in your game

i mean by that when you reach some point  or archived a bonus  some other game objects  might need  this information  you will have to inform your UI or some other enemies ect.


Using it is very simple

first of all  our example is a very simple scene  we have tree cubes Red,Blue and Gold Cubes

when player reachs Blue cube score increases on red cube score dicreases

And gold cube gets this information and appiers on screen

when player reaches gold cube  100 more score adds to player  and player control willbe disabled

its a basic example for focusing on pattern;

Since we have 3 different  behaved cubes we will have three different Scripts;

=> Red Cube Event onCollisionentered Invokes redCubeReached to subscribers

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RedCubeEvent : MonoBehaviour
{
    public static event Action redCubeReached;

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Player")  // assume that you only looking for player
            redCubeReached?.Invoke();
    }
}

=> Blue Cube Event OnCollisionentered Invokes cubeReached to all subscribers

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BlueCubeEvent : MonoBehaviour
{
    public static event Action cubeReached;

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Player")  // assume that you only looking for player
        {
            Debug.Log($"cube has been breached", this.gameObject);
            cubeReached?.Invoke();
        }
    }
}

=> Gold Cube Event

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GoldCubeEvent : MonoBehaviour
{

    public static event Action goldUnlocked;

    bool isRedCubeOk;
    bool isBlueCubeOk;
    MeshRenderer mesh;
    BoxCollider collider;
    private void Start()
    {
        mesh = this.GetComponent&ltMeshRenderer&gt();
        collider = this.GetComponent&ltBoxCollider&gt();
        BlueCubeEvent.cubeReached += CubeEvent_cubeReached;
        RedCubeEvent.redCubeReached += RedCubeAdditionalEvent_redCubeReached;
        mesh.enabled = false;
        collider.enabled = false;


    }

    private void RedCubeAdditionalEvent_redCubeReached()
    {
        isRedCubeOk = true;
        CheckStatsAndFireGoldEvent();
    }

    private void CubeEvent_cubeReached()
    {
        isBlueCubeOk = true;
        CheckStatsAndFireGoldEvent();
    }

    private void CheckStatsAndFireGoldEvent()
    {
        if (isRedCubeOk && isBlueCubeOk) // i can fire my gold event
        {
            collider.enabled = true;
            mesh.enabled = true;
            
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Player")
        {
            
            goldUnlocked?.Invoke();
        }
    }

}


=> Player Controller (simple for example) 
Player controller is listening for goldUnlocked event and Subscribing it by GoldCube_goldUnlocked method  its like  reaction to an event 

       
       using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField]
    float moveSpeed;

    bool isGameFinished;
    void Start()
    {
        isGameFinished = false;
        GoldCubeEvent.goldUnlocked += GoldCube_goldUnlocked;
    }

    private void GoldCube_goldUnlocked()
    {

        isGameFinished = true;
        Debug.Log("Player You have Reach the end of level Controls disabled now" );
        
    }

    /// 
    /// Very basic  movement system
    /// 
    void Update()
    {
        if (isGameFinished)
            return;
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 p = this.transform.position;
        p.x += h * moveSpeed;
        p.z += v * moveSpeed;
        this.transform.position = p;
    }
}

       
=> ScoreCounter 
Score Controller observes three different events with AddScore,SubstractScore,GoldEvent
as you see Score changes based on action

     using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ScoreCounter : MonoBehaviour
{
    [SerializeField]
    Text scoreText;
    int currentScore = 0;
    private void OnEnable()
    {
        // setting up observetions
        // subscriped methods
        BlueCubeEvent.cubeReached += AddScore;
        RedCubeEvent.redCubeReached += SubstractScore;
        GoldCubeEvent.goldUnlocked += GoldEvent;
    }

    private void GoldEvent()
    {
        currentScore += 100;
        Debug.Log($"This function is fired from gold Cube");
        scoreText.text = $"Score:{currentScore}";
    }

    private void SubstractScore()
    {
        Debug.Log($"This function is fired by RedcubeReached Event  The RedCube");
        currentScore--;
        currentScore = Mathf.Clamp(currentScore, 0, int.MaxValue);
        scoreText.text = $"Score:{currentScore}";


    }

    private void AddScore()
    {

        Debug.Log($"This function is fired by cubeReached Event The BlueCube ");
        currentScore++;
        scoreText.text = $"Score:{currentScore}";   
    }
    private void OnDisable()
    {
        // unsubscribe on disable  to prevent errors
        BlueCubeEvent.cubeReached -= AddScore;
        RedCubeEvent.redCubeReached -= SubstractScore;
    }
}

Observerpattern can be used in  many different games  by chaning events and combinig wiht different
scenarios  many problems may be solved easly
i hope it helps everyone 
Happy coding :)