Conquer waves of enemies coming at you in cosmic battle.
Cosmic Crusaders is a co-op action game where two players control a bear-riding frog and a shooter companion on a small planet. One player controls movement, while the other rotates the gun to fight off endless waves of enemies. Inspired by endless runners, the game tests teamwork and reaction speed as players survive for as long as possible.
Cosmic Crusaders is a cooperative survival game where two players control a bear and a frog, working together to fend off endless waves of enemies on a small planetary surface. The bear is responsible for movement, steering the team across the planet, while the frog controls the gun, rotating it to shoot at enemies. Movement and shooting are automatic, meaning players must focus on coordination and reaction speed to survive.
As a gameplay programmer on Cosmic Crusaders, I was responsible for various core systems, particularly those related to combat, UI, and enemy behavior. Below are some key areas I worked on:
This project improved my understanding of AI behavior, event-driven mechanics, and structuring game logic efficiently. It also taught me how to work within a larger team and coordinate development tasks effectively.
Download the files below to find out and read more about my personal contributions during this game project.
View key scripts I worked on in Cosmic Crusaders.
// Healing.cs - Controls health pickups
using UnityEngine;
public class Healing : MonoBehaviour {
Health playerHealth;
[SerializeField] private int healAmount = 20;
private Collider orbCollider;
bool canHeal;
private void Start() {
playerHealth = GameObject.FindGameObjectWithTag("Player").GetComponent();
orbCollider = GetComponent();
}
private void OnTriggerEnter(Collider collider) {
if (IsPlayer(collider) && playerHealth.currentHealth < playerHealth.maxHealth) {
int remainingHeal = Mathf.Min(healAmount, playerHealth.maxHealth - playerHealth.currentHealth);
playerHealth.ChangeHealth(remainingHeal);
}
}
private bool IsPlayer(Collider collider) {
return collider.CompareTag("Player");
}
private void Update() {
orbCollider.enabled = playerHealth.currentHealth < playerHealth.maxHealth;
}
}
// LoadingScreen.cs - Handles level loading UI
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections;
public class LoadingScreen : MonoBehaviour {
[SerializeField] private GameObject loadingScreen;
[SerializeField] private Slider loadingSlider;
[SerializeField] private float sceneLoadTime;
[SerializeField] private Button continueButton;
private bool canLoadScene = false;
private void Start() {
loadingScreen.SetActive(false);
continueButton.interactable = false;
}
public void LoadLevel(int levelToLoad) {
StartCoroutine(LoadLevelEnum(levelToLoad));
}
IEnumerator LoadLevelEnum(int levelToLoad) {
loadingScreen.SetActive(true);
loadingSlider.value = 0.3f;
yield return new WaitForSeconds(sceneLoadTime);
loadingSlider.value = 1.0f;
continueButton.interactable = true;
canLoadScene = true;
}
public void LoadSceneWithButton(int levelToLoad) {
if (canLoadScene) SceneManager.LoadScene(levelToLoad);
}
}
// InRangeEvent.cs - Triggers events based on player proximity
using UnityEngine;
using UnityEngine.Events;
public class InRangeEvent : MonoBehaviour {
[SerializeField] LayerMask includeLayer;
[SerializeField] float range;
public UnityEvent onInRange;
public UnityEvent onOutRange;
bool isInRange = false;
private void Update() {
Collider[] colliders = Physics.OverlapSphere(transform.position, range, includeLayer);
if (colliders.Length > 0) {
onInRange.Invoke();
isInRange = true;
} else if (isInRange) {
onOutRange.Invoke();
isInRange = false;
}
}
}
// Damaging.cs - Handles applying damage to health components
using UnityEngine;
using UnityEngine.Events;
public class Damaging : MonoBehaviour {
[SerializeField] private int damageAmount = -10;
[SerializeField] private LayerMask includeLayer;
public UnityEvent onDoDamage;
private void OnTriggerEnter(Collider collider) {
if ((includeLayer & (1 << collider.gameObject.layer)) != 0) {
if (collider.TryGetComponent(out Health health)) {
health.ChangeHealth(damageAmount);
onDoDamage.Invoke();
}
}
}
}
// Health.cs - Manages health changes, healing, and death
using UnityEngine;
using UnityEngine.Events;
public class Health : MonoBehaviour {
[SerializeField] public int maxHealth;
[HideInInspector] public int currentHealth;
public UnityEvent onTakeDamage, onDeath, onHealthReceived;
void Awake() { currentHealth = maxHealth; }
public void ChangeHealth(int changeAmount) {
currentHealth += changeAmount;
if (currentHealth > maxHealth) currentHealth = maxHealth;
if (currentHealth <= 0) {
currentHealth = 0;
onDeath.Invoke();
}
if (changeAmount < 0) onTakeDamage.Invoke();
if (changeAmount > 0) onHealthReceived.Invoke();
}
}
// Healthbar.cs - Updates UI slider based on health value
using UnityEngine;
using UnityEngine.UI;
public class Healthbar : MonoBehaviour {
public Slider healthBar;
private Health health;
private void Start() {
health = GetComponent();
healthBar.maxValue = health.currentHealth;
}
private void Update() {
healthBar.value = health.currentHealth;
}
}
// RotateTowardsTarget.cs - Makes enemies face the player
using UnityEngine;
public class RotateTowardsTarget : MonoBehaviour {
[SerializeField] private float lookRadius = 10f;
[SerializeField] private float rotationSpeed = 50;
[SerializeField] private LayerMask includeLayer;
void FixedUpdate() {
Collider[] colliders = Physics.OverlapSphere(transform.position, lookRadius, includeLayer);
if (colliders.Length > 0) FaceTarget(colliders[0].transform);
}
void FaceTarget(Transform target) {
Quaternion lookRot = Quaternion.LookRotation(target.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, lookRot, Time.deltaTime * rotationSpeed);
}
}
// SceneSwitcher.cs - Manages transitioning between scenes
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneSwitcher : MonoBehaviour {
[SerializeField] private int sceneIndex;
public void SwitchToNextScene() {
int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(currentSceneIndex + sceneIndex);
}
}
Check out the game and my contributions!