마우스를 클릭한 위치로 캐릭터 이동

단위 마우스 클릭을 이동하는 방법 – 오늘은 Unity C# 스크립트로 마우스 클릭 플레이어 캐릭터 이동 및 회전을 구현해 보겠습니다. 다음 비디오는 결과를 보여줍니다. Click-and-Move 작동 비디오

위 동작에는 하나의 Unity C# 클래스만 필요합니다. 다음과 같은 방법으로 ClickToMove.cs라는 모노 동작 기반 클래스를 만들고 플레이어 캐릭터 역할을 하는 게임 개체에 넣으면 즉시 실행됩니다.

다음은 코드 작성 방법에 대한 설명입니다.

ClickToMove Unity C# 스크립트 생성

먼저 Unity에서 C# 스크립트를 만들고 이름을 ClickToMove로 변경했습니다. 이 스크립트에서는 Start() 메서드를 사용하지 않을 것이므로 Update()를 제외하고 삭제했습니다. (물론 그냥 놔두셔도 됩니다.)

필드 선언

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour{
    public float movementSpeed = 10f;
    public float rotationSpeed = 10f;
    private void Update(){
 
    }
}

먼저 플레이어 캐릭터의 이동 속도와 마우스 클릭 지점까지의 회전 속도를 지정하기 위해 두 개의 변수를 선언했습니다. movementSpeed는 이동 속도이고 rotationSpeed는 회전 속도입니다. 각각의 기본값은 10f이며 나중에 변경할 수 있습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour{
    public float movementSpeed = 10f;
    public float rotationSpeed = 10f;
    private Vector3 destinationPoint;
    private void Update(){ 
    }
}

다음으로 우리는 이동하는 목적지 지점의 좌표를 저장할 변수 destinationPoint를 선언했습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
 
    public float movementSpeed = 10f;
 
 
    public float rotationSpeed = 10f;
 
 
    private Vector3 destinationPoint;
 
 
    private bool shouldMove = false;
 
 
    private void Update()
    {
  
    }
}

다음으로 플레이어 캐릭터의 이동을 제어하는 ​​플래그로 부울 변수인 shouldMove를 추가했습니다. 이는 플레이어 캐릭터가 목표 지점에 도달하면 멈춰야 하므로 플레이어 캐릭터의 이동을 제어하기 위한 것입니다.

목표 지점의 위치를 ​​가져옵니다

마우스 클릭 확인

이제 마우스 클릭으로 이동점의 좌표를 가져오는 부품을 만들어 봅시다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            
        }
    }
}

Input.GetMouseButtonDown(0)은 왼쪽 마우스 버튼이 눌렸는지 여부를 확인하는 메서드입니다. 마우스 왼쪽 버튼을 클릭하면 true를, 클릭하지 않으면 false를 반환합니다.

if 조건문은 왼쪽 마우스 버튼이 클릭되었는지 여부를 확인합니다. 클릭하면 조건문이 true가 되고 if 블록 안의 코드가 실행됩니다. 클릭하지 않으면 false이므로 if 블록 내부의 코드가 실행되지 않습니다.

목표 지점의 위치를 ​​가져옵니다

이제 마우스 클릭을 기반으로 실제 3D 세계에서 대상 이동 지점을 찾는 코드를 작성해 보겠습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                
            }
        }
 
    }
}

위의 코드는 3D 세계에서 마우스 클릭 포인트를 찾았을 때 패턴처럼 저장하여 사용할 수 있습니다. 각 행의 의미는 다음과 같습니다.

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

이 명령문은 Ray 유형의 객체인 광선을 생성합니다. 이렇게 생성된 레이는 다음 부분에서 마우스 클릭 포인트를 찾는 데 사용됩니다.

광선을 만들려면 Camera.main 개체의 ScreenPointToRay 메서드를 사용합니다. Camera.main은 현재 장면에 있는 기본 카메라를 나타냅니다.


ScreenPointToRay 메서드는 화면의 한 지점을 나타내는 Vector3를 매개 변수로 사용합니다. 위의 코드에서 Input.mousePosition은 마우스 커서의 현재(화면상의) 위치를 지정하는 매개변수로 사용됩니다.

화면에서 마우스 포인터의 위치를 ​​매개변수로 전달함으로써 ScreenPointToRay 메서드는 이제 기본 카메라 위치에서 시작하여 화면의 한 지점을 향해 확장되는 광선을 생성합니다. 다음 그림을 보시면 이해가 되실 겁니다.


위 이미지에서 플레이어의 눈(메인 카메라)에서 나온 광선이 2D 화면의 마우스 클릭 지점을 통과하여 3D 세계의 지면과 충돌합니다. 위 문장에서 생성된 Ray 객체가 이를 나타내는 것으로 이해할 수 있습니다.

레이캐스트 적중 이해

이제 다음 코드를 살펴보겠습니다.

RaycastHit hit;

이 코드는 Raycast 유형의 변수인 hit를 선언합니다. RaycastHit은 광선이 충돌하는 위치(3D 공간의 한 지점)에 대한 정보를 저장하는 데 사용되는 데이터 구조입니다.

if (Physics.Raycast(ray, out hit, 100f))

이 코드는 Physics 클래스의 Raycast 메서드를 사용하여 레이캐스팅을 수행합니다. Raycast 메서드는 위의 코드와 같이 세 가지 매개 변수를 사용합니다.

  • 캐스트할 광선을 나타내는 Ray 개체입니다. 이 경우 이전에 생성된 광선이 매개변수로 전달됩니다.
  • 레이캐스트 히트. 즉, 광선이 충돌하는 지점에 대한 데이터 개체입니다. 이 경우 위에서 얻은 히트가 매개변수로 전달됩니다.
  • 광선이 이동할 수 있는 최대 거리를 나타내는 부동 소수점 값입니다. 이 경우 100f가 매개변수로 전달되었습니다. 더 크거나 작은 숫자를 입력할 수 있지만 숫자가 너무 작으면 레이캐스팅으로 인해 충돌이 발생하지 않을 수 있습니다.

Physics.Raycast 메서드는 광선이 충돌체가 있는 객체와 충돌하면 true를 반환하고 그렇지 않으면 false를 반환합니다. 위의 코드에서 충돌이 감지되면 if 조건 블록 내부의 코드가 실행되고 충돌이 감지되지 않으면 if 블록 내부의 코드가 실행되지 않습니다.

따라서 위와 같은 방법으로 마우스 클릭이 움직이는 목표점에 대한 유효한 정보를 제공하는지 알 수 있다.

Physics.Raycast 메서드 사용

이제 조건문에 코드를 작성해 보겠습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                destinationPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);
 
                shouldMove = true;
            }
        }
 
    }
}

Physics.Raycast 메서드가 true를 반환하면 이제 Hit 매개변수가 충돌 지점에 대한 다양한 데이터를 자동으로 저장합니다. 따라서 이 히트를 분석하면 목표물이 어디로 이동하고 있는지 파악할 수 있습니다.

destinationPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);

목표 이동점은 위와 동일하게 hit에 포함된 정보로 생성할 수 있습니다.

참고로 Vector3 객체는 위의 코드에서 직접 생성했지만, 원래 기본값은 다음과 같이 hit.point를 직접 할당하는 것이었습니다.

destinationPoint = hit.point;

하지만 우리의 경우 hit.point의 y 좌표가 아니라 플레이어 캐릭터 게임 개체의 y 좌표인 transform.position.y를 사용했습니다. 그 이유는 현재 플레이어 캐릭터가 지면에 닿지 않고 약간 지면에서 떠 있기 때문에 이 높이를 유지하기 위해서입니다.


그렇지 않으면 캐릭터가 지면에 붙어 있는 경우 destinationPoint = hit.point; 당신은 그렇게 말할 자유가 있습니다.

이동과 관련된 플래그

이제 다음 코드를 살펴보겠습니다.

shouldMove = true;

이 코드의 의미는 분명합니다. shouldMove 플래그를 true로 설정하면 개체가 대상 지점을 향해 이동할 수 있습니다. 이 값이 나중에 false 로 변경되면, 즉 캐릭터가 목표에 도달하면 더 이상 움직일 수 없습니다. 아래 코드에서 확인할 수 있습니다.

이제 대상 이동 지점이 있으므로 다음으로 해야 할 일은 캐릭터를 해당 지점으로 회전하고 지정된 속도로 이동하는 것입니다. 이를 위한 코드를 추가해 보겠습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                destinationPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);
 
                shouldMove = true;
            }
        }
 
        if (shouldMove)
        {
            
        }
    }
}

이제부터의 코드는 플레이어 캐릭터가 움직일 수 있는 경우에만 의미가 있습니다. 그래서 위와 같이 조건문을 만들었습니다. 이제 이 안에 회전 관련 코드를 먼저 작성해 봅시다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                destinationPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);
 
                shouldMove = true;
            }
        }
 
        if (shouldMove)
        {
            Quaternion targetRotation = Quaternion.LookRotation(destinationPoint - transform.position);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);            
        }
    }
}

캐릭터의 회전과 관련된 이 코드 블록을 패턴으로 기억하고 사용하는 것이 좋습니다. 처음에는 원리를 파악하기 어렵지만 반복적으로 사용하다 보면 나도 모르게 의미를 이해하게 됩니다. 각 코드를 먼저 설명하겠습니다.

Quaternion targetRotation = Quaternion.LookRotation(destinationPoint - transform.position);

이 명령문은 목표 지점을 보기 위해 객체가 회전해야 하는 정도를 계산합니다. Quaternion.LookRotation 메서드는 전달 방향을 매개 변수로 사용합니다. 플레이어 캐릭터의 현재 위치에서 목적지를 바라보는 전방 방향은 destinationPoint에서 캐릭터 오브젝트의 현재 위치(transform.position)를 빼서 구할 수 있습니다.

이렇게 얻은 회전 값은 Quaternion 유형의 변수인 targetRotation에 저장할 수 있습니다.

부드러운 회전 구현

그럼 다음 코드를 봅시다.

transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

이 코드는 위에서 계산한 목표 회전 값을 향해 개체를 부드럽게 회전시키는 작업을 수행합니다. 이렇게 하려면 Quaternion 클래스의 Slerp 방법(구형 선형 보간)을 사용합니다.

Quaternion.Slerp() 메서드는 개체의 현재 회전(transform.rotation), 대상 회전(targetRotation) 및 회전 속도(rotationSpeed)를 매개 변수로 사용합니다. (이 때 Time.deltaTime 값에 회전율을 곱하면 게임의 프레임율과 관계없이 회전율이 일정하게 유지됩니다.)

이렇게 얻은 각 프레임에 대해 캐릭터가 회전할 대상 값을 transform.rotation에 할당합니다. 여기까지 코드를 작성하고 실행하면 캐릭터가 움직일 수 없어도 잘 돌아갑니다.

클릭하여 회전

캐릭터 이동 구현

이제 마지막 모션 부분을 작성해 보겠습니다. 지금까지 작성한 코드에 다음 문을 추가합니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                destinationPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);
 
                shouldMove = true;
            }
        }
 
        if (shouldMove)
        {
            Quaternion targetRotation = Quaternion.LookRotation(destinationPoint - transform.position);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
 
            transform.position = Vector3.MoveTowards(transform.position, destinationPoint, movementSpeed * Time.deltaTime);
 
        }
    }
}

이 코드는 플레이어 캐릭터 개체를 이전에 획득한 목표 지점으로 이동합니다.

Vector3.MoveTowards() 메서드에 객체의 현재 위치(transform.position), 대상 지점(destinationPoint) 및 객체가 얼마나 많이 움직이는지에 따른 “이동 속도(movementSpeed) x Time.deltaTime”의 세 가지 매개 변수를 전달합니다. 원하는 속도로 목적지에 도달할 수 있는지 확인합니다. 이 값을 플레이어 캐릭터 개체의 transform.position에 다시 할당할 수 있습니다.

처리가 목표 지점에 도달

이 코드를 추가하고 게임을 실행하면 클릭하여 캐릭터를 목표 지점으로 이동할 수 있습니다. 그러나 목표지점에서 멈추지 않고 계속 움직인다. 중지와 관련된 코드를 작성하지 않았기 때문입니다.

따라서 다음 코드를 추가하여 이 문제를 해결할 수 있습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ClickToMove : MonoBehaviour
{
    public float movementSpeed = 10f;
 
    public float rotationSpeed = 10f;
 
    private Vector3 destinationPoint;
 
    private bool shouldMove = false;
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                destinationPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);
 
                shouldMove = true;
            }
        }
 
        if (shouldMove)
        {
            Quaternion targetRotation = Quaternion.LookRotation(destinationPoint - transform.position);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
 
            transform.position = Vector3.MoveTowards(transform.position, destinationPoint, movementSpeed * Time.deltaTime);
 
            if (transform.position == destinationPoint)
            {
                shouldMove = false;
            }
        }
    }
}

이 코드는 객체의 위치가 목표 지점과 일치하는지 확인합니다. 그렇다면 이동 플래그는 false로 설정되고 플레이어 캐릭터 유닛은 이동을 멈춥니다.

위의 코드에서 해야 할 일

이 부분은 문제가 발생할 수 있으니 주의하시기 바랍니다. 예를 들어 게임의 프레임 속도가 낮으면(너무 느림) 위의 조건문(==)이 참인 순간을 놓칠 수 있습니다..

이러한 경우에 대비하여 캐릭터의 현재 위치와 목표 지점 사이의 거리를 계산하여 예를 들어 거리가 1미터 이상일 때만 이동하고 거리가 멀어질수록 정지하도록 코드를 변경할 수 있습니다. . 이 부분은 직접 해보시기 바랍니다.

지금까지 생성된 ClickToMove 스크립트는 게임 개체에 연결될 때 작동합니다. 스크립트를 생성, 확장 및 변환하려면 위의 지침을 따르십시오. 꽤 재미있는 Unity C# 스크립트 연구가 될 것입니다.

https://cjwoov.18#:~:text=%5BUnity%5D%20%EB%A7%88%EC%9A%B0%EC%8A%A4%20%ED%81%B4% EB%A6%AD%ED%95%9C%20%EC%A7%80%EC%A0%90%EC%9C%BC%EB%A1%9C%20%EC%BA%90%EB%A6% AD%ED%84%B0%20%EC%9D%B4%EB%8F%99%EC%8B%9C%ED%82%A4%EA%B8%B0%201%20Control.cs%3A,%EC %8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%202%20Behavior.cs%3A%20%EC%8B%A4%EC%A0%9C%20%EC%BA %90%EB%A6%AD%ED%84%B0%EC%9D%98%20%ED%96%89%EB%8F%99%EC%9D%84%20%EB%8B%B4%EB %8B%B9%ED%95%98%EB%8A%94%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8