โ ๋ณธ ๊ธ์ ์์ฑ์๊ฐ ๊ฐ๋ฐํ ๋ด์ฉ์ ์ ๋ฆฌํ ๊ธ๋ก ์๋ชป๋ ์ ์ด ์์ ์ ์์ด, ๋ฌธ์ ๊ฐ ์๋ค๋ฉด ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
โ ํด๋น ๋ด์ฉ์ ๊ณต์ ํ๊ฒ ๋๋ค๋ฉด, ๋ฐ๋์ ์ถ์ฒ๋ฅผ ๊ผญ ๋ช
์ํด์ฃผ๊ธฐ ๋ฐ๋๋๋ค.
[์ ๋ํฐ AR FPS ๊ฒ์ ๊ฐ๋ฐ] - 1. AR ํ๊ฒฝ์์ ์ด์ ๋ฐ์ฌํ๊ธฐ / Physics.Raycast
โ ๋ณธ ๊ธ์ ์์ฑ์๊ฐ ๊ฐ๋ฐํ ๋ด์ฉ์ ์ ๋ฆฌํ ๊ธ๋ก ์๋ชป๋ ์ ์ด ์์ ์ ์์ด, ๋ฌธ์ ๊ฐ ์๋ค๋ฉด ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. โ ํด๋น ๋ด์ฉ์ ๊ณต์ ํ๊ฒ ๋๋ค๋ฉด, ๋ฐ๋์ ์ถ์ฒ๋ฅผ ๊ผญ ๋ช ์ํด์ฃผ๊ธฐ ๋ฐ๋๋
vrworld.tistory.com
์ด ์ ์ ๊ตฌํ ์์ฝ์ผ๋ก 1~2๋ฒ๊น์ง ์ด์ด์ ์ด๋ฒ์๋ ๋๋จธ์ง 3~4๋ฒ์ ๋ํด ๊ธ์ ์จ ๋ด๋ ค๊ฐ๊ฒ ์ต๋๋ค.
Enemy(์ )์ ๋๋ค ๋ฐฐ์น
ํ์ฌ 1~2๋ฒ์ ๊ณผ์ ์ผ๋ก ์ธํด ํ๋ ์ด์ด์ ๋ชจ๋ ๋ฐ์ฌ๊ณผ์ ์ ๋ง์ณค๋ค. ์ด์ ํ๋ ์ด์ด ์๊ณผ ๋ค์ Enemy๋ฅผ ๋ฐฐ์นํด ์ฃผ์ด์ผ ํ๋ค.
๊ฒ์์ ์์ํ์ ๋ ์นด๋ฉ๋ผ๋ก ๋น์ถ๊ณ ์๋ ๋ฐฉํฅ๊ณผ AR Camera๋ฅผ ๊ธฐ์ค์ผ๋ก ๋น์ถ๊ณ ์๋ ๋ฐฉํฅ์ด ์๋ก ์ผ์นํ๊ธฐ ๋๋ฌธ์
๊ฒ์์์ ํ๋ ์ด์ด์ ์๊ณผ ๋ค์ ๊ธฐ์ค์ AR Camera๊ฐ ์ด๋ ๋ฐฉํฅ์ผ๋ก ๋ฐ๋ผ๊ณ ์๋์ง๋ก ์ ํด์ง๊ฒ ๋๋ค.
Hierarchy์ ๋ง์ฐ์ค ์ฐํด๋ฆญ์ ํ๋ฉด ๋น ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค ์ ์๋ค. ์์์ ์ค๋ช ์ ํตํด CubeSpawn์ ์ค๋ธ์ ํธ ์์น๋ ํ๋ ์ด์ด์ ์์ด๋ผ๊ณ ๋ณผ ์ ์๊ฒ ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก CubeBackSpawn ๋น ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ , ์ด ์ค๋ธ์ ํธ๋ ํ๋ ์ด์ด์ ๋ค์ ์์นํ๊ฒ ๋๋ค.
์ ์ฌ์ง์ Cube Spawn ์ค๋ธ์ ํธ์ ๋ํ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์๋ค. ์คํฌ๋ฆฝํธ Cube Spawn์ Spawn Object ์ฆ, Spawn ์ํค๋ ค๋ ์ค๋ธ์ ํธ๋ฅผ Prefab์ผ๋ก ๋ฃ์ด์ฃผ์๋ค.
public class CubeSpawn : MonoBehaviour
{
public Transform[] spawnPoints;
public GameObject SpawnObject; //Prefab์ผ๋ก ์์ฑ๋ ์ค๋ธ์ ํธ
public int xPos;
public int zPos;
public int enemyCount;
void Start()
{
StartCoroutine(StartSpawing());
}
IEnumerator StartSpawing()
{
while (enemyCount < 20)
{
xPos = Random.Range(-4, 8); //Position X์ถ -4~ 8 ์ฌ์ด์ ๋๋ค ๋ฒ์ ์์ฑ
zPos = Random.Range(6, 11); // Position Z์ถ 6 ~ 11 ์ฌ์ด์ ๋๋ค ๋ฒ์ ์์ฑ
//Prefab ์ค๋ธ์ ํธ๋ฅผ ์ธ์คํด์คํ ์์ผ์ ํธ์ถํ๋ค.
Instantiate(SpawnObject, new Vector3(xPos, Random.Range(-1, 1), zPos), Quaternion.identity); //(๋ณต์ ํ ๋์, ์์น, ๋ฐฉํฅ)
yield return new WaitForSeconds(2);
enemyCount += 1;
}
}
}
์คํฌ๋ฆฝํธ Cube Spawn์ ๋ํ ์ฌ์ง์ด๋ค. ์ฌ์ฉ์๊ฐ ๋ฐ๋ผ๋ณด๊ณ ์๋ ์์๋ Enemy๊ฐ 20๋ช ์ด ๋๊ธฐ ์ ๊น์ง Instantiate()ํจ์๋ฅผ ํธ์ถ์ ๋ฐ์ Prefab ์ค๋ธ์ ํธ๋ค์ ์ธ์คํด์ค ํ๊ฒ ๋ฉ๋๋ค.
์ธ์คํด์ค(Instance)๋ ํด๋์ค์ ๊ฐ์ฒด์ ๋ํด ๋ ์ฌ๋ฆฌ์๋ฉด ๋๋ค. ์ฝ๊ฒ ๋งํ๋ฉด ์ค๋ธ์ ํธ๋ค์ ํ์ํ ๋๋ง๋ค ์ฐ์ด์ ๋ง๋ค์ด๋ด์ด ๋ณต์ ํ์ ๋ง๋ค์ด ๋ด๋ ๊ฒ์ด๋ค.
์์์ ๋ณด์ฌ์ค Cube Spawn๊ณผ ์ ์ฌํ ํ์ ๋ณด์ฌ์ฃผ๊ณ ์๋ค. ๋๊ฐ์ด Spawn ํ ์ค๋ธ์ ํธ๋ฅผ Prefab์ผ๋ก ๋ฃ์ด์ค์๋ค.
public class CubeBackSpawn : MonoBehaviour
{
public Transform[] spawnPoints;
public GameObject BackSpawnObject; //Prefab์ผ๋ก ์์ฑ๋ ์ค๋ธ์ ํธ
public int BackxPos;
public int BackzPos;
public int BackCount;
// Start is called before the first frame update
void Start()
{
StartCoroutine(BackSpawing());
}
IEnumerator BackSpawing()
{
while (BackCount < 5)
{
BackxPos = Random.Range(-2, 6); //Position X์ถ -2~ 6 ์ฌ์ด์ ๋๋ค ๋ฒ์ ์์ฑ
BackzPos = Random.Range(-5, -2); // Position Z์ถ -5 ~ -2 ์ฌ์ด์ ๋๋ค ๋ฒ์ ์์ฑ
//Prefab ์ค๋ธ์ ํธ๋ฅผ ์ธ์คํด์คํ ์์ผ์ ํธ์ถํ๋ค.
Instantiate(BackSpawnObject, new Vector3(BackxPos, Random.Range(-1, 1), BackzPos), Quaternion.identity); //(๋ณต์ ํ ๋์, ์์น, ๋ฐฉํฅ)
yield return new WaitForSeconds(2);
BackCount += 1;
}
}
}
while ๋ฐ๋ณต๋ฌธ์ผ๋ก ๋ค์ Spawn ํ Enemy(์ )์ ๊ฐ์๋ฅผ 5๋ช ์ดํ๋ก ์กฐ๊ฑด์ ๊ฑธ์ด์ฃผ์๋ค.
์ฌ๊ธฐ์ Instantiate() ํจ์ ์์ Quaternion.identity๋ ํ์ ๊ฐ์ ๋ฐ๋ก ์ ์ํ์ง ์์์ ์๋ฏธํ๋ค.
Enemy์ ๋ํ ์ ๋ณด
Prefab ์ด๋?
์กฐ๊ธ ์ ์ Spawn ํ ์ค๋ธ์ ํธ์ Prefab์ผ๋ก ๋ง๋ค์ด ๋ฃ์ด์ค๋ค๊ณ ํ์๋ค.
Prefab์ '์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์์
'์ผ๋ก ์ ๋ํฐ ๊ณต์ ๋งค๋ด์ผ์์ ์ค๋ช
ํ๊ณ ์๋ค. ์ฐ๋ฆฌ๊ฐ ๋๊ฐ์ ์ค๋ธ์ ํธ๊ฐ ์ฌ๋ฌ ๊ฐ ํ์ํ๋ค๊ณ ํ์ ๋ ๋จ์ํ ๋ณต์ฌํ๋ค๋ ์ํฉ์ ๊ฐ์ ํด๋ณด์. ์ด ๋ ์ด ์ค๋ธ์ ํธ์ ์์ ์ฌํญ์ด ์๊ธด๋ค๋ฉด ํ๋ํ๋ ์ผ์ผ์ด ์์ ์ฌํญ์ ์ฒดํฌํด์ฃผ์ด์ผ ํ๋ค. ์ด ์์
์ ๋ถํ์ํ๊ณ ๋นํจ์จ์ ์ธ ์์
์ผ๋ก ์ด์ด์ง๊ฒ ๋ ๊ฒ์ด๋ค.
๋ง์ฝ, ์๋ณธ ํ๋๋ง ์์ ํ๋ฉด ์๋์ผ๋ก ๋ชจ๋ ๋ณต์ฌ๋ณธ์๋ ๋๊ฐ์ด ๊ทธ ์์ ์ฌํญ์ ๋ฐ์ํด์ฃผ๋ฉด ์ผ๋ง๋ ์ข์๊น?
๊ทธ๊ฒ ์ฐ๋ฆฌ๊ฐ ๋ฐ๋ก Prefab์ ์ฐ๋ ์ด์ ๊ฐ ๋๊ฒ ๋๋ค.
Prefab์ผ๋ก ๋ง๋ค์ด์ง Cube์ ๋ํ ์ ๋ณด์ด๋ค. Add Component๋ฅผ ํด๋ฆญํ์ฌ Box Collider๋ฅผ ๋ง๋ค์ด์ฃผ์. ๋ง๋ค์ด์ฃผ์ง ์์ผ๋ฉด ์ถฉ๋ ๊ฐ์ง๊ฐ ๋ฐ์ํ์ง ์์ ์ฐ๋ฆฌ๊ฐ ์ ์๊ฒ ์ด์ ์์ ๋ ์๋ฌด๋ฐ ์ผ์ด ์ผ์ด๋์ง ์๋ ํ์์ ๊ฒช๊ฒ ๋๋ค.
public class EnemyCube : MonoBehaviour
{
public float health = 20f;
public bool isEneymyDead; //bool ํ์
์ด๊ธฐ๊ฐ์ True
public void getdamage(float damageAmount)
{
if (!isEneymyDead) // ์ ์ด ์ฃฝ์ง ์์ผ๋ฉด
{
health -= damageAmount; //๋ฐ๋ฏธ์ง ๋ฐ์ ๋งํผ Enemy์ Health๊ฐ ๊น์ธ๋ค.
if (health <= 0)
{
Destroy(this.gameObject, 0.5f); //์ ์ด ์ฌ๋ผ์ง๋ค.
PlayerInform.instance.AddScore(1); // EnemyCube์ ํผ๊ฐ 0์ดํ์ผ ๋ ์ ์๊ฐ 1์ฉ์ฆ๊ฐ
}
}
}
}
๋ค์์ ์ ์ ๋ํ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ์คํฌ๋ฆฝํธ Enemy Cube ๋ชจ์ต์ด๋ค. ์ ์ health๋ 20์ผ๋ก ์ง์ ํด์ฃผ์๋ค.
get damage ํจ์๋ ์ฐ๋ฆฌ๊ฐ ์ด์ ์ ๋๋ง๋ค ์ฆ, HandGunFire ์คํฌ๋ฆฝํธ์์ shoot() ํจ์๊ฐ ํธ์ถ๋ ๋๋ง๋ค
damage Amount๋งํผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์ ์ health๋ฅผ ๊ฐฑ์ ํด์ค๋ค.
๋ง์ฝ, ์ ์ health๊ฐ 0 ์ดํ๋ก ๋จ์ด์ง ์ ์ ์ ์ฌ๋ผ์ง๊ฒ ๋๊ณ , UI์ ์ ์๊ฐ 1์ฉ ์ฆ๊ฐํ๊ฒ ๋๋ค.
์ฌ์ฉ์ UI์ ํ์ฌ Score ๊ฐฑ์ ์ํค๊ธฐ
์์์ ์ ์ health๊ฐ 0 ์ดํ์ผ ๋ " PlayerInform.instance.AddScore(1); " ์ ๋ง๋ UI์ ํ๋ ์ด์ด์ ์ ์๊ฐ 1์ฉ ์ฆ๊ฐํ๊ฒ ๋๋ค๊ณ ํ์๋ค. AddScore() ํจ์๋ PlayerInform ํด๋์ค์ ํจ์์ด๋ค. ์ฌ๊ธฐ์ PlayerInform ํด๋์ค๋ฅผ Static์ผ๋ก ์ ์ธ๋์ด ์์ด ์ด๋์์๋ ์ ๊ทผ์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค์๋ค. ์ฆ, PlayerInform์ ๋ํ ๋ณ์, ํจ์ ๋ฑ์ ๋ชจ๋ ๋ค๋ฅธ ํด๋์ค์์ ์ด์ฉํ ์ ์๊ฒ ๋๋ค.
https://dlemrcnd.tistory.com/8
Unity - ๋ค๋ฅธ ์คํฌ๋ฆฝํธ ํจ์, ๋ณ์๋ฅผ ๋ถ๋ฌ์ฌ๋ (๋์์ธ ํจํด ์ฑ๊ธํค)
๋ค๋ฅธ ์คํฌ๋ฆฝํธ์ ํจ์ ๋ณ์๋ฅผ ๋ถ๋ฌ์ค๊ณ ์ถ์ ๋๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋ค. ๊ทธ ์ค์ ์ฝ๊ฒ ์ธ ์ ์๋ ๋ฐฉ๋ฒ์ ์๊ฐ๋๋๋๋ก ์ ์ด๋ณด์๋ค. ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ๋ฐ์ดํฐ(Data) ์์ญ (์ ์ ๋ฉ๋ชจ๋ฆฌ) ์คํ(Stack)
dlemrcnd.tistory.com
์์์ 2๊ฐ์ ์ฌ์ง์ ํ๋ ์ด์ด ํ์ฌ Score๋ฅผ ๊ฒ์ UI์ ๋ณด์ฌ์ฃผ๊ณ ์๋ EnemyScore์ ๋ํ ์ปดํฌ๋ํธ ์ ๋ณด์ด๋ค.
์ด์ ์๊น AddScore() ํจ์์์ 1์ฉ ์ฆ๊ฐํ๋ ์ ์๋ฅผ ๊ฒ์ UI์์๋ 1์ฉ ์ฆ๊ฐํ๊ฒ ๋ณด์ฌ์ฃผ๋๋ก ์ฐ๊ฒฐํด์ฃผ์ด์ผ ํ๋ค.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; //UI์ ์ ๊ทผํ๊ธฐ ์ํด์ ์ฌ์ฉ
public class PlayerInform : MonoBehaviour
{
public static PlayerInform instance; // statci(์ ์ )์ผ๋ก ์ ์ธํ์ฌ ์ด๋์์๋ ์๊ธฐ ์์ ์ ์ ์ฅํ๋๋ก ๋ง๋ ๋ค.
public Text PlayerScore; //UI์ ํ์๋๋ "Score : "
private int CurrentScore = 0; //์ ์ ์ฃฝ์ผ๋๋ง๋ค ์ฌ๋ผ๊ฐ๋ ์ ์
void Awake()
{
if (!instance) instance = this; //์ด๊ฑฐ ์ค์..
// ์ ์ ์ผ๋ก ์์ ์ ์ฒดํฌํ์ฌ ์๊ธฐ ์์ ์ ์ ์ฅํ๋ค.
// ๋ฃ์ง ์๋๋ค๋ฉด nullreferenceexception ์ค๋ฅ ๋ฐ์
PlayerScore.text = CurrentScore.ToString("Score : 0"); // intํ์ผ๋ก ๋ฐ์ ์ ์๋ฅผ UI Text์ ๊ฐฑ์ ํ ์ ์๋๋ก ํ๋ณํ
}
public void AddScore(int getScore)
{
CurrentScore += getScore;
PlayerScore.text = CurrentScore.ToString("Score : 0"); // UI์ฐฝ์ ํ์ฌ ์ ์ ์
๋ฐ์ดํธ
}
}
PlayerInform ํด๋์ค ์ฝ๋์ ๋๋ค. ์์์ ์ธ๊ธํ๋ค์ํผ PlayerInform ์ปดํฌ๋ํธ ์์ฒด๋ฅผ static์ผ๋ก ์ ์ธํ์์ต๋๋ค.
AddScore() ํจ์ ์์์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ getScore๋ 1์ฉ ๋ฐ์์ฌ ๊ฒ์ ๋๋ค. ๊ทธ๋ ๊ฒ int ํ์ ์ CurrentScore ์ฆ, ํ์ฌ ์ ์๋ฅผ ๊ฐฑ์ ์์ผ์ฃผ์์ผ๋ฉฐ, .ToString()์ผ๋ก int ํ์ ์ String ํ์ ์ผ๋ก ํ ๋ณํํ์ฌ ํ๋ ์ด์ด UI์์๋ ์ ์๊ฐ ๊ฐฑ์ ๋๋๋ก ๋ง๋ ๊ฒ์ ๋๋ค.
์ง๊ธ๊น์ง ๊ตฌํ์ ์๋ฃํ์ ๋ ๋ชจ์ต์ ๋๋ค. ์ ์ด ๋๋ค์ผ๋ก ์์ฑ๋๊ณ , ํ๋ ์ด์ด์ ๊ณต๊ฒฉ, ํผ๊ฒฉ ์ฑ๊ณต ์์ ํ๋ ์ด์ด UI Score๊ฐ ๊ฐฑ์ ๋๊ณ ์๋ ๋ชจ์ต์ ์์์ ํตํด ํ์ธํ ์ ์์ต๋๋ค.
https://www.youtube.com/watch?v=ydjpNNA5804&list=PLoCI09s5z0sJafXrXzFwyPLMoOlztkgPe&index=4
https://www.youtube.com/watch?v=THnivyG0Mvo&list=PLoCI09s5z0sJafXrXzFwyPLMoOlztkgPe&index=3
๋ค์์ ์ฌ๊ฐ ํ๋ก์ ํธ๋ฅผ ์งํํ ๋ ๋์๋ฐ์๋ ์์์ ์ฒจ๋ถํ ๊ฒ์ ๋๋ค.
์ง๊ธ๊น์ง์ ๊ณผ์ ์ ๋ชจ๋ ๊ฑฐ์ณค๋ค๋ฉด AR FPS ๊ฐ๋ฐ์ ์ํ ์ด๊ธฐ ๊ตฌํ ์ ๋๋ ์๋ฃ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ค์์ ์ง๊ธ์ ๋ชจ์ต์์ ์ถ๊ฐ๋ก ๊ฐ๋ฐํ ๋ถ๋ถ๊ณผ ๊ฐ๋ฐ ์คํจํ๋ ๋ถ๋ถ์ ๊ณ์ํด์ ์ฌ๋ฆฌ๋๋ก ํ๊ฒ ์ต๋๋ค.