-
게임개발 8일차 (간단한 슈팅게임 6)게임 개발 2025. 6. 2. 21:26
오늘은 적 HP바 / 캐릭터-플레이어,적 상속 / 자동쏘기+속도제한을 구현했다.
public class Character : MonoBehaviour {
public virtual void Move() {
// 기본 이동 구현
}
}
public abstract class Character : MonoBehaviour {
public abstract void Attack();
}위처럼 기본 클래스에 virtual - override로 추가구현을 할 수도 있고
abstract - override로 자식에서 완전구현을 하도록 만들 수도 있다.
Bullet.cs의 일부이다.
private void OnTriggerEnter2D(Collider2D collision) // 충돌 시작할 때
{
if (collision.tag == "Wall") // 벽에 닿으면
{
gameObject.SetActive(false); // 총알 꺼짐
}
else if (collision.tag == "Enemy") // 적에 닿으면
{
Enemy enemy = collision.GetComponent<Enemy>(); // 적 오브젝트 정보를 가져오고
if (enemy != null) // 혹시나 GetComp가 enemy를 못가져올 수 있으니 안전장치
{
if (enemy.IsDead()) // 적이 죽어있다면
{
return; // 종료시켜서 총알 통과시킴
}
}
gameObject.SetActive(false); // 적이 살아있으면 총알 꺼짐
}
}저런식으로 GetComp를 실패했을 때 무시하고 아래 코드가 실행되면 런타임오류가 발생될 수 있으니 안전장치를 걸자.
public class KillManager : MonoBehaviour
{
public static KillManager Instance;
void Awake() // 활성화될 때
{
if (Instance == null) // 인스턴스가 없었으면
{
Instance = this; // 이 오브젝트가 이 클래스의 유일한 인스턴스가 됨
}
else
{
Destroy(gameObject); // 중복을 막기위해 이 오브젝트 파괴
}
}이 방식을 싱글톤 방식이라고 한다. 게임 전체에서 단 하나만 존재해야 하는 오브젝트 (KillManager, BGMManager) 등에 넣어서 사용한다고 한다. 게임전체에서 참조할 수 있는 public static으로 KillManager.Instance를 지정하고 단 하나만 존재하게 한 후 부르고 싶을 때 KillManager.Instance.Addkill() 이런식으로 이용한다고 한다.
유니티에서 시간을 지연 시킨 후 동작 시키기 위해서(죽는애니메이션을 보여주는 시간등등) 사용하는 함수에는
Invoke와 Coroutine이 있다.
Invoke(<어떤함수>, 1.5f)으로 아주 간단하게 구현가능하지만 정교한 제어가 어려워서 결국 Coroutine을 사용해야 한다고 한다.
private Coroutine shootCoroutine;
void Start()
{
StartCoroutine(SpawnBombs()); // 코루틴 시작
}IEnumerator SpawnBombs() // IEnumerator은 중간에 상태를 저장하며 순서대로 실행할 수 있게 하는 특별한 자료형
{
for (int i = 0; i < 5; i++)
{
Debug.Log($"💣 폭발 {i + 1}번!");
yield return new WaitForSeconds(3f); // 3초 기다림 (참고로 null은 다음 프레임까지만 기다림)
}
Debug.Log("💥 폭발 종료!");
}
총발사 최대속도를 0.3초로 제한하고 누르고 있으면 최대속도로 쏘도록 하는 기능을 구현했다.
private Coroutine shootCoroutine;
private float lastShootTime = 0f;
private float shootCooldown = 0.3f;void Update(){
if (Input.GetMouseButtonDown(0)) // 좌클릭 누르기 시작함
{
shootCoroutine = StartCoroutine(AutoShoot()); // 자동발사 기능 시작
}
if (Input.GetMouseButtonUp(0)) // 좌클릭 뗌
{
StopCoroutine(shootCoroutine); // 자동발사 기능 해제
}
if (Input.GetMouseButtonDown(0)) // 좌클릭 누르기 시작함
{
TryManualShoot(); // 자동발사와 별개로 동작하는 발사 함수 가동
}
}void TryManualShoot() // 수동발사함수
{
if (Time.time - lastShootTime >= shootCooldown) // 쿨타임이 돌았다면
{
Shoot(); // 발사
lastShootTime = Time.time; // 현재시각으로 last슛타임을 설정
}
}
IEnumerator AutoShoot()
{
while (true)
{
if (Time.time - lastShootTime >= shootCooldown)
{
Shoot();
lastShootTime = Time.time;
}
yield return new WaitForSeconds(0.05f); // 0.05초마다 반복하면서 0.5초 지났는지 체크
}
}Time.time 게임 시작 후 흐른 시간 (초) 타이머, 쿨다운, 주기적 실행 등에 사용 Time.deltaTime 한 프레임이 걸린 시간 (애니메이션 등에서 자주 사용) 움직임·속도 계산에 사용 Time.fixedTime FixedUpdate 기준의 시간 (물리엔진용)
적의 HPBar를 구현했다. 선생님과 만든 방식은 단순하게 캐릭터 스크립트를 플레이어 오브젝트에 삽입해서 하는 방식이었지만 플레이어와 적 스크립트 자체를 캐릭터 스크립트를 상속하게 만든 후 hp 바를 구현했다.
적 프리팹 -> HPBar라는 빈 오브젝트(위치용) -> 캔버스 -> 빨간바 이미지로 계층을 만든 후
(플레이어 HP바는 화면이라는 오버레이 밑에 고정되어 있기 때문에 플레이어 오브젝트 밑이 아닌 개별의 캔버스 아래에 있었다)
public class Enemy : Character
{
public RectTransform enemyHPBarRect;
private float maxHPBarWidth;
void Awake()
{
if (enemyHPBarRect != null)
maxHPBarWidth = enemyHPBarRect.sizeDelta.x;
}
public override void Initialize()
{
base.Initialize();
UpdateHPBar();
}
public override bool Hit(float damage)
{
base.Hit(damage);
if (HP < 0) HP = 0;
UpdateHPBar();
return HP > 0;
}
void UpdateHPBar()
{
if (enemyHPBarRect != null)
{
float ratio = HP / maxHP; // HP 비율 0~1
enemyHPBarRect.sizeDelta = new Vector2(maxHPBarWidth * ratio, enemyHPBarRect.sizeDelta.y);
}
}부모에서
public virtual bool Hit(float damage)
{
HP -= damage;
return HP > 0;
}로 구현하고
public override bool Hit(float damage)
{
base.Hit(damage);
if (HP < 0) HP = 0;
UpdateHPBar();
return HP > 0;
}자식에서 이렇게 이어 붙이는 방식이 아주 흥미로웠다.
이 게임은 여기까지 만들고 3D로 넘어가보려고 한다!!! 재밌었다!!!!!
'게임 개발' 카테고리의 다른 글
게임개발 10일차 (1인칭 스타터에셋 이해) (0) 2025.06.05 게임개발 9일차 (간단한 슈팅게임 7) (0) 2025.06.03 게임개발 7일차 (간단한 슈팅게임 5) (0) 2025.05.29 게임개발 6일차 (간단한 슈팅게임 4) (0) 2025.05.28 게임개발 5일차 (간단한 슈팅게임 3) (0) 2025.05.27