본문 바로가기

유니티/유니티 연습프로젝트

[유니티/연습 프로젝트] 몬스터 스폰, 피격, 처치 구현

728x90
반응형

몬스터 HP바

 

Canvas위에 Image 2개를 생성하여 HP바를 구현하였다.

 

HP바가 항상 몬스터의 머리 위에 떠있게 유지시키기 위해서 몬스터의 좌표를 Canvas좌표로 변환하여

두 개의 Image에 전달해주었다.

 

public class EnemyMove : MonoBehaviour
{
    public float hp;
    public RectTransform HpBar;
    public RectTransform HpBarBackGround;

    // Start is called before the first frame update
    void Start()
    {
        hp = 10;
    }

    // Update is called once per frame
    void Update()
    {
        HpBar.position = Camera.main.WorldToScreenPoint(new Vector2(transform.position.x, transform.position.y + 1));
        HpBarBackGround.position = Camera.main.WorldToScreenPoint(new Vector2(transform.position.x, transform.position.y + 1));
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

몬스터 피격

 

몬스터 피격 시 hp를 damage만큼 감소시키는 함수를 선언하고 PlayerMove 스크립트에서 피격 시 호출하였다.

 

public void EnemyTakeDamage(int damage)
{
    hp -= damage;
    HpBar.GetComponent<Image>().fillAmount = (float)hp / 10f;
    Debug.Log(hp);
}

 

 

 

 

PlayerMove 스크립트

 

damage 함수를 호출함과 동시에 Vector2.Lerp 함수를 사용하여 넉백까지 구현하였다.

 

Collider2D[] collider2Ds = Physics2D.OverlapBoxAll(AttackPos.position, AttackBoxSize, 0);
foreach (Collider2D collider in collider2Ds)
{
    if (collider.name == "Enemyprf(Clone)")
    {
        Enemy.GetComponent<EnemyMove>().EnemyTakeDamage(damage);
        if (RightState == true)
            EnemyKnockBackPos = new Vector2(Enemy.transform.position.x + 0.1f, Enemy.transform.position.y);
        else
            EnemyKnockBackPos = new Vector2(Enemy.transform.position.x - 0.1f, Enemy.transform.position.y);
    }
}

 

Enemy.transform.position = Vector2.Lerp(Enemy.transform.position, EnemyKnockBackPos, 10 * Time.deltaTime);

 

 

 

 

 

 

 

 

 

 

 

 

 몬스터 스폰

 

빈 오브젝트에 스크립트를 적용시키고 프리팹을 만들어서 몬스터의 스폰을 구현하였다.

 

적용된 코드는 다음과 같다.

 

public class EnemyGenerate : MonoBehaviour
{
    public GameObject Enemyprf;

    // Start is called before the first frame update
    void Start()
    {
        GameObject Enemy = Instantiate(Enemyprf) as GameObject;
        Enemy.transform.position = new Vector2(Random.Range(-55, 73) / 10f, -3.55f);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

 

 

 

 

 

 

 

 

 몬스터 처치

 

몬스터의 HP가 0이하가 되면 Destory함수를 사용하여 프리팹을 삭제하고 Player의 경험치를 1 증가시켜준다.

 

if (hp <= 0)
{
    player.GetComponent<PlayerMove>().exp++;
    Destroy(gameObject);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 최종코드

 

EnemyGenerate script

 

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

public class EnemyGenerate : MonoBehaviour
{
    public GameObject Enemyprf;
    // Start is called before the first frame update
    void Start()
    {
        GameObject Enemy = Instantiate(Enemyprf) as GameObject;
        Enemy.transform.position = new Vector2(Random.Range(-55, 73) / 10f, -3.55f);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

 

 

EnemyMove script

 

using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class EnemyMove : MonoBehaviour
{
    Rigidbody2D MyRigidbody2D;
    public float hp;
    public RectTransform HpBar;
    public RectTransform HpBarBackGround;
    GameObject player;

    public void EnemyTakeDamage(int damage)
    {
        hp -= damage;
        HpBar.GetComponent<Image>().fillAmount = (float)hp / 10f;
        Debug.Log(hp);
    }

    // Start is called before the first frame update
    void Start()
    {
        hp = 10;
        MyRigidbody2D = GetComponent<Rigidbody2D>();
        player = GameObject.Find("Player");
    }

    // Update is called once per frame
    void Update()
    {
        HpBar.position = Camera.main.WorldToScreenPoint(new Vector2(transform.position.x, transform.position.y + 1));
        HpBarBackGround.position = Camera.main.WorldToScreenPoint(new Vector2(transform.position.x, transform.position.y + 1));
        if (hp <= 0)
        {
            player.GetComponent<PlayerMove>().exp++;
            Destroy(gameObject);
        }
        
    }
}

 

 

 

 

PlayerMove script

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UIElements;

public class PlayerMove : MonoBehaviour
{
    Rigidbody2D MyRigidbody2D;
    Animator MyAnimator;

    
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.name == "Ground")
            GroundTag = true;
    }

    public int exp = 0;
    public int level = 1;
    public int speed = 15;
    public int jumpforce = 8;
    public int damage = 1;
    private float AttackTime = 0.56f;
    public float CurAttackTime = 0;
    public GameObject Enemy;
    public Transform AttackPos;
    private Vector2 AttackBoxSize = new Vector2(0.94f, 1.19f);
    private Vector2 EnemyKnockBackPos;
    bool RightState;
    bool GroundTag = false;
    

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(AttackPos.position, AttackBoxSize);
    }


    // Start is called before the first frame update
    void Start()
    {
        MyRigidbody2D = GetComponent<Rigidbody2D>();
        MyAnimator = GetComponent<Animator>();
        RightState = true;
        Enemy = GameObject.Find("Enemyprf(Clone)");
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Enemy == null)
            Enemy = GameObject.Find("Enemyprf(Clone)");
        MyAnimator.SetBool("Walk", false);
        MyAnimator.SetBool("Attack", false);


        if (CurAttackTime <= 0 && Input.GetKey(KeyCode.RightArrow))
        {
            MyAnimator.SetBool("Walk", true);
            transform.Translate(0.001f * speed, 0, 0);
            transform.localScale = Vector2.one;
            RightState = true;
        }
        if (CurAttackTime <= 0 && Input.GetKey(KeyCode.LeftArrow))
        {
            MyAnimator.SetBool("Walk", true);
            transform.Translate(-0.001f * speed, 0, 0);
            transform.localScale = new Vector2(-1, 1);
            RightState = false;
        }

        if (Input.GetKeyDown(KeyCode.LeftAlt) && (GroundTag && CurAttackTime <= 0))
        {
            GroundTag = false;
            MyRigidbody2D.AddForce(new Vector2(0, 100*jumpforce));
        }





        if (CurAttackTime <= 0 && Input.GetKeyDown(KeyCode.LeftControl))  // 공격시작
        {
            if (RightState == true)
                AttackPos.position = new Vector2(transform.position.x + 1.255f, transform.position.y - 0.3f);
            else
                AttackPos.position = new Vector2(transform.position.x - 1.255f, transform.position.y - 0.3f);

            CurAttackTime = AttackTime;
            if (Enemy != null)
            {
                Collider2D[] collider2Ds = Physics2D.OverlapBoxAll(AttackPos.position, AttackBoxSize, 0);
                foreach (Collider2D collider in collider2Ds)
                {
                    if (collider.name == "Enemyprf(Clone)")
                    {
                        Enemy.GetComponent<EnemyMove>().EnemyTakeDamage(damage);
                        if (RightState == true)
                            EnemyKnockBackPos = new Vector2(Enemy.transform.position.x + 0.1f, Enemy.transform.position.y);
                        else
                            EnemyKnockBackPos = new Vector2(Enemy.transform.position.x - 0.1f, Enemy.transform.position.y);
                        
                    }
                }
            }
        }
        else if (CurAttackTime >= 0.3f)
        {
            MyAnimator.SetBool("Attack", true);
            if (Enemy != null)
	            Enemy.transform.position = Vector2.Lerp(Enemy.transform.position, EnemyKnockBackPos, 10 * Time.deltaTime);
        }
        if (CurAttackTime >= 0)
            CurAttackTime -= Time.deltaTime;

    }
}

 

 

 

 

 

 

 

 수정할 점

 

프리팹을 생성하여 여러 마리의 몬스터를 생성해보았는데 생성된 객체의 이름이 전부 같다보니 몬스터를 공격할 때

다른 몬스터의 체력이 감소하는 오류가 있었다.

 

오버랩 박스로 충돌을 감지할 때 충돌된 오브젝트에 접근하던가 피격 구현 코드를 EnemyMove 스크립트에 작성하여서

프리팹에 복제될 수 있도록 변경해야할 것 같다.

 

 

 

 

 

 

 

728x90
반응형