๊ฒ์ ์์คํ ์ ์ฌ๋ฌ ํด๋์ค์์ ๊ฐํธํ ์ ๊ทผํ ์ ์๊ฒํ๋ค.
- ์ธ๋ถ ํด๋์ค์์ Player์ PoolManager์ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
- ์ฑ๊ธํค ํจํด์ ์ด์ฉํด ๊ตฌํํ์ฌ, ํน์ฌ๋ GameMangerํด๋์ค๊ฐ 2๊ฐ ์์ฑ๋๋ ๊ฒ์ ๋ง๋๋ค.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager instance;
public PoolManager pool;
public Player player;
private void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
if(instance != null)
Destroy(this.gameObject);
}
}
}
์ค๋ธ์ ํธ ํ๋ง์ ์ํ ์คํฌ๋ฆฝํธ
- ๊ฒ์ ์ค ์ค๋ธ์ ํธ๋ฅผ ์์ฑ ๋ฐ ํ๊ดด๋ฅผ ํ๊ฒ๋๋ฉด ์ฑ๋ฅ์ ์ ํ๊ฐ ๋ฐ์ํ ์ ์๋ค.
- SetActive๋ฅผ ์ฌ์ฉํด ์ค๋ธ์ ํธ์ ํ์ฑํ๋ก ์ฌํ์ฉํ์ฌ ํด๊ฒฐํ๋ค.
- ๋ณธ ๊ฒ์์ ๋ง์ ์ ๋ฐ ๊ณต๊ฒฉ ํํ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํ์๋ถ๊ฐ๊ฒฐํ๋ค.
- pools์ ๋ด๊ธด ์ค๋ธ์ ํธ๊ฐ ๋น์ด์๊ฑฐ๋ ๋ชจ๋ ํ์ฑํ ์ํ์ผ ๊ฒฝ์ฐ Instantiate์ผ๋ก ์๋ก ์์ฑํ๋ค.
- ๋นํ์ฑํ๋ ์ค๋ธ์ ํธ๊ฐ ์๋ค๋ฉด, ํ์ฑํ ์์ผ์ค๋ค.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolManager : MonoBehaviour
{
public GameObject[] prefabs;
private List<GameObject>[] pools;
private void Awake()
{
pools = new List<GameObject>[prefabs.Length];
for (int i = 0; i < pools.Length; i++)
{
pools[i] = new List<GameObject>();
}
}
public GameObject Get(int index)
{
GameObject select = null;
foreach (GameObject item in pools[index])
{
if (item.activeSelf == false)
{
select = item;
select.SetActive(true);
break;
}
}
if (select == null)
{
select = Instantiate(prefabs[index], transform);
pools[index].Add(select);
}
return select;
}
}
์ ๊ฐ์ง๋ฅผ ์ํ ์คํฌ๋ฆฝํธ
- Raycast๋ฅผ ์ด์ฉํด ์ ์ ํ์งํ๋ค.
- CircleCastAll : ํน์ ๋ฒ์ ๋ฐ ์์น์ ์ค๋ธ์ ํธ๋ค์ ๊ฐ์งํ๋ค.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Scanner : MonoBehaviour
{
public float scanRange;
public LayerMask targerLayer;
public RaycastHit2D[] targets;
public Transform nearestTarget;
private void FixedUpdate()
{
targets = Physics2D.CircleCastAll(transform.position, scanRange, Vector3.zero, 0, targerLayer);
nearestTarget = GetNearest();
}
Transform GetNearest()
{
Transform result = null;
float diff = 100;
foreach (RaycastHit2D target in targets)
{
Vector3 myPos = transform.position;
Vector3 targetPos = target.transform.position;
float curDiff = Vector3.Distance(myPos, targetPos);
if (curDiff < diff)
{
diff = curDiff;
result = target.transform;
}
}
return result;
}
}
์ ์์ฑ ์คํฌ๋
- ์ ์ ์ํํ๋ ์คํฌ๋ฆฝํธ
- SpawnData ํด๋์ค ์ฌ์ฉ
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
[System.Serializable]
public class SpawnData
{
public float spawnTime;
public int spriteType;
public int health;
public float speed;
}
public class Spawner : MonoBehaviour
{
//public Transform[] spawnPoint; // ์คํฐ์ง์ ์ด ๋ค์์ผ ๋
public Transform spawnPoint;
public SpawnData[] spawnDatas;
private int level;
private float timer;
private void Awake()
{
//spawnPoint = GetComponentsInChildren<Transform>();
}
void Update()
{
timer += Time.deltaTime;
// level = Mathf.Min(Mathf.FloorToInt(GameManager.instance.gameTime / 10f), spawnDatas.Length - 1);
// Mathf.FloorToInt : ์์์ ์๋๋ ๋ฒ๋ฆฌ๊ณ Intํ์ผ๋ก ๋ฐ๊พธ๋ ํจ์ ex) 3.4 -> 3
// Mathf.CeilToInt : ์์์ ์๋๋ฅผ ์ฌ๋ฆฌ๊ณ Intํ์ผ๋ก ๋ฐ๊พธ๋ ํจ์ ex) 3.4 -> 4
if (timer > spawnDatas[level].spawnTime)
{
timer = 0f;
Spawn();
}
}
void Spawn()
{
GameObject enemy = GameManager.instance.pool.Get(1);
enemy.transform.position = spawnPoint.position;
enemy.GetComponent<Enemy>().Init(spawnDatas[level]);
}
}
์ ์ ์๋, ์ฒด๋ ฅ, ์ด๋ ๋ฑ์ ๊ด๋ฆฌํ๋ ์คํฌ๋ฆฝํธ
- Dead() ํจ์๋ ์ ๋๋ฉ์ด์ ์ด๋ฒคํธ๋ฅผ ์ด์ฉํ์ฌ ์ ์ฌ๋ง์ 1์ด ๋ค์ ์์ฒด๊ฐ ์ฌ๋ผ์ง๋ค.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float speed;
public float health; // ํ์ฌ ์ฒด๋ ฅ
public float maxHealth;
public RuntimeAnimatorController[] animCon;
public Rigidbody2D target;
private bool isLive;
private Rigidbody2D rigid;
private Collider2D coll;
private Animator anim;
private SpriteRenderer spriter;
private WaitForFixedUpdate wait;
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
spriter = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
wait = new WaitForFixedUpdate();
coll = GetComponent<Collider2D>();
}
void FixedUpdate()
{
// GetCurrentAnimatorStateInfo : ํ์ฌ ์ ๋๋ฉ์ดํฐ์ ์ํ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
if(!isLive || anim.GetCurrentAnimatorStateInfo(0).IsName("Hit"))
return;
// 1. ํ๋ ์ด์ด๊ฐ ์์นํ ๋ฐฉํฅ ๊ตฌํ๊ธฐ
Vector2 dirVec = target.position - rigid.position;
// 2. ํ๋ ์ด์ด๊ฐ ์์นํ ๊ณณ์ผ๋ก ์ด๋ป๊ฒ ์์ง์ผ์ง ๊ณ์ฐ
Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
// 3. MovePosition์ผ๋ก ํ์ฌ ์์น์์ ๋ค์ ์์น๋ก ์ด๋ ์ํ
rigid.MovePosition(rigid.position + nextVec);
// 4. ๋ฆฌ์ง๋๋ฐ๋์ ๋ฌผ๋ฆฌ ์๋๊ฐ ์ด๋์ ์ํฅ์ ์ฃผ์ง ์๋๋ก ๋ณด์ํ๊ธฐ
rigid.velocity = Vector2.zero;
}
private void LateUpdate()
{
if(!isLive)
return;
spriter.flipX = target.position.x < rigid.position.x;
}
private void OnEnable()
{
target = GameManager.instance.player.GetComponent<Rigidbody2D>();
isLive = true;
coll.enabled = true;
rigid.simulated = true; // ๋ฆฌ์ง๋๋ฐ๋ ์ปดํฌ๋ํธ ๋นํ์ฑํ๋ simulated์์ ๊ด๋ฆฌ
spriter.sortingOrder = 2;
anim.SetBool("Dead", false);
health = maxHealth;
}
public void Init(SpawnData data)
{
anim.runtimeAnimatorController = animCon[data.spriteType];
speed = data.speed;
maxHealth = data.health;
health = data.health;
}
void Dead()
{
gameObject.SetActive(false);
}
IEnumerator KnockBack()
{
yield return wait; // ํ๋์ ๋ฌผ๋ฆฌํ๋ ์์ ๋๋ ์ด
Vector3 playerPos = GameManager.instance.player.transform.position;
Vector3 dirVec = transform.position - playerPos;
rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse);
}
private void OnTriggerEnter2D(Collider2D col)
{
if (!col.CompareTag("Bullet") || !isLive)
return;
health -= col.GetComponent<Bullet>().damage;
StartCoroutine("KnockBack");
if (health > 0)
{
// .. Live, Hit Action
anim.SetTrigger("Hit");
}
else
{
// .. Die
isLive = false;
coll.enabled = false;
rigid.simulated = false; // ๋ฆฌ์ง๋๋ฐ๋ ์ปดํฌ๋ํธ ๋นํ์ฑํ๋ simulated์์ ๊ด๋ฆฌ
spriter.sortingOrder = 1;
anim.SetBool("Dead", true);
}
}
}
์ ์ ๊ณต๊ฒฉํ๋ ํ์ ์คํฌ๋ฆฝํธ
- Scanner์คํฌ๋ฆฝํธ์์ ๋ฐ๊ฒฌํ ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์ ๊ณต๊ฒฉํ๋ค.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tower : MonoBehaviour
{
public int towerType; // ํ์ ์ ํ
public int damage; // ํ์ ๋ฐ๋ฏธ์ง
public float firePeriod; // ๋ฐ์ฌ ์ฃผ๊ธฐ
public float speed; // ๋ฐ์ฌ ์๋
private float timer;
private Scanner scanner;
private Quaternion towerLook;
private void Awake()
{
scanner = GetComponent<Scanner>();
}
void Update()
{
timer += Time.deltaTime;
if (timer > firePeriod)
{
timer = 0f;
Fire();
}
}
void Fire()
{
if (!scanner.nearestTarget)
return;
Debug.Log("๋ฐ์ฌ์ค : " + scanner.nearestTarget);
Vector3 targetPos = scanner.nearestTarget.position;
Vector3 dir = targetPos - transform.position;
dir = dir.normalized;
Transform bullet = GameManager.instance.pool.Get(towerType).transform;
bullet.position = transform.position;
bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);
bullet.GetComponent<Bullet>().Init(0, damage, speed, dir);
}
}
ํ์์์ ๋ฐ์ฌ๋ ์ด์ ์คํฌ๋ฆฝํธ
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float damage;
public int towerType;
private Rigidbody2D rigid;
private void Awake()
{
rigid = GetComponent<Rigidbody2D>();
}
public void Init(int towerType, float damage, float speed, Vector3 dir)
{
this.damage = damage;
if (towerType == 0) // normal Tower
{
rigid.velocity = speed * dir;
}
}
private void OnTriggerEnter2D(Collider2D col)
{
if (!col.CompareTag("Enemy"))
{
return;
}
rigid.velocity = Vector2.zero;
gameObject.SetActive(false);
}
private void OnTriggerExit2D(Collider2D col)
{
if (col.CompareTag("Border"))
{
rigid.velocity = Vector2.zero;
gameObject.SetActive(false);
}
}
}