Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 1월
- 수학
- 2월
- 코딩 테스트
- 7월
- 유니티
- 기초
- 백준
- 2023년
- 게임 엔진 공부
- 다이나믹 프로그래밍
- 2022년
- 6월
- 코딩 기초 트레이닝
- todolist
- 4월
- 2024년
- 5월
- 3월
- 입문
- 자료 구조
- 단계별로 풀어보기
- 개인 프로젝트 - 런앤건
- C/C++
- c++
- 개인 프로젝트
- 유니티 심화과정
- 골드메탈
- 2025년
- 프로그래머스
Archives
- Today
- Total
기록 보관소
[Unity/유니티] 기초-뱀서라이크: 타격감 있는 몬스터 처치 만들기[09] 본문
개요
유니티 독학을 위해 아래 링크의 골드메탈님의 영상들을 보고 직접 따라 해보면서 진행 상황을 쓰고 배웠던 점을 요약한다.
https://youtube.com/playlist?list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2
📚유니티 기초 강좌
유니티 게임 개발을 배우고 싶은 분들을 위한 기초 강좌
www.youtube.com
뱀서라이크: 타격감 있는 몬스터 처치 만들기[09]
1. 피격 리액션
//Enemy Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public RuntimeAnimatorController[] animCon;
public float health;
public float maxHealth;
public float speed;
public Rigidbody2D target; //쫓아갈 타겟(플레이어)
bool isLive;
Animator anim;
Rigidbody2D rigid;
SpriteRenderer spriter;
WaitForFixedUpdate wait;
void Awake() {
anim = GetComponent<Animator>();
rigid = GetComponent<Rigidbody2D>();
spriter = GetComponent<SpriteRenderer>();
wait = new WaitForFixedUpdate();
}
void FixedUpdate() {
if (!isLive || anim.GetCurrentAnimatorStateInfo(0).IsName("Hit")) //GetCurrentAnimationStateInfo : 현재 상태 정보를 가져오는 함수
return;
Vector2 dirVec = target.position - rigid.position; // 방향 = 위치 차이의 정규화(Normalized). 위치 차이 = 타겟 위치 - 나의 위치.
Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
rigid.MovePosition(rigid.position + nextVec); //플레이어의 키 입력값을 더한 이동 = 몬스터의 방향 값을 더한 이동
rigid.velocity = Vector2.zero; //물리 속도가 이동에 영향을 주지 않도록 속도 제거
}
void LateUpdate() {
if (!isLive)
return;
spriter.flipX = target.position.x < rigid.position.x;
}
void OnEnable() {
target = GameManager.instance.player.GetComponent<Rigidbody2D>(); //플레이어 할당
isLive = true;
health = maxHealth;
}
//데이터를 가져오기 위한 초기화 함수
public void Init(SpawnData data) {
anim.runtimeAnimatorController = animCon[data.spriteType];
speed = data.speed;
maxHealth = data.health;
health = data.health;
}
void OnTriggerEnter2D(Collider2D collision) {
if (!collision.CompareTag("Bullet"))
return;
health -= collision.GetComponent<Bullet>().damage; //총알 데미지만큼 Enemy 체력 감소
StartCoroutine(KnockBack());
if(health > 0) {
anim.SetTrigger("Hit");
}
else {
// .. Die
Dead();
}
}
IEnumerator KnockBack() {
yield return wait; //다음 하나의 물리 프레임 딜레이
Vector3 playerPos = GameManager.instance.player.transform.position;
Vector3 dirVec = transform.position - playerPos;
rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse);
}
void Dead() {
gameObject.SetActive(false);
}
}
- 몬스터는 rigidbody를 통해 물리적인 방법으로 플레이어를 향해 이동하기 때문에, Fixed Update에서 animation 상태에 따른 조건을 주지 않으면 KnockBack이 발동하지 않게 된다.
- 따라서 KnockBack을 정상적으로 실행하려면 위와 같이 Fixed Update의 if문에 조건을 추가해서 Hit 상태일 때는 이동하지 않게끔 만들어줘야한다.
2. 사망 리액션
//Enemy Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public RuntimeAnimatorController[] animCon;
public float health;
public float maxHealth;
public float speed;
public Rigidbody2D target; //쫓아갈 타겟(플레이어)
bool isLive;
Rigidbody2D rigid;
Collider2D coll;
Animator anim;
SpriteRenderer spriter;
WaitForFixedUpdate wait;
void Awake() {
rigid = GetComponent<Rigidbody2D>();
coll = GetComponent<Collider2D>();
anim = GetComponent<Animator>();
spriter = GetComponent<SpriteRenderer>();
wait = new WaitForFixedUpdate();
}
void FixedUpdate() {
if (!isLive || anim.GetCurrentAnimatorStateInfo(0).IsName("Hit")) //GetCurrentAnimationStateInfo : 현재 상태 정보를 가져오는 함수
return;
Vector2 dirVec = target.position - rigid.position; // 방향 = 위치 차이의 정규화(Normalized). 위치 차이 = 타겟 위치 - 나의 위치.
Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
rigid.MovePosition(rigid.position + nextVec); //플레이어의 키 입력값을 더한 이동 = 몬스터의 방향 값을 더한 이동
rigid.velocity = Vector2.zero; //물리 속도가 이동에 영향을 주지 않도록 속도 제거
}
void LateUpdate() {
if (!isLive)
return;
spriter.flipX = target.position.x < rigid.position.x;
}
void OnEnable() {
target = GameManager.instance.player.GetComponent<Rigidbody2D>(); //플레이어 할당
isLive = true;
coll.enabled = true;
rigid.simulated = true;
spriter.sortingOrder = 2;
anim.SetBool("Dead", false);
health = maxHealth;
}
//데이터를 가져오기 위한 초기화 함수
public void Init(SpawnData data) {
anim.runtimeAnimatorController = animCon[data.spriteType];
speed = data.speed;
maxHealth = data.health;
health = data.health;
}
void OnTriggerEnter2D(Collider2D collision) {
if (!collision.CompareTag("Bullet"))
return;
health -= collision.GetComponent<Bullet>().damage; //총알 데미지만큼 Enemy 체력 감소
StartCoroutine(KnockBack());
if(health > 0) {
anim.SetTrigger("Hit");
}
else {
isLive = false;
coll.enabled = false;
rigid.simulated = false; //rigidbody의 물리적 비활성화는 simulated를 false로 설정.
spriter.sortingOrder = 1; //SpriteRenderer의 Sorting Order를 감소시켜 다른 몬스터를 가리지 않게 함.
anim.SetBool("Dead", true);
}
}
IEnumerator KnockBack() {
yield return wait; //다음 하나의 물리 프레임 딜레이
Vector3 playerPos = GameManager.instance.player.transform.position;
Vector3 dirVec = transform.position - playerPos;
rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse);
}
void Dead() {
gameObject.SetActive(false);
}
}
- 이와 같이 Animation의 Event를 통해서 Enemy 스크립트의 Dead() 함수를 애니메이션을 통해 실행시킬 수 있다.
3. 처치 데이터 읽기
//GameManager Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
public static GameManager instance;
[Header("# Game Control")]
public float gameTime; //게임 시간 변수
public float maxGameTime = 2 * 10f; //최대 게임 시간 변수(20초).
[Header("# Player Info")]
public int level;
public int kill;
public int exp;
public int[] nextExp = { 3, 5, 10, 100, 150, 210, 280, 360, 450, 600 };
[Header("# Game Object")]
public PoolManager pool;
public Player player;
void Awake() {
instance = this;
}
void Update() {
gameTime += Time.deltaTime;
if (gameTime > maxGameTime) {
gameTime = maxGameTime;
}
}
public void GetExp() {
exp++;
if (exp == nextExp[level]) {
level++;
exp = 0;
}
}
}
//Enemy Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public RuntimeAnimatorController[] animCon;
public float health;
public float maxHealth;
public float speed;
public Rigidbody2D target; //쫓아갈 타겟(플레이어)
bool isLive;
Rigidbody2D rigid;
Collider2D coll;
Animator anim;
SpriteRenderer spriter;
WaitForFixedUpdate wait;
void Awake() {
rigid = GetComponent<Rigidbody2D>();
coll = GetComponent<Collider2D>();
anim = GetComponent<Animator>();
spriter = GetComponent<SpriteRenderer>();
wait = new WaitForFixedUpdate();
}
void FixedUpdate() {
if (!isLive || anim.GetCurrentAnimatorStateInfo(0).IsName("Hit")) //GetCurrentAnimationStateInfo : 현재 상태 정보를 가져오는 함수
return;
Vector2 dirVec = target.position - rigid.position; // 방향 = 위치 차이의 정규화(Normalized). 위치 차이 = 타겟 위치 - 나의 위치.
Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
rigid.MovePosition(rigid.position + nextVec); //플레이어의 키 입력값을 더한 이동 = 몬스터의 방향 값을 더한 이동
rigid.velocity = Vector2.zero; //물리 속도가 이동에 영향을 주지 않도록 속도 제거
}
void LateUpdate() {
if (!isLive)
return;
spriter.flipX = target.position.x < rigid.position.x;
}
void OnEnable() {
target = GameManager.instance.player.GetComponent<Rigidbody2D>(); //플레이어 할당
isLive = true;
coll.enabled = true;
rigid.simulated = true;
spriter.sortingOrder = 2;
anim.SetBool("Dead", false);
health = maxHealth;
}
//데이터를 가져오기 위한 초기화 함수
public void Init(SpawnData data) {
anim.runtimeAnimatorController = animCon[data.spriteType];
speed = data.speed;
maxHealth = data.health;
health = data.health;
}
void OnTriggerEnter2D(Collider2D collision) {
if (!collision.CompareTag("Bullet") || !isLive)
return;
health -= collision.GetComponent<Bullet>().damage; //총알 데미지만큼 Enemy 체력 감소
StartCoroutine(KnockBack());
if(health > 0) {
anim.SetTrigger("Hit");
}
else {
isLive = false;
coll.enabled = false;
rigid.simulated = false; //rigidbody의 물리적 비활성화는 simulated를 false로 설정.
spriter.sortingOrder = 1; //SpriteRenderer의 Sorting Order를 감소시켜 다른 몬스터를 가리지 않게 함.
anim.SetBool("Dead", true);
GameManager.instance.kill++;
GameManager.instance.GetExp();
}
}
IEnumerator KnockBack() {
yield return wait; //다음 하나의 물리 프레임 딜레이
Vector3 playerPos = GameManager.instance.player.transform.position;
Vector3 dirVec = transform.position - playerPos;
rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse);
}
void Dead() {
gameObject.SetActive(false);
}
}
'유니티 프로젝트 > 뱀서라이크' 카테고리의 다른 글
[Unity/유니티] 기초-뱀서라이크: 능력 업그레이드 구현[11] (0) | 2023.07.12 |
---|---|
[Unity/유니티] 기초-뱀서라이크: HUD 제작하기[10] (0) | 2023.07.11 |
[Unity/유니티] 기초-뱀서라이크: 자동 원거리 공격 구현[08] (0) | 2023.06.04 |
[Unity/유니티] 기초-뱀서라이크: 회전하는 근접무기 구현[07] (0) | 2023.06.01 |
[Unity/유니티] 기초-뱀서라이크: 소환 레벨 적용하기[06+] (0) | 2023.05.29 |