K-digital traning/Final Project

Gazzlers 개발일지 - Enemy1 공격 구현

내꺼블로그 2023. 11. 3. 16:35

(1) 총구가 Player를 향하도록 조준하는 부분

 

*Enemy1가 실시간으로 Player를 향해 LookAt을 하는 방식으로 구현

 

 

TestEnemy1Main.cs

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

public class TestEnemy1Main : MonoBehaviour
{
    [SerializeField]
    private Enemy1 enemy1;
    [SerializeField]
    private Transform Player;

    void Update()
    {
        this.enemy1.AimPlayer(this.Player);
    }
}

 

 

 

Enemy1.cs

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

public class Enemy1 : MonoBehaviour
{
    public void AimPlayer(Transform player)
    {
        this.transform.LookAt(player);
    }
}

 

 

 

 

 

 

 

조준은 되지만 움직임과 동시에 조준이 되고 있는 상황. Player의 움직임보다 늦게 조준이 되도록 수정한다.

 

 

 

 

응,,,무리,,,,,,,,,

처음 시도 : coroutine을 돌려 Player보다 느리게 움직이도록 하기 => Enemy1이 안움직이는 상황 발생(coroutine이 돌아가지고 않음)

두번째 시도 : Invoke를 사용하여 Enemy1이 좀 더 늦게 조준하도록 하기 => 늦게 돌리나 조준이 매끄럽게 이루어지지 않음.

 

결국 시도해봐야 되는 부분 => player의 위치값을 받고 slerp을 사용하여 직접 enemy1을 rotation하기.

우선 디테일한 부분은 좀 때려치우고(?) 빨리 다음 구현으로 넘어가쟈ㄱㄱ

 

 

 

(2) 총알 발사

 

 

 

1) 4초마다 3번씩 발사

 - Main.cs에서 coolTime을 관리하도록 하여 4초가 경과될 때마다 enemy1에게 player를 공격하도록 지시한다.

 - Coroutine을 사용하여 enemy1이 약간의 시간 간격을 두고 총알을 발사하도록 한다.

 - coolTime은 enemy1이 총알을 다 발사하고 난 뒤에 돌아야 하므로 대리자를 사용하여 enemy1이 Main에게 공격이 끝났음을 알려주도록 한다.

 

TestEnemy1Main.cs

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

    public class TestEnemy1Main : MonoBehaviour
    {
        [SerializeField]
        private Enemy1 enemy1;
        [SerializeField]
        private Transform player;
        private float coolTime = 4f;
        private float elapsedTime;
        private bool isAttack;
        void Start()
        {
            //enemy1이 공격이 끝났음을 알림.
            this.enemy1.onCompleteAttack = () =>
            {
                Debug.Log("Attack Complete");
                this.isAttack = false;      //공격상태 아님을 나타냄.
            };
        }

        // Update is called once per frame
        void Update()
        {
            this.enemy1.AimTarget(this.player);

            //공격중이 아닐 경우 elapsedTime 추가
            if (!this.isAttack)
                this.elapsedTime += Time.deltaTime;

            //쿨타임이 다 찼을 경우 공격.
            if(this.elapsedTime >= this.coolTime)
            {
                this.enemy1.AttackPlayer();
                this.isAttack = true;
                this.elapsedTime = 0;
            }
        }
    }

 

 

 

Enemy1.cs

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

    public class Enemy1 : MonoBehaviour
    {
        [SerializeField]
        private Transform muzzleTrans;
        private int attackCount = 3;                //최대 공격 횟수
        private float dealLossTime = 0.4f;          //공격 빈도

        public System.Action onCompleteAttack;
        public void AimTarget(Transform target)
        {
            this.transform.LookAt(target);
        }

        //player 공격 method
        public void AttackPlayer()
        {
            StartCoroutine(this.CoAttackPlayer());
        }

        //dealLossTime에 맞춰 player를 공격하는 method
        private IEnumerator CoAttackPlayer()
        {
            for(int i = 0; i < this.attackCount; i++)
            {
                BulletGenerator.Instance.GenerateBullet(this.muzzleTrans);
                yield return new WaitForSeconds(this.dealLossTime);
            }
            this.onCompleteAttack();        //공격이 완료되면 대리자를 사용하여 TestEnemy1Main.cs에게 공격 완료를 알림.
        }
    }

 

 

 

BulletGenerator.cs

 

 

 

Hierarchy

 

 

 

 

결과

 

 

 

 

2) BulletGenerator에서 실제 총알을 생성하여 발사

    - 총알이 player를 향해 가속을 받으며 날아옴

    - player보다 position.z값이 더 낮아지거나 player와 충돌할시 총알은 사라짐(player와 충돌시는 아직 구현하지 못함)

 

 

BulletGenerator.cs

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

namespace SJY
{
    public class BulletGenerator : MonoBehaviour
    {
        public static BulletGenerator Instance;
        [SerializeField]
        private GameObject bulletPrefab;
        private void Awake()
        {
            Instance = this;
        }

        public void GenerateBullet(Transform parent)
        {
            GameObject bulletGo = Instantiate(bulletPrefab, parent);
            bulletGo.transform.SetParent(null);
        }
    }
}

 

 

 

 

 

 

 

총구 위치로 총알을 생성

 

 

 

 

 

Bullet.cs

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

namespace SJY
{
    public class Bullet : MonoBehaviour
    {
        private Transform target;
        private Rigidbody rBody;
        public float maxSpeed = 10f;
        public float moveForce = 2.0f;
        // Start is called before the first frame update
        void Start()
        {
            this.target = GameObject.Find("CenterEyeAnchor").transform;
            this.rBody = this.GetComponent<Rigidbody>();
        }

        // Update is called once per frame
        void Update()
        {
            //player 방향으로 총알에 AddForce
            this.transform.LookAt(this.target);
            this.rBody.AddForce(this.transform.forward * this.moveForce, ForceMode.Acceleration);

            //총알 속도 조절
            if(this.rBody.velocity.magnitude > this.maxSpeed)
            {
                this.rBody.velocity = this.rBody.velocity.normalized * this.maxSpeed;
            }


            //총알이 player보다 뒤로 갈 시 destroy
            if(this.transform.position.z<=this.target.position.z)
            {
                Destroy(this.gameObject);
            }
        }
    }
}