유니티 시작-Dodge미니게임만들기
20261016 Unity 시작-Dodge미니게임만들기
Unity 화면 설정
- 메인 화면 우상단 Layout에서 기본 Layout을 설정 할 수 있다.
- 수업은 2By3인 상태로 Console창을 추가해서 진행한다.(화면 상단 Window -> General -> Console)
- SaveLayout을 통해서 개인설정을 저장 할 수 있다.
- Scene, Game, Hierarchy, Project, Inspector, Console 등을 보여주는 창들을 View라고 부른다.
구조
프로젝트의 기본 구조
- Scene -> GameObject -> Component 이다. Scene이 GameObject들을 가지고 있고 GameObject들은 각각 Component들을 가지고 있다.
GameObject 및 Component 생성
- Hierachy View에서 마우스 우클릭을 통하여 Create Empty, 2D Object, 3D Object 등을 선택하여 다양한 GameObject 들을 추가 할 수 있다.
- GameObject를 선택하고 Inspector View에서 최하단 AddComponent를 통해 Component를 추가 할 수 있다.
- 화면 상단 Play 버튼을 통해 테스트가 가능하며 Game View에서 사용자 입력을 받아볼 수 있다.
- 주의사항: Play중 자주 하는 실수
- 사용자 입력을 받을 때는 Game View가 선택이 되어있어야 한다. Game View를 선택 안하고 사용자 입력을 통해 움직이려고 시도하는경우 안움직인다.
- Game View 우상단 Mute Audio가 있다. Mute 상태로 소리가 안난다고 하는 경우가 있다.
- 화면이 이상해 보이는 경우 Game View상단 Scale이 잘못 되어있는 경우가 있다.
- 참고: Hierarcy View에서 한 GameObject를 다른 GameObject로 드래그 하면 자식으로 만들 수 있고 결합을 해제하려면 빈 공간으로 다시 끌어놓으면 된다.
조작
Scene View에서 q,w,e,r,t,y 키를 눌러서 각 기능별 마우스 동작을 선택하고 Scene화면에서의 여러 동작을 수행할 수 있으며 Shift, Alt, Ctrl 등과 조합 할 수 있다.
이때 조작하기 편하도록 화살표 등을 통해 시각적으로 표시해주는 것을 기즈모(Gizmo)라고 한다. 실제 조작할 수 있는 기능들은 핸들(Handle)이라고 부른다.
- Tools
- View Tool(Q): Scene 화면을 포시하는 카메라를 움직인다고 보면 된다. 카메라 이동및 회전 등이 가능하다.
- Move Tool(W): 선택된 Object를 마우스로 잡고 이동시키는 것이 가능하다.
- Rotate Tool(E): 선택된 Object를 마우스로 잡고 회전시키는 것이 가능하다.
- Scale Tool(R): 선택된 Object를 마우스로 크기를 조절하는 것이 가능하다.
- Rect Tool(T), Transform Tool(Y) 는 우선 오늘은 다루지 않는다.
Scene 기본 설정
- Scene의 기본적인 설정은 좌상단 Center와 Pivot중 Pivot으로 선택하고 Global과 Local중 Local을 선택 한 상태로 사용하자.
Center와 Pivot: 오브젝트를 조작하는 도구의 위치를 결정(기준점)
- Center: 오브젝트의 렌더링 영역 중심에 조작 도구를 표시하며 해당 위치를 기준으로 조작
- Pivot: 오브젝트의 실제 기준점(Transform 위치)에 조작 도구를 표시하며 해당 위치를 기준으로 조작
Global과 Local: 오브젝트를 조작하는 도구의 축 방향을 결정
- Global: 유니티 세계 전체를 기준으로 한 고정된 축 방향. 오브젝트를 회전시켜도 X, Y, Z 축 방향은 변하지 않음.
- Local: 선택한 오브젝트 자체의 방향을 기준으로함. 오브젝트가 회전하면 X, Y, Z축도 함께 회전한다. 단 Global / Local을 변경해도 오브젝트의 실제 좌표나 회전 값은 변경되지 않는다. Scene 뷰에서 조작할 때 사용하는 축의 방향만 바뀌는 것이다.
Visual Studio Code 연동하는 방법
- Unity 상단 Edit -> Preferences -> External Tools의 External Script Editor항목을 Visual Studio Code로 선택해준다.
- Visual Studio Code의 화면 좌측 Extensions에서 Unity 검색 후 설치한다.
- Run And Debug에서 Attach to Unity가 보이면 정상 설치.
- Explorer에서 Assets, Packages만 보이고 .meta 파일이 안보이면 정상.
- Visual Studio Code 연동이 안되어 있는 프로젝트는 Edit -> Preferences -> External Tools에서 Regenerate project files를 누르면 재시작 되면서 연동된다.
- 참고: Unity에서 프로젝트 여는 법. 화면 좌상단 Assets -> Open C# Project
Inspector View의 Mesh filter와 Mesh Renderer의 차이
- Mesh Filter : GameObject의 형태를 관리하는 Component
- Mesh Renderer : GameObject를 어떻게 색칠할 지 선택하는 등 GameObject의 보여지는 부분을 담당하는 Component
간단한 Material 생성 및 적용
- Project View 우클릭 혹은 화면 좌상단 Asset에서 Create -> Material을 하거나 Procject View의 좌상단
+버튼을 눌러서 Material을 클릭하면 생성된다. - 생성된 Material -> Surface Inputs -> Base Map에서 색상 변경이 가능하다.
- GameObject 선택 후 Inspector View의 Mesh Renderer -> Materials의 Element에 생성한 Material을 마우스로 끌어서 넣으면 적용이 가능하다.
코드(script) 생성
Project View 우클릭 혹은 화면 좌상단 Asset에서 Create -> MonoBehaviour Script를 하면 Script를 생성이 가능하며 Inspector View의 Component에 마우스로 끌어서 넣으면 적용이 가능하다.
- 주의사항
- Unity는 자동 저장 기능이 없음. 때문에 Scene을 더블클릭하여 다시열거나 할 때 저장하지 않으면 마지막 저장 시점으로 불러와져버린다.
- Play 중의 수정사항은 저장 안됨.(예를들어 수치 변경 같은 것들)
원하는 기능이 있는 함수를 찾을 때
Help -> Documentation 에서 메뉴얼 확인으로 필요한 함수들을 찾을 수 있다. 현재 실행중인 버전에 맞게 메뉴얼을 열어주므로 적극적으로 확인 할 것.
Project Setting
- Edit -> Project Setting -> Player -> Configuration -> Active Input Handling을 Both로 변경
- 사용자 입력에 대한 값을 받는 방식이며 Input Manager(Old), Input System Package(New), Both가 있음. Input Manager는 지원 종료 예정인 방식이고 Input System Package가 새로운 방식이며 Both는 그 두가지 방식을 모두 사용하는 설정이다.
- 이번 수업에서는 GetAxis를 시용할 예정이기 때문에 Both를 선택한 것이다.
- 변경 후 적용을 선택하면 재시작 된다.
Start와 Update 호출
Start: 실행될 때 한번만 호출.
- 해당하는 Component가 호출 될 때 실행된다.
- 정확하게는 해당 Component의 첫번째 Update가 호출되기 직전에 호출된다. Update: 일정 주기로 반복 호출
- Update 주기: frame당 한번씩 호출
Time.time과 Time.deltaTime
Time.time: 프레임당 값이(시간값) 증가. Time.deltaTime: 직전 프레임과 이번 프레임간의 시간 차이(간격)
Time.time은 시간 간격이 고정되어있지 않음.(Update마다 시간이 다름..) 만약 등속의 움직임을 만들고 싶다면 deltaTime을 이용한 시간차이를 계산해줘야함.
GameObject의 이동
GameObject의 transform.position에게 속도 * deltaTime을 입력하면 해당 방향으로 등속이동 한다.
- 속도 = 속력 * 방향
- 등속이동 = 속도 * deltaTime(속력 * 방향 * deltaTime)
// 특정 방향으로 등속이동 하도록 하는 예시
public float speed = 10f;// 임의의 속력 값
private void Update()
{
Vector3 direction = new Vector3(1f, 0f, 0f);// 방향 설정(x, y, z)
Vector3 delta = direction * speed * Time.deltaTime; // 속력 * 방향 * deltaTime
transform.position += delta;
}
- 참고:
Vector3는 클래스가 아닌 구조체다. 구조체는 값형이다. int, float 같은거라고 생각하면 된다.
InputManager를 사용한 Vector3초기화
Input Manager를 사용하여 vector3를 가져오는 방법에는 두가지 정도가 있다.
Input.GetAxisRaw와 Input.GetAxis. 예시:Input.GetAxisRaw("Horizontal"), Input.GetAxis("Vertical").
Project Settings -> Input Manager -> Axes 항목에 "Horizontal", "Vertical"이 있고 해당 설정에는 어떤 버튼을 누르면 해당 값이 입력되는지 등을 알 수 있다.
- Negative Button: 해당 Button을 누르면 음수반환
- Positive Button: 해당 Button을 누르면 양수반환
- Alt Negative Button: 해당 Button을 누르면 음수반환
- Alt Positive Button: 해당 Button을 누르면 양수반환
- 참고: Alt는 대체버튼이라고 보면 된다.
// InputManager 사용 예시
private void Update()
{
Vector3 direction = Vector3.zero; // Vector3 초기화.
direction.x = Input.GetAxis("Horizontal");// Input.GetAxisRaw("Horizontal")도 가능
direction.z = Input.GetAxis("Vertical");// Input.GetAxisRaw("Vertical")도 가능
}
Input.GetAxisRaw, GetAxis 차이
- GetAxisRaw를 사용하면 이동할 때 값이 0에서 바로 1로 감(속도가 순차적 상승이 아닌 한번에 올라감)
- GetAxis 사용 하면 가속구간, 감속구간이 생긴다.(순차적으로 증가하게 된다.)
- 참고: Project Settings -> Input Manager -> Axes의 Sensitivity 는 가속, 감속에 대한 보정값이다. 키보드는 true, false밖에 없기때문에 이에대한 보정으로 사용한다. 스틱의 경우 기울어짐에 따라 값이 다르기 때문에 키보드랑은 다르다. 물론 보정값이 필요하긴 하다.
위 예시대로만 입력하면 대각선의 경우 방향이 각각 1이 입력이 되어 대각선 이동시 속도가 빨라져버림. 이를 보정하기 위해 1이 넘어가면 1로 줄여줘야한다. .magnitude로 vector의 길이를 확인하고 Normalize로 1로 만들어줌.
// magnitude로 1이 넘어갈 경우 1로 줄이는 방법 예시
private void Update()
{
Vector3 direction = Vector3.zero; // Vector3 초기화.
direction.x = Input.GetAxis("Horizontal");// Input.GetAxisRaw("Horizontal")도 가능
direction.z = Input.GetAxis("Vertical");// Input.GetAxisRaw("Vertical")도 가능
if(direction.magnitude > 1f)
{
direction.Normalize();
}
}
Rigidbody를 사용한 움직임
- Rigidbody 사용할 때는 Transform사용 안함. Rigidbody 통한 움직임과 Transform을 통한 움직임이 서로 따로 동작한다고 봐야하기 때문이다.
- Rigidbody 사용하려면 public으로 사용할 경우 변수 선언 후 Inspector에서 player의 Rigidbody를 넣어주면 된다. 예시:
rb.linearVelocity = direction * speed;
// Rigidbody를 사용한 움직임 예시
public Rigidbody rb;
private void Update()
{
Vector3 direction = Vector3.zero; // Vector3 초기화.
direction.x = Input.GetAxis("Horizontal");// Input.GetAxisRaw("Horizontal")도 가능
direction.z = Input.GetAxis("Vertical");// Input.GetAxisRaw("Vertical")도 가능
if(direction.magnitude > 1f)
{
direction.Normalize();
}
rb.linearVelocity = direction * speed;
}
이와 같이 적용을 할 경우이동은 하지만 캡슐(Player)이 엉뚱하게 굴러다님. 여러 방향의 힘을 받기 때문임. rigidbody의 Constraints는 힘의 작용을 받지 않도록 잠글 수 있음. Freeze Position은 Y, Freeze Rotation은 X, Z를 잠그면 안굴러다닌다.
Unity에서 MonoBehaviour를 상속받으면 생성자를 통한 초기화는 사용하면 안됨
MonoBehaviour를 상속받으면 생성자를 쓰면 안됨. MonoBehaviour에서 해당 생성자를 이미 쓰고있기 때문.
생성자 대신 Start() 메서드를 이용할 것.
객체 생성시 값 초기화 순서
필드(Field) -> 인스펙터(Inspector) -> 스타트 메서드(Start()) 순으로 생성된다.
Start()에 있는 값이 마지막에 덮어씌워짐.
자주 하는 실수로 생성순서 확인을 안해서 값이 잘못 들어가는 경우가 있다.
예시:Start()에서 값 변경이 이미 있는데 인스펙터에 새로운 값 입력. 이 경우 Start()에 있는 값으로 초기화됨.
필드선언의 기본은 Private
수업에는 편의상 Public 프로퍼티를 사용하지만 원래는(예를들어 포폴같은거) public이 아니라 [SerializeField]후 private을 사용한다.
Public으로 하면 다른 곳에서의 접근이 가능하지만, [SerializeField] 후 Private은 Inspector에서 값을 넣을 수는 있으나 다른 곳에서의 접근이 안된다.
Inspector 외에 값을 불러오는 방법
Inspector에서 넣어주는 방법 외에도 불러오는 방법이 있다.
GetComponent<Rigidbody>(); (<Rigidbody> 이렇게 쓰는것은 제네릭(Generic) 인자다. <Rigidbody>자리에는 데이터 형이 들어간다. 클래스는 데이터 형이기 때문.)
//SerializeField 사용 예시 및 `GetComponent<Rigidbody>()` 사용 예시
[SerializeField]
private Rigidbody rb;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
위와 같이 쓰면 해당 GameObject가 가진 Component들 중에 Rigidbody를 가져온다.
X, Y, Z축의 사용
주로 3D에서는 Z축(파란 화살표)을 앞, 뒷면으로 한다.(화살표 방향이 앞) X축(빨간 화살표)은 좌, 우로 하며, Y축(녹색 화살표)은 상, 하로 한다.
총알 이동시 떨어지지 않도록 하는 방법
Rigidbody의 Use Gravity옵션을 켤 경우 중력에 영향을 받는 것 처럼 움직이게 된다. 총알이 떨어지지 않고 움직이기를 바란다면 해당 옵션을 꺼주면 된다.
충돌 확인 Collider
기본적으로 총알이 이동 중 어딘가에 부딛히면 충돌확인을 하며 멈추게 되는데 총알끼리도 부딛힐 경우 멈추어 버리게 된다. 이를 막기 위해선 Collider의 is Trigger 옵션을 꺼주면 된다. 해당 옵션이 체크가 안되어있으면 충돌시 멈춤. 체크가 되어있으면 충돌시 멈추지 않고 지나가지만 충돌 했는지는 별도로 확인이 가능하다.
- OnTriggerEnter(): 겹치는 순간의 프레임에 한번 발생
- OnTriggerStay(): 겹쳐있으면 매 프레임마다 발생
- OnTriggerExit(): 붙어있다가 떨어지는 순간의 프레임에 한번 발생
Tag시스템
일반적으로 충돌을 확인할 때 이름으로 비교하는 대신 Tag로 확인한다.
private void OnTriggerEnter(Collider other)
{
// Tag가 Player라면 해당 GameObject 비활성화
if(other.CompareTag("Player"))
{
other.gameObject.SetActive(false);
}
// Bullet이 아닌 다른 곳에 충돌할 경우 해당 Bullet 삭제
if(!other.CompareTag("Bullet"))
{
Destroy(gameObject);
}
}
Tag 생성하는 방법
GameObject 선택 후 Inspector View의 Tag 선택하는 곳에서 Add Tag -> Tags 아래의 +버튼을 누르고 Tag 이름 입력 후 Save
Prefab
만들어놓은 하나의 GameObject를 Prefab으로 만들어서 여러번 복사및 활용할 수 있다. Hierarchy에 있는 GameObject를 마우스로 끌어서 Project로 옮김.(asset으로 변경됨)
일정 시간마다 자동으로 Player 방향으로 총알 생성하는 방법
- Instantiate(): 해당 prefab생성하는 함수
- Instantiate(prefab에 해당하는 GameObject, 상성할 위치, 회전값)
- target 방향 구하는 방법.(현재는 Player 방향)
- A에서 B로 가는 방향을 구하고 싶으면 목적지 - 출발지 하고 Normalize(). 예시 (A-B).Normalize()
Tag를 통한 GameObject를 찾아서 가져오는 방법
FindGameObjectWithTag()를 통하여 게임오브젝트를 가져온다.
이름이 비슷한 FindGameObjectsWithTag()함수도 있으니 주의할것.
사용 예시 : GameObject findgo = GameObject.FindGameObjectWithTag("Player");
회전값 구하는 방법
target 방향 구하는 방법대로 방향을 구한 후 해당 방향을 Quaternion 클래스를 통해서 가져온다.
예시 Quaternion rotation = Quaternion.LookRotation(direction);
// 방향 구하는 방법
Vector3 position = transform.position; // Bullet을 생성할 BulletSpawner의 위치
Vector3 direction = target.position - position; // FindGameObjectWithTag로 구한 Target위치
direction.Normalize();
Quaternion quaternion = Quaternion.LookRotation(direction); // 회전값 구하는 함수.
Instantiate(bullets, position, quaternion); // Prefab을 생성하는 함수



