Prototyping Zombie Minigame
Player Prototyping
ZombiePlayerController Script
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using Micosmo.SensorToolkit; using System; using Sirenix.OdinInspector; using UnityEngine.Events; using HighlightPlus; 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("Movement Fine Tune")] public float runStamina = 15f; [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; [BoxGroup("Private Variable")] [ShowInInspector] private float _velocity; [BoxGroup("Private Variable")] [ShowInInspector] private float _storedRunStamina; private CharacterController _characterController; private ZombieHealth _zombieHealth; private HighlightEffect _highlight; [HideInEditorMode] public UnityEvent<float> sendEventToUI; [HideInEditorMode] public UnityEvent onPlayerDied; private void Awake() { Initialization(); } private void Start() { _storedRunStamina = runStamina; _zombieHealth.sendEventOnMinusHealth.AddListener(ReceivedEventOnPlayerHit); SendEventToUI(); } private void Initialization() { _characterController = this.GetComponent<CharacterController>(); _zombieHealth = this.GetComponent<ZombieHealth>(); _highlight = this.GetComponent<HighlightEffect>(); } private void Update() { if (_zombieHealth.IsDead()) { onPlayerDied.Invoke(); return; } _velocity = GetVelocity(); 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; SprintController(); if (Input.GetKey(KeyCode.LeftShift) && runStamina >= 0) { return desiredMoveDirection * movementSprintSpeed; } return desiredMoveDirection; } private void SprintController() { SendEventToUI(); if(GetVelocity() > 5) { runStamina -= Time.deltaTime; return; } if (runStamina < _storedRunStamina && GetVelocity() == 0) runStamina += Time.deltaTime; } 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 #region EVENT private void InitializeEvent() { if (sendEventToUI == null) sendEventToUI = new UnityEvent<float>(); SendEventToUI(); } private void SendEventToUI() { sendEventToUI.Invoke(runStamina); } private void ReceivedEventOnPlayerHit() { _highlight.HitFX(); } # endregion }
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; public float bulletDamage = 10; public RangeSensor _rangeSensor; private MeshRenderer _meshRenderer; private Pool _pool; private bool canMove = true; private void Awake() { _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(); if(_rangeSensor.GetNearestDetection().TryGetComponent(out ZombieHealth zombieHealth)) { zombieHealth.MinusHealth(bulletDamage); } StartCoroutine(DespawnGameObject(bulletCollideParticle.main.duration)); } private void OnDisable() { _rangeSensor.enabled = false; } private void OnEnable() { _rangeSensor.enabled = true; } #endregion }
