일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- todolist
- 1월
- 다이나믹 프로그래밍
- 2월
- 2025년
- 골드메탈
- 5월
- 기초
- 입문
- 개인 프로젝트 - 런앤건
- 게임 엔진 공부
- 단계별로 풀어보기
- 수학
- 코딩 기초 트레이닝
- 2024년
- 프로그래머스
- 유니티
- 7월
- 3월
- 2022년
- 10월
- 4월
- 개인 프로젝트
- C/C++
- 2023년
- 코딩 테스트
- 자료 구조
- c++
- 백준
- 유니티 심화과정
- Today
- Total
기록 보관소
[Unity/유니티] 기초-2D 플랫포머: 플레이어 피격 이벤트 구현하기[B19] 본문
개요
유니티 입문과 독학을 위해서 아래 링크의 골드메탈님의 영상들을 보며 진행 상황 사진 또는 캡처를 올리고 배웠던 점을 요약해서 적는다.
현재는 영상들을 보고 따라하고 배우는 것에 집중할 것이며, 영상을 모두 보고 따라한 후에는 개인 프로젝트를 설계하고 직접 만드는 것이 목표다.
https://youtube.com/playlist?list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2
유니티 강좌 기초 채널 Basic
유니티 개발을 처음 시작하시는 입문자 분들을 위한 기초 채널. [ 프로젝트 ] B00 ~ B12 (BE1) : 유니티 필수 기초 B13 ~ B19 (BE2) : 2D 플랫포머 B20 ~ B26 (BE3) : 2D 탑다운 대화형 RPG B27 ~ B37 (BE4) : 2D 종스크롤
www.youtube.com
2D 플랫포머: 플레이어 피격 이벤트 구현하기[B19]
1. 함정(가시) 추가
- Tag와 Layer를 구분 지음으로써 같은 Enemy(몬스터/가시)끼리는 물리 충돌이 일어나지 않게 할 것이다. 즉, 몬스터는 플레이어와는 달리 가시를 통과할 수 있다.
2. 물리 레이어 설정
- 물리 레이어는 레이어끼리 충돌 설정을 관리할 수 있다.
- 현재 목적인 같은 Enemy끼리 물리 충돌이 일어나지 않도록 하려면, 물리 레이어에서 Enemy가 겹치는 부분을 체크 해제하면된다.
- PlayerDamaged 레이어는 이름처럼 플레이어가 피해를 입었을 때를 가르킨다. 플레이어가 피해를 한번에 연속해서 받지 않도록 일종의 무적 시간을 주기 위해, PlayerDamaged와 Enemy 레이어는 물리 충돌 체크를 해제해준다.
- 기본적으로 Player 스프라이트는 Player 레이어로 설정해둔다.
3. 몬스터와의 충돌 이벤트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour {
public float maxSpeed;
public float jumpPower;
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
Animator anim;
void Awake() {
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
rigid.freezeRotation = true; //이동시 굴러가기 방지
}
void Update() {
//점프
if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping")) { //스페이스바, 점프 애니메이션이 작동중이지 않다면
rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
anim.SetBool("isJumping", true); //Jump 애니메이션 추가
}
//멈출 때 속도
if (Input.GetButtonUp("Horizontal")) {
//normalized : 벡터 크기를 1로 만든 상태
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//방향 전환
if (Input.GetButton("Horizontal"))
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1; //-1은 왼쪽 방향
//애니메이션 전환
if (Mathf.Abs(rigid.velocity.x) < 0.3) //정지 상태, Mathf : 수학관련 함수를 제공하는 클래스
anim.SetBool("isWalking", false);
else
anim.SetBool("isWalking", true);
}
void FixedUpdate() {
float h = Input.GetAxisRaw("Horizontal"); //좌,우 A, D
rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);
//오른쪽 속도 조절
if (rigid.velocity.x > maxSpeed) //velocity : 리지드바디의 현재 속도
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); //y축 값을 0으로 하면 멈춤
//왼쪽 속도 조절
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
//점프 후 착지시 애니메이션 전환(레이캐스트)
if (rigid.velocity.y < 0) { //y축 속도 값이 0보다 클때만. 땅에 있으면 레이 표시 X
Debug.DrawRay(rigid.position, Vector3.down, new Color(0, 1, 0)); //레이 표시
RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform")); //레이에 닿는 물체
if (rayHit.collider != null) //레이에 닿는 물체가 있다면
if (rayHit.distance < 0.5f)
anim.SetBool("isJumping", false);
}
}
void OnCollisionEnter2D(Collision2D collision) { //충돌 발생시
if (collision.gameObject.tag == "Enemy") {
Debug.Log("플레이어가 맞았습니다");
}
}
}
- 만들어두었던 태그를 활용해서 플레이어가 몬스터와 가시에 닿으면 인식하게 만들었다.
4. 무적 시간 설정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour {
public float maxSpeed;
public float jumpPower;
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
Animator anim;
void Awake() {
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
rigid.freezeRotation = true; //이동시 굴러가기 방지
}
void Update() {
//점프
if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping")) { //스페이스바, 점프 애니메이션이 작동중이지 않다면
rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
anim.SetBool("isJumping", true); //Jump 애니메이션 추가
}
//멈출 때 속도
if (Input.GetButtonUp("Horizontal")) {
//normalized : 벡터 크기를 1로 만든 상태
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//방향 전환
if (Input.GetButton("Horizontal"))
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1; //-1은 왼쪽 방향
//애니메이션 전환
if (Mathf.Abs(rigid.velocity.x) < 0.3) //정지 상태, Mathf : 수학관련 함수를 제공하는 클래스
anim.SetBool("isWalking", false);
else
anim.SetBool("isWalking", true);
}
void FixedUpdate() {
float h = Input.GetAxisRaw("Horizontal"); //좌,우 A, D
rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);
//오른쪽 속도 조절
if (rigid.velocity.x > maxSpeed) //velocity : 리지드바디의 현재 속도
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); //y축 값을 0으로 하면 멈춤
//왼쪽 속도 조절
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
//점프 후 착지시 애니메이션 전환(레이캐스트)
if (rigid.velocity.y < 0) { //y축 속도 값이 0보다 클때만. 땅에 있으면 레이 표시 X
Debug.DrawRay(rigid.position, Vector3.down, new Color(0, 1, 0)); //레이 표시
RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform")); //레이에 닿는 물체
if (rayHit.collider != null) //레이에 닿는 물체가 있다면
if (rayHit.distance < 0.5f)
anim.SetBool("isJumping", false);
}
}
void OnCollisionEnter2D(Collision2D collision) { //충돌 발생시
if (collision.gameObject.tag == "Enemy") {
OnDamaged(collision.transform.position);
}
}
void OnDamaged(Vector2 targetPos) { //충돌 이벤트 무적 효과 함수
//레이어 변경(무적)
gameObject.layer = 11; //11번 레이어, PlayerDamaged
//충돌시 스프라이트 색상 변화
spriteRenderer.color = new Color(1, 1, 1, 0.4f); //Color(R,G,B,투명도)
//충돌시 튕겨짐
//목표물 기준 왼쪽에서 닿으면 왼쪽으로, 오른쪽에서 닿으면 오른쪽으로
int dirc = transform.position.x - targetPos.x > 0 ? 1 : -1;
rigid.AddForce(new Vector2(dirc, 1), ForceMode2D.Impulse);
}
}
- 이제 Enemy 레이어와 충돌시 무적 설정은 완료되었다. 하지만 아직 무적 해제는 작성하지 않았으므로 레이어가 계속 PlayerDamaged 상태로 존재한다. 따라서 무적 시간을 정하고 해제될 수 있도록 만들어야한다.
5. 무적 시간 해제
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour {
public float maxSpeed;
public float jumpPower;
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
Animator anim;
void Awake() {
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
rigid.freezeRotation = true; //이동시 굴러가기 방지
}
void Update() {
//점프
if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping")) { //스페이스바, 점프 애니메이션이 작동중이지 않다면
rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
anim.SetBool("isJumping", true); //Jump 애니메이션 추가
}
//멈출 때 속도
if (Input.GetButtonUp("Horizontal")) {
//normalized : 벡터 크기를 1로 만든 상태
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//방향 전환
if (Input.GetButton("Horizontal"))
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1; //-1은 왼쪽 방향
//애니메이션 전환
if (Mathf.Abs(rigid.velocity.x) < 0.3) //정지 상태, Mathf : 수학관련 함수를 제공하는 클래스
anim.SetBool("isWalking", false);
else
anim.SetBool("isWalking", true);
}
void FixedUpdate() {
float h = Input.GetAxisRaw("Horizontal"); //좌,우 A, D
rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);
//오른쪽 속도 조절
if (rigid.velocity.x > maxSpeed) //velocity : 리지드바디의 현재 속도
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); //y축 값을 0으로 하면 멈춤
//왼쪽 속도 조절
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
//점프 후 착지시 애니메이션 전환(레이캐스트)
if (rigid.velocity.y < 0) { //y축 속도 값이 0보다 클때만. 땅에 있으면 레이 표시 X
Debug.DrawRay(rigid.position, Vector3.down, new Color(0, 1, 0)); //레이 표시
RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform")); //레이에 닿는 물체
if (rayHit.collider != null) //레이에 닿는 물체가 있다면
if (rayHit.distance < 0.5f)
anim.SetBool("isJumping", false);
}
}
void OnCollisionEnter2D(Collision2D collision) { //충돌 발생시
if (collision.gameObject.tag == "Enemy") {
OnDamaged(collision.transform.position);
}
}
void OnDamaged(Vector2 targetPos) { //충돌 이벤트 무적 효과 함수
//레이어 변경(무적)
gameObject.layer = 11; //11번 레이어, PlayerDamaged
//충돌시 스프라이트 색상 변화
spriteRenderer.color = new Color(1, 1, 1, 0.4f); //Color(R,G,B,투명도)
//충돌시 튕겨짐
//목표물 기준 왼쪽에서 닿으면 왼쪽으로, 오른쪽에서 닿으면 오른쪽으로
int dirc = transform.position.x - targetPos.x > 0 ? 1 : -1;
rigid.AddForce(new Vector2(dirc, 1) * 7, ForceMode2D.Impulse);
Invoke("OffDamaged", 3); //3초 뒤 OffDamaged 함수 실행
}
void OffDamaged() { //충돌 이벤트 무적 해제 함수
//레이어 변경(원래대로)
gameObject.layer = 10; //10번 레이어, Player
spriteRenderer.color = new Color(1, 1, 1, 1);
}
}
- 이전에 배웠던 Invoke 함수를 활용해서 무적 시간(3초) 뒤에 레이어를 되돌리는 OffDamaged 함수를 실행하도록하면된다.
6. 애니메이션
- Damaged 애니메이션을 생성하고, Animation창을 열어서 첫번째 모션은 삭제하고, 두번째 모션을 복사해서 3초대에 붙여넣어 수정한다.
- Trigger : 방아쇠 역할의 매개변수, 값이 없다는 것이 특징이다.
- Any State -> Exit : 현재 상태 상관없이 실행 후 복귀. Damaged 애니메이션은 어떤 애니메이션(Idle, Walk, Jump) 중이든 충돌 이벤트가 발생하면 실행하고 복귀해야하므로 넣었다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour {
public float maxSpeed;
public float jumpPower;
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
Animator anim;
void Awake() {
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
rigid.freezeRotation = true; //이동시 굴러가기 방지
}
void Update() {
//점프
if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping")) { //스페이스바, 점프 애니메이션이 작동중이지 않다면
rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
anim.SetBool("isJumping", true); //Jump 애니메이션 추가
}
//멈출 때 속도
if (Input.GetButtonUp("Horizontal")) {
//normalized : 벡터 크기를 1로 만든 상태
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//방향 전환
if (Input.GetButton("Horizontal"))
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1; //-1은 왼쪽 방향
//애니메이션 전환
if (Mathf.Abs(rigid.velocity.x) < 0.3) //정지 상태, Mathf : 수학관련 함수를 제공하는 클래스
anim.SetBool("isWalking", false);
else
anim.SetBool("isWalking", true);
}
void FixedUpdate() {
float h = Input.GetAxisRaw("Horizontal"); //좌,우 A, D
rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);
//오른쪽 속도 조절
if (rigid.velocity.x > maxSpeed) //velocity : 리지드바디의 현재 속도
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); //y축 값을 0으로 하면 멈춤
//왼쪽 속도 조절
else if (rigid.velocity.x < maxSpeed*(-1))
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
//점프 후 착지시 애니메이션 전환(레이캐스트)
if (rigid.velocity.y < 0) { //y축 속도 값이 0보다 클때만. 땅에 있으면 레이 표시 X
Debug.DrawRay(rigid.position, Vector3.down, new Color(0, 1, 0)); //레이 표시
RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform")); //레이에 닿는 물체
if (rayHit.collider != null) //레이에 닿는 물체가 있다면
if (rayHit.distance < 0.5f)
anim.SetBool("isJumping", false);
}
}
void OnCollisionEnter2D(Collision2D collision) { //충돌 발생시
if (collision.gameObject.tag == "Enemy") {
OnDamaged(collision.transform.position);
}
}
void OnDamaged(Vector2 targetPos) { //충돌 이벤트 무적 효과 함수
//레이어 변경(무적)
gameObject.layer = 11; //11번 레이어, PlayerDamaged
//충돌시 스프라이트 색상 변화
spriteRenderer.color = new Color(1, 1, 1, 0.4f); //Color(R,G,B,투명도)
//충돌시 튕겨짐
//목표물 기준 왼쪽에서 닿으면 왼쪽으로, 오른쪽에서 닿으면 오른쪽으로
int dirc = transform.position.x - targetPos.x > 0 ? 1 : -1;
rigid.AddForce(new Vector2(dirc, 1) * 7, ForceMode2D.Impulse);
//애니메이션 변경
anim.SetTrigger("doDamaged");
Invoke("OffDamaged", 3); //3초 뒤 OffDamaged 함수 실행
}
void OffDamaged() { //충돌 이벤트 무적 해제 함수
//레이어 변경(원래대로)
gameObject.layer = 10; //10번 레이어, Player
spriteRenderer.color = new Color(1, 1, 1, 1);
}
}
- Trigger형 매개변수는 값이 없으므로 별 다른 입력없이 그냥 .SetTrigger("매개변수 이름")만 쓰면 발동한다. 피격 애니메이션이므로 OnDamaged 함수에 넣었다.
'유니티 프로젝트 > 2D 플랫포머' 카테고리의 다른 글
[Unity/유니티] 기초-2D 플랫포머: 스테이지를 넘나드는 게임 완성하기[BE2] (0) | 2022.02.15 |
---|---|
[Unity/유니티] 기초-2D 플랫포머: 몬스터 AI 구현하기[B18] (0) | 2022.02.13 |
[Unity/유니티] 기초-2D 플랫포머: 타일맵으로 플랫폼 만들기[B17] (0) | 2022.02.13 |
[Unity/유니티] 기초-2D 플랫포머: 플레이어 점프 구현하기[B16] (0) | 2022.02.11 |
[Unity/유니티] 기초-2D 플랫포머: 플레이어 이동 구현하기[B15] (0) | 2022.02.10 |