본문 바로가기

Unity 공부/Unity_2D

[Day 7] 타격감 있는 몬스터 처치 구현

[ 타격감 있는 몬스터 처치 구현 ] --> 몬스터가 처치 될 때의 효과 넣기

  • 기존의 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