제작하고 있는 게임 SignalHome은 외계에 고립된 플레이어가 신호기를 발동시켜 지구에 도움을 요청하고, 탈출하는 게임 입니다. 그렇다면 맵에 신호기가 존재하고, 플레이어는 그것을 찾아 발동시켜야겠죠?
스토리 흐름은 다음과 같습니다.
불탄 연구실과 홀로 생존한 플레이어. 곧 외계에서 지구로 돌아가야 하지만, 신호기가 박살난 상태. 신호기에 응축되어있던 에너지는 모두 빠져나갔으며, 여분도 없어져버렸다. 고민하던 찰나 연구실에서 신호기의 존재에 대한 pdf를 발견한다.
이곳에서 처음 발견한 외계 문서에는 이 행성에 엄청난 에너지를 품고 있는 곳이 5곳이 있다고 한다. 우리는 외계 문서에 따라 그것을 '신호기'라고 부른다. 흡사 재단같이 생겼으며, 에너지가 농축된 특정 외계 보석을 넣으면 신호기가 발동된다.
신호기 위치에 대한 설명은 단 한 곳밖에 존재하지 않는다. 신호기에 보석을 넣으면 다음 신호기의 위치가 드러난다. 보석을 돌린 순간, 외계 에너지가 급증하는 곳을 찾아가면 된다.
해당 신호기 주변에 여러개 존재한다.
이제 스토리에서 중요한 신호기 스크립트를 짜봅시다. SemaphoreSytstem 스크립트를 생성합니다.
신호기는 순번대로 진행됩니다. 그러니 현재 게임 진행상태에 어디까지의 신호기까지 진행했는지 저장해야만 합니다.
// GameState.cs
// 첫번째 신호기는 이미 열려있음
public static int currentSemaphoreNumber = 0;
미리 맵에 신호기 다섯개를 배치합니다. 그리고 GameManager의 Inspector에 넣습니다.
// GameManager.cs
[Header("Semaphore")]
public SemaphoreSystem[] semaphores;
private void Start()
{
for (int i = 0; i < GameState.currentSemaphoreNumber + 1; i++)
{
SetActiveSemaphore(i);
}
}
public void SetActiveSemaphore(int num)
{
if (num < 0 || num >= semaphores.Length) return;
semaphores[num].gameObject.SetActive(true);
if (num < GameState.currentSemaphoreNumber)
{
semaphores[num].isUnlocked = true;
}
}
// SemaphoreSystem.cs
[Header("Semaphore Settings")]
public int number;
public Transform keyCrystalPoint;
public GameObject keyCrystalPrefab;
private bool isUnlocked = false;
private void Start()
{
if (isUnlocked)
{
SpawnKeyCrystal();
}
}
private void SpawnKeyCrystal()
{
if (keyCrystalPrefab && keyCrystalPoint)
{
GameObject keyCrystal = Instantiate(keyCrystalPrefab, keyCrystalPoint.position, keyCrystalPoint.rotation);
keyCrystal.transform.SetParent(keyCrystalPoint);
keyCrystal.transform.localPosition = Vector3.zero;
keyCrystal.transform.localRotation = Quaternion.identity;
}
}
F를 누르면 KeyCrystal이 삽입되게 합시다.
// InteractionDetector.cs
private void CheckInteraction()
{
// 기존 코드...
else if (hit.collider.CompareTag("Semaphore"))
{
AddCrystalKey(hit.collider.gameObject);
}
}
private void AddCrystalKey(GameObject hitObject)
{
if (playerItemHandler.currentItem)
{
if (playerItemHandler.currentItem.itemData.itemID == 31)
{
SemaphoreSystem semaphore = hitObject.GetComponent<SemaphoreSystem>();
if (semaphore)
{
semaphore.SpawnKeyCrystal();
GameState.currentSemaphoreNumber++;
gameManager.SetActiveSemaphore(GameState.currentSemaphoreNumber);
inventory.RemoveItemFromInstance(playerItemHandler.currentItem);
}
}
}
}
보석을 넣은 후 2초 후, 이펙트가 활성화되게 해봅시다. 먼저 넣고 싶은 이펙트를 보석이 아닌 신호기에 붙여주세요!
// SemaphoreSystem.cs
[Header("Particle Settings")]
public ParticleSystem particleSystem1;
public ParticleSystem particleSystem2;
private void Start()
{
if (!isUnlocked)
{
particleSystem1.Stop();
particleSystem2.Stop();
}
else
{
SpawnKeyCrystal();
}
}
public void SpawnKeyCrystal()
{
if (keyCrystalPrefab && keyCrystalPoint)
{
// 기존 코드...
Invoke("ShowPartical", 2f);
}
}
void ShowPartical()
{
particleSystem1.Play();
particleSystem2.Play();
}
첫 번째 신호기에 보석을 넣으면 2초 후에 이펙트가 일어납니다. 또한, 다음 신호기의 모습이 보이는 것 또한 확인할 수 있습니다.
모든 신호기에 보석을 놓게 되면 차례대로 빛이 나오더니 위를 향해 빛줄기를 발사하게 됩니다. 해당 빛줄기 파티클을 직접 만들어볼까요? 일단 신호기 프리팹으로 이동합니다.
Hierarchy에서 우클릭 후 Effects -> Line 으로 라인 렌더를 생성해주세요.
// SemaphoreSystem.cs
[Header("Line Setting")]
public LineRenderer lineRenderer;
private void Awake()
{
lineRenderer.useWorldSpace = false;
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, Vector3.zero); // 오브젝트 중심
lineRenderer.SetPosition(1, Vector3.up * 50f); // 위로 50m
}
Project에서 Create -> Material 를 생성합니다.
설정을 한 후 SemaphoreSystem 스크립트에서 Awake에 lineRenderer.material = beamMaterial 이라고 타이핑 해주세요.
모든 신호기가 가동되면 동시에 빔이 쏘아올려집니다. 그렇다면 게임 상태에서 현재 신호기가 모두 발동됐다는 신호를 보내야겠죠?
// GameState.cs
public static bool IsOperate = false;
// GameManager.cs
public void SetOperateSemaphore()
{
if (!GameState.IsOperate) return;
foreach (SemaphoreSystem semaphore in semaphores)
{
semaphore.lineRenderer.enabled = true;
}
}
// SemaphoreSystem.cs
void ShowPartical()
{
particleSystem1.Play();
particleSystem2.Play();
// 마지막 신호기에 보석을 넣었을때만 실행됨
if (number >= 4)
{
GameState.IsOperate = true;
gameManager.SetOperateSemaphore();
}
}
이제 파티클이 생성된 후, 모든 신호기에서 빔이 나오는 것을 확인할 수 있습니다.

다음 글에서는: