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

배근철·2022년 8월 2일
0

GoldMetal BE4

목록 보기
5/11

✍ UI 배치

  • Life는 Image배열, 점수는 Text로 표현한다.
  • UI가 해상도에 맞지 않을 때
    • Canvas에 Canvas Scaler에서 Constant Pixel Size(픽셀 고정)으로 되어 있는걸, Scale With Screen Size로 바꿔준다.
  • 죽었을 때 game over를 나타내는 Text와 , 재시작 Button을 추가
    • 2개는 빈오브젝트를 생성해서 묶어준다.
  • 크기를 알맞게 맞춰줘서 그림과 같이 배치했다.

✍ UI 로직 작성

Score 계산

  • Enemy에 enemyScore변수를 추가하고, 파괴 됐을 때 player의 score점수를 올려준다.
if (health <= 0)
        {
            Player playerLogic = player.GetComponent<Player>();
            playerLogic.score += enemyScore;
            Destroy(gameObject);
        }
  • GameManager의 Update문에서 ScoreText를 업데이트해준다.
    • 세자리마다 쉼표로 나눠주기 위해 string.Format("{0:n0}")을 사용.
 // UI Score Update
        Player playerLogic = player.GetComponent<Player>();
        scoreText.text = string.Format("{0:n0}", playerLogic.score);

Life 로직

  • 적에게 맞았을 때 , Image를 투명상태로 만들어 남아있는 Life만 보이게 한다.
  • GameManager에 UpdateLife함수를 추가해서 구현
    public void UpdateLife(int Life)
      {
          // #. UI Init Disable
          for (int i = 0; i < 3; i++)
              lifeImage[i].color = new Color(1, 1, 1, 0);
          // #. Life Active
          for (int i = 0; i < Life; i++)
              lifeImage[i].color = new Color(1, 1, 1, 1);
      }
  • GameManager에 GameOver함수를 만들고, Life가 0이되면 GameOver함수를 실행

    public void GameOver()
      {
          gameOverSet.SetActive(true);
      }

  • OnClick 이벤트에 적용할 함수를 생성
       public void Retry()
       {
           SceneManager.LoadScene(0);
       }

✍ 예외처리

  • Enemy L의 총알이 2개인데 2개의 총알을 모두 맞고 Life가 2번 깎여나가는 현상 발생
    • bool값을 정의해서 이미 맞은 상태면 Life를 깎지 않는다.
    if (isHit)
                  return;

✍ 전체코드

1. Player.cs

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 int score;
  public int health;
  public float speed;
  public float power;
  public float curShotDelay;
  public float maxShotDelay;
  public bool isHit;

  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"))
      {
          if (isHit)
              return;

          isHit = true;
          health--;
          gameManager.UpdateLife(health);
          if (health == 0)
              gameManager.GameOver();
          else
              gameManager.RespawnPlayer();

          gameObject.SetActive(false);
          Destroy(collision.gameObject);
      }
  }

  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;

          }
      }
  }
}

2. GameManager.cs

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

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

  public GameObject player;

  public float maxSpawnDelay;
  public float curSpawnDelay;

  public Text scoreText;
  public Image[] lifeImage;
  public GameObject gameOverSet;

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

      // UI Score Update

      Player playerLogic = player.GetComponent<Player>();
      scoreText.text = string.Format("{0:n0}", playerLogic.score);


  }

  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 playerLogic = player.GetComponent<Player>();
      playerLogic.isHit = false;
      player.transform.position = Vector3.down * 4f;
      player.SetActive(true);
  }

  public void UpdateLife(int Life)
  {
      // #. UI Init Disable
      for (int i = 0; i < 3; i++)
          lifeImage[i].color = new Color(1, 1, 1, 0);

      // #. Life Active
      for (int i = 0; i < Life; i++)
          lifeImage[i].color = new Color(1, 1, 1, 1);
  }

  public void GameOver()
  {
      gameOverSet.SetActive(true);
  }

  public void Retry()
  {
      SceneManager.LoadScene(0);
  }

}

3. Enemy.cs

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

public class Enemy : MonoBehaviour
{
  public string enemyName;
  public float speed;
  public int enemyScore;
  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)
      {
          Player playerLogic = player.GetComponent<Player>();
          playerLogic.score += enemyScore;
          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);
      }
  }
}

4. Bullet.cs

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

public class Bullet : MonoBehaviour
{

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

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

0개의 댓글