
다음 이미지와 같이 Scene을 만들어서 Title을 실행.
그리고 상위 폴더에 Script라는 폴더 생성.
그 다음, 그 폴더 안에 Script를 만들어 SceneChanger라 명명
만든 C# Script를 들어가 사용할 헤더를 설정.
Update로 매 프레임마다 한 번씩 Space가 눌렸는지 확인한 다음
빌드에 세팅을 올려둔 다음
Title Scene에서 게임 오브젝트를 추가하여 그곳에 만든 C# Script를 붙여주고
실행 시 Scene 전환이 이뤄지는 것을 확인할 수 있게 된다.
기능을 추가해보도록 할 것인데 만일 Esc키를 눌리면
이렇게 씬을 넘어갈 수 있도록 설정을 했어도 Esc로 불가하다. Game Scene에서는 추가를 안해놨기 때문이다. 그래서 Scene이 넘어가더라도 살려놔야 한다.
단순하게는 GameScene에도 넣어놔도 상관은 없을 것이다.
그러나 다른 방법이 존재한다.
로드가 되더라도 파괴되지 않게끔 하겠다고 직관적인 표현으로 되어 있다.
자동으로 편성이 된다.

문제는 이를 반복하면 자동으로 계속 늘어나게 된다. SceneChanger가 늘어나면 늘어날수록 Scene Changer가 다수를 동시 구동한다.
추가적인 처리가 필요한다. 이것은 Singleton Pattern에서 다루게 된다.
지금으로써는 동일한 객체가 있다면 죽여놓아야 한다.
private void Start()
{
// Scene 전체적으로 판단할 수 밖에 없으므로 Find를 사용해볼 것이다.
SceneChanger s = FindObjectOfType<SceneChanger>();
// 만일 다른 SceneChanger가 있으면 찾겠지만 단 하나 남은 SceneChanger가 있을 수 있다.
// 그래서 null이 아니고 자신이 아니어야 한다.
if (s != null && s != this)
{
// 파괴
}
DontDestroyOnLoad(gameObject);
}
파괴의 측면에서 싱글톤 패턴이 이런 아이디어로 접근하게 되는 것.
지금은 직관적으로 두 곳 모두에 이것을 적용시키도록 하자.
현재 문자열 기반으로 실수가 많으므로 빌드 인덱스 기준으로 가보도록 하면
첫 화면
Space 입력 시
Esc 입력 시
GameScene로 이동을 하여 키 입력을 받아보도록 해볼 것이다. Cube 하나와 C# Script를 하나 생성한다.
트랜스폼은 모든 게임 오브젝트에 다 달려있다.
이 상황에서 소스 코드에서 제어를 하려면 가져와야 할 것이 있다.
private void Move()
{
float x = Input.GetAxisRaw("Horizontal"); // Raw는 단위 벡터로 설정된다.
float z = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(x, 0, z); // 이제 이것을 토대로 단위 벡터를 만들어야 한다.
//movement.Normalize(); // 연산을 통해 단위벡터 출력.
//movement.normalized; // 값만을 가져올 경우.
}
이제 이동 속도가 필요. transform.을 들어가 position을 살펴보면 기능들이 잘 구현이 되어 있음을 알 수 있다.
Translate, Rotate 등 함수 호출들이 되어 있는 상태.
하지만 각 PC마다의 이동 속도의 차이가 프레임에 따라 다를 수 있기 때문에
이렇게 Time.deltaTime을 추가 처리해줘야 한다.
다음과 같이 플레이 시 이동이 가능함을 볼 수 있다.
하지만 나중에는 물리 엔진에서 속도를 지정해서 명령을 내리는 것이 필요하다. 현재 형태와는 다를 것이다.
이젠 다른 방법을 해볼 것이다. 
지금은 적용을 했을 때 내부적으로 더해주는 것.
아까와 동일하게 적용이 된다.
그런데 이런 경우도 있다. 타겟팅하여 이동하는 방식도 있다. 이 방식에서는 당연히 찍어서 가면 되는데 이 상태에서는 시도할만한 요소가 존재한다.

MoveTorward를 쓰면 되는데 구조체에서 지원하는 기능을 써볼 것이다.
뱀서류를 이렇게 추적시킬 수 있게 된다.
일정한 속도로 움직이게 할 수도 있지만 멀수록 빠르게 가까울수록 느리게 하는 방법도 가능하다. Vector3에서 제공하는 Lerp를 사용해볼 것이다.
Lerp는 선형 보간이다. 
이미지 상 확인은 안되지만 실질적으로 속도가 점점 느려져서 다가오는 것을 확인할 수 있다.
바로 사용해보도록 하자. 
R키를 누르고 있으면 회전하고 이동까지 되는 것을 확인할 수 있다.
물론 Rotate도 보간이 가능하다. Quaternion에서도 Lerp를 지원한다.
RotateAround라는 것이 존재하는데 Goal에 작업을 걸 것인데 
이렇게 공전처럼 돌아가는 형태가 된다.
이외에도 LookRotation도 존재. 그럼 이것을 이용하여
using System;
using UnityEngine;
public class CubeMovement : MonoBehaviour
{
//private Transform _transform;
private void Awake()
{
// CubeMovement를 찾아다가 붙이기.
// _transform = GetComponent<Transform>();
// 이미 Transform은 모든 오브젝트에 달려있으므로 transform.으로 바로 얻어와 쉽게 쓸 수 있다.
}
[SerializeField] private float _moveSpeed;
[SerializeField] private Transform _target;
[SerializeField] private float _rotateSpeed;
private void Update()
{
Vector3 movement = GetMovement();
Move(movement);
CubeRotate();
/*Move();
//MoveToTarget();
CubeRotate();*/
}
private void CubeRotate()
{
// 키가 계속 눌리는 동안 돌아가게끔 만들 것이다.
/*if (Input.GetKey(KeyCode.R))
{
// 회전은 특정 축을 기준으로 회전한다. up, right, forward를 쓰는데 이게 축 기준의 방향인 것.
transform.Rotate(Vector3.up * _rotateSpeed * Time.deltaTime);
}*/
}
private void MoveToTarget()
{
// 헌재 위치, 타깃은 Transform이므로 포지션으로 접근 가능, moveSpeed에 DeltaTime.
/*transform.position = Vector3.MoveTowards(transform.position,
_target.position,
_moveSpeed * Time.deltaTime);*/
// MoveTowards와는 다르게 원리상 0~1의 범위값인데 0.5면 반에 도달하면 멈추고 또 반 이런 식으로 진행된다.
transform.position = Vector3.Lerp(transform.position, _target.position, _moveSpeed * Time.deltaTime);
}
private void Move(Vector3 movement)
{
if (movement == Vector3.zero)
{
return;
}
/*float x = Input.GetAxisRaw("Horizontal"); // Raw는 단위 벡터로 설정된다.
float z = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(x, 0, z); // 이제 이것을 토대로 단위 벡터를 만들어야 한다.
movement.Normalize(); // 연산을 통해 단위벡터 출력.*/
//movement.normalized; // 값만을 가져올 경우.
// 방향에다가 속도를 곱해서 더해주면 이동이 된다.
//transform.position += movement * _moveSpeed * Time.deltaTime;
// 하지만 프레임 단위가 필요.
transform.Translate(movement * _moveSpeed * Time.deltaTime);
}
private Vector3 GetMovement()
{
float x = Input.GetAxisRaw("Horizontal"); // Raw는 단위 벡터로 설정된다.
float z = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(x, 0, z); // 이제 이것을 토대로 단위 벡터를 만들어야 한다.
movement.Normalize(); // 연산을 통해 단위벡터 출력.
//movement.normalized; // 값만을 가져올 경우.
return movement.normalized;
}
}
이제 보간과 LookRotation 적용
하지만 문제점은 방향 유지가 되어야 하는데 안되고 있다.
using System;
using UnityEngine;
public class CubeMovement : MonoBehaviour
{
//private Transform _transform;
private void Awake()
{
// CubeMovement를 찾아다가 붙이기.
// _transform = GetComponent<Transform>();
// 이미 Transform은 모든 오브젝트에 달려있으므로 transform.으로 바로 얻어와 쉽게 쓸 수 있다.
}
[SerializeField] private float _moveSpeed;
[SerializeField] private Transform _target;
[SerializeField] private float _rotateSpeed;
private void Update()
{
Vector3 movement = GetMovement();
Move(movement);
CubeRotate(movement);
/*Move();
//MoveToTarget();
CubeRotate();*/
}
private void CubeRotate(Vector3 movement)
{
// 키가 계속 눌리는 동안 돌아가게끔 만들 것이다.
/*if (Input.GetKey(KeyCode.R))
{
// 회전은 특정 축을 기준으로 회전한다. up, right, forward를 쓰는데 이게 축 기준의 방향인 것.
transform.Rotate(Vector3.up * _rotateSpeed * Time.deltaTime);
}*/
//if (movement == Vector3.zero)
if (movement.z == 0)
{
return;
}
Quaternion look = Quaternion.LookRotation(movement);
transform.rotation = Quaternion.Slerp(
transform.rotation,
look,
_rotateSpeed * Time.deltaTime
);
}
private void MoveToTarget()
{
// 헌재 위치, 타깃은 Transform이므로 포지션으로 접근 가능, moveSpeed에 DeltaTime.
/*transform.position = Vector3.MoveTowards(transform.position,
_target.position,
_moveSpeed * Time.deltaTime);*/
// MoveTowards와는 다르게 원리상 0~1의 범위값인데 0.5면 반에 도달하면 멈추고 또 반 이런 식으로 진행된다.
transform.position = Vector3.Lerp(transform.position, _target.position, _moveSpeed * Time.deltaTime);
}
private void Move(Vector3 movement)
{
if (movement == Vector3.zero)
{
return;
}
/*float x = Input.GetAxisRaw("Horizontal"); // Raw는 단위 벡터로 설정된다.
float z = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(x, 0, z); // 이제 이것을 토대로 단위 벡터를 만들어야 한다.
movement.Normalize(); // 연산을 통해 단위벡터 출력.*/
//movement.normalized; // 값만을 가져올 경우.
// 방향에다가 속도를 곱해서 더해주면 이동이 된다.
//transform.position += movement * _moveSpeed * Time.deltaTime;
// 하지만 프레임 단위가 필요.
transform.Translate(movement * _moveSpeed * Time.deltaTime);
}
private Vector3 GetMovement()
{
float x = Input.GetAxisRaw("Horizontal"); // Raw는 단위 벡터로 설정된다.
float z = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(x, 0, z); // 이제 이것을 토대로 단위 벡터를 만들어야 한다.
movement.Normalize(); // 연산을 통해 단위벡터 출력.
//movement.normalized; // 값만을 가져올 경우.
return movement.normalized;
}
}
완성된 바라보며 이동하는 방식.
using System;
using UnityEngine;
public class CubeMovement : MonoBehaviour
{
[SerializeField] private float _moveSpeed;
[SerializeField] private Transform _target;
[SerializeField] private float _rotateSpeed;
private void Update()
{
Vector3 movement = GetMovement();
Move(movement);
CubeRotate(movement);
}
private void CubeRotate(Vector3 movement)
{
if (movement == Vector3.zero)
{
return;
}
Quaternion look = Quaternion.LookRotation(movement);
transform.rotation = Quaternion.Slerp(
transform.rotation,
look,
_rotateSpeed * Time.deltaTime
);
}
private void MoveToTarget()
{
transform.position = Vector3.Lerp(transform.position, _target.position, _moveSpeed * Time.deltaTime);
}
private void Move(Vector3 movement)
{
if (movement == Vector3.zero) // 원래가 정답이었음
{
return;
}
transform.Translate(Vector3.forward * _moveSpeed * Time.deltaTime);
}
private Vector3 GetMovement()
{
float x = Input.GetAxisRaw("Horizontal"); // Raw는 단위 벡터로 설정된다.
float z = Input.GetAxisRaw("Vertical");
Vector3 movement = new Vector3(x, 0, z);
return movement.normalized;
}
}