[ 타격감 있는 몬스터 처치 구현 ] --> 몬스터가 처치 될 때의 효과 넣기
- 기존의 Enemy 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float speed;
public float hp;
public float maxhhp;
public RuntimeAnimatorController[] animCon;
public Rigidbody2D target;
bool isLive;
Rigidbody2D rigid;
Collider2D coll;
Animator anim;
SpriteRenderer spriter;
WaitForFixedUpdate wait; // WaitForFixedUpdate 변수
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")){ // Hit 상태일 때, 몬스터가 정지
return;
}
Vector2 dirVec = target.position - rigid.position;
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 = 3;
anim.SetBool("Dead", false);
hp = maxhhp;
}
public void Init(SpawnData data){
anim.runtimeAnimatorController = animCon[data.spriteType];
speed = data.speed;
maxhhp = data.hp;
hp = data.hp;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (!collision.CompareTag("Bullet") || !isLive){
return;
}
hp -= collision.GetComponent<Bullet>().damage;
StartCoroutine(KnockBack()); // 현재 상태를 가져오는 함수 StartCoroutine()으로 KnockBack() 호출
if (hp > 0) {
anim.SetTrigger("Hit"); // Animator의 Hit 상태로 변경하기 위해, 트리거 Hit으로 변경
}
else{
isLive = false; // 몬스터가 사망
coll.enabled = false; // 충돌 로직 비활성화
rigid.simulated = false; // 물리적 상호작용 비활성화
spriter.sotringOrder = 1; // Order in Layer 설정
anim.SetBool("Dead", true); // 상태 : 사망
}
}
IEnumerator KnockBack(){ // 몬스터가 맞았을때 넉백효과
yield return wait; // 다음 하나의 물리 프레임을 딜레이
Vector3 playerPos = GameManager.instance.player.transform.position; // Player의 위치
Vector3 dirVec = transform.position - playerPos; // Player의 반대방향 = [현재 위치 - 플레이어 위치]
rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse); // Player의 반대방향으로 힘 가하기
}
void Dead(){
gameObject.SetActive(false);
}
}
- Animation의 Enemy파일에 애니메이션 열기(더블클릭)
- 키프레임 선택 후 Ctrl + C로 복사
- 1초 구간을 클릭하고 Ctrl + V로 붙여넣기
- 1초 구간에 Add Event --> Add Event 버튼을 통해 애니메이션 이벤트 추가
- Anim Con에 등록돼있는 몬스터 종류만큼 같은 작업 해주기 - 몬스터 프리펩 열기(더블클릭)
- Animation의 Event에 Dead() 함수 설정
- Enemy Inspector의 Controller를 바꿔가며 몬스터 종류만큼 같은 작업 해주기 - 기존의 GameManager 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager instance;
[Header("# Game Conrol")] // Header를 통해 이쁘게 구분
public float gameTime;
public float maxGameTime = 2 * 10f;
[Header("# Player Info")] // Header를 통해 이쁘게 구분
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")] // Header를 통해 이쁘게 구분
public PoolManager pool;
public Player player;
private 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 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float speed;
public float hp;
public float maxhhp;
public RuntimeAnimatorController[] animCon;
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")){
return;
}
Vector2 dirVec = target.position - rigid.position;
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 = 3;
anim.SetBool("Dead", false);
hp = maxhhp;
}
public void Init(SpawnData data){
anim.runtimeAnimatorController = animCon[data.spriteType];
speed = data.speed;
maxhhp = data.hp;
hp = data.hp;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (!collision.CompareTag("Bullet") || !isLive){ // 몬스터가 죽어있을 때, 피격효과X
return;
}
hp -= collision.GetComponent<Bullet>().damage;
StartCoroutine(KnockBack());
if (hp > 0) {
anim.SetTrigger("Hit");
}
else{
isLive = false;
coll.enabled = false;
rigid.simulated = false;
spriter.sortingOrder = 2;
anim.SetBool("Dead", true);
GameManager.instance.kill++; // kill수 증가
GameManager.instance.GetExp(); // 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);
}
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
★Slow and Steady★
'Unity 공부 > Unity_2D' 카테고리의 다른 글
| [Day 9] 능력 업그레이드 구현 (0) | 2023.07.15 |
|---|---|
| [Day 8] HUD 제작 (0) | 2023.07.14 |
| [Day 6] 자동 원거리 공격 구현 (0) | 2023.07.12 |
| [Day 5] 회전하는 근접무기 구현 (0) | 2023.07.11 |
| [Day 4] 소환 레벨 적용 (2) | 2023.07.10 |