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;
}
}