Welcome to GEMENTAR TOUR PUO V2 Development Documentation. Enjoy your stay!

This is an old revision of the document!


Player Prototyping

ZombiePlayerController Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using Micosmo.SensorToolkit;
using System;
using Sirenix.OdinInspector;
 
public class ZombiePlayerController : MonoBehaviour
{
    [BoxGroup("GameObject Serialization")]
    public GameObject cross;
    [BoxGroup("GameObject Serialization")]
    public Transform charater;
 
    [BoxGroup("DoLookAt Fine Tune")]
    public float lookAtSpeed = 1f;
 
    [BoxGroup("Movement Fine Tune")]
    public float movementSpeed = 1f;
    [BoxGroup("Movement Fine Tune")]
    public float movementSprintSpeed = 1f;
    [BoxGroup("Movement Fine Tune")]
    public float jumpHeight = 1f;
    [BoxGroup("Movement Fine Tune")]
    public float groundGravity = 1f;
 
    [BoxGroup("Private Variable")]
    [ShowInInspector]
    private bool _groundedStatus;
    [BoxGroup("Private Variable")]
    [ShowInInspector]
    private Vector3 _finalMoveValue;
    [BoxGroup("Private Variable")]
    [ShowInInspector]
    private float _fowardDirection;
    [BoxGroup("Private Variable")]
    [ShowInInspector]
    private float _righDirection;
 
    private CharacterController _characterController;
 
    private void Awake()
    {
        Initialization();
    }
 
    private void Initialization()
    {
        _characterController = this.GetComponent<CharacterController>();
    }
 
    private void Update()
    {
        SetRightFowardDirection();
 
        PlayerLookAtCross();
 
        //this will update _movement value that will be called by MovePlayer(_movement);
        SetFinalMoveValue();
 
        MovePlayer(_finalMoveValue);
    }
 
    #region INPUT
    private Vector3 InputRelativeToCamera() 
    {
        //reading the input:
        float horizontalAxis = Input.GetAxis("Horizontal");
        float verticalAxis = Input.GetAxis("Vertical");
 
        //assuming we only using the single camera:
        var camera = Camera.main;
 
        //camera forward and right vectors:
        var forward = camera.transform.forward;
        var right = camera.transform.right;
 
        //project forward and right vectors on the horizontal plane (y = 0)
        forward.y = 0f;
        right.y = 0f;
        forward.Normalize();
        right.Normalize();
 
        //this is the direction in the world space we want to move:
        var desiredMoveDirection = (forward * verticalAxis + right * horizontalAxis).normalized * movementSpeed;
 
        if(Input.GetKey(KeyCode.LeftShift))
        {
            return desiredMoveDirection * movementSprintSpeed;
        }
 
        return desiredMoveDirection;
    }
 
    private float _jumpDuration = 0;
 
    private float InputMovementJump()
    {
 
        if (!_groundedStatus)
        {
            _jumpDuration -= Time.deltaTime * groundGravity;
        }
        else
        {
            _jumpDuration = Input.GetAxis("Jump");
        }
 
        return _jumpDuration;
    }
    #endregion
 
    #region MONOBEHAVIOUR
    private void SetRightFowardDirection()
    {
        //This method will take dot value to detect character moving direction in local axis (so kalau axis tu rotate dia akan rotate sama)
        _righDirection = Vector3.Dot(transform.right, new Vector3(_finalMoveValue.x, 0f, _finalMoveValue.z));
        _fowardDirection = Vector3.Dot(transform.forward, new Vector3(_finalMoveValue.x, 0, _finalMoveValue.z));
    }
 
    private void PlayerLookAtCross() => charater.DOLookAt(cross.transform.position, lookAtSpeed, AxisConstraint.Y);
 
    private void SetFinalMoveValue()
    {
        Vector3 _moveDirectionAtXZ = InputRelativeToCamera();
        float _jumpDuration = InputMovementJump();
 
        _finalMoveValue = new Vector3(_moveDirectionAtXZ.x, _jumpDuration * jumpHeight, _moveDirectionAtXZ.z);
 
    }
 
    private void MovePlayer(Vector3 _finalMoveValue) =>  _characterController.Move(_finalMoveValue * Time.deltaTime);
    #endregion
 
    #region SET METHOD
    public void SetWhenGrounded() => _groundedStatus = true;
 
    public void SetWhenNotGrounded() =>  _groundedStatus = false;
    #endregion
 
    #region GET METHOD
    public bool IsGroundedStatus() => _groundedStatus;
 
    public bool GetCursor() => Cursor.visible;
 
    public float GetFowardDiretion() => _fowardDirection;
 
    public float GetRightDirection() => _righDirection;
 
    public float GetVelocity() => _characterController.velocity.magnitude;
    #endregion
}

ZombiePlayerCharacterAnimationController Script

using Animancer;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ZombiePlayerCharacterAnimationController : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private ClipTransition _idle;
    [SerializeField] private ClipTransition _moveFoward;
    [SerializeField] private ClipTransition _moveBackward;
    [SerializeField] private ClipTransition _moveRight;
    [SerializeField] private ClipTransition _moveLeft;
    [SerializeField] private ClipTransition _runFoward;
    [SerializeField] private ClipTransition _runBackward;
    [SerializeField] private ClipTransition _runRight;
    [SerializeField] private ClipTransition _runLeft;
 
    [SerializeField] private AudioSource _parentAudioSource;
    [SerializeField] private AudioClip _walkStepSoud;
    [SerializeField] private AudioClip _runStepSound;
 
    private ZombiePlayerController playerController;
 
    private void Start()
    {
        playerController = FindObjectOfType<ZombiePlayerController>();
        _parentAudioSource = playerController.GetComponent<AudioSource>();
    }
 
    private void Update()
    {
        _Animancer.Play(_idle);
 
        MovementAnimationPlayByVelocity();
    }
 
    private void MovementAnimationPlayByVelocity()
    {
        if (playerController.GetVelocity() > 4) // If player running
        {
            PlayMovementByAnimation(_runFoward, _runBackward, _runRight, _runLeft, _runStepSound);
 
        }
        else
        {
            PlayMovementByAnimation(_moveFoward, _moveBackward, _moveRight, _moveLeft, _walkStepSoud);
        }
    }
 
    private void PlayMovementByAnimation(ClipTransition foward, ClipTransition backward, ClipTransition right, ClipTransition left, AudioClip stepSound)
    {
        if (playerController.GetFowardDiretion() > 1f)
        {
           var anim =  _Animancer.Play(foward);
 
            anim.Events.Add(0.30f, () => _parentAudioSource.PlayOneShot(stepSound));
            anim.Events.Add(0.80f, () => _parentAudioSource.PlayOneShot(stepSound));
        }
 
        if (playerController.GetFowardDiretion() < -1f)
        {
            var anim = _Animancer.Play(backward);
 
            anim.Events.Add(0.30f, () => _parentAudioSource.PlayOneShot(stepSound));
            anim.Events.Add(0.80f, () => _parentAudioSource.PlayOneShot(stepSound));
        }
 
        if (playerController.GetRightDirection() > 1f)
        {
            var anim = _Animancer.Play(right);
 
            anim.Events.Add(0.30f, () => _parentAudioSource.PlayOneShot(stepSound));
            anim.Events.Add(0.80f, () => _parentAudioSource.PlayOneShot(stepSound));
        }
 
        if (playerController.GetRightDirection() < -1f)
        {
            var anim = _Animancer.Play(left);
 
            anim.Events.Add(0.30f, () => _parentAudioSource.PlayOneShot(stepSound));
            anim.Events.Add(0.80f, () => _parentAudioSource.PlayOneShot(stepSound));
        }
    }
}

ZombieGunController Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
using HellTap.PoolKit;
using UnityEngine.Events;
using SkyConsole.Utils;
 
public class ZombieGunController : MonoBehaviour
{
    [BoxGroup("GameObject Initialization")]
    public Spawner gunBarrelPoolSpawner;
    [BoxGroup("Weapon Porperties")]
    public float bulletSpeed;
    [BoxGroup("Weapon Porperties")]
    public float shootCooldown = 1f;
    [BoxGroup("Weapon Porperties")]
    private int bullet = 10;
    [BoxGroup("Weapon Porperties")]
    public AudioClip shootSound;
    [BoxGroup("Weapon Porperties")]
    public AudioClip emptyShootSound;
    [BoxGroup("Weapon Porperties")]
    public AudioSource gunSoundSource;
 
    [HideInEditorMode]
    public UnityEvent<int> sendEventToUI;
 
    private void Start()
    {
        gunSoundSource = this.GetComponent<AudioSource>();
        InitializeEvent();
    }
 
    private void Update()
    {
        BulletShootHandler();
    }
 
    [SerializeField]
    private float timer = 0;
    private void BulletShootHandler()
    {
        if (timer > 0)
        {
            timer -= Time.deltaTime;
            return;
        }
 
        if (Input.GetKey(KeyCode.Mouse0))
        {
            timer = shootCooldown;
 
            if (bullet == 0)
            {
                PlaySound(emptyShootSound);
                return;
            }
 
            if (gunBarrelPoolSpawner != null)
            {
                gunBarrelPoolSpawner.Play();
                PlaySound(shootSound);
                bullet -= 1;
                SendEventToUI();
            }
        }
    }
 
    private void PlaySound(AudioClip sound)
    {
        gunSoundSource.PlayOneShot(sound);
    }
 
 
    #region EVENT
    private void InitializeEvent()
    {
        if (sendEventToUI == null) sendEventToUI = new UnityEvent<int>();
        SendEventToUI();
    }
 
    private void SendEventToUI()
    {
        sendEventToUI.Invoke(bullet);
    }
    #endregion
 
    public void addBullet(int bulletCount)
    {
        bullet += bulletCount;
        SendEventToUI();
    }
}

ZombieCameraController Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Micosmo.SensorToolkit;
using DG.Tweening;
using System;
using Sirenix.OdinInspector;
 
public class ZombieCameraController : MonoBehaviour
{
    [BoxGroup("Serialize GameObject")]
    public GameObject cross;
    [BoxGroup("Serialize GameObject")]
    public GameObject crossCylinder;
    [BoxGroup("Serialize GameObject")]
    public GameObject player;
 
    [BoxGroup("Cross Fine Tuning")]
    public float crossSpeed = 1f;
 
    [BoxGroup("Camera Porperties")]
    public float zTilt;
    [BoxGroup("Camera Porperties")]
    public float xTilt;
 
    private Camera _camera;
    private RaySensor _sensor;
    private RangeSensor _crossRangeSensor;
 
    private void Awake()
    {
        _sensor = this.GetComponent<RaySensor>();
        _camera = this.GetComponent<Camera>();
        _crossRangeSensor = cross.GetComponentInChildren<RangeSensor>();
    }
 
    private void Update()
    {
        MoveRaycastToMousePosition();
        CameraMovement();
        SetCrossCylinderActive();
    }
 
    private void MoveRaycastToMousePosition()
    {
        var ray = _camera.ScreenPointToRay(Input.mousePosition);
        _sensor.Direction = ray.direction;
 
        MoveCrossToRaycastObstructionRayHit();
    }
 
    private void MoveCrossToRaycastObstructionRayHit()
    {
        float x = _sensor.GetObstructionRayHit().Point.x;
        float z = _sensor.GetObstructionRayHit().Point.z;
 
        if (_sensor.IsObstructed) cross.transform.DOMove(new Vector3(x, cross.transform.position.y, z), crossSpeed);
    }
 
    private void CameraMovement()
    {
        this.transform.DOLookAt(player.transform.position, 1f);
 
        float x = player.transform.position.x + xTilt;
        float z = player.transform.position.z + zTilt;
        this.transform.DOMove(new Vector3(x, this.transform.position.y, z), 1f);
    }
 
    private void SetCrossCylinderActive()
    {
        if (_crossRangeSensor.GetNearestDetection() != null)
        {
            crossCylinder.SetActive(true);
        }
        else
        {
            crossCylinder.SetActive(false);
        }
    }
}

ZombieBullet Script

using Micosmo.SensorToolkit;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using HellTap.PoolKit;
using Sirenix.OdinInspector;
using SkyConsole.Utils;
 
public class ZombieBullet : MonoBehaviour
{
    public float bulletSpeed = 25f;
    public ParticleSystem bulletCollideParticle;
 
    private RangeSensor _rangeSensor;
    private MeshRenderer _meshRenderer;
    private Pool _pool;
 
    private bool canMove = true;
 
    private void Awake()
    {
        _rangeSensor = this.GetComponent<RangeSensor>();
        _meshRenderer = this.GetComponent<MeshRenderer>();
        _pool = FindObjectOfType<Pool>();
 
        _rangeSensor.OnSomeDetection.AddListener(ReceivedListenerOnCollided);
    }
 
    private void Update()
    {
        moveBullet(canMove);
    }
 
    private void moveBullet(bool canMove)
    {
        if(canMove == true) transform.position += transform.forward * Time.deltaTime * bulletSpeed;
    }
 
    private IEnumerator DespawnGameObject(float duration)
    {
 
        yield return new WaitForSeconds(duration);
 
        canMove = true;
        _pool.Despawn(this.gameObject);
    }
 
    #region Called From Event & Outside
    private void ReceivedListenerOnCollided()
    {
        canMove = false;
        bulletCollideParticle.Play();
 
        StartCoroutine(DespawnGameObject(bulletCollideParticle.main.duration));
    }
 
    private void OnDisable()
    {
        _rangeSensor.enabled = false;
    }
 
    private void OnEnable()
    {
        _rangeSensor.enabled = true;
    }
    #endregion
 
}

NPC Prototyping

ZombieNpcMovingNashMeshController Script

using Sirenix.OdinInspector;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
 
public class ZombieNpcMovingNashMeshController : MonoBehaviour
{
    [BoxGroup("Debug Value")]
    [SerializeField] private string d_tranfsormName;
    [BoxGroup("Debug Value")]
    [SerializeField] private float d_remainingDistance;
    [BoxGroup("Debug Value")]
    [SerializeField] private float d_velocity;
 
    [BoxGroup("Movement Tweak")] [SerializeField] private float _walkSpeed = 1;
    [BoxGroup("Movement Tweak")] [SerializeField] private float _runSpeed = 3;
 
    [SerializeField] private List<Transform> _checkPoint;
    private int checkPointIndex = 0;
    private int currentIndex = 0;
 
    private NavMeshAgent _navMeshAgent;
    private ZombieAnimationController _zombieAnimationController;
 
    [SerializeField] private Transform movePositionTransform;
 
    private void Awake()
    {
        _navMeshAgent = GetComponent<NavMeshAgent>();
        _zombieAnimationController = GetComponent<ZombieAnimationController>();
        _navMeshAgent.updateRotation = false;
    }
 
    private void Update()
    {
 
        if (_navMeshAgent.remainingDistance <= _navMeshAgent.stoppingDistance)
        {
 
            currentIndex = checkPointIndex == _checkPoint.Count - 1 ? checkPointIndex = 0 : checkPointIndex += 1;
 
        }
 
        MoveAgentToDestination(_checkPoint[currentIndex]);
    }
 
    private void MoveAgentToDestination(Transform transform)
    {
        _navMeshAgent.destination = transform.position;
 
        d_tranfsormName = transform.gameObject.name;
        d_remainingDistance = _navMeshAgent.remainingDistance;
        d_velocity = _navMeshAgent.velocity.magnitude;
 
        if (_navMeshAgent.velocity.sqrMagnitude > Mathf.Epsilon)
        {
            this.transform.rotation = Quaternion.LookRotation(_navMeshAgent.velocity.normalized);
        }
    }
 
    [Button]
    public void MakeCharacterWalk()
    {
        _navMeshAgent.speed = _walkSpeed;
    }
 
    [Button]
    public void MakeCharacterRunning()
    {
        _navMeshAgent.speed = _runSpeed;
    }
 
    [Button]
    public void MakeCharacterPunch()
    {
        _zombieAnimationController.PlayAction(_zombieAnimationController.attack);
    }
}

ZombieAnimationController Script

using Animancer;
using Sirenix.OdinInspector;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
 
public class ZombieAnimationController : MonoBehaviour
{
    private AnimancerComponent _Animancer;
    [SerializeField] public ClipTransition idle;
    [SerializeField] public ClipTransition moveFoward;
    [SerializeField] public ClipTransition runFoward;
    [SerializeField] public ClipTransition attack;
    [SerializeField] private AvatarMask _baseBody;
    [SerializeField] private AvatarMask _upperBody;
 
    private AnimancerLayer _baseLayer;
    private AnimancerLayer _upperBodyLayer;
 
    //private CharacterController _characterController;
    private NavMeshAgent _navMeshAgent;
 
    private void Awake()
    {
        Initialization();
 
        InitializationAnim();
    }
 
    private void Initialization()
    {
        //_characterController = GetComponent<CharacterController>();
        _navMeshAgent = GetComponent<NavMeshAgent>();
        _Animancer = GetComponentInChildren<AnimancerComponent>();
    }
 
    private void InitializationAnim()
    {
        _baseLayer = _Animancer.Layers[0];
        _upperBodyLayer = _Animancer.Layers[1];
 
        _baseLayer.SetMask(_baseBody);
        _upperBodyLayer.SetMask(_upperBody);
        attack.Events.OnEnd = OnActionEnd;
    }
 
    private void Update()
    {
        //if(_characterController.velocity.magnitude > 1f)
        if (_navMeshAgent.velocity.magnitude > 1f)
        {
            _baseLayer.Play(moveFoward, 1f);
        }
 
        //if (_characterController.velocity.magnitude > 2f)
        if(_navMeshAgent.velocity.magnitude > 2f)
        {
            _baseLayer.Play(runFoward, 1f);
        }
    }
 
    bool _canBePlayed = true;
    public void PlayAction(ClipTransition clip)
    {
        if (!_canBePlayed) return;
 
        _upperBodyLayer.Play(clip);
 
        StartCoroutine(PlayActionDelay(clip.Clip.length));
    }
 
    private IEnumerator PlayActionDelay(float length)
    {
        _canBePlayed = false;
        yield return new WaitForSeconds(length);
        _canBePlayed = true;
    }
 
    private void OnActionEnd()
    {
        _upperBodyLayer.StartFade(0, 1f);
    }
}


QR Code
QR Code wiki:prototyping (generated for current page)
Hello World!
DokuWiki with monobook... rules!