✍ 적 생성 강화
- 정면에서만 적이 나오는게 아니라 좌 우 에서도 나오도록 스폰지역을 추가함
- 좌,우에서 적이 등장하면 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 변수를 넣을 수 없다.
- 목표물로의 방향은 목표물위치 - 자신의 위치
Vector3 dirVecR = player.transform.position - (transform.position + Vector3.right * 0.3f);
- 즉 플레이어의 위치 - 적의 위치가 적이 플레이어를 쏘는 방향
- 프리펩에 프리펩 오브젝트는 할당이 가능하므로, Enemy에 EnemyBullet변수는 넣을 수 있다.
전체 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