EasyCastleUNITY

유니티 Raycast hit 응용 (Warp && Translate) 본문

유니티 기초

유니티 Raycast hit 응용 (Warp && Translate)

EasyCastleT 2023. 8. 4. 17:30

Warp

화면을 클릭하면, 캐릭터가 해당 위치로 워프

Ray를 응용하여 캐릭터 워프

 MisakiController: 캐릭터 움직임 담당 클래스 

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

public class MisakiController : MonoBehaviour
{
    Animator anim;
    public float moveSpeed = 10.0f;
    public int state;
    public Transform target;

    // Start is called before the first frame update
    void Start()
    {
        this.anim = this.GetComponent<Animator>();
        this.state = 0;
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.LookAt(this.target);
        Debug.Log(state);
        if (state == 1)
        {
            this.StartRun();
        }

        //if (this.transform.position.z > 30)
        //{
        //    Debug.Log("Misaki Stand");
        //    this.moveSpeed = 0;
        //    this.state = 0;
        //    this.anim.SetInteger("Run", state);
        //}
        
    }

    public void StartRun()
    {
      //  this.transform.Translate(this.moveSpeed * Time.deltaTime, 0, this.moveSpeed * Time.deltaTime);
        this.transform.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);
    }

    public void StateChange()
    {
        if (state == 1) //1이면 Run
        {
            this.state = 0;
            this.anim.SetInteger("Run", state);


        }
        else if (state == 0) //0이면 Stand
        {
            state = 1;
            this.anim.SetInteger("Run", state);

        }

    }
}

PositionController : Ray를 응용하여 클릭한 위치를 받아오고, 캐릭터의 위치를 담당하는 클래스 

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

public class PositionController : MonoBehaviour
{
    public GameObject MisakiGo;
    private MisakiController misaki;
    // Start is called before the first frame update
    void Start()
    {
        this.misaki = this.MisakiGo.GetComponent<MisakiController>();
       
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitData;
            
            if (Physics.Raycast(ray.origin,ray.direction*1000f, out hitData))
            {
                Vector3 hitPosition = hitData.point;
                //Ray와 충돌되면
                Debug.Log(hitPosition);
                MisakiGo.transform.position = hitPosition;
                //misaki.target.position=hitPosition;
            }
            Debug.DrawRay(ray.origin, ray.direction * 1000f, Color.red,1f);
        }
       
    }
}

Translate

 

클릭한 좌표로 캐릭터가 이동, 클릭한 좌표에 도착하면 이상하게 움직이는 문제가 있다.

이 문제를 해결하기 위해서는 애니메이션을 응용하는 것이 좋을 것 같다.

 MisakiController: 캐릭터 움직임 담당 클래스 

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

public class MisakiController : MonoBehaviour
{
    Animator anim;
    public float moveSpeed = 10.0f;
    public int state;
    public Transform target;

    // Start is called before the first frame update
    void Start()
    {
        this.anim = this.GetComponent<Animator>();
        this.state = 0;
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.LookAt(this.target);
        Debug.Log(state);
        if (state == 1)
        {
            this.StartRun();
        }

        //if (this.transform.position.z > 30)
        //{
        //    Debug.Log("Misaki Stand");
        //    this.moveSpeed = 0;
        //    this.state = 0;
        //    this.anim.SetInteger("Run", state);
        //}
        
    }

    public void StartRun()
    {
      //  this.transform.Translate(this.moveSpeed * Time.deltaTime, 0, this.moveSpeed * Time.deltaTime);
        this.transform.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);
    }

    public void StateChange()
    {
        if (state == 1) //1이면 Run
        {
            this.state = 0;
            this.anim.SetInteger("Run", state);


        }
        else if (state == 0) //0이면 Stand
        {
            state = 1;
            this.anim.SetInteger("Run", state);

        }

    }
}

PositionController : Ray를 응용하여 클릭한 위치를 받아오고, 캐릭터의 위치를 담당하는 클래스 

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

public class PositionController : MonoBehaviour
{
    public GameObject MisakiGo;
    private MisakiController misaki;
    // Start is called before the first frame update
    void Start()
    {
        this.misaki = this.MisakiGo.GetComponent<MisakiController>();
       
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitData;
            
            if (Physics.Raycast(ray.origin,ray.direction*1000f, out hitData))
            {
                Vector3 hitPosition = hitData.point;
                //Ray와 충돌되면
                Debug.Log(hitPosition);
                //MisakiGo.transform.position = hitPosition;
                misaki.target.position=hitPosition;
            }
            Debug.DrawRay(ray.origin, ray.direction * 1000f, Color.red,1f);
        }
       
    }
}

Button에는 MisakiController의 StateChange에 연결하였다. 

 

Translate 문제 해결

 

위에서 이동하는 것에 대한 문제점을 보완한 버전

MisakiController

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

public class MisakiController : MonoBehaviour
{
    Animator anim;
    public float moveSpeed = 10.0f;
    public int state;
    public Transform target;
    private bool isMoveStart = false;
    private Vector3 targetPosition;

    // Start is called before the first frame update
    void Start()
    {
        this.anim = this.GetComponent<Animator>();
       // this.state = 0;
    }

    // Update is called once per frame
    void Update()
    {
        //왼쪽 버튼을 누른다면 
        if (Input.GetMouseButtonDown(0))
        {
            //화면좌표를 월드상의 Ray객체로 만든다 
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            //화면에 Ray를 출력 
            Debug.DrawRay(ray.origin, ray.direction * 100f, Color.green, 2f); //2f : 2초동안 보여줌 

            RaycastHit hit; //변수를 정의하고 
            //Ray와 Collider를 충돌체크 하는 메서드 
            if (Physics.Raycast(ray.origin, ray.direction, out hit))
            {
                //충돌 되었을때 충돌 정보가 hit변수에 담긴다 
                Debug.Log(hit.point);   //충돌된 지점의 월드 좌표 
                //충돌 지점으로 나를 이동함 
                //this.transform.position = hit.point;
                this.targetPosition = hit.point;
                //해당 방향을 처다보고 
                this.transform.LookAt(hit.point);
                //달리는 애니메이션 실행 
                this.anim.SetInteger("Run", 1);
                this.isMoveStart = true;
            }
        }


        //이동 로직 
        if (this.isMoveStart)
        {
            //로컬좌표계로 정면으로 이동함 
            this.transform.Translate(Vector3.forward * 5f * Time.deltaTime);
            float distance = Vector3.Distance(this.transform.position, this.targetPosition);
            if (distance <= 0.1f)
            {
                this.isMoveStart = false;
                this.anim.SetInteger("Run", 0);
            }
        }
    }

    
}

애니메이터 화면 전에 포스팅 참고