본문 바로가기
유니티/C#

14. 간단 로그라이크 만들기 - 5

by 찡사랑방 2023. 4. 6.
728x90
728x90

상속 -> 제네릭(Generic), 추상메소드, 추상클래스 

상속을 받는 다는건 다 쓴다는 것 

but 플레이어와 에너미가 다름 -> 제네릭을 만들어서 플레이어의 경우 -wall 로 에너미의 경우 - player로 

 

protected 부모-자식 

abstract(추상메소드) - 이름만 존재 -> 내용은 상속을 받은 쪽에서 채운다

virtual - override

 

MovingObj 코드 

using UnityEngine;
using System.Collections;
using System;

//한번에 한칸만 움직이도록

public abstract class MovingObject : MonoBehaviour
{
    [SerializeField] float moveSpeed;
    [SerializeField] LayerMask BlockingLayer;

    protected Animator myAnim;
    Rigidbody2D myrigid;
    BoxCollider2D myCollider;

   protected void Start()
    {
        myrigid = GetComponent<Rigidbody2D>();
        myCollider = GetComponent<BoxCollider2D>();
        myAnim = GetComponent<Animator>();
    }

    //private void Update()
    //{
    //    int h = (int)Input.GetAxis("Horizontal"); //GetAxis VS GetAxisRaw 
    //    int v = (int)Input.GetAxis("Vertical"); //GetAxis VS GetAxisRaw 

    //    if (h != 0 || v != 0) AttempMove<Wall>(h, v);
    //}


    //player --> wall공격
    //enemy --> player 공격
    //이동? 공격?
   protected virtual void AttempMove<T>(int xDir, int yDir) //<>->제네릭 : 일부의 요소의 차이만 존재 -> 호출 시 결정
    {
        RaycastHit2D hit;
        bool canMove = Move(xDir, yDir, out hit);
        if (canMove) return; //공격여부확인 -> ray에 감지된 대상이 존재 -> wall 인지 다른 존재인지 
        T target = hit.transform.GetComponent<T>();
        if (target != null) Attack(target);
    }

    protected abstract void Attack<T>(T target);
    
    protected bool Move(int xDir, int yDir, out RaycastHit2D hit) //이동할 곳에 장애물 존재여부 확인
    {
        Vector2 start = transform.position;
        Vector2 end = start + new Vector2(xDir, yDir);

        myCollider.enabled = false;
        hit = Physics2D.Linecast(start, end, BlockingLayer);
        myCollider.enabled = true;

        if (hit.transform == null) //rat에 감지된 물체가 없다 ---> 이동하시오
        {
            StartCoroutine(SmoothMove(end));
            return true;
        }
        return false; // 공격여부판단


    }
    //코루틴 -> 쉬는 시간
   protected IEnumerator SmoothMove(Vector3 end)
    {
        //magnitude(루트 계산 후의 결과), sqrMagnitude(루트 계산 전)
        float distance = (end - transform.position).sqrMagnitude;

        while (distance != 0)
        {
            //조금씩 이동

            Vector3 newPos = Vector3.MoveTowards(transform.position, end, moveSpeed * Time.deltaTime);
            myrigid.MovePosition(newPos);

            distance = distance = (end - transform.position).sqrMagnitude;
            yield return null; // while 과 실과 바늘 

        }
    }
}

 

 

 

Player 코드

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;

public class Player : MovingObject
{
    [SerializeField] Text foodText;

    int food;
    int damage = 1;
    int delayTime = 2;
    int pointPerFood = 10;
    int pointPerSoda = 20;


    private void OnEnable() //활성화
    {
        food = GameManager.instance.PlayerFood;
        foodText.text = "Food : " + food;
    }

    //비활성
    private void OnDisable() => GameManager.instance.PlayerFood = food;

    private void Update()
    {

        if (GameManager.instance.playerTurn == false) return;
        int h = (int)Input.GetAxis("Horizontal"); //GetAxis VS GetAxisRaw 
        int v = (int)Input.GetAxis("Vertical"); //GetAxis VS GetAxisRaw 

        if (h != 0 || v != 0) AttempMove<Wall>(h, v);
    }

    protected override void AttempMove<T>(int xDir, int yDir)
    {
        base.AttempMove<T>(xDir, yDir); //base -> 부모  this -> 나

        GameManager.instance.playerTurn = false;

        food--;// 1개 삭제
        foodText.text = "Food : " + food;
        CheckIfGameOver();
    }

    void CheckIfGameOver()
    {
        if (food <= 0)
        {
            print("GameOver");
        }

    }

    public void LossFood(int loss)
    {
        food -= loss;
        CheckIfGameOver();
    }

    protected override void Attack<T>(T target)
    {
        Wall wall = target as Wall;
        wall.DamageWall(damage);
    }


    //food, soda, exit 처리 -> OnTrigger
    private void OnTriggerEnter2D(Collider2D collision)
    {

        switch (collision.tag) //if 를 3개 이상 써야하는 경우
        {
            case "Food":
                food += pointPerFood;
                foodText.text = "+" + pointPerFood + ",Food:" + food;
                collision.gameObject.SetActive(false);
                break;
            case "Soda":
                food += pointPerSoda;
                foodText.text = "+" + pointPerSoda + ",Food:" + food;
                collision.gameObject.SetActive(false);
                break;
            case "Exit":
                Invoke("Restart", delayTime);
                gameObject.SetActive(false);
                break;
        }

    }

    void Restart()
    {

        SceneManager.LoadScene(SceneManager.GetActiveScene().name); //SceneManager.GetActiveScene 지금 열려있는 씬


    }
}

 

 

Enemy 스크립트

 

using UnityEngine;
using System.Collections;

public class Enemy : MovingObject
{

    [SerializeField] int damage;

    protected override void Attack<T>(T target)
    {
        Player player = target as Player;
        player.LossFood(damage);
    }
}
728x90