Hazard Survivor
In the development of Hazard Survivor, my contributions include the implementation of diverse obstacles, enemies, and their behaviors. Additionally, I engineered a road generation system, incorporating both random and weighted random elements to ensure dynamic and engaging level layouts to give a basis to work on 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() // OverheatSFX - green, LaserSFX - yellow, Shooting - red
{
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)); // Gold
KickStartLaser();
audioData.clip = laserSfx;
if (!audioData.isPlaying)
audioData.PlayDelayed(0.3f);
StartCoroutine(FadeInLaser());
yield return new WaitUntil(() => _readyToShoot);
}
}
void SetShooting(bool shootingState) //Plays overheat sfx if set to false!
{
if (shootingState)
{
shootingCollider.enabled = true;
audioData.clip = shootingSfx;
if (!audioData.isPlaying)
audioData.Play();
bulletParticleEffect.Play();
}
else
{
bulletParticleEffect.Stop();
shootingCollider.enabled = false;
_readyToShoot = false;
if (audioData.isPlaying)
audioData.Stop();
audioData.clip = overheatSfx;
if (!audioData.isPlaying)
audioData.Play();
}
}
void KickStartLaser()
{
var currentMaterialStartColor =
lineRenderer
.startColor;
var currentMaterialEndColor = lineRenderer.endColor;
currentMaterialStartColor.a = laserKickStartAmount;
currentMaterialEndColor.a = laserKickStartAmount;
lineRenderer.startColor = currentMaterialStartColor;
lineRenderer.endColor = currentMaterialEndColor;
}
private IEnumerator FadeInLaser()
{
while (lineRenderer.startColor.a < 1f)
{
var currentMaterialStartColor =
lineRenderer
.startColor;
var currentMaterialEndColor = lineRenderer.endColor;
currentMaterialStartColor.a += 0.01f;
currentMaterialStartColor.a += 0.01f;
lineRenderer.startColor = currentMaterialStartColor;
lineRenderer.endColor = currentMaterialEndColor;
yield return new WaitForSeconds(0.04f);
}
_readyToShoot = true;
}
void SetLaserColor(Color newColor)
{
Gradient tempGradient = new Gradient();
GradientColorKey[] tempColorKeys = new GradientColorKey[2];
tempColorKeys[0] = new GradientColorKey(newColor, 0);
tempColorKeys[1] = new GradientColorKey(newColor, 1);
tempGradient.colorKeys = tempColorKeys;
lineRenderer.colorGradient = tempGradient;
}
}
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((Vector3)(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;
}
public void RagdollModeOff()
{
foreach (Collider col in ragDollColliders)
{
col.enabled = false;
}
foreach (Rigidbody rigid in limbsRigidbodies)
{
rigid.isKinematic = true;
}
mainAnimator.enabled = true;
mainCollider.enabled = true;
GetComponent<Rigidbody>().isKinematic = false;
}
}