[골드메탈 BE4] 따라하기 4

배근철·2022년 8월 1일
0

GoldMetal BE4

목록 보기
4/11

✍ 적 생성 강화

  • 정면에서만 적이 나오는게 아니라 좌 우 에서도 나오도록 스폰지역을 추가함
  • 좌,우에서 적이 등장하면 velocity가 아래가 아니므로, 코드를 수정
  • 생성 위치에 따라 속도를 다르게 설정하고, 속도 방향에 따라 적 비행기 회전을 적용
  • z축 Rotate 90도
  • Vector3.back*90 -> Vector3.back = (0,0,-1)
  • Vector3.forward*90 -> Vector3.forward = (0,0,1)

적 생성 코드

 void SpawnEnemy()
    {
        int randomEnemy = Random.Range(0, 3);
        int spawnPoint = Random.Range(0, 7);

        GameObject enemy = Instantiate(enemyObjs[randomEnemy], spawnPoints[spawnPoint].position, spawnPoints[spawnPoint].rotation);

        Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
        Enemy enemyLogic = enemy.GetComponent<Enemy>();
        enemyLogic.player = player;

        if(spawnPoint == 5) // Left Spawn
        {
            enemy.transform.Rotate(Vector3.forward * 90);
            rigid.velocity = new Vector2(1, -enemyLogic.speed);
        }

        else if(spawnPoint == 6) // Right Spawn
        {
            enemy.transform.Rotate(Vector3.back * 90);
            rigid.velocity = new Vector2(-1, -enemyLogic.speed);
        }

        else // Front Spawn
        {
            rigid.velocity = new Vector2(0, -enemyLogic.speed);
        }
    
    }

✍ 적 공격 구현

  • 적의 총알을 프리펩으로 만들어서 구현하기.
  • 플레이어 프리펩을 복사해서 만들고 Open Prefab으로 적의 총알에 맞게 수정한다.
  • 위 그림처럼 Scene옆에 생겨나고 수정을 다 한 후 , Scene을 누르면 자동으로 저장되고 Scene화면으로 돌아간다.
  • 이름과 태그 Collider를 적절히 수정해준다.
  • 플레이어의 로직을 재활용해서 만든다.
  • 적의 총알은 플레이어를 향해 쏘므로 플레이어 변수가 필요하다.
    -> 그런데 프리펩은 이미 scene에 올라온 오브젝트에 접근이 불가능하다.
    -> 즉, Enemy에 Player 변수를 넣을 수 없다.
    • 적 생성 직후 플레이어 변수를 넘겨주는 것으로 해결.
    • GameManager에서 Player를 적이 생성할 때 함수로 넘겨준다.
      enemyLogic.player = player;
  • 목표물로의 방향은 목표물위치 - 자신의 위치
 Vector3 dirVecR = player.transform.position - (transform.position + Vector3.right * 0.3f);
  • 즉 플레이어의 위치 - 적의 위치가 적이 플레이어를 쏘는 방향
  • 프리펩에 프리펩 오브젝트는 할당이 가능하므로, Enemy에 EnemyBullet변수는 넣을 수 있다.
  • 총알속도가 너무 빠르다 -> 좌표를 그대로 사용했기때문
  • 좌표를 단위화 시켜야 된다.
  • 단위벡터 만드는법 -> 벡터.normalized -> 벡터가 단위값으로 변환
    rigidR.AddForce(dirVecR.normalized * 4, ForceMode2D.Impulse);

전체 Enemy 코드

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

public class Enemy : MonoBehaviour
{
    public string enemyName;
    public float speed;
    public int health;
    public float curShotDelay;
    public float maxShotDelay;

    public Sprite[] sprites;

    public GameObject BulletA;
    public GameObject BulletB;
    public GameObject player;

    SpriteRenderer spriteRenderer;


    void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    void Update()
    {
        Fire();
        Reload();
    }

    void Reload()
    {
        curShotDelay += Time.deltaTime;
    }

    void Fire()
    {

        if (curShotDelay < maxShotDelay)
            return;


       if(enemyName == "S")
        {
            GameObject Bullet = Instantiate(BulletA, transform.position, transform.rotation);
            Rigidbody2D rigid = Bullet.GetComponent<Rigidbody2D>();

            Vector3 dirVec = player.transform.position - transform.position;
            rigid.AddForce(dirVec.normalized * 10, ForceMode2D.Impulse);
        }

       else if(enemyName == "L")
        {
            GameObject BulletR = Instantiate(BulletB, transform.position + Vector3.right * 0.3f, transform.rotation);
            GameObject BulletL = Instantiate(BulletB, transform.position + Vector3.left * 0.3f, transform.rotation);
            Rigidbody2D rigidR = BulletR.GetComponent<Rigidbody2D>();
            Rigidbody2D rigidL = BulletL.GetComponent<Rigidbody2D>();
            Vector3 dirVecR = player.transform.position - (transform.position + Vector3.right * 0.3f);
            Vector3 dirVecL = player.transform.position - (transform.position + Vector3.left * 0.3f);
            rigidR.AddForce(dirVecR.normalized * 4, ForceMode2D.Impulse);
            rigidL.AddForce(dirVecL.normalized * 4, ForceMode2D.Impulse);
        }


        curShotDelay = 0;
    }


    void onDamaged(int dmg)
    {
        health -= dmg;
        spriteRenderer.sprite = sprites[1];
        Invoke("ReturnSprite", 0.1f);

        if (health <= 0)
            Destroy(gameObject);
    }

    void ReturnSprite()
    {
        spriteRenderer.sprite = sprites[0];
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "BorderBullet")
            Destroy(gameObject);

        else if(collision.gameObject.tag == "PlayerBullet")
        {
            Bullet bullet = collision.gameObject.GetComponent<Bullet>(); // collision.gameObject에서 GetComponent한다
            onDamaged(bullet.dmg);
            Destroy(collision.gameObject);
        }
    }
}

✍ 피격이벤트 구현

  • Player의 OnTriggerEnter에서 적이랑 부딪히거나, 적의 총알에 맞았을 때 상황 구현
  • UI를 구현하기 전이므로, 게임오브젝트를 껏다 키는 형식으로 구현
  • 플레이어가 죽고 복귀시키는 로직은 GameManager에서 관리한다.
  • 죽은상태
  • 부활

게임매니저에 구현한 부활 코드

  public void RespawnPlayer()
    {
        Invoke("RespawnPlayerExe", 2f);
    }

    public void RespawnPlayerExe()
    {
        player.transform.position = Vector3.down * 4f; // 플레이어의 초기위치
        player.SetActive(true);
    }

플레이어에서 맞았을 때 코드

 else if(collision.gameObject.tag == "Enemy" || (collision.gameObject.tag == "EnemyBullet"))
        {
            gameManager.RespawnPlayer();
            gameObject.SetActive(false);
        }

GameManager 전체코드

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

public class GameManager : MonoBehaviour
{
    public GameObject[] enemyObjs;
    public Transform[] spawnPoints;

    public GameObject player;

    public float maxSpawnDelay;
    public float curSpawnDelay;

    void Update()
    {
        curSpawnDelay += Time.deltaTime;
        
        if(curSpawnDelay > maxSpawnDelay)
        {
            SpawnEnemy();
            maxSpawnDelay = Random.Range(0.5f, 3f);
            curSpawnDelay = 0;
        }

    }

    void SpawnEnemy()
    {
        int randomEnemy = Random.Range(0, 3);
        int spawnPoint = Random.Range(0, 7);

        GameObject enemy = Instantiate(enemyObjs[randomEnemy], spawnPoints[spawnPoint].position, spawnPoints[spawnPoint].rotation);

        Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
        Enemy enemyLogic = enemy.GetComponent<Enemy>();
        enemyLogic.player = player;

        if(spawnPoint == 5) // Left Spawn
        {
            enemy.transform.Rotate(Vector3.forward * 90);
            rigid.velocity = new Vector2(1, -enemyLogic.speed);
        }

        else if(spawnPoint == 6) // Right Spawn
        {
            enemy.transform.Rotate(Vector3.back * 90);
            rigid.velocity = new Vector2(-1, -enemyLogic.speed);
        }

        else // Front Spawn
        {
            rigid.velocity = new Vector2(0, -enemyLogic.speed);
        }
    
    }

    public void RespawnPlayer()
    {
        Invoke("RespawnPlayerExe", 2f);
    }

    public void RespawnPlayerExe()
    {
        player.transform.position = Vector3.down * 4f;
        player.SetActive(true);
    }

}

Player 전체코드

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

public class Player : MonoBehaviour
{
    public bool isTouchTop;
    public bool isTouchBottom;
    public bool isTouchLeft;
    public bool isTouchRight;

    public float speed;
    public float power;
    public float curShotDelay;
    public float maxShotDelay;

    public GameManager gameManager;
    public GameObject BulletA;
    public GameObject BulletB;

    Animator anim;

    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        Move();
        Fire();
        Reload();
    }

    void Reload()
    {
        curShotDelay += Time.deltaTime;
    }

    void Fire()
    {
        if (!Input.GetButton("Fire1")) // Fire1은 마우스좌클릭
            return;

        if (curShotDelay < maxShotDelay)
            return;


        switch(power)
        {
            case 1:
                // Power 1
                GameObject Bullet = Instantiate(BulletA, transform.position, transform.rotation);
                Rigidbody2D rigid = Bullet.GetComponent<Rigidbody2D>();
                rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                break;
            case 2:
                // Power 2
                GameObject BulletR = Instantiate(BulletA, transform.position + Vector3.right*0.1f, transform.rotation);
                GameObject BulletL = Instantiate(BulletA, transform.position + Vector3.left*0.1f, transform.rotation);
                Rigidbody2D rigidR = BulletR.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidL = BulletL.GetComponent<Rigidbody2D>();
                rigidR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                break;
            case 3:
                // Power 3
                GameObject BulletRR = Instantiate(BulletA, transform.position + Vector3.right*0.35f, transform.rotation);
                GameObject BulletCC = Instantiate(BulletB, transform.position, transform.rotation);
                GameObject BulletLL = Instantiate(BulletA, transform.position + Vector3.left*0.35f, transform.rotation);
                Rigidbody2D rigidRR = BulletRR.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidCC = BulletCC.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidLL = BulletLL.GetComponent<Rigidbody2D>();
                rigidRR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidCC.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidLL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                break;

        }
        

        curShotDelay = 0;
    }

    void Move()
    {
        float h = Input.GetAxisRaw("Horizontal");
        if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
            h = 0;
        float v = Input.GetAxisRaw("Vertical");

        if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
            v = 0;

        Vector3 curPos = transform.position;
        Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;

        transform.position = curPos + nextPos;

        // Animation

        if (Input.GetButtonUp("Horizontal") || Input.GetButtonDown("Horizontal"))
        {
            anim.SetInteger("Input", (int)h);

        }
    }

    public void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Border")
        {
            switch(collision.gameObject.name)
            {
                case "Top":
                    isTouchTop = true;
                    break;
                case "Bottom":
                    isTouchBottom = true;
                    break;
                case "Left":
                    isTouchLeft = true;
                    break;
                case "Right":
                    isTouchRight = true;
                    break;
                   
            }
        }

        else if(collision.gameObject.tag == "Enemy" || (collision.gameObject.tag == "EnemyBullet"))
        {
            gameManager.RespawnPlayer();
            gameObject.SetActive(false);
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Border")
        {
            switch (collision.gameObject.name)
            {
                case "Top":
                    isTouchTop = false;
                    break;
                case "Bottom":
                    isTouchBottom = false;
                    break;
                case "Left":
                    isTouchLeft = false;
                    break;
                case "Right":
                    isTouchRight = false;
                    break;

            }
        }
    }
}

출처 - https://www.youtube.com/c/GoldMetal

0개의 댓글