

[์์ฑ ๋ชจ๋] -> [๋ฌผ๋ฆฌ ์ค์ ๋ชจ๋] -> [์ ๋ ฅ ๊ฐ์ง ๋ชจ๋] -> [ํญ๋ฐ ์๋ฎฌ๋ ์ด์ ๋ชจ๋]
spawnRate ์ ๋ฐ๋ผ ์ ํด์ง ๋น๋๋ก ์ค๋ธ์ ํธ ์์ฑ.spawnArea ๋ฒ์ ๋ด์์ ๋๋คํ X, Z ์ขํ๋ฅผ ์ ํํ๊ณ , ๊ณ ์ ๋ spawnHeight๋ฅผ Y ์ขํ๋ก ์ฌ์ฉํ์ฌ ๊ณต์ค์์ ๋ํ.spawnPrefabs ๋ฐฐ์ด์์ ๋๋ค ์ธ๋ฑ์ค๋ฅผ ์ ํํ์ฌ ๋ค์ํ ํ๋ฆฌํน์ด ํผํฉ๋์ด ์์ฑ.Rigidbody์ Collider๊ฐ ์์ผ๋ฉด ์๋์ผ๋ก ์ถ๊ฐ.ContinuousDynamic ์ถฉ๋ ๊ฐ์ง ๋ชจ๋๋ฅผ ์ค์ ํ์ฌ ๊ณ ์ ์ด๋์ ํ๊น ํ์ (ํฐ๋๋ง)์ ๋ฐฉ์ง.linearDamping, angularDamping์ ์กฐ์ ํ์ฌ ๊ณต๊ธฐ ์ ํญ ๋ฑ ์์ฐ์ค๋ฌ์ด ๊ฐ์ ํจ๊ณผ ๋ถ์ฌ.UnityEngine.InputSystem)์ ์ฌ์ฉํ์ฌ ๋ง์ฐ์ค ์ผ์ชฝ ํด๋ฆญ์ ๊ฐ์ง.Camera.main.ScreenPointToRay ๋ก ๋ง์ฐ์ค ์์น์์ 3D ๊ณต๊ฐ์ผ๋ก Ray๋ฅผ ๋ฐ์ฌ.Physics.RaycastAll ์ ์ฌ์ฉํ์ฌ Ray ๊ฒฝ๋ก์์ ๋ชจ๋ ์ฝ๋ผ์ดํฐ๋ฅผ ๊ฒ์ฌ. ๋จ์ผ Raycast์ ๋ฌ๋ฆฌ ๊ฒน์ณ์ง ์ค๋ธ์ ํธ ์ค ๋ค์ ์๋ "ํญ๋ฐ ํธ๋ฆฌ๊ฑฐ"๋ ๊ฐ์ง.explosionRadius ๋ด์ ๋ชจ๋ Rigidbody๋ฅผ ํ์.proximity (0.0 ~ 1.0)์ ๊ณ์ฐํ์ฌ, ์ค์ฌ์ ๊ฐ๊น์ธ์๋ก ๊ฐํ ํ์ด ๊ฐํด์ง๋๋ก.radialForce(์ํ ํ์ฐ๋ ฅ)์ upwardForce(์์ง ์์น๋ ฅ) ๋ฅผ ์กฐํฉํ์ฌ ํญ๋ฐ ์ ๋ฌผ์ฒด๊ฐ ์๋ก ์๊ตฌ์น๋ฉฐ ์ฌ๋ฐฉ์ผ๋ก ํผ์ง๋ ๋ฌผ๋ฆฌ ํจ๊ณผ๋ฅผ ๊ตฌํ.์คํฌ๋ฆฝํธ ๋ด๋ถ์์ instance.tag = "ExplosionTrigger"๋ฅผ ํ ๋นํ๋ฏ๋ก, ํด๋น ํ๊ทธ๊ฐ ํ๋ก์ ํธ์ ๋ฑ๋ก๋์ด ์์ด์ผ ํจ.
1. ์๋จ ๋ฉ๋ด์์ Edit > Project Settings > Tags & Layers ์ ํ
2. Tags ๋ฐฐ์ด์ ๋น ์ฌ๋กฏ์ ๋๋ธํด๋ฆญ
3. ExplosionTrigger๋ฅผ ์
๋ ฅ ํ ์ํฐ
4. ์ค์ ์ฐฝ ๋ซ๊ธฐ
UnityException: Tag: ExplosionTrigger is not defined ์๋ฌ๊ฐ ๋ฐ์.Camera.main ์ด ์ ์ ์๋ํ๋ ค๋ฉด ๋ฉ์ธ ์นด๋ฉ๋ผ์ MainCamera ํ๊ทธ๊ฐ ํ ๋น๋์ด ์์ด์ผ ํจ.
1. Hierarchy ์์ ๋ฉ์ธ ์นด๋ฉ๋ผ ์ ํ
2. Inspector ์๋จ Tag ๋๋กญ๋ค์ด์์ MainCamera ์ ํ (์์ผ๋ฉด Add Tag ๋ก ๋ฑ๋ก)
Mesh Renderer ๊ฐ ํฌํจ๋์ด ์๋์ง ํ์ธ.Spawn Prefabs ๋ฐฐ์ด์ ํ๋ฆฌํน์ ๋๋๊ทธ&๋๋กญ.์คํฌ๋ฆฝํธ๊ฐ ๋ฐํ์์ Rigidbody ์ Collider ๋ฅผ ์๋ ์ถ๊ฐํ์ง๋ง, ํ๋ฆฌํน ๋จ๊ณ์์ ๋ฏธ๋ฆฌ ์ค์ ํด ๋๋ฉด ๋ถํ์ํ ์ปดํฌ๋ํธ ์ถ๊ฐ ๋ก์ง์ ์๋ตํ ์ ์์ต๋๋ค.
Rigidbody ์ถ๊ฐ: Use Gravity ์ฒดํฌ, Is Kinematic ํด์ Collider ์ถ๊ฐ: BoxCollider ๋๋ MeshCollider (Convex ์ฒดํฌ)using UnityEngine;
using UnityEngine.InputSystem; // Unity New Input System ๋ค์์คํ์ด์ค (๋ง์ฐ์ค ์
๋ ฅ ์ฒ๋ฆฌ์ฉ)
using System.Collections.Generic; // List<T> ์ ๋ค๋ฆญ ์ปฌ๋ ์
์ฌ์ฉ
public class MeshSpawnerManager : MonoBehaviour
{
// =========================================================
// [Inspector ๋
ธ์ถ ๋ณ์: ์์ฑ ์ค์ ]
// =========================================================
[Header("๐ฆ ์์ฑ ์ค์ ")]
[Tooltip("์ด ์์ฑํ ์ค๋ธ์ ํธ ๊ฐ์")]
public int maxSpawnCount = 500; // ์์คํ
์ด ์์ฑํ ์ต๋ ์ค๋ธ์ ํธ ์ (ํ๋ง ํ๋)
[Tooltip("์ด๋น ์์ฑ ๊ฐ์ (๋น๋)")]
[Range(1f, 50f)] // Inspector ์์ 1~50 ๋ฒ์ ์ฌ๋ผ์ด๋ ์ ๊ณต
public float spawnRate = 10f; // ์ด๋น ์์ฑํ ์ค๋ธ์ ํธ ๊ฐ์ (์: 10 = 0.1 ์ด๋น 1 ๊ฐ ์์ฑ)
[Tooltip("์์ฑ ์์น์ Y ์ถ ๋์ด")]
public float spawnHeight = 5f; // ์ค๋ธ์ ํธ๊ฐ ์์ฑ๋ ๋์ด (๊ณต์ค์์ ๋ํ ์์)
[Tooltip("์์ฑ ๋ฒ์ (X, Z ํฌ๊ธฐ)")]
public Vector2 spawnArea = new Vector2(5f, 5f); // X, Z ์ถ ๋๋ค ์์ฑ ์์ญ์ ๋๋น/๊ธธ์ด
[Tooltip("์์ฑํ ํ๋ฆฌํน ๋ฐฐ์ด โ Index 0 ์ด ํญ๋ฐ ํธ๋ฆฌ๊ฑฐ ๋์")]
public GameObject[] spawnPrefabs = new GameObject[5]; // ์ต๋ 5 ์ข
ํ๋ฆฌํน ๋ฑ๋ก ๊ฐ๋ฅ (์ธ๋ฑ์ค 0 ์ ํน์ ์ญํ )
// =========================================================
// [Inspector ๋
ธ์ถ ๋ณ์: ํญ๋ฐ ์ค์ ]
// =========================================================
[Header("๐ฅ ํญ๋ฐ ์ค์ ")]
[Tooltip("ํญ๋ฐ ์ํฅ ๋ฐ๊ฒฝ")]
public float explosionRadius = 1f; // ํญ๋ฐ ์์ ์ผ๋ก๋ถํฐ ํ์ด ์์ฉํ๋ ์ต๋ ๊ฑฐ๋ฆฌ
[Tooltip("์์ชฝ์ผ๋ก ๋ ์์ค๋ฅด๋ ํ")]
public float upwardForce = 50f; // ํญ๋ฐ ์ Y ์ถ ์์ ๋ฐฉํฅ์ผ๋ก ๊ฐํด์ง๋ ํ (์์น๋ ฅ)
[Tooltip("์์ผ๋ก ํผ์ง๋ ํ")]
public float radialForce = 30f; // ํญ๋ฐ ์์ ์์ ๋ฐ๊นฅ ๋ฐฉํฅ (์ํ) ์ผ๋ก ๊ฐํด์ง๋ ํ (ํ์ฐ๋ ฅ)
// =========================================================
// [Private ์์ ๋ฐ ๋ฉค๋ฒ ๋ณ์]
// =========================================================
// Element 0 ์ธ์คํด์ค๋ฅผ ์๋ณํ๊ธฐ ์ํ ํ๊ทธ
// โ ๏ธ Unity ๋ฉ๋ด Edit > Project Settings > Tags & Layers ์์ "ExplosionTrigger" ํ๊ทธ๋ฅผ
// ๋ฏธ๋ฆฌ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์์ผ๋ฉด ๋ฐํ์์ ํ๊ทธ ํ ๋น ์ ์๋ฌ ๋ฐ์
private const string TRIGGER_TAG = "ExplosionTrigger";
private int currentSpawnCount = 0; // ํ์ฌ๊น์ง ์์ฑ๋ ์ค๋ธ์ ํธ ์นด์ดํธ
private float spawnTimer = 0f; // ๋ค์ ์์ฑ๊น์ง์ ์๊ฐ ๋์ ํ์ด๋จธ
private List<Rigidbody> spawnedObjects = new List<Rigidbody>(); // ์์ฑ๋ ๋ชจ๋ Rigidbody ์ฐธ์กฐ ์ ์ฅ (ํญ๋ฐ ์ ํ์์ฉ)
// =========================================================
// [Unity LifeCycle: Start]
// =========================================================
void Start()
{
// ๋ฐ๋ฅ ํ๋ฉด ์๋ ์์ฑ (ํ
์คํธ ํ๊ฒฝ ๊ตฌ์ถ์ฉ)
InitializeFloor();
// ํ๋ฆฌํน ๋ฐฐ์ด ์ ํจ์ฑ ๊ฒ์ฌ (๋ ์์ ๊ฒฝ๊ณ ์ถ๋ ฅ)
ValidatePrefabs();
}
// =========================================================
// [Unity LifeCycle: Update]
// =========================================================
void Update()
{
// -----------------------------------------------------
// [1. ์ค๋ธ์ ํธ ์์ฑ ๋ก์ง]
// -----------------------------------------------------
// ์ต๋ ์์ฑ ๊ฐ์์ ๋๋ฌํ์ง ์์ ๊ฒฝ์ฐ์๋ง ์์ฑ ์งํ
if (currentSpawnCount < maxSpawnCount)
{
spawnTimer += Time.deltaTime; // ํ๋ ์ ๊ฒฝ๊ณผ ์๊ฐ ๋์
// ์ค์ ๋ ์์ฑ ์ฃผ๊ธฐ (1/spawnRate) ์ ๋๋ฌํ๋ฉด
if (spawnTimer >= 1f / spawnRate)
{
spawnTimer = 0f; // ํ์ด๋จธ ๋ฆฌ์
SpawnObject(); // ์ค๋ธ์ ํธ ์์ฑ ํจ์ ํธ์ถ
}
}
// -----------------------------------------------------
// [2. ๋ง์ฐ์ค ํด๋ฆญ ๊ฐ์ง ๋ก์ง (New Input System)]
// -----------------------------------------------------
// Mouse.current ๊ฐ ์ ํจํ๊ณ (๋ฐ์คํฌํฑ ํ๋ซํผ), ์ผ์ชฝ ๋ฒํผ์ด ์ด๋ฒ ํ๋ ์์ ๋๋ ธ๋ค๋ฉด
if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
{
HandleClickExplosion(); // ํญ๋ฐ ์ฒ๋ฆฌ ํจ์ ํธ์ถ
}
}
// =========================================================
// [Private Method: ๋ฐ๋ฅ ํ๋ฉด ์๋ ์์ฑ]
// =========================================================
void InitializeFloor()
{
// PrimitiveType.Plane ์ผ๋ก ๊ธฐ๋ณธ ํ๋ฉด ๋ฉ์ ์์ฑ
GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Plane);
floor.name = "Ground_Floor"; //Hierarchy ์์ ์๋ณํ๊ธฐ ์ฌ์ด ์ด๋ฆ ์ง์
// ํ๋ฉด ํฌ๊ธฐ ์กฐ์ (๊ธฐ๋ณธ 10x10 ์ 100x100 ์ผ๋ก ์ค์ผ์ผ์
)
floor.transform.localScale = new Vector3(10f, 1f, 10f);
// ๋ฐ๋ฅ์ ์์ (0,0,0) ์ ์์น์ํด
floor.transform.position = Vector3.zero;
}
// =========================================================
// [Private Method: ํ๋ฆฌํน ๋ฐฐ์ด ์ ํจ์ฑ ๊ฒ์ฌ]
// =========================================================
void ValidatePrefabs()
{
// ๋ฐฐ์ด์ด ์์ ํ ๋น์ด์๋ ๊ฒฝ์ฐ ์๋ฌ ๋ก๊ทธ ์ถ๋ ฅ
if (spawnPrefabs.Length == 0)
{
Debug.LogError("spawnPrefabs ๋ฐฐ์ด์ด ๋น์ด์์ต๋๋ค.");
return;
}
// ๊ฐ ์ฌ๋กฏ์ ์ํํ๋ฉฐ ๋ (null) ์ฐธ์กฐ๊ฐ ์๋์ง ๊ฒ์ฌ
for (int i = 0; i < spawnPrefabs.Length; i++)
{
if (spawnPrefabs[i] == null)
Debug.LogWarning($"์ธ๋ฑ์ค {i}์ ํ๋ฆฌํน์ด ๋น์ด์์ต๋๋ค.");
}
}
// =========================================================
// [Private Method: ์ค๋ธ์ ํธ ์์ฑ ๋ฐ ๋ฌผ๋ฆฌ ์ค์ ]
// =========================================================
void SpawnObject()
{
// ํ๋ฆฌํน ๋ฐฐ์ด์ด ๋น์ด์์ผ๋ฉด ์์ฑ ์ค๋จ
if (spawnPrefabs.Length == 0) return;
// 0 ๋ถํฐ ๋ฐฐ์ด ๊ธธ์ด๊น์ง ๋๋ค ์ธ๋ฑ์ค ์ ํ (๊ท ๋ฑ ํ๋ฅ )
int index = Random.Range(0, spawnPrefabs.Length);
GameObject prefab = spawnPrefabs[index];
// ์ ํ๋ ํ๋ฆฌํน์ด ๋์ด๋ฉด ์คํต
if (prefab == null) return;
// -----------------------------------------------------
// [๋๋ค ์์ฑ ์์น ๊ณ์ฐ]
// -----------------------------------------------------
// X, Z ๋ spawnArea ๋ฒ์ ๋ด์์ ๋๋ค, Y ๋ ๊ณ ์ ๋ spawnHeight
Vector3 spawnPos = new Vector3(
Random.Range(-spawnArea.x / 2f, spawnArea.x / 2f), // X: -area/2 ~ +area/2
spawnHeight, // Y: ๊ณ ์ ๋์ด
Random.Range(-spawnArea.y / 2f, spawnArea.y / 2f) // Z: -area/2 ~ +area/2
);
// ํ๋ฆฌํน ์ธ์คํด์คํ (์์น: spawnPos, ํ์ : ๋๋ค)
GameObject instance = Instantiate(prefab, spawnPos, Random.rotation);
// -----------------------------------------------------
// [Rigidbody ์ปดํฌ๋ํธ ์ค์ ]
// -----------------------------------------------------
Rigidbody rb = instance.GetComponent<Rigidbody>();
// Rigidbody ๊ฐ ์์ผ๋ฉด ๋์ ์ผ๋ก ์ถ๊ฐ
if (rb == null) rb = instance.AddComponent<Rigidbody>();
// ๋ฌผ๋ฆฌ ์์ฑ ์ค์
rb.isKinematic = false; // ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์
์ ์ํด ์ ์ด๋๋๋ก ์ค์
rb.mass = 1f; // ์ง๋ 1kg (๊ธฐ๋ณธ๊ฐ)
rb.linearDamping = 0.1f; // ์ ํ ์๋ ๊ฐ์ (๊ณต๊ธฐ ์ ํญ ํจ๊ณผ)
rb.angularDamping = 0.05f; // ๊ฐ์๋ ๊ฐ์ (ํ์ ์ ํญ ํจ๊ณผ)
rb.useGravity = true; // ์ค๋ ฅ ์ ์ฉ (๋ํ ํจ๊ณผ)
// ๊ณ ์ ์ด๋ ์ ์ถฉ๋์ ๋์น์ง ์๋๋ก ์ ๋ฐํ ๊ฐ์ง ๋ชจ๋ ์ค์
rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
// -----------------------------------------------------
// [Collider ์ปดํฌ๋ํธ ์ค์ ]
// -----------------------------------------------------
Collider col = instance.GetComponent<Collider>();
// Collider ๊ฐ ์์ผ๋ฉด ๊ธฐ๋ณธ ๋ฐ์ค ์ฝ๋ผ์ด๋ ์ถ๊ฐ
if (col == null) col = instance.AddComponent<BoxCollider>();
// -----------------------------------------------------
// [ํญ๋ฐ ํธ๋ฆฌ๊ฑฐ ํ๊ทธ ํ ๋น]
// -----------------------------------------------------
// ์ธ๋ฑ์ค 0 ๋ฒ ํ๋ฆฌํน (๋ฐฐ์ด์ ์ฒซ ๋ฒ์งธ ์์) ์๋ง ํน์ ํ๊ทธ ๋ถ์ฌ
// ์ด ํ๊ทธ๊ฐ ๋ถ์ ์ค๋ธ์ ํธ๋ง ๋ง์ฐ์ค ํด๋ฆญ ์ ํญ๋ฐ์ ํธ๋ฆฌ๊ฑฐํจ
if (index == 0)
{
instance.tag = TRIGGER_TAG;
}
// ์์ฑ๋ Rigidbody ๋ฅผ ๊ด๋ฆฌ ๋ฆฌ์คํธ์ ๋ฑ๋ก (ํญ๋ฐ ์ ํ์ ๋์)
spawnedObjects.Add(rb);
// ์์ฑ ์นด์ดํธ ์ฆ๊ฐ
currentSpawnCount++;
}
// =========================================================
// [Private Method: ๋ง์ฐ์ค ํด๋ฆญ ํญ๋ฐ ์ฒ๋ฆฌ]
// =========================================================
// Physics.RaycastAll ์ฌ์ฉ ์ด์ :
// - ํ๋ฆฌํน์ด ๊ฒน์ณ ์์ธ ์ํ์์ Physics.Raycast(๋จ์ผ) ๋ ๋งจ ์ ์ค๋ธ์ ํธ๋ง ํํธํจ
// - RaycastAll ์ ๋ ์ด ๊ฒฝ๋ก ์์ ๋ชจ๋ ์ฝ๋ผ์ด๋๋ฅผ ๋ฐํํ๋ฏ๋ก
// - ๊ฐ๋ ค์ง ์์น์ Element 0(ํธ๋ฆฌ๊ฑฐ) ๋ ๊ฐ์ง ๊ฐ๋ฅ
void HandleClickExplosion()
{
// ๋ฉ์ธ ์นด๋ฉ๋ผ๊ฐ ์์ผ๋ฉด ์๋ฌ ๋ก๊ทธ ์ถ๋ ฅ ํ ์ค๋จ
if (Camera.main == null)
{
Debug.LogError("MainCamera ํ๊ทธ๊ฐ ์ค์ ๋ ์นด๋ฉ๋ผ๊ฐ ์์ต๋๋ค.");
return;
}
// ํ์ฌ ๋ง์ฐ์ค ํฌ์ง์
์ฝ๊ธฐ (New Input System ๋ฐฉ์)
Vector2 mousePos = Mouse.current.position.ReadValue();
// ์นด๋ฉ๋ผ์์ ๋ง์ฐ์ค ์์น๋ฅผ ์ง๋๊ฐ๋ 3D ๋ ์ด ์์ฑ
Ray ray = Camera.main.ScreenPointToRay(mousePos);
// ๋ ์ด์ ๊ต์ฐจํ๋ ๋ชจ๋ ์ฝ๋ผ์ด๋ ํ์ (๊ฑฐ๋ฆฌ ์ ํ ์์: Mathf.Infinity)
RaycastHit[] hits = Physics.RaycastAll(ray, Mathf.Infinity);
// ํํธ๋ ๋ชจ๋ ์ฝ๋ผ์ด๋ ์ํ
foreach (RaycastHit hit in hits)
{
// ํํธ๋ ์ค๋ธ์ ํธ๊ฐ "ExplosionTrigger" ํ๊ทธ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด
if (hit.collider.CompareTag(TRIGGER_TAG))
{
Debug.Log($"โ
Element 0 ํด๋ฆญ ๊ฐ์ง: {hit.collider.gameObject.name}");
// ํํธ ์ง์ ์ ์๋ ์ขํ๋ฅผ ์์ ์ผ๋ก ํญ๋ฐ ํธ๋ฆฌ๊ฑฐ ์คํ
TriggerExplosionAt(hit.collider.transform.position);
// ์ฒซ ๋ฒ์งธ ํธ๋ฆฌ๊ฑฐ๋ง ๋ฐ์ํ๋๋ก ๋ฃจํ ์ข
๋ฃ (return)
return;
}
}
}
// =========================================================
// [Private Method: ํญ๋ฐ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์
]
// =========================================================
// ํญ๋ฐ ์์ ๊ธฐ์ค ๋ฐ๊ฒฝ ๋ด ๋ชจ๋ Rigidbody ์ ํ ์ ์ฉ
void TriggerExplosionAt(Vector3 origin)
{
// ๊ด๋ฆฌ ๋ฆฌ์คํธ์์ ์ด๋ฏธ ํ๊ดด๋ (null) Rigidbody ์ ๊ฑฐ (๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ)
spawnedObjects.RemoveAll(rb => rb == null);
// ๋ชจ๋ ๋ฑ๋ก๋ Rigidbody ์ํ
foreach (Rigidbody rb in spawnedObjects)
{
// ํ์ฌ ์ค๋ธ์ ํธ์ ํญ๋ฐ ์์ ์ฌ์ด์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ
float dist = Vector3.Distance(rb.position, origin);
// ํญ๋ฐ ๋ฐ๊ฒฝ์ ๋ฒ์ด๋ ์ค๋ธ์ ํธ๋ ๋ฌด์
if (dist > explosionRadius) continue;
// ํญ๋ฐ ์์ ์์ ์ค๋ธ์ ํธ๋ฅผ ํฅํ๋ ๋ฐฉํฅ ๋ฒกํฐ ๊ณ์ฐ
Vector3 dir = rb.position - origin;
// ๋ฐฉํฅ ๋ฒกํฐ๊ฐ 0 ์ ๋งค์ฐ ๊ฐ๊น์ฐ๋ฉด (์ ํํ ์ค์ฌ์ ์๋ ๊ฒฝ์ฐ)
// ๋๋๊ธฐ ์ค๋ฅ ๋ฐฉ์ง ๋ฐ ์์ ๋ฐฉํฅ์ผ๋ก ํ์ ์ฃผ๊ธฐ ์ํด ๋๋ค ๋จ์ ๋ฒกํฐ ์ฌ์ฉ
if (dir.sqrMagnitude < 0.001f)
dir = Random.onUnitSphere;
// ๋ฐฉํฅ ๋ฒกํฐ ์ ๊ทํ (๊ธธ์ด 1 ๋ก ๋ง๋ค์ด ํ์ ๋ฐฉํฅ๋ง ์ถ์ถ)
dir.Normalize();
// ๊ฑฐ๋ฆฌ์ ๋ฐ๋ฅธ ํ์ ์ธ๊ธฐ ๋ณด์ (proximity)
// dist/explosionRadius: 0(์ค์ฌ) ~ 1(๊ฒฝ๊ณ)
// 1 - clamp(...): 1(์ค์ฌ, ๊ฐํจ) ~ 0(๊ฒฝ๊ณ, ์ฝํจ)
float proximity = 1f - Mathf.Clamp01(dist / explosionRadius);
// ์ต์ข
ํ ๋ฒกํฐ ๊ณ์ฐ: (์ํ ํ์ฐ๋ ฅ + ์์ง ์์น๋ ฅ) * ๊ฑฐ๋ฆฌ ๋ณด์ ๊ณ์
Vector3 force = (dir * radialForce + Vector3.up * upwardForce) * proximity;
// Rigidbody ์ ์๊ฐ์ ์ธ ํ (Impulse) ์ ์ฉ
// ForceMode.Impulse: ์ง๋์ ๊ณ ๋ คํ ์๊ฐ ๊ฐ์๋ (ํญ๋ฐ ๊ฐ์ ์ผํ์ฑ ํ์ ์ ํฉ)
rb.AddForce(force, ForceMode.Impulse);
}
Debug.Log($"๐ฅ ํญ๋ฐ ์๋ฃ. ์์ : {origin}");
}
}
RaycastAll ์ฌ์ฉ ์ด์ ์ผ๋ฐ์ ์ธ ๊ฒ์์์ ๋ง์ฐ์ค ํด๋ฆญ ํ์ ์ Physics.Raycast (๋จ์ผ ํํธ) ๋ฅผ ์ฌ์ฉํ์ง๋ง ์ด ์ํธ์ํฌ๋ ๋ค์๊ณผ ๊ฐ์ ํน์ํ ์ํฉ์ด ๋ฐ์.
Raycast ๋ ๋ ์ด ๊ฒฝ๋ก์ ๊ฐ์ฅ ๊ฐ๊น์ด ์ฝ๋ผ์ด๋ ํ๋๋ง ๋ฐํํ๋ฏ๋ก, ๋ค์ ์จ์ ํธ๋ฆฌ๊ฑฐ๋ฅผ ๊ฐ์งํ์ง ๋ชปํจ. ๋ฐ๋ฉด RaycastAll ์ ๊ฒฝ๋ก์์ ๋ชจ๋ ์ฝ๋ผ์ด๋๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํํ๋ฏ๋ก, foreach ๋ฃจํ์์ ํ๊ทธ๋ฅผ ๊ฒ์ฌํ์ฌ ๊ฐ๋ ค์ง ํธ๋ฆฌ๊ฑฐ๋ ์ ํํ๊ฒ ์ฐพ์ ์ ์์.
๐ก ์ฑ๋ฅ ๊ณ ๋ ค์ฌํญ: ์ค๋ธ์ ํธ๊ฐ ๋งค์ฐ ๋ง์ ๊ฒฝ์ฐ
RaycastAll์ ๋น์ฉ์ด ๋์ต๋๋ค. ์ด ์คํฌ๋ฆฝํธ๋ ์ต๋ 500 ๊ฐ ์ ๋์ ์ค๋ธ์ ํธ๋ฅผ ๊ฐ์ ํ๊ณ ์ค๊ณ๋์์ผ๋ฉฐ, ๋ ๋ง์ ์๊ฐ ํ์ํ๋ค๋ฉด ๋ ์ด์ด ๋ง์คํฌ (layerMask) ๋ฅผ ํ์ฉํ๊ฑฐ๋ ๊ณต๊ฐ ๋ถํ (QuadTree ๋ฑ) ๊ธฐ๋ฒ์ ์ถ๊ฐ๋ก ์ ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
Vector3 force = (dir * radialForce + Vector3.up * upwardForce) * proximity;
dir * radialForce: ํญ๋ฐ ์ค์ฌ์์ ๋ฐ๊นฅ์ผ๋ก ํผ์ง๋ ์ํ ๋ฐฉํฅ ํ. Vector3.up * upwardForce: ๋ฌด์กฐ๊ฑด ์์ชฝ์ผ๋ก ์์ฉํ๋ ํ. * proximity: ๊ฑฐ๋ฆฌ์ ๋ฐ๋ผ ํ์ด ์ฝํด์ง๋๋ก. ์ค์ฌ์ ๊ฐ๊น์ด ๋ฌผ์ฒด๋ ๊ฐํ๊ฒ, ๊ฐ์ฅ์๋ฆฌ๋ ์ฝํ๊ฒ ๋ ์๊ฐ๋ฏ๋ก ์์ฐ์ค๋ฌ์ด ํญ๋ฐ ํ์ฐ์ ๊ตฌํ.damping, collisionDetectionMode ๋ฑ) ์ด ์ฝ๋์์ ์ผ๊ด๋๊ฒ ์ ์ฉ๋์ด ์๋ฎฌ๋ ์ด์
์ฌํ์ฑ ๋ณด์ฅ