-
[유니티 2D 스터디] 캐릭터 이동, 벽 충돌처리쾌락없는 책임 (공부)/Unity 2021. 3. 11. 21:29반응형
<전체 소스코드>
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMove : MonoBehaviour{ Rigidbody2D rigid; SpriteRenderer spriteRenderer; Animator anim; public float maxSpeed; public float jumpPower; public int jumpCount = 0; public int maxJumpCount = 2; // 방향을 가져오기 위한 변수 Vector3 dirVec; // 레이로 스캔하는 물체 받아오는 변수 GameObject scanObject; void Awake() { rigid = GetComponent<Rigidbody2D>(); spriteRenderer = GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>(); } void Update(){ // 버튼에서 손을 떼면 움직임 멈춤 if(Input.GetButtonUp("Horizontal")){ rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.2f, rigid.velocity.y); } // Flip if (Input.GetButton("Horizontal")) spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == 1; // 걷는 애니메이션 if (Mathf.Abs(rigid.velocity.x) < 0.2f || jumpCount > 0) //속도가 0이라면 = 단위벡터가 0 anim.SetBool("isWalk", false); else anim.SetBool("isWalk", true); //바라보는 방향 float h = Input.GetAxisRaw("Horizontal"); if(h == -1) dirVec = Vector3.left; else if(h == 1) dirVec = Vector3.right; // 점프 if(Input.GetKeyDown(KeyCode.Space) && jumpCount < maxJumpCount){ rigid.velocity = Vector2.up * jumpPower; jumpCount++; } } void FixedUpdate(){ // 좌우 이동 float h = Input.GetAxisRaw("Horizontal"); rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse); // 최대 스피드 maxSpeed 를 넘지 못하게 함 if(rigid.velocity.x > maxSpeed) rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); else if(rigid.velocity.x < -maxSpeed) rigid.velocity = new Vector2(-maxSpeed, rigid.velocity.y); // 플레이어 아래로 쏘는 ray, 내려올때만 if(rigid.velocity.y < 0){ Debug.DrawRay(rigid.position, Vector3.down, new Color(1, 0, 0)); RaycastHit2D downRay = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Ground")); if(downRay.collider != null && downRay.distance < 0.5f){ Debug.Log("땅"); jumpCount = 0; } } // 조사를 하기 위한 Ray // 씬 상에서 빨간색 선을 쏴서 레이에 닿으면 상호작용 가능하게 개조하면 됨 Debug.DrawRay(rigid.position, dirVec * 1.5f, new Color(1, 0, 0)); RaycastHit2D rayHit2 = Physics2D.Raycast(rigid.position, dirVec, 1.5f, LayerMask.GetMask("Object")); if(rayHit2.collider != null) { scanObject = rayHit2.collider.gameObject; } else { scanObject = null; } } }
<FixedUpdate와 Update 차이>
- Update : 프레임 단위로 호출되는 함수, 단발적인 키 입력을 받기 좋음
- FixedUpdate : Update와 달리 일정한 시간으로 호출되는 함수, 지속적인 키 입력을 받기 좋음
업데이트 함수는 프레임 단위로 호출되기 때문에 물리 엔진과 다른 시간을 가진다고 합니다. 그래서 물리 충돌과 관련한 기능들은 FixedUpdate에서 구현해야 한다고 합니다.
<변수 설명>
Rigidbody2D rigid; SpriteRenderer spriteRenderer; Animator anim;
위 3개는 각각 플레이어의 리지드바디, 스프라이트랜더러, 애니메이션 컨트롤러를 가져오기 위한 변수로 Awake 함수에서 초기화 되었습니다.
public float maxSpeed; public float jumpPower; public int jumpCount = 0; public int maxJumpCount = 2;
maxSpeed의 경우 플레이어의 최대 이동 속도를 의미하며 jumpPower은 AddForce에서 Vector2.up에 곱해지게 됩니다.
jumpCount와 maxJumpCount는 각각 현재 플레이어의 점프 횟수와 최대 횟수를 의미합니다. maxJumpCount 변수 조작으로 점프 횟수를 조정할 수 있으며 이후 아이템 등을 통해서 늘어날 여지가 있게 public으로 선언했습니다.
// 방향을 가져오기 위한 변수 Vector3 dirVec; // 레이로 스캔하는 물체 받아오는 변수 GameObject scanObject;
위 두 변수는 플레이어 앞에 달려 있는 Ray의 방향을 정해주기 위해 있으며 dirVec에 방향이 달리게 되며 scanObject에는 Ray에 닿은 물체를 가져오게 됩니다.
<플레이어 이동>
1. 좌 우 이동
void Update(){ // 버튼에서 손을 떼면 움직임 멈춤 if(Input.GetButtonUp("Horizontal")){ rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.2f, rigid.velocity.y); } } void FixedUpdate(){ // 좌우 이동 float h = Input.GetAxisRaw("Horizontal"); rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse); // 최대 스피드 maxSpeed 를 넘지 못하게 함 if(rigid.velocity.x > maxSpeed) rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); else if(rigid.velocity.x < -maxSpeed) rigid.velocity = new Vector2(-maxSpeed, rigid.velocity.y); }
기본적으로 FixedUpdate에서 키보드 입력을 받습니다. 유니티 프로젝트 설정에 있는 Horizontal을 이용해 해당하는 키 (방향키, AD)를 입력받으면 rigid.AddForce를 통해 오른쪽으로 힘을 가해줍니다. 왼쪽의 경우 변수 h가 음수가 되어서 왼쪽으로 이동하게 됩니다.
일단 저 AddForce의 경우 물체에 계속해서 힘을 가하는것이라 속도가 점점 빨라지게 됩니다. 때문에 아래 if문을 통해 maxSpeed란 변수보다 빠를 수 없게 제어를 해 줍니다.
Update에 있는 코드는 키보드에서 손을 떼는 순간 속도를 급격하게 줄여 마찰과 공기저항 등을 통해 플레이어가 빠르게 정지할 수 있도록 해주는 코드입니다.
2. 점프
void Update(){ // 점프 if(Input.GetKeyDown(KeyCode.Space) && jumpCount < maxJumpCount){ rigid.velocity = Vector2.up * jumpPower; jumpCount++; } } void FixedUpdate(){ // 플레이어 아래로 쏘는 ray, 내려올때만 if(rigid.velocity.y < 0){ Debug.DrawRay(rigid.position, Vector3.down, new Color(1, 0, 0)); RaycastHit2D downRay = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Ground")); if(downRay.collider != null && downRay.distance < 0.5f){ Debug.Log("땅"); jumpCount = 0; } } }
좌우 이동의 경우 키보드를 지속적으로 누르는 반면 범프의 경우 단발적으로 누르는 이벤트라 Update에서 키 입력을 받는다고 합니다. (from. 유튜브) 점프를 했을 시 플레이어를 위로 띄우게 되고 이 때 jumpPower만큼 힘을 가하게 됩니다.
점프 횟수의 경우 maxJumpCount로 컨트롤하고 있는데 키 입력 점프시 jumpCount 변수를 1씩 증가시키고 키 입력에서 jumpCount < maxJumpCount인지 조건을 넣어줬습니다. 프로젝트에서는 maxJumpCount를 2로 두어서 2단 점프까지 할 수 있습니다.
jumpCount는 플레이어가 땅에 닿으면 0으로 초기화가 되며 플레이어가 땅에 닿는건 RaycastHit2D를 통해서, 이 Ray는 플레이어가 공중에서 떨어질때만 나오게 됩니다.
+ 점프 관련 개선점
- 지금의 Ray는 단일 ray로 플레이어 중심에서 내려오게 됩니다. 때문에 플랫폼 끝에 걸치는 경우 점프 초기화가 안되는 경우가 예상됩니다.
<애니메이션 전환>
애니메이션의 경우 스프라이트의 애니메이션이 다양하지 않아 좌우 전환, 달리기 모션만 처리했습니다.
1. Flip
void Update(){ // Flip if (Input.GetButton("Horizontal")) spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == 1; //바라보는 방향 float h = Input.GetAxisRaw("Horizontal"); if(h == -1) dirVec = Vector3.left; else if(h == 1) dirVec = Vector3.right; }
SpriteRenderer를 통해서 좌우 회전을 하게 되는데 인스펙터창의 Flip X가 눌려진게 true (==1) 눌리지 않은게 false (==0) 현재 스크립트가 담긴 스프라이트들에 따라 1로 만들지 -1로 만들지 살펴봐야 합니다.
아래 바라보는 방향의 경우 좌, 우 조사를 하기 위한 Ray가 플레이어 방향을 바라볼 수 있게끔 dirVec 변수에 담아주는 과정이며 dirVec는 전역변수입니다.
2. 애니메이션 전환
void Update(){ // 걷는 애니메이션 if (Mathf.Abs(rigid.velocity.x) < 0.2f || jumpCount > 0) //속도가 0이라면 = 단위벡터가 0 anim.SetBool("isWalk", false); else anim.SetBool("isWalk", true); }
애니메이션의 경우 idle, walk 2가지를 준비했으며 isWalk 변수가 true가 되면 걷는 애니메이션으로 변경되게 했습니다.
속도가 0이거나 jumpCount가 양수 (점프를 한 상태) 일 경우 isWalk는 false가 되어 idle 모션이 되고 외의 경우에는 걷는 모션이 됩니다.
<벽과의 충돌처리>
벽의 경우 material을 추가해 마찰을 0으로 만들어 플레이어가 매달릴 수 없게 만들었습니다.
반응형'쾌락없는 책임 (공부) > Unity' 카테고리의 다른 글
유니티 인게임 메뉴 만들기 - 게임 일시정지, 재시작 등 (0) 2021.03.14 유니티 2D 시네머신 사용기 - 맵 이동시, 카메라 전환, confiner change (2) 2021.03.13 유니티 - 플레이어에게 총을 쏘는 적 (0) 2021.01.15 유니티 - 플레이어 슬라이딩 구현 (0) 2021.01.04 유니티 - 보스몬스터 패턴 1 : 플레이어 감지 후 공격 (0) 2021.01.03