모름

05. damage system

이번 장은 Interface, virtual, protected, override을 사용했습니다.

 

Projectile.cs (총알 스크립트)

private void OnHitObject(RaycastHit hit)
{
    IDamgeable damgeableObject = hit.collider.GetComponent<IDamgeable>();
    if(damgeableObject != null)
    {
        damgeableObject.TakeHit(damage, hit);
    }

    GameObject.Destroy(this.gameObject);
}

 

우선 Projectile.cs를 보겠습니다. 총알에 달려있는 스크립트입니다. 총알은 적을 감지합니다. 그렇다면 감지한 적에게 데미지를 줬다고 메세지를 전달해야합니다. 여기서 메세지를 전달하는 방법이 IDamageble이라는 인터페이스를 만들어 감지한 적이 맞을만한 상대인지 판단하는것입니다. 이 인터페이스를 이용하여 데미지를 입을 오브젝트인 플레이어와 에너미에게 메세지를 보냅니다.

 

참고로 저는 여기서 인터페이스는 특정 클래스에 함수를 강제할 수 있는 추상화 껍데기라고 이해했습니다. 또한 인터페이스의 경우 앞의 첫 글자에 'I'를 붙이는게 일반적이라고 합니다.

 

IDamageable.cs (인터페이스)

using UnityEngine;

public interface IDamgeable {
    void TakeHit(float damage, RaycastHit hit);
}

 

인터페이스인 IDamageable 스크립트입니다. 간결합니다. 데미지를 입는 존재에게 약속시킬 함수의 이름은 TakeHit()입니다. 플레이어와 적 모두 데미지를 입기 때문에 이 인터페이스를 약속받을 대상이 됩니다.

 

그 전에 플레이어와 적은 공통점이 있습니다. 바로 데미지를 받을 체력이 필요하다는 점입니다. 때문에 체력을 관리하는 클래스를 만들어줍니다. LivingEntitiy.cs는 플레이어, 에너미 둘 다 사용이 가능하도록 구성돼야합니다.

 

LivingEntity.cs (체력관리, IDamageable을 상속)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LivingEntity : MonoBehaviour, IDamgeable {

    public float myStartingHealth;
    protected float health;
    protected bool dead;

    protected virtual void Start()
    {
        health = myStartingHealth;
    }
    public void TakeHit(float damage, RaycastHit hit)
    {
        health -= damage;

        if(health <= 0 &!dead)
        {
            Die();
        }
    }

    protected void Die()
    {
        dead = true;
        GameObject.Destroy(gameObject);
    }
}

 

LivingEntity는 IDamageable를 상속받습니다. 이 클래스에선 체력을 설정하고 데미지판정, 죽음판정을 관리합니다. 그리고 다시 한 번 LivingEntity는 Player와 Enemy에 최종적으로 상속됩니다.

 

Player.cs (플레이어, IDamageable를 상속받은 LivingEntity를 상속)

public class Player : LivingEntity
{
    public float moveSpeed = 5f;

    Camera viewCamera;
    PlayerController controller;
    GunController gunController;

    protected override void Start()
    {
        base.Start();
        controller = GetComponent<PlayerController>();
        viewCamera = Camera.main;
        gunController = GetComponent<GunController>();
    }

 

위는 Player클래스입니다. LivingEntity를 그대로 상속받았습니다. 하지만 LivingEntity와 똑같은 Start함수를 쓰고 있었으므로 함께 서기위해, LivingEntity의 Start함수를 protected virtual void Start()로 바꿨습니다. virtual은 상속 받은 클래스에서 함수를 다시 정의하고 싶을 때 사용한다합니다(?)만 문장이 복잡하니 용도를 기억하는 쪽으로 학습하겠습니다.

 

서로 똑같은 함수 명을 가지고 있을 때 일반적으로 상속받은 함수를 사용할 수 없습니다. 만약 상속받은 함수를 이용하고 싶다면 virtual을 통해 접근할 수 있습니다. 그리고 상속받는 클래스는 override해줘서 받아줘야합니다. 그리고 마지막으로 base.Start();를 통해서 부모의 Start함수에 스타팅체력을 정상 호출 했습니다.

 

다음 튜토리얼은 스폰 시스템을 다룹니다.