모뉴먼트 밸리 플레이어 움직임을 만들어 보겠습니다
우선 저번글에서 맵과 착시현상을 구현했는데요
이번 글에서는 플레이어 움직임을 구현해 보도록 하겠습니다
우선 플레이어가 움직일 수 있는 길을 표현하는 스크립트를 작성해야 합니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Road : MonoBehaviour
{
//연결되어있는 길을 저장하는 List
[field:SerializeField] public List<Road> connectRoad { get; private set; } = new();
//Ray의 레이어마스크
[SerializeField] private LayerMask roadMask;
private void Awake()
{
//Ray를 쏠 방향을 담아놓은 배열
Vector3[] dirs =
{
Vector3.forward, Vector3.up,
Vector3.back, Vector3.down,
Vector3.right, Vector3.left
};
foreach(var dir in dirs)
{
if(Physics.Raycast(transform.position, dir, out var info, 1.3f, roadMask))
{
//자신의 주변에 길이 있다면 리스트에 추가해주기
connectRoad.Add(info.transform.GetComponent<Road>());
}
}
}
}
Road스크립트는 저희가 저번에 만들었던 맵의 블록에 들어가게 될 것이며 자신과 인접한 블록을 가지고 있습니다
그다음은 플레이어입니다
플레이어는 자신이 지금 있는 길로부터 타깃이 되는 길까지 최단거리를 찾아 이동합니다
BFS알고리즘을 약간 참고하여 작성했습니다
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Player : MonoBehaviour
{
//플레이어가 지금 있는 길
[SerializeField] private Road currentRoad;
public void Move(Road targetRoad)
{
var poss = GetPositions(targetRoad);
if (poss == null) return;
currentRoad = targetRoad;
Sequence seq = DOTween.Sequence();
//DOTWeen을 이용해 움직이기
foreach(var item in poss)
{
seq.Append(transform.DOMove(item + new Vector3(0, 1, 0), 0.3f).SetEase(Ease.Linear));
}
}
/// <summary>
/// 최단거리의 길 탐색하기
/// </summary>
/// <param name="targetRoad"></param>
/// <returns></returns>
private List<Vector3> GetPositions(Road targetRoad)
{
Queue<(List<Vector3> roads, Road oldRoad, Road serchRoad)> visitedQ = new();
foreach(var road in currentRoad.connectRoad)
{
visitedQ.Enqueue((new() { currentRoad.transform.position }, currentRoad, road));
}
while(visitedQ.Count > 0)
{
var current = visitedQ.Dequeue();
if(current.serchRoad == targetRoad)
{
current.roads.Add(current.serchRoad.transform.position);
return current.roads;
}
foreach(var road in current.serchRoad.connectRoad)
{
if(road == current.oldRoad) continue;
//값 복사
var copyList = current.roads.ToList();
copyList.Add(current.serchRoad.transform.position);
visitedQ.Enqueue((copyList, current.serchRoad, road));
}
}
return null;
}
}
그리고 PlayerController에서 플레이어에게 움직이라는 명령을 내리는 식으로 디자인하였습니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private LayerMask roadMask;
[SerializeField] private Player player;
private void Update()
{
//마우스 좌클릭 시
if (Input.GetMouseButtonDown(0))
{
CameraRay();
}
}
private void CameraRay()
{
//마우스 클릭위치로 발사되는 Ray
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out var hitInfo, 1000, roadMask))
{
player.Move(hitInfo.transform.GetComponent<Road>());
}
}
}
자 이제 코드는 끝났습니다
우선 저번에 만든 큐브들에 모두 Road 스크립트를 넣어주세요
그리고 Road라는 LayerMask를 만들어주세요
Main카메라의 컬링마스크에 Road도 포함되게 설정해 주세요
Road스크립트의 마스크를 Road로 설정해 주세요
그 후 착시현상이 일어나는 부분의 Road를 서로 이어주세요
이런 식으로 드래그 드롭으로 이어주시면 됩니다
그 후 플레이어 오브젝트를 만든 후 적절히 배치해 줍니다
플레이어에 Top레이어를 넣고 Player와 PlayerController스크립트를 넣어주세요 그 후 인자들을 알맞게 설정해 주세요
플레이어에게 Top레이어를 넣어서 이상하게 보이는 부분이 있을 수 있습니다 그런 부분은 저번글에서 했던 것처럼 Quad를 넣어주시면 됩니다
저는 추가로 스페이스바를 누르면 다리가 돌아가는 코드도 작성했습니다
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Handle : MonoBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
transform.DORotate(new Vector3(90, 0, 0), 0.3f);
}
}
}
이제 완성입니다 실행해 보시면 잘 작동하는 것을 확인할 수 있습니다
마지막으로 여렵거나 따라 하기 힘드신 분들을 위하여 프로젝트를 유니티 페키지화 시켜 놓았습니다
'유니티 > 모뉴먼트 밸리 모작' 카테고리의 다른 글
[Unity] 모뉴먼트 밸리 모작 - 1. 착시현상 구현 (0) | 2024.02.22 |
---|