2025년, 코딩은 선택이 아닌 필수!

2025년 모든 학교에서 코딩이 시작 됩니다. 먼저 준비하는 사람만이 기술을 선도해 갑니다~

응용프로그래밍/유니티기초

[유니티기초]2-05. 플레이어 위치를 찾아서 그쪽으로 이동을 해 보자.

파아란기쁨1 2022. 6. 1. 17:29
반응형
목표

플레이어 를 태그로 찾아서 그 위치로 이동하는 부분을 구현해 보자.

 

실습

플레이어에 태그를 Player 로 선택하자.

2022.06.01 - [응용프로그래밍/유니티기초] - [유니티기초]2-04. 애니메이션

 

[유니티기초]2-04. 애니메이션

목표 오크와 드래곤이 각각 공격 명령을 받으면 공격하는 행동을 취하고 움직임,사망 등의 애니메이션을 만들어 보자. 실습 1. 먼저 드래곤의 이미지를 살펴 봅시다. 주어진 이미지는 attack(공격)

thinkmath2020.tistory.com

애니메이션을 만들었던 orc 에 다음과 같이 스크립트를 추가하면 Player 위치를 찾아서 이동하는 것을 확인 할 수 있다.

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

public class Monster : MonoBehaviour
{

    GameObject player = null;

    private Vector3 targetPosition;
    public bool lookRight = true;
    public float speed=0.5f;
    private Animator animator;
    // Start is called before the first frame update
    void Start()
    {
       player = GameObject.FindWithTag("Player"); 
       animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        targetPosition = player.transform.position;
        //transform.position = Vector3.MoveTowards(gameObject.transform.position,player.GameObject.transform,2.0f) ;   
        if (targetPosition.x > transform.position.x && !lookRight) //타겟이 오른쪽에 있으면서 현재 왼쪽을 바라 보고 있으면 방향 회전
          Flip();
        if(targetPosition.x < transform.position.x && lookRight)
          Flip();
        
        var p = transform.position;
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);

	    //Vector3 vel = targetPosition - transform.position;
        //vel = Vector3.ClampMagnitude(vel, speed * Time.deltaTime);
        //transform.position += vel;

        animator.SetFloat("speed", (transform.position - p).magnitude/Time.deltaTime);
    }

    public void Flip()
    {
        var s = transform.localScale;
        s.x *= -1;
        transform.localScale = s;
        lookRight = !lookRight;
    }
}

태그 이름으로 객채를 찾는 것은 GameObject.FindWithTag("Player");

Flip() 에서는 localScale 의 x축을 이용하여 좌우를 반전 하도록 처리했다.

animator 의 speed 값을 주어서 walk 애니메이션을 동작하도록 처리했다.

Vector3.MoveTowards 로 타겟 위치로 speed 속도로 이동하도록 처리했다.

 

 

전체 코드

-Dragon.cs

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

public class Dragon : MonoBehaviour,IMonster
{
    public void Fly()
    {
        Debug.Log("날기");
    }

    public void Attack(){
        Debug.Log("Dragon이 공격을 합니다.");
    }

    public void Say(){
        Debug.Log("Dragon이 말을 합니다.");
    } 

}

- GameManager.cs

using UnityEngine;
using UnityEngine.SceneManagement;

// 점수와 게임 오버 여부를 관리하는 게임 매니저
public class GameManager : MonoBehaviour {
    // 외부에서 싱글톤 오브젝트를 가져올때 사용할 프로퍼티
    public static GameManager instance
    {
        get
        {
            // 만약 싱글톤 변수에 아직 오브젝트가 할당되지 않았다면
            if (m_instance == null)
            {
                // 씬에서 GameManager 오브젝트를 찾아 할당
                m_instance = FindObjectOfType<GameManager>();
            }

            // 싱글톤 오브젝트를 반환
            return m_instance;
        }
    }

    private static GameManager m_instance; // 싱글톤이 할당될 static 변수

    private int score = 0; // 현재 게임 점수
    public bool isGameover { get; private set; } // 게임 오버 상태


    private void Awake() {
        // 씬에 싱글톤 오브젝트가 된 다른 GameManager 오브젝트가 있다면
        if (instance != this)
        {
            // 자신을 파괴
            Destroy(gameObject);
        }
    }

    private void Start() {
        FindObjectOfType<PlayerMovement>().onDeath += EndGame;
    }

    // 점수를 추가하고 UI 갱신
    public void AddScore(int newScore) {
        // 게임 오버가 아닌 상태에서만 점수 증가 가능
        if (!isGameover)
        {
            // 점수 추가
            score += newScore;
            // 점수 UI 텍스트 갱신
            UIManager.instance.UpdateScoreText(score);
        }
    }

    // 게임 오버 처리
    public void EndGame() {
        // 게임 오버 상태를 참으로 변경
        isGameover = true;
        // 게임 오버 UI를 활성화
        UIManager.instance.SetActiveGameoverUI(true);
    }
    
    private void Update() {

    }

}

- IMonster.cs

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

public interface IMonster 
{
    public void Attack();
    public void Say(); //여기서는 정의만 한다.
}

- Monster.cs

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

public class Monster : MonoBehaviour
{

    GameObject player = null;

    private Vector3 targetPosition;
    public bool lookRight = true;
    public float speed=0.5f;
    private Animator animator;
    private float atackDelay = 0;
    private bool Attack = false;
    // Start is called before the first frame update
    void Start()
    {
       player = GameObject.FindWithTag("Player"); 
       animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        if(!Attack){
            targetPosition = player.transform.position;
            //transform.position = Vector3.MoveTowards(gameObject.transform.position,player.GameObject.transform,2.0f) ;   
            if (targetPosition.x > transform.position.x && !lookRight) //타겟이 오른쪽에 있으면서 현재 왼쪽을 바라 보고 있으면 방향 회전
            Flip();
            if(targetPosition.x < transform.position.x && lookRight)
            Flip();
            
            var p = transform.position;
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);

            //Vector3 vel = targetPosition - transform.position;
            //vel = Vector3.ClampMagnitude(vel, speed * Time.deltaTime);
            //transform.position += vel;

            animator.SetFloat("speed", (transform.position - p).magnitude/Time.deltaTime);
        } 
        else {
            atackDelay+=Time.deltaTime;
            if(atackDelay<1) return;
            atackDelay=0;
            animator.SetTrigger("attack");
            Attack=false;
        }
        
    }

    public void Flip()
    {
        var s = transform.localScale;
        s.x *= -1;
        transform.localScale = s;
        lookRight = !lookRight;
    }
    private void OnCollisionEnter2D(Collision2D other) {
        if(other.gameObject.tag=="Player"){
            Attack = true;
            atackDelay = 0f;
            //animator.SetTrigger("attack");
            Debug.Log("OnCollisionEnter2D");
        }
    }
    private void OnCollOnCollisionExit2D(Collision2D other) {
        if(other.gameObject.tag=="Player"){
            Attack = false;
            //animator.SetTrigger("attack");
            Debug.Log("OnCollOnCollisionExit2D");
        }
    }
}

- ObjectSpawner.cs

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

public class ObjectSpawner : MonoBehaviour
{

    public GameObject circle;
    public Transform FirePos;
    // Start is called before the first frame update
    Rigidbody2D rb; //Rigidbody 를 연결할 변수 선언
    public float speed = 5.0f; // 이동 속도
    Vector3 dir;

    private void Awake() {
        
        //Quaternion.identity 회전값(0,0,0)
        /*Quaternion rotation = Quaternion.Euler(0,0,0); //각도를 나타내는 오일러를 Quaternion 으로 변환 
        
        c1.name = "동그라미1";
        c1.GetComponent<SpriteRenderer>().color = Color.yellow; //생성된 객체 색상 변경
        c1.transform.position = new Vector3(-3,3,0); //생성된 객체 위치 변경
        c1.transform.localScale = new Vector3(0.5f,0.5f,0); //생성된 객체 크기 변경

        Destroy(c1,3f);
        */
        /*
        for(int y=0;y<10;y++){
            for(int x=0;x<10;x++){
                Vector3 position = new Vector3(-4.5f + x,-4.5f + y,0);
                Instantiate(circle,position,Quaternion.identity);
            }
        }
        */
    }
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();  //자신의 Rigidbody 를 가져와서 rb에 연결
        dir = Vector3.right;
    }

    // Update is called once per frame
    void Update()
    {


    }
}

- Orc.cs

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

public class Orc : MonoBehaviour,IMonster
{
    public void WarCry()
    {
        Debug.Log("전투함성");
    }

    public void Attack(){
        Debug.Log("Orc가 공격을 합니다.");
    }

    public void Say(){
        Debug.Log("Orc가 말을 합니다.");
    } 

    public void Update(){
        
    }

}

- PlayerInput.cs

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

public class PlayerInput : MonoBehaviour
{
    public string moveAxisName = "Vertical"; // 앞뒤 움직임을 위한 입력축 이름
    public string rotateAxisName = "Horizontal"; // 좌우 회전을 위한 입력축 이름
    public string fireButtonName = "Fire1"; // 발사를 위한 입력 버튼 이름
    public string jumpButtonName = "Jump"; // 점프를 위한 입력 버튼 이름

    // 값 할당은 내부에서만 가능
    public float move { get; private set; } // 감지된 움직임 입력값
    public float rotate { get; private set; } // 감지된 회전 입력값
    public bool fire { get; private set; } // 감지된 발사 입력값
    public float jump { get; private set; } // 감지된 점프 입력값

    // 매프레임 사용자 입력을 감지
    private void Update() {
       
        // 게임오버 상태에서는 사용자 입력을 감지하지 않는다
        if (GameManager.instance != null && GameManager.instance.isGameover)
        {
            move = 0;
            rotate = 0;
            fire = false;
            jump = 0;
            return;
        }

        // move에 관한 입력 감지
        move = Input.GetAxis(moveAxisName);
        // rotate에 관한 입력 감지
        rotate = Input.GetAxis(rotateAxisName);
        // fire에 관한 입력 감지
        fire = Input.GetButton(fireButtonName);
        // jump 관한 입력 감지
        jump = Input.GetAxis(jumpButtonName);
    }
}

- PlayerMovement.cs

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

public class PlayerMovement : MonoBehaviour
{
    private int score = 0;
    public bool dead { get; protected set; } // 사망 상태
    public event Action onDeath; // 사망시 발동할 이벤트
    public float speed = 10f; // 이동 속도
    Rigidbody2D rb;
    // Start is called before the first frame update
    private void Awake() {
      UIManager.instance.SetActiveGameoverUI(false);  
      Debug.Log("PlayerMovement");
    }
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();  
    }

    // Update is called once per frame
    void Update()
    {
        if(dead) return;
        GameManager.instance.AddScore(++score);

        float xInput = Input.GetAxis("Horizontal");
        float zInput = Input.GetAxis("Vertical");
        float yInput = Input.GetAxis("Jump");

        float xSpeed = xInput * speed;
        float zSpeed = zInput * speed;
        float ySpeed = yInput * speed;

        transform.position += new Vector3(xSpeed,ySpeed,zSpeed) * Time.deltaTime;
        //UIManager.instance.UpdateScoreText(++score);    
    }

    private void OnCollisionEnter2D(Collision2D other) {
        if(other.gameObject.tag=="bottom"){
            //Die(); 
        }

        IMonster monster = other.gameObject.GetComponent<IMonster>();
        if(monster!=null) {
            monster.Say();
            Rigidbody2D otherrb = other.gameObject.GetComponent<Rigidbody2D>();
            otherrb.constraints = RigidbodyConstraints2D.FreezeAll;
            /*
            Animator animator = other.gameObject.GetComponent<Animator>();
            animator.SetTrigger("Die");
            */
        }
    }

    // 사망 처리
    public virtual void Die() {
        // onDeath 이벤트에 등록된 메서드가 있다면 실행
        if (onDeath != null)
        {
            onDeath();
        }

        // 사망 상태를 참으로 변경
        dead = true;
    }
}

- TraceScript.cs

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

public class TraceScript : MonoBehaviour
{
    public GameObject player; //추적할 게임 오브젝트
    private Transform trace; //추적할 게임 오브젝트의 transform
    // Start is called before the first frame update
    void Start()
    {
        trace = player.transform;
    }

    // Update is called once per frame
    void Update()
    {
        //transform.position = new Vector3(trace.position.x,trace.position.y,-10); 
        transform.position = Vector3.Lerp(transform.position,new Vector3(trace.position.x,trace.position.y,-10),0.5f*Time.deltaTime);
        //transform.position.z = -10;
        //transform.TranslateZ(-10); //카메라를 원래 z축으로 이동  
    }
}

- UIManager.cs

using UnityEngine;
using UnityEngine.SceneManagement; // 씬 관리자 관련 코드
using UnityEngine.UI; // UI 관련 코드

// 필요한 UI에 즉시 접근하고 변경할 수 있도록 허용하는 UI 매니저
public class UIManager : MonoBehaviour {
    // 싱글톤 접근용 프로퍼티
    public static UIManager instance
    {
        get
        {
            if (m_instance == null)
            {
                m_instance = FindObjectOfType<UIManager>();
            }

            return m_instance;
        }
    }

    private static UIManager m_instance; // 싱글톤이 할당될 변수


    public Text scoreText; // 점수 표시용 텍스트
    public GameObject gameoverUI; // 게임 오버시 활성화할 UI 


    // 점수 텍스트 갱신
    public void UpdateScoreText(int newScore) {
        scoreText.text = "Score : " + newScore;
    }

    // 게임 오버 UI 활성화
    public void SetActiveGameoverUI(bool active) {
        gameoverUI.SetActive(active);
    }

    // 게임 재시작
    public void GameRestart() {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}
반응형