나 개발자 진짜 되냐?

[ Unity 뱀서라이크 게임을 만들어보자 10 ] 넉백 구현 + 데미지 피격 구현 본문

유니티를 공부해봐요!/초급이에요!

[ Unity 뱀서라이크 게임을 만들어보자 10 ] 넉백 구현 + 데미지 피격 구현

Snow Rabbit 2024. 10. 12. 02:00

아마 뱀서라이크 게임 마지막일 거 같다.

넉백과 데미지 입는 거만 구현하면

아무래도 뱀서라이크 게임은 완성될 거 같다.

 

흐흐

마무리 파이팅해보자!


넉백 구현을 위해 우리는

TopDownMovement를 만져줘야 한다.

변수 두 개 추가!

if문으로 넉백이 되면,

fixedDeltaTime을 빼준다.

그다음에 넉백 함수 구현

넉백 될 때 위치는 뒤로 밀리듯

상대의 원래 위치에서 넉백 위치값이랑 빼주는 시스템

if문을 통해서

원래 위치보다 커지면

위치에 넉백 더하세요!

 

그럼 추가 내용 끝!


 

자 이제 데미지 구현을 해보자

 

먼저 데미지를 입어야 하니 체력이 있어야 한다.

< HealthSystem.cs >

using System;
using UnityEngine;

public class HealthSystem : MonoBehaviour
{
    //무적시간 작성, 이시간이 지나야 피격시 피가 닳도록
    [SerializeField] private float healthChangeDelay = 0.5f;
    // 플레이의 능력치 가져오기
    private CharacterStatHandler statsHandler;
    // 마지막 공격을 받고 얼마나 시간이 지났는지 알기위해
    private float timeSinceLastChange = float.MaxValue;
   //공격 받는지 여부 bool 지금은 안받으니 false
    private bool isAttacked = false;

    // 체력이 변했을 때 할 행동들을 정의하고 적용 가능
    public event Action OnDamage;
    public event Action OnHeal;
    public event Action OnDeath;
    public event Action OnInvincibilityEnd;

    public float CurrentHealth { get; private set; }

    // get만 구현된 것처럼 프로퍼티를 사용하는 것
    // 이렇게 하면 데이터의 복제본이 여기저기 돌아다니다가 싱크가 깨지는 문제를 막을 수 있어요!
    public float MaxHealth => statsHandler.CurrentStat.maxHealth;

    private void Awake() // 나랑 관련된것, 보통 getcomponent
    {
        statsHandler = GetComponent<CharacterStatHandler>();
    }

    private void Start() //현재의 체력 정의
    {
        CurrentHealth = MaxHealth;
    }

    private void Update() //공격을 받았을때 타임을 돌게 한다
    {   //공격을 받았다면
        if (isAttacked && timeSinceLastChange < healthChangeDelay)
        {   //시간 누적
            timeSinceLastChange += Time.deltaTime;
            if (timeSinceLastChange >= healthChangeDelay) // 값이 오버됐다면
            {   //비어있을수도있으니 ? 추가
                OnInvincibilityEnd?.Invoke();
                //공격 끝났으니 false
                isAttacked = false;
            }
        }
    }

    public bool ChangeHealth(float change) //
    {
        // 무적 시간에는 체력이 달지 않음
        if (timeSinceLastChange < healthChangeDelay)
        {   //공격을 하지않고 넘겼다.
            return false;
        }

        timeSinceLastChange = 0f;
        CurrentHealth += change;
        // [최솟값을 0, 최댓값을 MaxHealth로 하는 구문]
        CurrentHealth = Mathf.Clamp(CurrentHealth, 0, MaxHealth);
        // CurrentHealth = CurrentHealth > MaxHealth ? MaxHealth : CurrentHealth;
        // CurrentHealth = CurrentHealth < 0 ? 0 : CurrentHealth; 와 같아요!

        if (CurrentHealth <= 0f) // 만약에 죽으면
        {
            CallDeath();
            return true;
        }

        if (change >= 0)
        {
            OnHeal?.Invoke();
        }
        else
        {
            OnDamage?.Invoke();
            isAttacked = true;
        }


        return true;
    }

    private void CallDeath()
    {
        OnDeath?.Invoke();
    }
}

 

주석을 아주 친절하게 달아두었다.

 

자 이렇게 코드를 새로 하나 만들어서 짰다면

 

조금 고쳐야 할 부분들이 있다.

 

1. AnimationController

여기에 health을 넣어보자!

 

체력시스템 추가하고 get

 

다음 Start에서 

 

이벤트 등록 해준다.

 

자 다음에 이동해야 할 스크립트는

 

2. ProjectileController

 

여기서 OnTriggerEnter2D를 보면

제일 밑에 elseif로 피격 시 조건이 있다.

 

여기를 수정!

 

그리고 밑에 함수 하나 추가

넉백이죠!

 

다음에 우리가 코드를 수정해야 하는 부분은

단거리 친구들을 좀 만져보려고 한다.

 

3. TopDownContactEnemyController

 

여기서도 먼저 health 넣어주고!

다음 start 와서

get 해주고 데미지를 주는 식을 써준다.

 

다음, 닿았을 때 함수를 만들어보자

닿았을 땐? OnTriggerEnter2D

 

 

이렇게 해주면

닿은 애들이 누구인지 데이터를 얻을 수 있다.

 

하지만 

거리가 벌어지거나 뭐 

여러 이유로 닿은 게 풀리면 더 이상

데이터를 얻어선 안된다.

 

그리고 데미지 피격은 어디서 하냐

Fixed에서 해주는데

이유는 주석에 적었다

 

이제 ApplyHealthChange로 가보자!

 

자 체력을 만들어주었으니

다 닳으면

없어지거나 죽는 것을 구현해 보자!

새로운 클래스를 만들어준다.

 

< DestroyOnDeath.cs >

using UnityEngine;

public class DestroyOnDeath : MonoBehaviour
{
    private HealthSystem healthSystem;
    private Rigidbody2D rigidbody;

    private void Start()
    {
        healthSystem = GetComponent<HealthSystem>();
        rigidbody = GetComponent<Rigidbody2D>();
        // 실제 실행 주체는 healthSystem임
        healthSystem.OnDeath += OnDeath;
    }

    void OnDeath() // 캐릭터 반투명화 + 컴포넌트 꺼주기
    {
        // 멈추도록 수정
        rigidbody.velocity = Vector3.zero;

        // 약간 반투명한 느낌으로 변경
        foreach (SpriteRenderer renderer in transform.GetComponentsInChildren<SpriteRenderer>())
        {
            //컬러를 다바꾸는게 아니라 rgb로 바꿀 예정이다.
            //원래는 이렇게 하나바꾸는게 어려운데 우리는 컬러를 가져와서
            //바꿔주고 다시 넣어주는 방법으로 바꿔줄 수 있게 했다.
            Color color = renderer.color;
            color.a = 0.3f;
            renderer.color = color;
        }

        // 스크립트 더이상 작동 안하도록 함
        foreach (Behaviour component in transform.GetComponentsInChildren<Behaviour>())
        {
            component.enabled = false;
        }

        // 2초뒤에 파괴
        Destroy(gameObject, 2f);
    }
}

주석이 왕 많은 곳이 있다.

간단하게 설명하면

이렇게 코드를 한 줄로는 못쓴다.

그래서 위에처럼

따로 써주는 것이다.

 

 

 

자 다음에 코드 짰으니

유니티에 가서 넣어보자!!

 

넣을 때

health의 경우 몬스터와 플레이어 모두 갖기 때문에

 

 

요렇게 3개 해서

add component 해주면

한꺼번에 가능!!

 

파괴는

몬스터 두 개한테만 블록 씌워서 추가해 준다.

 

 

그럼 게임 완성..!!!!!!!!

 

룰루

 

그 뒤에 몬스터들 복사하는 것..

그리고 더 나아가

웨이브 구현,

웨이브에 따른 몬스터 량,

플레이어 공격력 등등

더 많이 해볼 예정이다.

 

일단 뱀서류게임 반쯤 완성!!