1. 유니티 스크립트 작성법
○ 유니티 스크립트 작성
- 프로젝트가 생성되면 Unity Editor를 열고, 스크립트를 작성할 수 있는 코드 편집기를 선택함 (예: Visual Studio)
- 스크립트를 작성할 폴더를 생성하고, 해당 폴더에 새로운 C# 스크립트 파일을 만듬
- 스크립트 파일을 더블 클릭하여 코드 편집기에서 스크립트를 염
- 스크립트 파일에는 게임의 로직, 오브젝트의 동작, 입력 처리 등을 정의하는 코드를 작성함
○ 스크립트 작성 방법
- MonoBehaviour를 상속받은 클래스를 작성함. 이 클래스는 유니티의 게임 오브젝트와 연결된 스크립트로 동작함
(유니티의 이벤트 함수를 사용하기 위해서 꼭 상속 받아야 함)
- 필요한 변수, 함수, 이벤트 등을 정의하고 구현함. 게임의 동작을 위한 로직을 작성함
- 필요한 Unity 함수들을 오버라이딩하여 원하는 동작을 구현할 수 있음.(진짜 오버라이딩은 아니고 오버라이딩과 비슷함)
예를 들어, Start()
, Update()
, FixedUpdate()
등을 활용할 수 있음
- 필요에 따라 다른 스크립트나 Unity의 컴포넌트와 상호작용하는 코드를 작성할 수 있음
○ 스크립트 라이프 사이클
- Monobehaviour를 상속받는 클래스들은 유니티 이벤트 함수를 활용할 수 있음
- 게임 오브젝트의 생명 주기 동안 호출되는 특정한 메서드들의 순서와 타이밍
- 게임 오브젝트의 생성, 초기화, 업데이트, 파괴 등과 관련된 작업을 수행
- Awake : 게임 오브젝트가 생성될 때 호출되는 메서드. 주로 초기화 작업이 수행
- OnEnable : 게임 오브젝트가 활성화될 때 호출되는 메서드
- Start : 게임 오브젝트가 활성화되어 게임 루프가 시작될 때 호출되는 메서드. 초기 설정 및 시작 작업을 수행
[여기까지 첫 프레임 시작 전에 발동]
- FixedUpdate : 물리 엔진 업데이트 시 호출되는 메서드. 물리적인 시뮬레이션에 관련된 작업을 처리할 때 사용
- Update : 매 프레임마다 호출되는 메서드로, 게임 로직의 주요 업데이트가 이루어짐
- LateUpdate : Update 메서드 호출 이후에 호출되는 메서드. 다른 오브젝트의 업데이트가 완료된 후에 작업을 수행하는 데 유용
랜더링과 직접적으로 연관된 카메라 이동같은 것을 업데이트함
- OnDisable : 게임 오브젝트가 비활성화될 때 호출되는 메서드
- OnDestroy : 게임 오브젝트가 파괴될 때 호출되는 메서드. 자원 정리 및 해제 작업이 수행됨
- OnApplicationQuit : 껐을 때 호출되는 메서드
이벤트 함수 실행 순서 참고링크
2. 핵심 기능 소개
○ Pixels Per Unit (PPU)
- Pixels Per Unit (PPU): 스프라이트의 픽셀 수와 해당 스프라이트가 게임 세계에서 차지하는 공간의 관계를 설명함.
예를 들어, PPU가 100이라면 스프라이트의 100픽셀은 게임 세계에서 1 유니티 단위를 나타냄
- 스프라이트의 크기: PPU 값이 클수록 스프라이트는 작아짐. 이는 더 많은 픽셀이 동일한 게임 세계의 공간에 매핑되기 때문
- 물리 시뮬레이션: PPU 값은 물리 시뮬레이션에 영향을 미침. 높은 PPU 값은 더 작은 스프라이트를 생성하므로, 이는 더 높은 해상도의 물리 시뮬레이션을 가능하게 함
- 퍼포먼스: 높은 PPU 값은 더 많은 연산을 필요로 함. 이는 성능에 영향을 미칠 수 있음. 따라서, 필요한 만큼의 PPU 값을 설정하는 것이 중요함
- 일관성: 모든 스프라이트에 대해 일관된 PPU 값을 사용하는 것이 좋음. 이는 스프라이트간의 크기 비율을 일정하게 유지하고, 물리적 행동의 일관성을 보장하는 데 도움이 됨.
- 각 게임 오브젝트는 Transform 컴포넌트를 가지고, Transform 컴포넌트는 게임 오브젝트의 위치, 회전, 및 크기(scale)를 정의함
- 게임 오브젝트는 다른 게임 오브젝트의 '자식'이 될 수 있음
- 부모 게임 오브젝트의 Transform이 변경되면(예: 이동, 회전, 크기 변경), 그 자식 오브젝트들의 Transform도 동일하게 적용됨
- 이렇게, 게임 오브젝트들 사이에 계층적인 관계가 형성되고 이를 '트리 구조'라고도 부름
- 이 구조는 복잡한 씬을 구성하고 관리하는데 유용합니다. 예를 들어, 차량 게임 오브젝트 내부에 각각의 부품(바퀴, 핸들 등)을 자식 게임 오브젝트로 두면, 차량의 Transform이 변경될 때 각 부품들도 함께 움직임
- 이름이 Transform인 이유
이유는 트랜스폼의 데이터들이 부모에 대한 변환(Transformation)을 나타내고 있기 때문.
예를 들어, position이 2, 0, 0인 트랜스폼이 있다면, 부모에 대해 position이 2만큼 x로 떨어져있다라는 것
○ 월드 좌표계(World Coordinate System)
- 월드 좌표계는 게임 세계의 전체적인 참조 프레임을 제공함
- 이는 모든 게임 오브젝트가 공유하며, 월드 좌표계에서의 위치는 게임 환경 내에서 오브젝트의 절대적인 위치를 나타냄
- 월드 좌표계는 변하지 않고 일정하게 유지됨
- 스크립트에서는 position, rotation, lossyScale 를 통해 참조함
○ 로컬 좌표계(Local Coordinate System)
- 유니티에서 인스펙터창에서 볼 수 있는 position, scale, rotation 등이 로컬 좌표계에 따른 값에 해당함
- 이는 월드 좌표계가 아닌 부모에 대한 좌표를 말하며, 부모에 대해 x축으로 2만큼 떨어져 있으면 이 오브젝트의 로컬 포지션은 (2, 0, 0)이 되는 것
- 스크립트에서는 localPosition, localRotation, localScale 등이 있음
Input.GetAxis
는 유니티의 입력 시스템에서 사용되는 메서드
- 이 메서드는 입력 축의 값을 반환함
- 입력 축은 주로 키보드나 조이스틱과 같은 입력 장치의 입력을 나타냄
GetAxis
메서드는 -1부터 1 사이의 값을 반환하는데, 입력 장치의 움직임에 따라 해당 값이 변경됨
- 값이 0에 가까울수록 입력이 없거나 중립 상태를 나타내며, 양수 값은 양 방향 입력을, 음수 값은 음 방향 입력을 나타냄
GetAxis
메서드는 주로 플레이어의 움직임, 회전, 점프 등을 처리하는 데 사용됨
- 예를 들어, 수평 이동을 처리하는 경우, 좌우 화살키의 입력에 따라
Input.GetAxis("Horizontal")
을 사용하여 좌우 방향의 값을 얻을 수 있음
- 이 값은 플레이어의 이동 속도나 회전 속도와 같은 변수에 적용하여 게임 오브젝트를 제어할 수 있음
○ TIme.deltaTime
- 이전 프레임부터 현재 프레임까지의 경과 시간을 나타냄
deltaTime
은 게임의 프레임 속도에 상관없이 일정한 시간 간격으로 동작하는 게임을 만들 때 유용하게 사용됨
(delta는 차이를 말할때 주로 쓰임)
- 주로 움직임, 애니메이션, 물리 시뮬레이션 등에서 시간에 따른 변화를 조정하는 데 사용됨
- 예를 들어,
transform.Translate(Vector3.forward * speed * Time.deltaTime)
과 같이 사용하면 프레임 속도에 관계없이 speed
만큼의 일정한 이동 속도를 보장할 수 있음
Time.deltaTime
은 초 단위의 값을 반환하며, 1초에 1에 가까운 값을 가짐
- 게임의 로직이 매 프레임마다 일정한 속도로 실행되어야 할 때,
deltaTime
을 이용하여 이동, 회전, 애니메이션 등의 연산에 일정한 시간 간격을 적용할 수 있음
- 이를 통해 게임이 일정한 속도로 동작하고, 다양한 기기나 환경에서도 일관된 경험을 제공하고 제어할 수 있음
○ 접근 제한자와 직렬화 속성
public
- 직렬화 했다고도 표현함
- 변수나 메서드가 외부에서 접근 가능하도록 공개
- 다른 클래스나 스크립트에서 해당 멤버에 접근하여 값을 설정하거나 호출
private
- 변수나 메서드가 같은 클래스 내에서만 접근 가능하도록 제한
- 다른 클래스나 스크립트에서는 접근할 수 없고, 해당 클래스 내부에서만 사용
- 보통 내부 상태를 관리하거나 내부 구현에 사용
SerializeField
- private이지만 직렬화 하고 싶을 때 사용
private
로 선언된 변수를 인스펙터에서 직접 접근
- 기본적으로
private
변수는 인스펙터에 표시되지 않지만, SerializeField
를 사용하면 해당 변수가 인스펙터에서 수정 가능한 필드로 표시
참고링크
- 예시코드
public class ExampleClass : MonoBehaviour
{
public int publicVariable;
private int privateVariable;
[SerializeField]
private int serializedFieldVariable;
private void Start()
{
publicVariable = 10; // 외부에서 접근 가능
privateVariable = 20; // 클래스 내부에서만 접근 가능
serializedFieldVariable = 30; // 인스펙터에서 접근 가능
}
}
3. 이동 기본 코드 작성
- 구 인풋 시스템(InputManager)을 기반으로 코드를 작성
(InputManager도 아직 많이 활용함)
- InputManagerMovement 작성
using UnityEngine;
public class InputManagerMovement : MonoBehaviour
{
Rigidbody2D rigidbody;
// private이지만 인스펙터 표출은 하고 싶어!
[SerializeField] private float speed;
// Start is called before the first frame update
void Start()
{
// Rigidbody2D를 캐싱합니다.
rigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
// Input Manager에서 Vertical축과 Horizontal축의 입력을 받아옴
// float vertical = Input.GetAxis("Vertical");
// float horizontal = Input.GetAxis("Horizontal");
// 퍼프레임마다 Vertical축과 Horizontal축을 가져옴
// GetAxis는 보정이 있어서 캐릭터의 움직임이 딱딱 끊기지 않음
float vertical = Input.GetAxisRaw("Vertical");
float horizontal = Input.GetAxisRaw("Horizontal");
// GetAxisRaw 는 +1, -1 입력만 받아서 딱딱 끊김
Vector2 direction = new Vector2(horizontal, vertical);
// 정규화를 하고 싶음 : 길이를 1로 만드는 작업
// 벡터에 normalized를 하면 벡터의 길이를 1로 만듬
// 예를 들어, vertical, horizontal 모두 1인 경우, direction의 크기는 1보다 크게 될 수 있는데, 이를 1로 맞춰줌
direction = direction.normalized;
// rigidbody.velocity는 해당 물체가 1초당 움직이는 거리를 말함
rigidbody.velocity = direction * speed;
}
}
- Vector2
- 2차원 벡터를 나타내는 자료형
- 이를 통해 x와 y 좌표를 가진 점을 나타내거나 2D 게임이나 물리 연산에서 방향과 크기를 표현하는 데 사용됨
- 주로 2D 공간에서의 위치, 속도, 힘 등의 벡터 값을 계산하는 데 유용
- Vector3가 3차원 벡터를 나타내는 것과 달리 Vector2는 2D 공간에서 사용됨
- Vector2는 두 개의 float 값을 갖는 자료형으로, 주로 다음과 같은 상황에서 사용됨
- 게임 캐릭터의 위치나 이동 방향
- 물리 연산에서 속도나 가속도 계산
- UI 요소의 위치 계산