Wednesday, 1 February 2023

I've published a full Unity3d Course for you!

 Hello everyone in this post I'd like to let you know that I've created two great courses for Udemy Platform.😀


 First course is a more Beginner friendly course we will  start with Unity basics and create our game
What you'll learn
Understanding Unity Basics and Beyond
Unity Colliders
How to Use Rigidbody
Understanding Developing a real game and improvements
Creating Different Enemy AI system
Unity C# coding with advanced systems Object oriented programming
Creating Singleton Object in Generic Classes
Unity Event System
Creating Custom Editor Scripts
Adding AudioSource And Play Audio in most effective way
This Course is more  detailed and I'm covering howto use  Design Patterns in game development.
How to Use mostly used assets like DoTween To speed up your development

Learn Unity C# Like Pro Pacman into 3D

C# Essentials

Learn Unity3D Mobile Games with Best C# Design Patterns!

What you'll learn?

Game Object Pooling with details

Creating Singleton Pattern objects in the right way

Observer Pattern Real game implementation

Implementing Event Driven Game Developlment with some event Managers

Implementing finite state pattern with complete guidance

Learn C# Design Patterns with real game development

Examinate Best Practice implementation of C# and real Object Oriented Programing

Instead of only developing game learn the development system and use it in your own games

You will learn most professionaly used game development techniques in the insdustry

You Will learn how to import animations and switch between animations

Using Cinemachine adding shake system with cinemachine







Sunday, 23 January 2022

Unity How To implement Factory Pattern

Factory Pattern is very popular if you are looking for creating kind of same objects with different properties for example implementing additional properties to factorized game object like adding different colors abilities

Most important step is to create a good factory class which can be implemented in to most different  situations I prefer a static class with generic option because there can be different  objects it completely isolates from other classes.

One certain property is imprtant in our example its "Name" property name of prefab or game object to create from factory

In Our example thjere are different type of buildings "House","Office","Government" buildings they both have same properties and some of them may change.


PackageLink is here  ClickTo Download


I started with a building FactoryGenerator Class

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

public static class FactoryGenerator<T> where T : class
{
    
    // Name of prefab or game object
    private const string NAME = "Name";
    // dictionary for keeping created factories and find by name when its needed
    private static Dictionary<string, T> factoryTypesByName;
    // check if system started by a simple null check
    private static bool isinitialized = factoryTypesByName != null;
    public static void InitializeFactoryGenerator()
    {
        
        // if started no need to work code again
        if (isinitialized) { return; }
        // creawte instance of dictionary to add
        factoryTypesByName = new Dictionary<string, T>();
        // get all the factories which arent abstract and child of our main class provided with (T)  
        // this line uses System.Linq
        var factoryTypes = Assembly.GetAssembly(typeof(T)).GetTypes().Where(x => x.IsClass && !x.IsAbstract && x.IsSubclassOf((typeof(T))));
       
        foreach (var type in factoryTypes)
        {
            //Creates instance of subclass
            var factory = Activator.CreateInstance(type) as T;
            // get Name property of class as string 
            var rslt = factory.GetType().GetProperty(NAME).GetValue(factory) as string;
            // add to Dictionary
            factoryTypesByName.Add(rslt, factory);
        }
    }
    /// 
    /// calls from factory by PrefabName
    /// 
    ///
    /// 
    public static T CreateObject(string Code)
    {
        // get first macth of class and return as class
        return factoryTypesByName.Where(v => v.Key == Code).Select(x => x.Value).FirstOrDefault();
    }
}


  
=> And Main FactoryClass as a base class to other factory classes
*** This class has one rule has to have a "Name" property to provide name of Prefab
=> We may add different virtual methods for base operations and override some of them to improve  since it's a simple example I have added only a few  fields

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

public abstract class Buildings:MonoBehaviour
{
    public abstract string Name { get; }
    // property of a building
    public abstract Color buildingColor { get; }
    // sample creation of building
    public virtual void CreateBuilding()
    {
    /// creates object based on name
        GameObject gmObj = Resources.Load(this.Name) as GameObject;
        Instantiate(gmObj);
        gmObj.transform.position = Vector3.zero;
    }
}



those two classes are the main structure for factory pattern now its time to create different types of factorized objects all the classes will be the same but can be changed easily and separately all of them are Inherited from the "Buildings" Class

=> Office Class

public class Office : Buildings
{
    public override string Name => "Office";

    public override Color buildingColor => Color.red;

    public override void CreateBuilding()
    {
        base.CreateBuilding();
    }
}

=>Hause Class

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

public class House : Buildings
{
    public override string Name => "House";

    public override Color buildingColor => Color.green;

    public override void CreateBuilding()
    {
        base.CreateBuilding();
    }
}
=> Government Class
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Government : Buildings
{
    public override string Name => "Government";

    public override Color buildingColor => Color.blue;

    public override void CreateBuilding()
    {
        base.CreateBuilding();
       
    }
}
=> Finally we havve all structure we need now its time to call from factory
Create a simple scene and create 3 prefabs in "Resources" Folder Make sure prefabname is same as property "Name" Than add 3 Buttons to your Scene like this 
And Add An Empty Game object Add "CreateFromFactory" script to this object

Assign Buttons one by one 
HouseButton=>CreateHause
OfficeButton=>CreateOffice
GovernmentButton=>CreateGovernment

=>"CreateFromFactory" Class is  should be like below
calls the factory by object name and creates game objects

public class CreateFromFactory : MonoBehaviour
{
    private void Start()
    {
        // setup building factory;
        FactoryGenerator<Buildings>.InitializeFactoryGenerator();
    }

    public void CreateOffice()
    {
        this.CreateFactory("Office");
    }
    public void CreateHause()
    {
        this.CreateFactory("House");
    }
    public void CreateGovernment()
    {
        this.CreateFactory("Government");
    }


    private void CreateFactory(string name)
    {
        Buildings rslt = FactoryGenerator<Buildings>.CreateObject(name);
        rslt.CreateBuilding();
    }

}
=>Result
Its normal you may think like why arent be just instantiating objects yes it can be made but 
to manage every object in game and gaining control over properties e specially when you have  same object with different proprerties this approach cames in handy 
and keeps your much cleaner and readable  every time
Also improves reuseablity of code with different projects.


Happy Coding 





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 :)


     

Sunday, 31 October 2021

Unity Implementing Command Pattern

To Implement a Command Pattern you need Two Classes first


"ICommand" as "Interface" And CommandList to hold all commands


ICommand Interface;

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

public interface  ICommand 
{
    void Execute();
    void Undo();
}


CommandList Class (No monoBehaviour inheritance**)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class CommandList
{
    private const int MAXCOMMAND = 100;
    private Stack<ICommand> commandList = new Stack<ICommand>();

    public void Execute(ICommand command)
    {
        command.Execute();
        if (commandList.Count < MAXCOMMAND)
            commandList.Push(command);
    }

    public void Undo()
    {
        if (commandList.Count <= 0)
            return;
        commandList.Pop().Undo();
    }

  
}




 those two classes is main implementation  after that you can use those classes based on your sceneraio;

For example you scale your cube based on your imput
 and you move your cube based on your mouse movement
So command will be seperated  like "MoveCommand" and "ScaleCommand"


Move Command (Inherites from ICommand);


public class MoveCommand : ICommand
{

    private Transform movingObject;
    private Vector3 direction;
    private float moveSpeed;
    public MoveCommand(Transform transform,Vector3 direction,float moveSpeed)
    {
        this.movingObject = transform;
        this.direction = direction;
        this.moveSpeed = moveSpeed;
    }
     public void Execute()
    {
        this.movingObject.transform.position += this.direction* moveSpeed;
    }

    public void Undo()
    {
        this.movingObject.transform.position -= this.direction* moveSpeed;
    }

}

Scale Command(Inherites from ICommand);

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

public class ScaleCommand : ICommand
{
    private float scalefactor;
    private Transform transform;
    public ScaleCommand(float scalefactor,Transform transform)
    {
        this.scalefactor = scalefactor;
        this.transform = transform;
    }

    public void Execute()
    {
        this.transform.localScale += Vector3.one * scalefactor;
    }

    public void Undo()
    {
        this.transform.localScale -= Vector3.one * scalefactor;
    }

 
}
 
To Finalize every thing and combine mechanics togeter you have to call those classes 

let's say "CubeController" to our Main Class

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

public class CubeController : MonoBehaviour
{
    // Start is called before the first frame update
    [SerializeField]
    float moveSpeed;
    [SerializeField]
    float scaleUpMultiplyer;
    Vector3 lastPos;
    Vector3 deltaPos;
    // Update is called once per frame
    CommandList commands = new CommandList();
    void Update()
    {

        MovingInputs();
        ScaleInputs();
        UndoInput();
    }

    void ScaleInputs()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            commands.Execute(new ScaleCommand(scaleUpMultiplyer, this.transform));
        }

    }
    void UndoInput()
    {
        if (Input.GetKey(KeyCode.Q))
        {
            commands.Undo();
        }
        if (Input.GetKeyDown(KeyCode.Z))
        {
            commands.Undo();
        }
    }
    void MovingInputs()
    {
        if (Input.GetMouseButtonDown(0))
        {
            lastPos = Input.mousePosition;
        }
        else if (Input.GetMouseButton(0))
        {
            deltaPos = Input.mousePosition - lastPos;

            commands.Execute(new MoveCommand(this.transform, deltaPos, moveSpeed));
        }
       
    }
}



you can  do commands and undo commands with this system  every new mechanic will be Inherited from ICommand   like  Coloring Cube,RotatingCube and  can be Undo  using CommandList
Feel Free to ask any questions :)

Happy Coding :)