Medusa's Last Stand is a top-down 2D action shoot 'em up where you play as Medusa shooting snakes, venom and petrifying the cyber greek soldiers that captured you. Won Best Design Game Jam Award.
/*
* Carlos Adan Cortes De la Fuente
* All rights reserved. Copyright (c)
* Email: dev@carlosadan.com
*/
public abstract class Weapon : MonoBehaviour, IAttack
{
    [SerializeField]
    protected Transform origin;
    
    [SerializeField]
    private float fireRate;
    
    private float deltaFire;
    [SerializeField, Range(0,1f)]
    private float cookOffStep = 0.1f;
    
    private void Update()
    {
        deltaFire += Time.deltaTime;
    }
    public float Attack(Quaternion direction)
    {
        if(deltaFire > fireRate)
        {
            WeaponAttack(direction);
            deltaFire = 0f;
            return cookOffStep;
        }
        return 0;
    }
    
    protected abstract void WeaponAttack(Quaternion direction);
}
// Example with a close range weapon
public class CloseRangeWeapon : Weapon
{
    [SerializeField]
    private float damage = 5f;
	[SerializeField]
    private GameObject hitBox;
    protected override void WeaponAttack(Quaternion direction)
    {
        GameObject newGO = Instantiate(hitBox, origin.position, direction);
        newGO.GetComponent<HitBox>().damage = damage;
    }
    public float GetDamage()
    {
        return damage;
    }
}
// Example with a ranged weapon
public class MachineGun : Weapon 
{
    [SerializeField]
    private GameObject bullet;
    
	protected override void WeaponAttack(Quaternion direction)
    {
        Instantiate(bullet, origin.position, direction);
        AkSoundEngine.PostEvent("Play_MachineGun", gameObject);
    }
}
										
									
/*
* Carlos Adan Cortes De la Fuente
* All rights reserved. Copyright (c)
* Email: dev@carlosadan.com
*/
// Base UI class
public abstract class UIScreen : MonoBehaviour 
{
    private void OnEnable()
    {
        UIScreenEnabled();	
    }
    private void OnDisable()
    {
        UIScreenDisabled();
    }
    
    protected abstract void UIScreenEnabled();
    protected abstract void UIScreenDisabled();
}
// Example Game Screen Usage
public class GameScreen : UIScreen 
{
    [Header("Kills & Score")] 
    [SerializeField]
    private Text killText;
    [SerializeField]
    private Text scoreText;
    [Header("Petrify Counter")]
    [SerializeField]
    private GameObject petrifyPowerIcon;
    [SerializeField]
    private GameObject petrifyContainer;
    [Space]
    [SerializeField]
    private GameObject healthBar;
    [SerializeField]
    private Color fullhealth;
    [SerializeField]
    private Color lowhealth;
    
    #region Screen Life Cycle
        protected override void UIScreenEnabled() 
        {
            Cursor.visible = false;
            AudioManager.Instance.PlayEvent("Stop_Music_Loop_Menu");
        }
        
        protected override void UIScreenDisabled()
        {
            Cursor.visible = true;
        }
    #endregion
    private void Update()
    {
        if((Input.GetKeyDown(KeyCode.Escape)))
		{
            UIManager.Instance.ShowScreen<PauseScreen>();
		}
        if(GameManager.Instance.IsGameOver())
        {
            StartCoroutine(ShowGameOverScreen());
        }
    }
    public void SetPowerIcons(int powersLeft)
    {
        foreach (Transform child in petrifyContainer.transform) 
        {
            GameObject.Destroy(child.gameObject);
        }
        for(int i = 0; i < powersLeft; i++)
        {
            GameObject newIcon = Instantiate(petrifyPowerIcon, Vector3.zero, Quaternion.identity);
            newIcon.transform.SetParent(petrifyContainer.transform);
            newIcon.transform.localScale = Vector3.one;
        }
    }
    public void SetKills(int count)
    {
        killText.text = "Kills: " + count;
    }
    
    public void SetScore(int count)
    {
        scoreText.text = "Score: " + count;
    }
    public void SetHealth(float health)
    {
        Vector3 newScale = healthBar.transform.localScale;
        newScale.x = health / 100f;
        healthBar.transform.localScale = newScale;
        healthBar.GetComponent<Image>().color = Color.Lerp(lowhealth, fullhealth, newScale.x);
    }
    IEnumerator ShowGameOverScreen()
    {
        yield return new WaitForSeconds(0.5f);
        UIManager.Instance.ShowScreen<GameOverScreen>();
        yield return null;
    }
}