객체 지향 언어의 큰 장점 중 하나인 다형성에 대해 알아보자.
다형성은 문자 그대로 해석하면 '여러가지 형태'
라는 뜻이다. C#에서 다형성은 자식 클래스를 부모 클래스로 다룰 수 있게 하는 것이다. 조금 더 자세히 설명하자면, 부모 클래스를 상속받아 새로운 메소드도 만들고 기존 부모 클래스의 메소드를 오버라이드하여 다양한 자식클래스를 만드는 것이다.
간단한 예를 들면 몬스터라는 카테고리에는 좀비, 드래곤 등이 포함될 수 있다. 공격한다, 죽는다 등 같이 여러부분 공통점이 있을 것이다. 이럴 때 굳이 좀비와 드래곤에 공통된 부분을 반복해서 작성하는 것이 아니라 부모클래스인 몬스터에 작성하여 효율적으로 코딩하는 것이 다형성을 이용하는 것이다.
<예시> : Monster 다형성 예시
// Monster.cs
public calss Monster : MonoBehaviour {
public float damage = 100;
public void Attack() {
Debug.Log("공격");
}
public void Die() {
Debug.Log("죽음");
}
}
// Zombie.cs
public class Zombie : Monster {
public void Revive() {
Debug.Log("부활");
}
}
// Dragon.cs
public class Dragon : Monster {
public void Breath() {
Debug.Log("불 뿜기")
}
}
이제 다형성을 활용해서 여러가지 아이템을 만들어보자!
먼저 부모클래스에 작성할 아이템의 공통점에 대해 생각해보자.
- 플레이어가 획득하면 사라진다.
- 생성되고 시간이 지나면 사라진다.
- 획득시 플레이어에게 이로운 효과가 발생한다.
내가 생각했을 땐 이정도가 있는 것 같다. 이제 스크립트로 만들어보자.
// Item.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Item : MonoBehaviour
{
public virtual void Use()
{
Debug.Log("사용");
}
public virtual void GetItem()
{
Use();
Destroy(gameObject);
}
public virtual void DisappearItem()
{
Destroy(gameObject, 10f);
}
}
Use() -> 해당 아이템의 효과가 즉시 적용된다.
GetItem() -> 아이템을 먹으면 즉시 사용되며 아이템 오브젝트는 사라진다.
DisappearItem() -> 아이템이 생성된지 10초가 지나면 사라진다.
이제 이 부모 클래스를 토대로 회복, 보호막, 맵 전체 총알 없애기 아이템을 만들어보자. 다형성을 이용해 구현하려면 부모클래스에서 구현하는 공통적인 부분에는 virtual이라는 키워드를 사용해서 함수를 만들어야한다. virtual은 자식 클래스에서 해당 함수를 재정의 할 수 있도록 하용한다는 의미이다.
따라서 부모클래스에서 virtual로 만든 함수를 자식클래스에서 override를 이용해서 재정의하면 된다.
// HealItem.cs
using UnityEngine;
public class HealItem : Item
{
private void Start()
{
DisappearItem();
}
// 체력이 최대가 아닐경우 1회복
public override void Use()
{
SoundManager.instance.Heal_Play();
PlayerHealth playerhealth = GameObject.Find("Player").GetComponent<PlayerHealth>();
if (playerhealth.Health < 5)
{
playerhealth.Health++;
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
GetItem();
}
}
}
// BarrierItem.cs
using UnityEngine;
public class BarrierItem : Item
{
BarrierRange barrier;
private void Start()
{
barrier = GameObject.Find("Player").transform.Find("barrierRange").gameObject.GetComponent<BarrierRange>();
DisappearItem();
}
// 베리어 생성 (5초간 무적)
public override void Use()
{
SoundManager.instance.Barrier_Play();
barrier.BarrierStart();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
GetItem();
}
}
}
// DestroyItem.cs
using UnityEngine;
public class DestroyItem : Item
{
private void Start()
{
DisappearItem();
}
// 맵에 있는 모든 총알 제거
public override void Use()
{
SoundManager.instance.Destroy_Play();
GameObject.Find("Canvas").transform.Find("DestroyImage").gameObject.SetActive(true);
GameObject.Find("DestroyParent").transform.Find("DestroyRange").gameObject.SetActive(true);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
GetItem();
}
}
}
모든 아이템은 Use 메소드를 오버라이드하여 아이템마다 고유 효과를 만들어줬고, DisappearItem와 GetItem메소드는 부모클래스인 Item의 메소드를 그대로 사용하였다.