1. 모든 객체에 있는 Transform컴포넌트의 position, rotation 속성을 지속해서 변경하는 것이다.
2. 내장된 물리엔진을 이용해 물리적인 힘(Force)또는 회전력(Torque)을 가해 변경시키는 것이다.
애니메이션으로도 이동및 회전을 할 수 있지만, 이건 Transform컴포넌트의 속성값을 연속적으로 기록한 것을 재생하는 것이기 때문에 Transform컴포넌트를 이용하는 방법이다.
하이라키의 Player Object을 선택한후 인스펙터뷰에서 Add Component에서 new Script를 선택하고 PlayerCtrl로 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
transform.position += new Vector3(h, 0f, v);
}
}
h,v를 입력 받아 Vector3 구조체를 만들어 transform.position에 "+=" 연산해준다.
h,v의 범위는 WASD나 화살표키에 따라 -1f~1f의 범위를 갖기 때문에 Player는 전후좌우로 잘 움직인다.
주의할건 Vector3(h,v,0f)가 아니라 Vector(h,0f,v)라는 거다 유니티는 3차원 좌표시스템인데 y는 위아래를 뜻한다. 따라서 x는 좌우 z는 전후를 뜻한다.
Play해보면 무지하게 빠르지만 잘 움직인다. 왜냐하면 Update()함수는 컴퓨터마다 다르자만 1초에 대략 60번 정도는 호출되기 때문이다. 그리고 이렇게 자주 호출되기때문에 되도록이면 무거운 처리를 피해야한다.
다음과 같이 자주호출될 Transform의 참조를 tr에 저장해놓고 사용하면 좀 가벼워진다. 이걸 컴포넌트캐시라고 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
// Start is called before the first frame update
Transform tf;
void Start(){
tf = GetComponent<Transform>();
}
// Update is called once per frame
void Update(){
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
tf.position += new Vector3(h, 0f, v);
}
}
tf.position += new Vector3(h, 0f, v);를 처리해주는 Translate()라는 함수가 있다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
// Start is called before the first frame update
Transform tf;
void Start(){
tf = GetComponent<Transform>();
}
// Update is called once per frame
void Update(){
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
tf.Translate(new Vector3(h, 0f, v));
}
}
현재 움직임이 너무 빠르다. 왜냐하면 매프레임 호출되기 때문이다. 따라서 움직임을 작게하면 되지만 그렇게 되면 컴퓨터의 성능에 따라 속도차이가 나게 된다. 따라서 매 프레임의 시간간격을 곱해주면 컴퓨터의 성능에 관계없이 움직임 속도가 일정하게 된다. 성능이 나쁜 컴퓨터는 시간간격이 크기 때문에 그만큼 많이 움직이기 때문이다.
d(거리) = v1*t1 = v2*t2 , 컴퓨터 성능에 속도는 비례하지만 프레임간시간간격은 반비례한다.
간단하게 빠른 컴퓨터는 조금 움직이게 해주는거다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
// Start is called before the first frame update
Transform tf;
void Start(){
tf = GetComponent<Transform>();
}
// Update is called once per frame
void Update(){
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
tf.Translate(Time.deltaTime * new Vector3(h, 0f, v));
}
}
단위벡터를 이용해 이동 벡터를 만들수 있다.
Vector3 dir = Vector3.right*x + Vector3.forward*v;
단위벡터와 단위벡터의 합은 √2가 될수 있으므로 스칼라값을 1로 만들기 위해 단위벡터로 만들려면 dir.normalized를 사용해야한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour {
// Start is called before the first frame update
Transform tf;
private float speed;
void Start() {
tf = GetComponent<Transform>();
speed = 8f;
}
// Update is called once per frame
void Update() {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 dir = Vector3.right* h + Vector3.forward* v;
tf.Translate(dir.normalized * speed * Time.deltaTime);
}
}
Input은 외부에서 들어오는 입력값을 관리하는 클래스다. 최근에 추가된 InputSystem도 있지만 다음에 설명하겠다.
유니티는 자주 사용하는 키보드, 마우스, 조이스틱 입력에 대한 조합을 미리 정의해 놓왔고 InputManager에서 관리한다.
입력 관리자
Input Manager창에서 프로젝트에 대한 입력 축 및 축과 관련된 행동을 정의할 수 있습니다. 액세스하려면 Unity의 메인 메뉴에서Edit > Project Settings로 이동한 후 오른쪽 내비게이션에서Input Manager를 선택합니다.
입력 관리자는 다음 타입의 컨트롤을 사용합니다.
키는 W 키, Shift 키, 스페이스바 등과 같은 물리적 키보드의 모든 키를 의미합니다.
버튼은 리모콘의 X 버튼처럼 물리적 컨트롤러(예: 게임패드)에 있는 버튼을 가리킵니다.
가상 축(복수형:축)은 버튼, 키 등과 같은 컨트롤에 매핑됩니다. 사용자가 컨트롤을 활성화하면 축은 [–1..1] 범위의 값을 수신합니다. 이 값은 스크립트에서 사용할 수 있습니다. Horizontal, Vertical, Fire1, Fire2, Mouse X와 같은 추상적인 개념의 이름으로 정의되어 있다.
Input.GetKey("a")와 같이 위에 명시된 명명 규칙을 사용하여 특정 키 또는 버튼에 대한 입력을 쿼리할 수도 있습니다. 예를 들면 다음과 같습니다.
스크립트에서 가상 축 사용 스크립트에서 가상 축에 액세스하기 위해 축 이름을 사용할 수 있습니다. 예를 들어 Horizontal 축의 현재 값을 쿼리하고 변수에 저장하려면 다음과 같이 Input.GetAxis를 사용할 수 있습니다.
Input.GetAxis("Input Manager Axes 이름")으로 값을 얻어 올수 있다.
Input.GetAxis는 -1.0f~1.0f의 변화하는 값을 얻어오는데, 누루고 있으면 0f에서 -1f나 1f로 가속되는 값이 리턴된다.
Input.GetAxisRaw -1.0f, 0f, 1.0f의 3개중 하나의 값이 전달된다.
두 개 이상의 축이 동일한 이름을 사용하는 경우 쿼리는 절대값이 가장 큰 축을 반환합니다. 따라서 축 이름에 두 개 이상의 입력 기기를 할당할 수 있습니다.
예를 들어 Horizontal이라는 이름으로 두 개의 축을 만든 후 하나는 키보드 입력에 할당하고 다른 하나는 조이스틱 입력에 할당할 수 있습니다. 사용자가 조이스틱을 사용하는 경우 입력은 조이스틱에서 수신되고 키보드 입력은 null입니다. 그렇지 않으면 입력은 키보드에서 수신되고 조이스틱 입력은 null입니다. 이를 통해 여러 컨트롤러의 입력을 처리하는 단일 스크립트를 작성할 수 있습니다.
예제
Horizontal및Vertical축의 입력과transform.Translate메서드를 사용하여 XZ 공간(전방, 후방, 왼쪽, 오른쪽)에서 게임 오브젝트를 움직일 수 있습니다. 움직이려는 게임 오브젝트에 연결된 스크립트의update()메서드에 다음 코드를 추가하십시오.
float moveSpeed = 10;
//Define the speed at which the object moves.
float horizontalInput = Input.GetAxis("Horizontal");
//Get the value of the Horizontal input axis.
float verticalInput = Input.GetAxis("Vertical");
//Get the value of the Vertical input axis.
transform.Translate(new Vector3(horizontalInput, verticalInput, 0) * moveSpeed * Time.deltaTime);
//Move the object to XYZ coordinates defined as horizontalInput, 0, and verticalInput respectively.
Time.deltaTime은 마지막 프레임 이후 경과한 시간을 나타냅니다. moveSpeed 변수를 Time.deltaTime과 곱하면 게임 오브젝트가 프레임마다 일정한 속도로 움직입니다.
Input class는 다음과 같은 함수들을 지원하면 눌렸을때 눌리고 있을때 떨어졌을때를 구별할 수 있습니다.
유니티엔진의 코어 부분은 C++로 제작됐다. 유티는 스크립트언어로 C#을 지원한다. C++와 비슷해서 어렵지 않다. 객체지향 다형화에 대해 선지식이 필요하다.
여기서는 C#을 사용하는 법에 대해서는 다른곳에서 많이 다루었기 때문에 자세히 설명하지 않겠다. 책이나 다른 사이트를 참조해주시기 바란다.
유니티의 주요 이벤트 함수
프로젝트뷰에서 Scripts폴더를 하나만들고 우클릭을 하고 Create>Script를 하고 Ex란 이름으로 Scripts폴더에 저장하자.
더블클릭하면 지정된 에디터가 열리면서 자동생성된 코드가 보인다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ex : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
Ex로 저장된 스크립터에는 공교롭게 Ex라는 class가 만들어져 있다.
Ex라는 class는 MonoBehaviour라는 class에서 상속되었다.
MonoBehaviour 클래스는 기본적으로 모든 Unity 스크립트가 파생되는 기본 클래스입니다. Unity의 프로젝트 창에서 C# 스크립트를 생성하면 MonoBehaviour에서 자동으로 상속되며, 템플릿 스크립트를 제공합니다. MonoBehaviour 클래스는 에디터에서 게임 오브젝트에 스크립트를 연결할 수 있는 프레임워크를 제공할 뿐만 아니라,시작및업데이트등과 같은 유용한 이벤트에 대한 연결을 제공합니다.
MonoBehaviour 클래스를 사용하면 코루틴을 시작, 중지 및 관리할 수 있습니다. 코루틴은 특정 시간 동안 기다리거나 특정 작업이 완료될 때까지 기다리면서 다른 코드가 계속 실행되도록 해주는 비동기 코드 작성 방식입니다.
Ex class는 내부에 Start()와 Update()라는 이벤트 함수가 보인다. 이벤트 함수란 특정 상화에서 유니티엔진이 자동으로 호출해주는 함수이다.
이벤트
MonoBehaviour 클래스는 대규모 이벤트 메시지 컬렉션에 대한 액세스를 제공하며, 이를 통해 현재 프로젝트에서 발생하는 상황에 따라 코드를 실행할 수 있습니다. 다음은 일반적인 몇 가지 예입니다. 전체 리스트는MonoBehaviour 스크립트 레퍼런스 페이지의Messages섹션을 참조하십시오.
Start- 게임 오브젝트가 존재하기 시작할 때 호출됩니다(씬이 로드될 때 또는 게임 오브젝트가 인스턴스화될 때 호출).
참고: 일부 브라우저에서는 SVG 이미지 파일을 지원하지 않습니다. 위 이미지가 올바르게 표시되지 않는 경우(예를 들어 텍스트가 보이지 않는 경우)Google Chrome또는Mozilla Firefox등 다른 브라우저를 사용해 보십시오.
첫 번째 씬 로드
다음 함수는 씬이 시작할 때(씬에서 오브젝트마다 한 번) 호출됩니다.
Awake:이 함수는 항상 Start 함수 전에 호출되며 프리팹이 인스턴스화 된 직후에 호출됩니다. 게임 오브젝트가 시작하는 동안 비활성 상태인 경우 Awake 함수는 활성화될 때까지 호출되지 않습니다.
OnEnable:(오브젝트가 활성화된 경우에만): 오브젝트 활성화 직후 이 함수를 호출합니다. 레벨이 로드되거나 스크립트 컴포넌트를 포함한 게임 오브젝트가 인스턴스화될 때와 같이 MonoBehaviour를 생성할 때 이렇게 할 수 있습니다.
씬에 추가된 모든 오브젝트에 대해 Start, Update 등 이전에 호출된모든스크립트를 위한 Awake 및 OnEnable 함수가 호출됩니다. 따라서 게임플레이 도중 오브젝트를 인스턴스화될 때는 실행되지 않습니다.
에디터
Reset:오브젝트에 처음 연결하거나Reset커맨드를 사용할 때 스크립트의 프로퍼티를 초기화하기 위해 Reset을 호출합니다.
OnValidate:OnValidate는 오브젝트가 역직렬화될 때를 포함하여 스크립트의 프로퍼티가 설정될 때마다 호출되며, 이는 에디터에서 씬을 열 때와 도메인을 다시 로드한 후와 같이 다양한 시기에 발생할 수 있습니다.
첫 번째 프레임 업데이트 전에
Start:스크립트 인스턴스가 활성화된 경우에만 첫 번째 프레임 업데이트 전에 호출됩니다.
씬 에셋에 포함된 모든 오브젝트에 대해 Update 등 이전에 호출된 모든 스크립트를 위한 Start 함수가 호출됩니다. 따라서 게임플레이 도중 오브젝트를 인스턴스화될 때는 실행되지 않습니다.
프레임 사이
OnApplicationPause:이 함수는 일시 정지가 감지된 프레임의 끝, 실질적으로는 일반 프레임 업데이트 사이에 호출됩니다. 게임에 일시정지 상태를 가리키는 그래픽스를 표시하도록OnApplicationPause가 호출된 후에 한 프레임이 추가로 실행됩니다.
업데이트 순서
게임 로직, 상호작용, 애니메이션, 카메라 포지션의 트랙을 유지할 때, 사용 가능한 몇몇 다른 이벤트가 존재합니다. 일반적인 패턴은Update함수에 대부분의 작업을 수행하는 것이지만, 사용할 수 있는 다른 함수도 있습니다.
FixedUpdate:FixedUpdate는 종종Update보다 더 자주 호출됩니다. 프레임 속도가 낮은 경우 프레임당 여러 번 호출될 수 있으며 프레임 속도가 높은 경우 프레임 사이에 호출되지 않을 수 있습니다. 모든 물리 계산 및 업데이트는FixedUpdate후 즉시 발생합니다.FixedUpdate의 움직임 계산을 적용할 때Time.deltaTime만큼 값을 곱할 필요가 없습니다.FixedUpdate가 프레임 속도와 관계없이 신뢰할 수있는 타이머에서 호출되기 때문입니다.
Update:Update는 프레임당 한 번 호출됩니다. 프레임 업데이트를 위한 주요 작업 함수입니다.
LateUpdate:LateUpdate는Update가 끝난 후 프레임당 한 번 호출됩니다.Update에서 수행된 모든 계산은LateUpdate가 시작할 때 완료됩니다.LateUpdate는 일반적으로 다음의 3인칭 카메라에 사용합니다. 캐릭터를 움직이고Update로 방향을 바꾸게 하는 경우LateUpdate에서 모든 카메라 움직임과 로테이션 계산을 수행할 수 있습니다. 이렇게 하면 카메라가 포지션을 추적하기 전에 캐릭터가 완전히 움직였는지 확인할 수 있습니다.
일반적으로 순서가 명시적으로 문서화되거나 설정 가능한 경우를 제외하고, 다른 게임 오브젝트에 대해 동일한 이벤트 함수가 호출되는 순서를 사용해서는 안 됩니다. (플레이어 루프를 보다 세세하게 제어해야 하는 경우PlayerLoop API를 사용할 수 있습니다.)
동일한 MonoBehaviour 서브 클래스의 다른 인스턴스에 대해 이벤트 함수가 호출되는 순서를 지정할 수 없습니다. 예를 들어 한 MonoBehaviour의Update함수는 다른 게임 오브젝트(해당 부모 또는 자식 게임 오브젝트 포함)의 동일한 MonoBehaviour에 대해Update함수 전후에 호출될 수 있습니다.
한 MonoBehaviour 서브 클래스의 이벤트 함수가 다른 서브 클래스의 이벤트 함수 전에 호출되도록 지정할 수 있습니다(Project Settings 창의 Script Execution Order 패널 사용). 예를 들어 두 개의 스크립트(EngineBehaviour, SteeringBehaviour)가 있는 경우 EngineBehaviour가 항상 SteeringBehaviour 전에 업데이트되도록 스크립트 실행 순서를 설정할 수 있습니다.
OnStateMachineEnter:State Machine Update단계 동안 컨트롤러의 상태 머신이 엔트리 상태를 통과하는 전환을 만들 때 이 콜백이 첫 번째 업데이트 프레임에 대해 호출됩니다.StateMachine하위 상태에 대한 전환의 경우에는 호출되지 않습니다.
Fire Animation Events:마지막 업데이트 시간과 최신 업데이트 시간 사이에 샘플링된 모든 클립에서 모든 애니메이션 이벤트를 호출합니다.
StateMachineBehaviour (OnStateEnter/OnStateUpdate/OnStateExit):레이어가 최대 3개의 활성 상태(현재 상태, 중단된 상태, 다음 상태)를 가질 수 있습니다. 이 함수는OnStateEnter,OnStateUpdate또는OnStateExit콜백을 정의하는 StateMachineBehaviour 컴포넌트가 포함된 각 활성 상태에 대해 호출됩니다.
제일 먼저 함수가 현재 상태에 대해 호출되고 중단된 상태에 대해 호출된 후 마지막으로 다음 상태에 대해 호출됩니다.
OnAnimatorMove:업데이트 프레임마다 루트 모션을 수정할 수 있도록 각 Animator 컴포넌트에 대해 한 번 호출됩니다.
StateMachineBehaviour(OnStateMove):이 콜백을 정의하는StateMachineBehaviour가 포함된 각 활성 상태에 대해 호출됩니다.
OnAnimatorIK:애니메이션 IK를 설정합니다.IK pass가 활성화된 각 애니메이터 컨트롤러 레이어에 대해 한 번 호출됩니다.
휴머노이드 릭을 사용하는 경우에만 이 이벤트가 실행됩니다.
StateMachineBehaviour(OnStateIK):IK pass가 활성화되어 있는 레이어에서 이 콜백을 정의하는StateMachineBehaviour컴포넌트가 포함된 각 활성 상태에 대해 호출됩니다.
WriteProperties:다른 모든 애니메이션화된 프로퍼티를 메인 스레드에서 씬에 작성합니다.
유용한 프로파일 마커
스크립트 라이프사이클 플로우차트에 표시된 일부 애니메이션 함수는 호출할 수 없는 이벤트 함수입니다. 즉, Unity가 애니메이션을 처리할 때 호출되는 내부 함수입니다.
이 함수에는 프로파일 마커가 있으므로프로파일러를 사용하여 프레임에서 Unity가 호출하는 시간을 확인할 수 있습니다. Unity가 이러한 함수를 호출하는 시간을 알면 호출한 이벤트 함수가 실행된 시간을 정확하게 파악하는 데 도움이 됩니다.
예를 들어FireAnimationEvents콜백에서Animator.Play를 호출한다고 가정해 보겠습니다.State Machine Update및Process Graph함수가 실행된 후에FireAnimationEvents콜백이 발동했다는 사실을 알면 애니메이션 클립이 즉시 재생되는 것이 아니라 다음 프레임에서 재생된다는 것을 예측할 수 있습니다.