오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 29일차(팀 프로젝트 끝 )

2023. 12. 7. 22:10스파르타코딩클럽 게임개발

반응형

프로젝트가 끝났다.

발표도 마무리 되었고 코드 피드백은 받지 않았지만 기분 좋았다.

 

https://youtu.be/Iq0WOOD30RE?si=WkC-ZUF7DKxhQXfO

우리가 만들 게임의 시연영상

 

나는 여기서 스토리 몬스터, 몬스터 스프라이트를 맡았는데

 

더욱 많은 기능을 만들고 싶었지만  아쉽게도 유니티에 관련한 지식이 부족하여 더이상 기능을 추가 하지 못했다.

 

강의를 좀더 자세히 들었다면 더욱 기능을 추가할 수 있었겠지만 참 아쉽다.

 

스토리 신도 이미와 대사를 추가하고 좀 더 박진감있게 만들고 싶었지만 그러지 못했다.

 

하고싶은것이 많았기에 더욱 아쉬웠다.

 

우리 팀원들도 정말 열심히 했다..

 

내가 부족해서 몬스터 구현에 시간을 많이 잡아먹었다.;

 

조금더 공부하자

 

 

 

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  

public class Monster : MonoBehaviour  
{  
    public float speed;  
    public float health;  
    public float maxHealth;  
    public float Damege;  
    public bool IsBoss;  

    bool isLive;  

    public RuntimeAnimatorController\[\] animCon;  
    public Rigidbody2D target;  
    public AudioClip HitAudio;  

    Rigidbody2D rigid;  
    Collider2D coll;  
    Animator anim;  
    SpriteRenderer spriter;  
    WaitForFixedUpdate wait;  
    AudioSource ApplyDamage;  




    // \[우진영\] 드랍 아이템 연결을 위해 추가  
    public int exp;  
    public int money;  
    GameObject expPrefab;  
    GameObject moneyPrefab;  


    private void Awake()  
    {  
        ApplyDamage = GetComponent<AudioSource>();  
        rigid = GetComponent<Rigidbody2D>();  
        spriter = GetComponent<SpriteRenderer>();  
        anim = GetComponent<Animator>();  
        wait = new WaitForFixedUpdate();  
        coll = GetComponent<Collider2D>();  
        expPrefab = Resources.Load<GameObject>("Item/Droppable/Droppable Exp");  
        moneyPrefab = Resources.Load<GameObject>("Item/Droppable/Droppable Money");  
    }  

    void FixedUpdate()  
    {  
        if (IsBoss)  
        {  
            transform.localScale = new Vector3(10, 10, 1);  
            transform.localRotation = Quaternion.identity;  
        }  
        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;  
    }  

    private void LateUpdate()  
    {  
        if (GameManager.Instance.player.isDead) return;  

        if (!isLive) return;  
        spriter.flipX = target.position.x < rigid.position.x;  
    }  

    private 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;  
        Damege = data.Damege;  
        IsBoss = data.IsBoss;  
        exp = data.exp;  
        money = data.money;  
    }  

    private void OnTriggerEnter2D(Collider2D collision)  
    {  
        if (!collision.CompareTag("Weapon") || !isLive) return;  

        if (collision.GetComponent<Weapon>() != null)  
            health -= collision.GetComponent<Weapon>().Damage;  

        if (health > 0)  
        {  
            StartCoroutine(KnockBack());  
            ApplyDamage.clip = HitAudio;  
            ApplyDamage.Play();  
            anim.SetTrigger("Hit");  
        }  
        else  
        {  
            isLive = false;  
            coll.enabled = false;  
            rigid.simulated = false;  
            spriter.sortingOrder = 1;  
            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 Attack()  
    {  
        anim.SetTrigger("Attack");  
    }  

    void Dead()  
    {  
        gameObject.SetActive(false);  
        var expObj = Instantiate(expPrefab, transform.position, Quaternion.identity).GetComponent<Droppable\_EXP>();  
        var moneyObj = Instantiate(moneyPrefab, transform.position, Quaternion.identity).GetComponent<Droppable\_Money>();  
        expObj.value = exp;  
        moneyObj.value = money;  
        if (IsBoss) GameManager.Instance.GameOver(true);  
        transform.localScale = new Vector3(1, 1, 1);  
        transform.localRotation = Quaternion.identity;  
        spriter.color = Color.white;  

    }  
}

나의 몬스터 스크립트다.

여기에는 의도치 않는 코드가 있는데 바로 이부분인데

transform.localScale = new Vector3(1, 1, 1);

transform.localRotation = Quaternion.identity;

spriter.color = Color.white;

 

원래 dead가 아닌 OnEnable에서 실행되었어야 하는 코드다.

 

하지만 애니매이션이 거의 끝나는 상황에 저 OnEnable이 실행되어서 애니매이션 마지막의 장면에 있는 

 

스케일과 컬러 등 속성들이 그대로 옮겨지면서 새로 생겨나게 된다.

 

그러면 죽으면서 쓰러진 몬스터가 그 모습 그대로 다시 생성되서 누운채로 몬스터가 나타나는 것.

 

이 문제를 해결하기 위해 튜터님과 상담을 하였는데

 

코드로서 문제 해결은 하지 말고 run 애니매니션을 시작할때 스케일과 컬러 그리고 로테이션을 기본상태로 조정하면 

 

간편하게 해결 할 수 있다고 헀다.

 

다른 방법도 있는데 애니매이션을 강제로 코드로서 변환시켜 실행시킬수 있다고 한다.

 

그 방법을 사용하면 런으로 실행되면서 dead가 끝나기 때문에 다시 생성될때는 원래 상태 그대로 생성되는것

 

하지만 그 방법을 사용하면 코드와 애니매이터 두가지에서 애니매이션을 조정하게 되기 때문에 

 

한눈에 보기 어렵다고 한다.

 

그렇기 때문에 코드로만 사용하던가 애니매이터로만 사용해서 애니매이션을 조정하는 것이 중요하다.

 

 

반응형