This commit is contained in:
김도환
2026-05-10 02:13:54 +09:00
parent e8ce7eb653
commit ee05d6eda9
23 changed files with 549 additions and 148 deletions

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using Unicorn.Hitbox;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace Unicorn.Boss
{
public class AttackManager: MonoBehaviour
{
private Dictionary<EntityId, float> _projMap;
private Dictionary<EntityId, UnicornHitbox> _projHitboxMap;
private const float Lifetime = 5f;
private void Start()
{
_projMap = new Dictionary<EntityId, float>();
_projHitboxMap = new Dictionary<EntityId, UnicornHitbox>();
}
private void FixedUpdate()
{
foreach (Transform o in transform)
{
var entityId = o.GetEntityId();
if (_projMap.TryAdd(entityId, 0f))
{
if (o.TryGetComponent(out UnicornHitbox hitbox))
_projHitboxMap.Add(entityId, hitbox);
}
if (o.gameObject.activeInHierarchy)
_projMap[entityId] += Time.fixedDeltaTime;
else continue;
if (_projMap[entityId] > Lifetime)
{
o.gameObject.SetActive(false);
_projMap[entityId] = 0f;
continue;
}
if (!_projHitboxMap.TryGetValue(entityId, out var unicornHitbox)) continue;
o.transform.Translate(o.right * (unicornHitbox.hitboxData.hitboxSpeed * Time.fixedDeltaTime), Space.World);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 88e10741af6249658ff3e467495bf561
timeCreated: 1778331143

View File

@@ -1,8 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using Unicorn.Hitbox;
using UnityEngine;
using NotImplementedException = System.NotImplementedException;
namespace Unicorn.Boss
{
@@ -15,6 +15,7 @@ namespace Unicorn.Boss
private UnicornPhase _unicornPhase = UnicornPhase.Start;
private Queue<GameObject> _p1Ps = new Queue<GameObject>();
private SpriteRenderer _renderer;
private const float P1PC = 12;
public Transform projContainer;
@@ -23,14 +24,17 @@ namespace Unicorn.Boss
private void Start()
{
_renderer = GetComponent<SpriteRenderer>();
StartCoroutine(Started());
base.Start();
}
private IEnumerator Started()
{
while (_p1Ps.Count < 50)
const float target = 360*5/P1PC;
while (_p1Ps.Count < target)
{
for (var i = 0; i < 5 && _p1Ps.Count < 50; i++) //프레임당 5개씩 생성
for (var i = 0; i < 5 && _p1Ps.Count < target; i++) //프레임당 5개씩 생성
{
var instantiate = Instantiate(phase1Proj, projContainer);
_p1Ps.Enqueue(instantiate);
@@ -46,26 +50,52 @@ namespace Unicorn.Boss
}
// 수정된 Phase1 로직
private IEnumerator Phase1()
{
_unicornPhase = UnicornPhase.P1;
for (int i = 0; i < 360 / P1PC; i++)
float angleStep = 360f / P1PC; // 각도 간격 (30도)
for (int i = 0; i < P1PC; i++)
{
var dequeue = _p1Ps.Dequeue();
dequeue.SetActive(true);
dequeue.transform.position = transform.position;
var rotationEulerAngles = transform.rotation.eulerAngles;
rotationEulerAngles.z += (360 / P1PC) * i;
dequeue.transform.rotation = Quaternion.Euler(rotationEulerAngles);
float targetAngle = transform.rotation.eulerAngles.z + (angleStep * i);
dequeue.transform.rotation = Quaternion.Euler(0, 0, targetAngle);
_p1Ps.Enqueue(dequeue);
yield return new WaitForSeconds(.2f);
}
yield return new WaitForSeconds(5);
yield return new WaitForSeconds(1);
StartCoroutine(Phase1());
}
protected override void OnKnockback(DamageInfo info)
{
//No KnockBack
}
protected override void OnDeath()
{
transform.DOScale(0f, 3f).SetEase(Ease.Linear).OnComplete(() =>
{
gameObject.SetActive(false);
base.OnDeath();
});
}
protected override void OnDamaged(DamageInfo info)
{
StopCoroutine(HitColor());
StartCoroutine(HitColor());
base.OnDamaged(info);
}
private IEnumerator HitColor()
{
_renderer.color = new Color(1f, 0.8f, 0.8f);
yield return new WaitForSeconds(0.5f);
_renderer.color = Color.white;
}
}
}

View File

@@ -0,0 +1,10 @@
using UnityEngine;
namespace Unicorn
{
public class GameManager: MonoBehaviour
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc10e4b8623544638c8e15879ff85de7
timeCreated: 1778342698

View File

@@ -4,15 +4,15 @@ namespace Unicorn.Hitbox
{
public class UnicornHitbox : MonoBehaviour
{
public UnicornAttackDataSObj attackData;
public UnicornHitboxDataSObj hitboxData;
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.TryGetComponent(out LivingEntity target)) return;
var info = new DamageInfo
{
Damage = attackData.damage,
KnockbackForce = attackData.knockbackForce,
Damage = hitboxData.damage,
KnockbackForce = hitboxData.knockbackForce,
HitPoint = transform.position
};

View File

@@ -3,9 +3,10 @@
namespace Unicorn.Hitbox
{
[CreateAssetMenu(fileName = "NewAttackData", menuName = "Unicorn/AttackData")]
public class UnicornAttackDataSObj: ScriptableObject
public class UnicornHitboxDataSObj: ScriptableObject
{
public float damage;
public float knockbackForce;
public float hitboxSpeed;
}
}

View File

@@ -0,0 +1,31 @@
using System;
using UnityEngine;
namespace Unicorn
{
public class HpBar : MonoBehaviour
{
private LivingEntity _parent;
public GameObject fill;
private void Start()
{
if (!transform.parent.TryGetComponent(out _parent))
{
gameObject.SetActive(false);
return;
}
UpdateHealth();
}
public void UpdateHealth()
{
var scale = Math.Max(_parent.health, 0f) / _parent.maxHealth;
fill.transform.localScale = new Vector3(scale, 1, 1);
fill.transform.localPosition = new Vector3((scale-1) / 2, 0, 0);
//1 -> 0
//0 -> -0.5
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 177f745ebb3c415e8e5c73b53c18636b

View File

@@ -5,21 +5,18 @@ namespace Unicorn
{
public partial class LivingEntity : MonoBehaviour
{
public float maxHealth = 20.0f;
public float health = 20.0f;
public GameObject hpBarPrefab;
private Rigidbody2D Rb { get; set; }
private bool _invulnerable = false;
private HpBar _hpBar;
private void Start()
protected void Start()
{
Rb = TryGetComponent(out Rigidbody2D rb) ? rb : null;
}
private void OnTriggerEnter2D(Collider2D other)
{
if (Rb == null) return;
var transformPosition = other.transform.position - transform.position;
Rb.linearVelocity = Vector2.zero;
Rb.AddForce(transformPosition.normalized * health, ForceMode2D.Impulse);
var hpBar = Instantiate(hpBarPrefab, transform);
hpBar.TryGetComponent(out _hpBar);
}
public void Damage(DamageInfo info)
@@ -27,6 +24,7 @@ namespace Unicorn
if (_invulnerable) return;
health -= info.Damage;
OnDamaged(info);
OnKnockback(info);
if (health <= 0.0f) OnDeath();
}
@@ -34,10 +32,14 @@ namespace Unicorn
protected virtual void OnDeath() { }
protected virtual void OnDamaged(DamageInfo info) { }
protected virtual void OnDamaged(DamageInfo info)
{
if (_hpBar) _hpBar.UpdateHealth();
}
protected virtual void OnKnockback(DamageInfo info)
{
var dir = transform.position - info.HitPoint;
Rb.AddForce(dir.normalized * info.KnockbackForce, ForceMode2D.Impulse);
}

View File

@@ -8,11 +8,13 @@ namespace Unicorn.Player
protected override void OnDamaged(DamageInfo info)
{
Debug.Log(health);
base.OnDamaged(info);
}
protected override void OnDeath()
{
Debug.Log("주것서영.");
base.OnDeath();
}
}
}

View File

@@ -9,6 +9,7 @@ namespace Unicorn.Player
{
public GameObject attackHitbox;
private UnicornInputSystem _unicornInput;
private bool _attackAvailable = true;
private void Start()
{
_unicornInput = UnicornInput.Unicorn;
@@ -22,14 +23,18 @@ namespace Unicorn.Player
private void Attack(InputAction.CallbackContext obj)
{
if (!_attackAvailable) return;
StartCoroutine(OnAttack());
}
private IEnumerator OnAttack()
{
_attackAvailable = false;
attackHitbox.SetActive(true);
yield return new WaitForSeconds(0.5f);
attackHitbox.SetActive(false);
yield return new WaitForSeconds(0.1f);
_attackAvailable = true;
}
}
}