2023. 7. 21. 22:43ㆍC# & Unity 공부
오늘은 플레이어가 이동하는 것을 구현해 볼 것이다.
물리력에 의한 이동
우선 배우기 앞서, 플레이어가 이동해야 하므로,
밑의 사진처럼 움직일 수 있는 땅을 만들어주고, 카메라도 뒤로 땡겨주자.
그리고 스크립트를 관리할 파일 또한 만들어주자.
그리고 PlayerMove라는 스크립트 파일을 만들어서 다음과 같이 코드를 짜준다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
Rigidbody2D rigid;
void Awake() //플레이어 오브젝트가 만들어졌을 때
{
rigid = GetComponent<Rigidbody2D>();
}
void FixedUpdate() //플레이어가 움직이는 물리연산이므로
{
float h = Input.GetAxisRaw("Horizontal");
rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
}
}
그리고 실행시키면 문제점을 발견할 수 있다.
FixedUpdate는 1초에 50번 정도 사이클을 가지고
AddForce로 주었기 때문에 힘을 1초에 50번을 주었다고 생각하면 된다.
한 마디로 엄청 빠르다는 것이다.
그래서 가속도를 무한으로 받지 않기 위해 최대 속력을 정해줄 것이다.
주석을 보면서 코드를 다음과 같이 짜보자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
public float maxSpeed; //최대속도 변수(public으로 설정하여 Inspector 창에 뜸
Rigidbody2D rigid;
void Awake() //플레이어 오브젝트가 만들어졌을 때
{
rigid = GetComponent<Rigidbody2D>();
}
void FixedUpdate() //플레이어가 움직이는 물리연산이므로
{
//Move by Control
float h = Input.GetAxisRaw("Horizontal");
rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
//Right Max Speed
//현재 물체의 속도가 최대 속도를 넘었다면
//속도를 최대속도로 한정
//y축 속도를 0으로 해버리면 공중에 멈춤으로 0으로 설정 X
if (rigid.velocity.x > maxSpeed)
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
//Left Max Speed
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
}
}
실행시켜보면 Max Speed가 생겨서 직접 관리할 수 있으면서,
최대 속도가 제한된 것을 확인할 수 있다.
다음으로는 다음 시간에 오르막길을 만들어 볼 것인데,
그에 앞서서 지형이 마찰력을 한 번 뺴볼 것이다.
지형의 Material에 기본적으로 주어지는 마찰력이 있다.
이 마찰력을 0로 만들어서 빙판처럼 만들어 볼 것이다.
그래야 플레이어가 오르막길을 잘 올라갈 수 있다.
재질을 만들어 볼 것이다.
그리고 Physical2D 파일의 이름을 PlayerMove라고 해주자.
PlayerMove의 Inspector 창에 나와 있는 Friction (마찰력)을 0으로 하고,
모든 땅 오브젝트에다가 집어넣자.
그리고 실행시켜보면 마치 빙판길처럼 조그만 힘을 가해도
미끄러지는 것을 확인할 수 있다.
저항 설정
그러면 땅의 마찰력을 잡아줬으니, 우리는 다른 힘으로 이 문제를 해결해야한다.
공기 저항을 이용할 것이다.
플레이어를 선택하고 Inspector 창을 보면 두 가지의 Drag가 있다.
그 중, 우리가 사용할 것은 Linear Drag이다.
Linear Drag : 공기 저항, 이동 시 속도를 느리게 해준다. 단 너무 높게 잡지 않는다.
점프하고 내려올 때도 공기 저항을 받기 때문이다.
Angular Drag에서 Angular은 회전을 의미한다. 현재 쓸 필요가 없으니 나중에 알아보도록 하자.
우선 Linear Drag를 1이나 2로 바꾸면 속도가 점점 줄어드는 것을 확인할 수 있다.
그러나, 우리가 원하는 것은 키보드에서 손을 땠을 때 속도가 급격하게 줄어들어서
현재와 같이 빙판에서 미끄러지는 효과를 없애는 것이다.
다음과 같이 Update함수를 구현해주자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class PlayerMove : MonoBehaviour
{
public float maxSpeed; //최대속도 변수(public으로 설정하여 Inspector 창에 뜸
Rigidbody2D rigid;
void Awake() //플레이어 오브젝트가 만들어졌을 때
{
rigid = GetComponent<Rigidbody2D>();
}
//지속적인 키 입력은 FixedUpdate에서 하는 게 좋지만,
//단발적인 키 입력은 Update에서 하는게 훨씬 더 좋다.
//FixedUpdate는 1초에 약 50번 돌고, Update는 약 60번식 돈다
//그래서 단발적인 키 입력은 FixedUpdate에서 하면 키가 씹힐 수도 있다.
//이를 방지하기 위해 Update에다가 해주는 게 좋다.
void Update()
{
if(Input.GetButtonUp("Horizontal")) //Up은 떼는 것
{
//Stop speed
//rigid.velocity = new Vector2(0.5, rigid.velocity.y);
//오른쪽으로 가는지 왼쪽으로 가는 지 모름
//normalized : 벡터 크기를 1로 만든 상태 (단위 벡터)
//rigid.velocity.x는 현재 가고 있는 수평방향의 속력과 방향을 모두 알수 있음
//rigid.velocity.normalized => 현재 속도를 1로 만듦
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
}
void FixedUpdate() //플레이어가 움직이는 물리연산이므로
{
//Move by Control
float h = Input.GetAxisRaw("Horizontal");
rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
//Right Max Speed
//현재 물체의 속도가 최대 속도를 넘었다면
//속도를 최대속도로 한정
//y축 속도를 0으로 해버리면 공중에 멈춤으로 0으로 설정 X
if (rigid.velocity.x > maxSpeed)
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
//Left Max Speed
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
}
}
위와 같이 코드를 짜고 실행시켜 주면, 좀 더 부드럽게 멈추는 것을 확인할 수 있다.
그리고 다음으로 넘어가기 전에
Freeze Rotation을 체크하고 넘어가자.
Freeze Rotation : 오브젝트 회전을 얼리는 옵션
이를 체크하면 오브젝트가 넘어지는 것을 방지할 수 있다.
애니메이션 순환
이제 애니메이션을 건드릴 차례이다.
왼쪽 방향키를 누르면 문워크를 하고 있으며, 저번 시간에는 애니메이션을 두 개 넣었는데,
걸을 때 걷는 모션이 나오지 않는다.
이번에는 애니메이션을 컨트롤을 해볼 것이다.
우선 왼쪽을 볼 때, 왼쪽으로 뒤집어지는 것부터 구현해보겠다.
생각보다 간단하다.
캐릭터의 Sprite Renderer에서 Flip을 눌러보면 뒤집혀지는 것을 확인 할 수 있다.
이것을 C# 스크립트로 구현을 하면 된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class PlayerMove : MonoBehaviour
{
public float maxSpeed; //최대속도 변수(public으로 설정하여 Inspector 창에 뜸
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
void Awake() //플레이어 오브젝트가 만들어졌을 때
{
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
//지속적인 키 입력은 FixedUpdate에서 하는 게 좋지만,
//단발적인 키 입력은 Update에서 하는게 훨씬 더 좋다.
//FixedUpdate는 1초에 약 50번 돌고, Update는 약 60번식 돈다
//그래서 단발적인 키 입력은 FixedUpdate에서 하면 키가 씹힐 수도 있다.
//이를 방지하기 위해 Update에다가 해주는 게 좋다.
void Update()
{
if(Input.GetButtonUp("Horizontal")) //Up은 떼는 것
{
//Stop speed
//rigid.velocity = new Vector2(0.5, rigid.velocity.y);
//오른쪽으로 가는지 왼쪽으로 가는 지 모름
//normalized : 벡터 크기를 1로 만든 상태 (단위 벡터)
//rigid.velocity.x는 현재 가고 있는 수평방향의 속력과 방향을 모두 알수 있음
//rigid.velocity.normalized => 현재 속도를 1로 만듦
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//Direction Sprite (방향 전환)
//flipX는 Bool값이다. Input을 통해 들어오는 값이 -1이면 뒤집는다.
if (Input.GetButton("Horizontal"))
{
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;
}
}
void FixedUpdate() //플레이어가 움직이는 물리연산이므로
{
//Move by Control
float h = Input.GetAxisRaw("Horizontal");
rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
//Right Max Speed
//현재 물체의 속도가 최대 속도를 넘었다면
//속도를 최대속도로 한정
//y축 속도를 0으로 해버리면 공중에 멈춤으로 0으로 설정 X
if (rigid.velocity.x > maxSpeed)
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
//Left Max Speed
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
}
}
저장하고 실행하면
이렇게 뒤집어지는 모습을 볼 수 있다.
그 다음은 애니메이션을 건드릴 차례이다.
키를 눌렀을 떄 걷는 애니메이션이 나오게 해보자.
우선 Animator에 들어가 대기 상태를 우클릭 해서 Make Transition을 통해 화살표를 이어주자
Transition. : 애니메이션 상태를 옮겨가는 통로
그리고 좌측을 보면 파라미터가 있다.
+를 누르면 float, int, bool, trigger가 있다.
이는 애니메이터 매개변수이다.
애니메이터 매개변수 : 상태를 바꿀 때 필요한 변수
+를 눌러서 bool을 선택하고 isWalking을 하나 만들어주자.
그리고 화살표를 클릭한 뒤 Conditions에서 +를 눌러준다.
아래 사진은 isWalking이라는 조건을 만족하면 Walk 애니메이션을 실행한다는 뜻이다
그리고 타임라인은 애니메이션이 바뀔 때 부드럽게 바꾸어주는 그런 것이다.
2D 애니메이션이기 때문에 즉각즉각 바뀌면 되므로 겹치는 건 없애주면 된다.
그리고 Has Exit Time을 해제해준다.
Has Exit Time : 애니메이션이 끝날 때까지 상태를 유지
저것을 해제하지 않으면 이동을 멈췄을 때도 애니메이션이 다 끝날 때까지
뛰는 모션이 나오게 된다.
반대쪽도 똑같이 Condition에 유의하며 만들어준다.
준비는 완료되었으나, isWalking을 바꿔주는 건 스크립트로 구현해야 한다.
Animator 컴포넌트를 받아서 속도가 0일 때, 저 상태를 끌 수 있도록 만들어주자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class PlayerMove : MonoBehaviour
{
public float maxSpeed; //최대속도 변수(public으로 설정하여 Inspector 창에 뜸
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
Animator anim;
void Awake() //플레이어 오브젝트가 만들어졌을 때
{
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
}
//지속적인 키 입력은 FixedUpdate에서 하는 게 좋지만,
//단발적인 키 입력은 Update에서 하는게 훨씬 더 좋다.
//FixedUpdate는 1초에 약 50번 돌고, Update는 약 60번식 돈다
//그래서 단발적인 키 입력은 FixedUpdate에서 하면 키가 씹힐 수도 있다.
//이를 방지하기 위해 Update에다가 해주는 게 좋다.
void Update()
{
if(Input.GetButtonUp("Horizontal")) //Up은 떼는 것
{
//Stop speed
//rigid.velocity = new Vector2(0.5, rigid.velocity.y);
//오른쪽으로 가는지 왼쪽으로 가는 지 모름
//normalized : 벡터 크기를 1로 만든 상태 (단위 벡터)
//rigid.velocity.x는 현재 가고 있는 수평방향의 속력과 방향을 모두 알수 있음
//rigid.velocity.normalized => 현재 속도를 1로 만듦
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//Direction Sprite (방향 전환)
//flipX는 Bool값이다. Input을 통해 들어오는 값이 -1이면 뒤집는다.
if (Input.GetButton("Horizontal"))
{
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;
}
//Animation
if (Mathf.Abs(rigid.velocity.x) < 0.3)
anim.SetBool("isWalking", false);
else
anim.SetBool("isWalking", true);
//Mathf : 수학 관련 함수를 제공하는 클래스 (Unity에서 제공)
//Abs() : 절댓값을 나타냄
}
void FixedUpdate() //플레이어가 움직이는 물리연산이므로
{
//Move by Control
float h = Input.GetAxisRaw("Horizontal");
rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
//Right Max Speed
//현재 물체의 속도가 최대 속도를 넘었다면
//속도를 최대속도로 한정
//y축 속도를 0으로 해버리면 공중에 멈춤으로 0으로 설정 X
if (rigid.velocity.x > maxSpeed)
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
//Left Max Speed
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
}
}
Mathf 클래스의 Abs() (절댓값) 함수를 사용하여 0.3 (오른쪽)이거나 -0.3(왼쪽)보다
속도가 줄어들면 캐릭터가 멈추게 만들었다.
'C# & Unity 공부' 카테고리의 다른 글
Unity 2D - 5. 타일맵으로 플랫폼 만들기 (0) | 2023.07.30 |
---|---|
Unity 2D - 4. 플레이어 점프 구현하기 (0) | 2023.07.28 |
Unity 2D - 2. 아틀라스와 애니메이션 (0) | 2023.07.20 |
Unity 2D - 1. 프로젝트 준비하기 + 에셋 다운로드 (1) | 2023.07.19 |
9-2. 첫 번째 프로젝트 (결승점, 장면, 스테이지 추가, UI생성, 빌드) (0) | 2023.07.12 |