← All projects

Hazard Survivor

Type: Casual Mobile Runner · Engine: Unity

Hazard Survivor

In the development of Hazard Survivor, my contributions include implementing diverse obstacles, enemies, and their behaviors. I also engineered a road generation system incorporating both random and weighted-random elements to ensure dynamic and engaging level layouts as a basis for level design.

Code Snippets

Player

public class Player : Character
{
    public delegate void OnPlayerDead();
    public static OnPlayerDead playerDied;

    public FloatingJoystick _joystick;
    public GameObject _deadScene;
    public GameObject _gamehud;
    public AudioSource _themeSong;
    [SerializeField] private CinemachineVirtualCamera cmVcam;
    public bool isBeingKilled = false;
    [SerializeField] internal BoxManager _boxManager;

    private void Awake()
    {
        characterRigidbody = GetComponent<Rigidbody>();
    }

    private void Start()
    {
        CanMove = true;
    }

    private void OnEnable()
    {
        playerDied += characterDeath.SlowTime;
        playerDied += StopCamera;
    }

    private void OnDisable()
    {
        playerDied -= characterDeath.SlowTime;
        playerDied -= StopCamera;
    }

    private void StopCamera()
    {
        cmVcam.Follow = null;
        cmVcam.LookAt = null;
    }

    public void GetKilled(Transform hostileTransform, float localXOffset, float localZOffset, Action playerAnimation)
    {
        GetComponent<Character>().CanMove = false;
        this.transform.parent = hostileTransform;
        transform.localRotation = Quaternion.identity;
        Vector3 newPosition = new Vector3(
            transform.localPosition.x + localXOffset,
            transform.localPosition.y,
            transform.localPosition.z + localZOffset);
        transform.localPosition = newPosition;
        playerAnimation();
    }
}

Turret Behaviour

public class TurretBehaviour : MonoBehaviour, IDamageDealer
{
    [SerializeField] private float shootingDuration;
    [SerializeField] AudioSource audioData;
    [SerializeField] private AudioClip shootingSfx;
    [SerializeField] private AudioClip laserSfx;
    [SerializeField] private AudioClip overheatSfx;
    [SerializeField] ParticleSystem bulletParticleEffect;
    [SerializeField] Collider shootingCollider;
    [SerializeField] private float horizontalForceRadius;
    [SerializeField] private LineRenderer lineRenderer;
    [SerializeField] private float laserKickStartAmount;

    private bool _readyToShoot;
    private Renderer _renderer;

    void Start() { StartCoroutine(Fire()); }

    void OnEnable()
    {
        lineRenderer = GetComponent<LineRenderer>();
        _renderer = GetComponent<Renderer>();
    }

    private void OnTriggerEnter(Collider other) { DealDamage(other.gameObject); }

    public void DealDamage(GameObject other)
    {
        other.GetComponent<Death>()?.Die(
            other.TryGetComponent(out Player temp),
            DeathCause.Turret,
            horizontalForceRadius, null);
    }

    private IEnumerator Fire()
    {
        while (_renderer.enabled)
        {
            SetShooting(true);
            SetLaserColor(Color.red);
            yield return new WaitForSeconds(shootingDuration);

            SetShooting(false);
            SetLaserColor(Color.clear);
            yield return new WaitForSeconds(overheatSfx.length);

            SetLaserColor(new Color(255, 215, 0));
            KickStartLaser();

            audioData.clip = laserSfx;
            if (!audioData.isPlaying)
                audioData.PlayDelayed(0.3f);

            StartCoroutine(FadeInLaser());
            yield return new WaitUntil(() => _readyToShoot);
        }
    }
}

Ragdoll Manager

public class RagdollManager : MonoBehaviour
{
    public BoxCollider mainCollider;
    public GameObject mainRig;
    public Animator mainAnimator;

    private Character character;
    Rigidbody[] limbsRigidbodies;
    Collider[] ragDollColliders;

    private void Awake() { character = GetComponent<Character>(); }

    void Start()
    {
        GetRagdollBits();
        RagdollModeOff();
        GetComponent<Rigidbody>().centerOfMass = Vector3.zero;
        GetComponent<Rigidbody>().inertiaTensorRotation = Quaternion.identity;
    }

    void GetRagdollBits()
    {
        ragDollColliders = mainRig.GetComponentsInChildren<Collider>();
        limbsRigidbodies = mainRig.GetComponentsInChildren<Rigidbody>();
    }

    public void RagdollModeOn(DeathCause causeOfDeath, float? horizontalForceRadius, float? verticalForceAmount)
    {
        character.CanMove = false;
        if (mainAnimator != null) mainAnimator.enabled = false;

        Destroy(gameObject, 3f);
        foreach (Collider col in ragDollColliders) col.enabled = true;

        if (causeOfDeath == DeathCause.Regular)
        {
            foreach (Rigidbody rigid in limbsRigidbodies) rigid.isKinematic = false;
        }
        else if (causeOfDeath == DeathCause.Explosion)
        {
            foreach (Rigidbody rigid in limbsRigidbodies)
            {
                rigid.isKinematic = false;
                rigid.AddForce(
                    transform.right * Random.Range((float)-horizontalForceRadius, (float)horizontalForceRadius) +
                    transform.up * verticalForceAmount +
                    transform.forward * Random.Range((float)-horizontalForceRadius, (float)horizontalForceRadius),
                    ForceMode.Impulse);
            }
        }
        else if (causeOfDeath == DeathCause.Turret)
        {
            foreach (Rigidbody rigid in limbsRigidbodies)
            {
                rigid.isKinematic = false;
                rigid.AddForce(
                    new Vector3(transform.position.x * (float)horizontalForceRadius, 0f, 0f),
                    ForceMode.Impulse);
            }
        }

        mainCollider.enabled = false;
        GetComponent<Rigidbody>().isKinematic = true;
    }
}