basically the whole game

This commit is contained in:
Sylvia 2026-07-09 04:59:48 -07:00
parent 949135cecb
commit 96dcfa9064
315 changed files with 34386 additions and 396 deletions

View file

@ -13,12 +13,24 @@ public class Ability : MonoBehaviour
public Transform origin;
public Vector3 direction;
public bool TryAbility()
[Header("SFX")]
[SerializeField] protected AudioClip abilitySound;
[SerializeField] protected float volume = 1f;
[Header("Animation")]
[SerializeField] private Animator animator;
[SerializeField] private string attackTrigger;
public virtual bool TryAbility()
{
if (currentCooldown <= 0)
{
currentCooldown = cooldown;
AbilityEffects();
if (animator)
{
animator.SetTrigger(attackTrigger);
}
return true;
}
return false;

View file

@ -0,0 +1,17 @@
using UnityEngine;
public class BossMovesToARandomPositionForNoReason : EnemyAbility
{
//i hope you like the script name
//because the bosses in touhou do this
//anyways
[SerializeField] private Enemy thisEnemy;
protected override void AbilityEffects()
{
StopCoroutine(thisEnemy.currentMovementRoutine);
Vector3 newPosition = WaveManager.instance.GetRandomEnemyPoint();
thisEnemy.originalPosition = newPosition;
StartCoroutine(thisEnemy.MoveToPosition(thisEnemy.transform.position,
newPosition, thisEnemy.moveSpeed));
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: da4b31636e5bcca7195f27d578e71ebb

View file

@ -0,0 +1,104 @@
using System.Collections.Generic;
using Core.Extensions;
using UnityEngine;
public class CirnoFreezeDeflect : EnemyAbility
{
[Header("Direction")]
private Vector3 playerPos;
[Header("Deflection")]
[SerializeField] private float deflectionSpeed;
[SerializeField] private float deflectionSpeedVariance;
[SerializeField] private float deflectionAngleMin = -48;
[SerializeField] private float deflectionAngleMax = 90;
public List<Projectile> projectilesInRange = new();
public List<Projectile> projectilesAffected = new();
[SerializeField] private float deflectionDelay;
private float currentDelay;
[Header("Effects")]
[SerializeField] private ParticleSystem deflectionParticles;
[SerializeField] private AudioClip deflectionSound;
[SerializeField] private float sweepDissipationTime;
private float currentDissipationTime;
[SerializeField] private GameObject swordSweepEffect;
[SerializeField] private Color freezeColor;
protected override void Start()
{
base.Start();
playerPos = WaveManager.instance.GetRandomPlayerPoint();
}
protected override void AbilityEffects()
{
projectilesAffected = projectilesInRange;
foreach (Projectile projectile in projectilesAffected.ToArray())
{
if (!projectile)
{
projectilesInRange.Remove(projectile);
continue;
}
projectile.sprite.color = freezeColor;
projectile.speed = 0;
}
currentDelay = deflectionDelay;
playerPos = WaveManager.instance.GetRandomPlayerPoint();
}
protected override void Update()
{
base.Update();
transform.Lookat2D(playerPos);
if (currentDelay > 0)
{
currentDelay -= Time.deltaTime;
if (currentDelay <= 0)
{
DeflectProjectiles();
currentDissipationTime = sweepDissipationTime;
swordSweepEffect.SetActive(true);
}
}
if (currentDissipationTime > 0)
{
currentDissipationTime -= Time.deltaTime;
if (currentDissipationTime <= 0)
{
swordSweepEffect.SetActive(false);
}
}
}
private void DeflectProjectiles()
{
GameManager.instance.deflections += projectilesInRange.Count;
foreach (Projectile projectile in projectilesAffected.ToArray())
{
if (!projectile)
{
projectilesAffected.Remove(projectile);
continue;
}
projectile.transform.eulerAngles = new Vector3(0, 0, Random.Range(deflectionAngleMin, deflectionAngleMax));
projectile.direction = projectile.transform.right;
projectile.tag = tag;
projectile.speed = deflectionSpeed + Random.Range(-deflectionSpeedVariance, deflectionSpeedVariance);
projectile.Deflected();
Instantiate(deflectionParticles, projectile.transform);
}
projectilesAffected.Clear();
WaveManager.instance.audioSource.PlayOneShot(deflectionSound, volume);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag(tag))
{
if (other.TryGetComponent(out Projectile isProjectile) && isProjectile.deflectable)
{
projectilesInRange.Add(isProjectile);
}
}
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9e06f35db4bdec1eb8b8b6b92a9d463c

View file

@ -3,9 +3,19 @@ using UnityEngine;
public class EnemyAbility : Ability
{
[SerializeField] private float cooldownDelta;
void Start()
[SerializeField] private bool willLookAtPlayer;
protected virtual void Start()
{
cooldown += Random.Range(-cooldownDelta, cooldownDelta);
currentCooldown = Random.Range(0, cooldown);
}
public override bool TryAbility()
{
if (willLookAtPlayer)
{
direction = WaveManager.instance.GetRandomPlayerPoint();
}
return base.TryAbility();
}
}

View file

@ -0,0 +1,98 @@
using System;
using System.Collections;
using Core.Extensions;
using UnityEngine;
using Random = UnityEngine.Random;
public class EnemyBulletPattern : EnemyAbility
{
[Serializable]
public class ProjectileDirection
{
public Projectile projectile;
public Transform direction;
public float timing;
public int amount;
public float burstTiming;
public float projectileSpeed;
public bool aimedShot;
}
[SerializeField] protected ProjectileDirection[] projectileDirections;
[SerializeField] private bool randomAim;
protected override void AbilityEffects()
{
base.AbilityEffects();
transform.Lookat2D(direction);
if (randomAim)
{
transform.eulerAngles = new Vector3(0, 0, Random.Range(0, 360f));
}
foreach (ProjectileDirection projectileDirection in projectileDirections)
{
if (projectileDirection.timing <= 0 && projectileDirection.amount <= 1)
{
ShootProjectile(projectileDirection.projectile, projectileDirection.direction.position, projectileDirection.projectileSpeed, projectileDirection.aimedShot);
}
else if (projectileDirection.amount > 1)
{
StartCoroutine(BurstFire(projectileDirection, projectileDirection.amount,
projectileDirection.burstTiming));
}
else
{
StartCoroutine(DelayedShot(projectileDirection, projectileDirection.timing));
}
}
}
public void ShootProjectile(Projectile projectile, Vector3 location, float speed, bool aimed)
{
Projectile newProjectile = Instantiate(projectile, origin.position, Quaternion.identity);
Vector3 projectileDirection = location;
if (aimed)
{
projectileDirection = WaveManager.instance.GetRandomPlayerPoint();
}
newProjectile.transform.Lookat2D(projectileDirection);
newProjectile.damage = power;
newProjectile.tag = tag;
if (speed > 0f)
{
newProjectile.speed = speed;
}
}
private IEnumerator BurstFire(ProjectileDirection projectile, int burstCount, float burstDelay)
{
int currentCount = 0;
while (currentCount < burstCount)
{
ShootProjectile(projectile.projectile, projectile.direction.position, projectile.projectileSpeed, projectile.aimedShot);
currentCount++;
yield return new WaitForSeconds(burstDelay);
}
yield break;
}
private IEnumerator DelayedShot(ProjectileDirection projectile, float delay)
{
float currentDelayTiming = 0f;
while (currentDelayTiming < delay)
{
currentDelayTiming += Time.deltaTime;
if (currentDelayTiming > delay)
{
if (projectile.amount > 1)
{
StartCoroutine(BurstFire(projectile, projectile.amount, projectile.burstTiming));
}
else
{
ShootProjectile(projectile.projectile, projectile.direction.position, projectile.projectileSpeed, projectile.aimedShot);
}
}
yield return null;
}
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c037b51b973541048a47ffa9cd8f01c0

View file

@ -0,0 +1,28 @@
using System.Collections;
using UnityEngine;
public class EnemyBurstFire : EnemyBulletPattern
{
[SerializeField] private int burstCount;
[SerializeField] private float burstDelay;
protected override void AbilityEffects()
{
foreach (ProjectileDirection projectile in projectileDirections)
{
StartCoroutine(BurstFire(projectile));
}
}
private IEnumerator BurstFire(ProjectileDirection moveDirection)
{
int currentCount = 0;
while (currentCount < burstCount)
{
//ShootProjectile(moveDirection.projectile, direction);
currentCount++;
yield return new WaitForSeconds(burstDelay);
}
yield break;
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 72297b32aef434ec4bc31531226ecf79

View file

@ -0,0 +1,58 @@
using UnityEngine;
public class EnemyTackle : EnemyAbility
{
private Vector3 originalPosition;
private Vector3 movePosition;
[SerializeField] private Enemy thisEnemy;
public float distanceToReturn;
public float distanceToDamage;
private bool isCloseToPlayer;
private bool returning;
[Header("Speeds")]
[SerializeField] private float tackleSpeed;
[SerializeField] private float returnSpeed;
protected override void AbilityEffects()
{
base.AbilityEffects();
returning = false;
thisEnemy.onTakeDamage += ReturnToPosition;
originalPosition = transform.position;
movePosition = WaveManager.instance.GetRandomPlayerPoint();
thisEnemy.isStalled = true;
thisEnemy.preventWobble = true;
StopCoroutine(thisEnemy.currentMovementRoutine);
thisEnemy.currentMovementRoutine = StartCoroutine(thisEnemy.MoveToPosition(originalPosition, movePosition, tackleSpeed));
}
protected override void Update()
{
base.Update();
if (!returning)
{
if (Vector3.Distance(transform.position, movePosition) < distanceToReturn && !isCloseToPlayer)
{
isCloseToPlayer = true;
}
else if (isCloseToPlayer && Vector3.Distance(transform.position, movePosition) < distanceToDamage)
{
WaveManager.instance.player.TakeDamage(power);
ReturnToPosition();
}
}
}
private void ReturnToPosition()
{
thisEnemy.onTakeDamage -= ReturnToPosition;
returning = true;
if (thisEnemy.currentMovementRoutine != null)
{
StopCoroutine(thisEnemy.currentMovementRoutine);
}
thisEnemy.preventWobble = false;
thisEnemy.isStalled = true;
thisEnemy.currentMovementRoutine = StartCoroutine(thisEnemy.MoveToPosition(transform.position, originalPosition, returnSpeed));
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 089b592119ba967b4a9972a273c9f625

View file

@ -0,0 +1,5 @@
using UnityEngine;
public class PlayerAbility : Ability
{
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a5ff6f41c57bf3c338e65eda7d30a2b8

View file

@ -16,6 +16,8 @@ public class ReisenShoot : Ability
[SerializeField] private float maxChargeTime;
[SerializeField] private float chargeCooldown;
private float currentChargeCooldown;
[Header("Effects")]
[SerializeField] private Transform chargeMeter;
protected override void AbilityEffects()
{
if (currentChargeCooldown > 0)
@ -24,17 +26,20 @@ public class ReisenShoot : Ability
}
else
{
isCharging = true;
currentMouseHoldTime = mouseHoldTime;
}
}
private void ShootBullet(Projectile projectileToShoot, int damage)
{
WaveManager.instance.audioSource.PlayOneShot(projectileToShoot.projectileShootSFX, projectileToShoot.volume);
direction = cam.ScreenToWorldPoint(Input.mousePosition);
Projectile newProjectile = Instantiate(projectileToShoot, origin.position, Quaternion.identity);
newProjectile.transform.Lookat2D(direction);
newProjectile.damage = damage;
newProjectile.tag = tag;
newProjectile.playerBullet = true;
GameManager.instance.projectilesShot++; //i shouldn't be directly modifying the variable but i don't actually care
}
protected override void Update()
@ -43,8 +48,9 @@ public class ReisenShoot : Ability
if (currentMouseHoldTime >= 0)
{
currentMouseHoldTime -= Time.deltaTime;
if (currentMouseHoldTime <= 0 && Input.GetMouseButton(1) && currentChargeTime <= 0)
if (currentMouseHoldTime <= 0 && Input.GetMouseButton(0) && currentChargeTime <= 0)
{
currentChargeTime += mouseHoldTime;
isCharging = true;
}
else if (Input.GetMouseButtonUp(0))
@ -55,12 +61,13 @@ public class ReisenShoot : Ability
if (isCharging && Input.GetMouseButton(0)) //this code REEKS
{
currentChargeTime += Time.deltaTime;
chargeMeter.localScale = new Vector3(Math.Clamp(currentChargeTime, 0, maxChargeTime)/maxChargeTime, 1f, 1f);
}
else if (isCharging && Input.GetMouseButtonUp(0))
else if (currentChargeTime > 0 && isCharging && Input.GetMouseButtonUp(0))
{
Debug.Log("here");
currentChargeTime = 0;
ShootBullet(chargedProjectile, power * (int)Math.Clamp(currentChargeTime, 0, maxChargeTime));
currentChargeTime = 0;
chargeMeter.localScale = new Vector3(0f, 1f, 1f);
currentChargeCooldown = chargeCooldown;
isCharging = false;
}
@ -69,6 +76,6 @@ public class ReisenShoot : Ability
{
currentChargeCooldown -= Time.deltaTime;
}
Debug.Log(currentChargeTime);
//Debug.Log(currentChargeTime);
}
}

View file

@ -0,0 +1,16 @@
using UnityEngine;
public class SpawnSummon : EnemyAbility
{
[SerializeField] private int amount;
[SerializeField] private int amountVariance;
[SerializeField] private Enemy summon;
protected override void AbilityEffects()
{
int selectedAmount = amount + Random.Range(-amountVariance, amountVariance);
for (int i = 0; i < amount; i++)
{
WaveManager.instance.SpawnEnemy(summon);
}
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 17a599629000237739758466652c275f

View file

@ -1,16 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Mathematics;
using Core.Extensions;
using UnityEngine;
using Random = UnityEngine.Random;
public class YoumuDeflect : Ability
{
[SerializeField] private Camera cam;
private List<Projectile> projectilesInRange = new();
public float deflectionAngleMin = -48;
public float deflectionAngleMax = 90;
[Header("Deflection")]
[SerializeField] private float deflectionSpeed;
[SerializeField] private float deflectionSpeedVariance;
[SerializeField] private float deflectionAngleMin = -48;
[SerializeField] private float deflectionAngleMax = 90;
[SerializeField] private Projectile chargeProjectile;
[SerializeField] private float destructionChance;
[Header("Entity Detection")]
[SerializeField] private float detectionRadius;
[SerializeField] private LayerMask entityLayer;
[Header("SlashCharge")]
[SerializeField] private float mouseHoldTime;
private float currentMouseHoldTime;
@ -20,12 +30,15 @@ public class YoumuDeflect : Ability
[SerializeField] private float chargeCooldown;
private float currentChargeCooldown;
private float currentUnleashedChargeTime;
[Header("Charge Effects")]
[SerializeField] private AudioClip chargeSlashSFX;
[SerializeField] private float chargeVolume = 1f;
[SerializeField] private Transform chargeMeter;
[Header("Effects")]
[SerializeField] private ParticleSystem deflectionParticles;
[SerializeField] private GameObject swordSweepEffect;
[SerializeField] private GameObject chargeSweepEffect;
private float currentDissipationTime = 0f;
[SerializeField] private float dissipationTime;
[SerializeField] private AudioClip noHitSlashSFX;
[SerializeField] private float noHitVolume = 1f;
protected override void AbilityEffects()
@ -38,20 +51,28 @@ public class YoumuDeflect : Ability
else
{
currentMouseHoldTime = mouseHoldTime;
currentChargeTime = 0;
}
}
private void RegularDeflection()
{
//Debug.Log("Regular Deflection");
swordSweepEffect.gameObject.SetActive(true);
currentDissipationTime = dissipationTime;
DeflectProjectiles();
if (projectilesInRange.Count > 0)
{
DeflectProjectiles();
}
else
{
WaveManager.instance.audioSource.PlayOneShot(noHitSlashSFX, noHitVolume);
}
foreach (Enemy enemy in DetectEnemies())
{
enemy.TakeDamage(power);
}
}
private void DeflectProjectiles()
{
GameManager.instance.deflections += projectilesInRange.Count;
foreach (Projectile projectile in projectilesInRange.ToList())
{
if (!projectile)
@ -62,17 +83,28 @@ public class YoumuDeflect : Ability
projectile.transform.eulerAngles = new Vector3(0, 0, Random.Range(deflectionAngleMin, deflectionAngleMax));
projectile.direction = projectile.transform.right;
projectile.tag = tag;
projectile.speed = deflectionSpeed + Random.Range(-deflectionSpeedVariance, deflectionSpeedVariance);
ParticleSystem newParticles = Instantiate(deflectionParticles, projectile.transform);
projectile.Deflected();
float destructionRoll = Random.Range(0f, 1f);
if (destructionRoll < destructionChance)
{
Destroy(projectile.gameObject);
}
projectilesInRange.Remove(projectile);
}
WaveManager.instance.audioSource.PlayOneShot(abilitySound, volume);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag(tag) && other.TryGetComponent(out Projectile isProjectile))
if (!other.CompareTag(tag))
{
projectilesInRange.Add(isProjectile);
if (other.TryGetComponent(out Projectile isProjectile) && isProjectile.deflectable)
{
projectilesInRange.Add(isProjectile);
}
}
}
@ -80,21 +112,22 @@ public class YoumuDeflect : Ability
{
if (!other.CompareTag(tag) && other.TryGetComponent(out Projectile isProjectile) && projectilesInRange.Contains(isProjectile))
{
projectilesInRange.Add(isProjectile);
projectilesInRange.Remove(isProjectile);
}
}
private void ShootBullet(Projectile projectileToShoot, int damage)
{
Debug.Log(damage);
direction = cam.ScreenToWorldPoint(Input.mousePosition);
Projectile newProjectile = Instantiate(projectileToShoot, origin.position, Quaternion.identity);
newProjectile.transform.Lookat2D(direction);
newProjectile.damage = damage;
newProjectile.tag = tag;
newProjectile.playerBullet = true;
}
protected override void Update()
{
base.Update();
if (currentDissipationTime > 0)
{
currentDissipationTime -= Time.deltaTime;
if (currentDissipationTime <= 0)
{
swordSweepEffect.SetActive(false);
}
}
if (currentMouseHoldTime >= 0)
{
@ -102,6 +135,7 @@ public class YoumuDeflect : Ability
if (currentMouseHoldTime <= 0 && Input.GetMouseButton(1) && currentChargeTime <= 0)
{
isCharging = true;
currentChargeTime += mouseHoldTime;
}
else if (Input.GetMouseButtonUp(1))
{
@ -111,33 +145,36 @@ public class YoumuDeflect : Ability
if (isCharging && Input.GetMouseButton(1)) //this code REEKS
{
currentChargeTime += Time.deltaTime;
chargeMeter.localScale = new Vector3(Math.Clamp(currentChargeTime, 0, maxChargeTime)/maxChargeTime, 1f, 1f);
}
else if (isCharging && Input.GetMouseButtonUp(1))
{
Debug.Log("here");
chargeSweepEffect.SetActive(true);
currentUnleashedChargeTime = Math.Clamp(currentChargeTime, 0, maxChargeTime) * 2;
ShootBullet(chargeProjectile, power * (int)Math.Clamp(currentChargeTime, 0, maxChargeTime));
currentChargeTime = 0;
WaveManager.instance.audioSource.PlayOneShot(chargeSlashSFX, chargeVolume);
currentChargeCooldown = chargeCooldown;
isCharging = false;
chargeMeter.localScale = new Vector3(0f, 1f, 1f);
}
else if (currentUnleashedChargeTime > 0)
{
currentUnleashedChargeTime -= Time.deltaTime;
if (currentUnleashedChargeTime < 0)
{
chargeSweepEffect.SetActive(false);
}
if (projectilesInRange.Count > 0)
{
DeflectProjectiles();
}
}
if (currentChargeCooldown > 0)
{
currentChargeCooldown -= Time.deltaTime;
}
Debug.Log(currentChargeTime);
//Debug.Log(currentChargeTime);
}
private Enemy[] DetectEnemies()
{
Collider2D[] entitiesFound = Physics2D.OverlapCircleAll(transform.position, detectionRadius, entityLayer);
List<Enemy> enemiesFound = new();
foreach (Collider2D foundEntity in entitiesFound)
{
if (!foundEntity.CompareTag(tag) && foundEntity.TryGetComponent(out Enemy isEnemy))
{
enemiesFound.Add(isEnemy);
}
}
return enemiesFound.ToArray();
}
}