1. 오늘의 할 일
개인 씬을 만들었습니다. (aka. 팀플)
그리고 그런 와중에 나와 마주하는 수많은, 심각한 오류는 아닌데 뭔가 2%부족하거나 아무튼 마음에 안 드는 것들.
이걸 처리해야겠죠.
GO. 출발.
2. 제작 시작🛠️
1. 카운트 다운 진행 중 Card가 안나타나게 만들기.
예시
카운트다운, 일단 완성한 것부터 확인하자.
사실 저 장면도 완벽한 것은 아닌 것이, 저 상태에서 카드를 누르면 눌린다.(...)
(즉, 시간이 가기 전에 카드를 먼저 맞춰버릴 수 있다) >게임 시작 전까지 카드를 보여주는 패널을 false로 바꿨다가 게임 시작과 동시에 true로 변경할 것
코드1
public class GameManager : MonoBehaviour
{ //중간 요소들은 생략한다.
public GameObject CardBoard;
void Update()
{
//타이머 진행 중략
//타이머가 끝나면 게임이 시작됨
if (GStart)
{
if (time >= 0f)
{
CardBoard.SetActive(true); //게임이 시작되자 CardBoard를 SetAcrtive를 true로 전환
time -= Time.deltaTime; //게임이 시작되고나서부터 time값 감소 시작
timeTxt.text = time.ToString("N2");
}
else //시간 초과
{
time = 0f;
FailBoard.SetActive(true);
PlayBoard.SetActive(false);
CardBoard.SetActive(false); //게임이 끝나자 CardBoard를 SetAcrtive상태를 false로 전환
Time.timeScale = 0.0f;
timeTxt.text = time.ToString("N2");
}
}
}
}
CardBoard를 껐다켰다 하기만 하면 되니까 어렵지 않다.
결과
Q. 그럼 저 카운트다운 영역은 어떻게 만들었나요?
2. 카운트다운 화면 제작
실행 시 오브젝트의 움직임
하나씩 꺼졌다가 켜졌다가 마지막에 전부 꺼지는 것이 보인다.
저걸 구현한 코드는 아래와 같다.
코드2
//class를 포함해 다른 기능의 코드들은 전부 중략처리
//타이머
private int Timer = 0; //정수>타이머로 명명하여 0으로 처리함
//타이머 지나가는 동안 꺼지고 켜질 요소들
public GameObject CPanel; //검은색 반투명 오버레이
public GameObject NumA; //3
public GameObject NumB; //2
public GameObject NumC; //1
public GameObject NumGO;
void Start()
{
//게임 시작 시 초기값 설정
Time.timeScale = 1.0f;
Timer = 0;
CPanel.SetActive(false);
NumA.SetActive(false);
NumB.SetActive(false);
NumC.SetActive(false);
NumGO.SetActive(false);
}
void Update()
{
//타이머 진행
if (Timer == 0)
{
CPanel.SetActive(true);
}
if (Timer <= 200)
{
Timer++;
if (Timer > 0)
{
NumA.SetActive(true);
}
if (Timer > 50)
{
NumB.SetActive(true);
NumA.SetActive(false);
}
if (Timer > 100)
{
NumC.SetActive(true);
NumB.SetActive(false);
}
if (Timer >= 150)
{
NumGO.SetActive(true);
NumC.SetActive(false);
}
if (Timer >= 200)
{
NumGO.SetActive(false);
CPanel.SetActive(false);
GStart = true;
}
}
//타이머가 끝나면 게임이 시작됨
}
timer가 update되면서, 일정 수치가 넘어갈 때마다 하나씩 꺼지고, 켜지고, 마지막에는 전부 꺼진 뒤 게임을 실행하는 bool값을 true로 전환시켰다.
그럼 코드 1에 적어둔 대로, CardBoard가 열리면서 생성된 카드가 보이고, deltatime이 감소하면서 0까지 타이머가 흐르게 된다.
3. 그러나 여기서 문제는 끝나지 않았다.
문제 영상
보다시피. 카드가 한 번에 한 장만 열리지 않는다.
같은 걸 연속으로 누르는 걸 방지하는 처리를 해둬서 같은 카드를 연속으로 누르면 사라진다던가,
서로 다른 카드를 눌렀는데도 사라지는 사태는 발생하지 않지만….
카드.cs에서 canClick을 써서 막아보려했더니 안 막힌다.
그럼 GameManager를 건드려야 한다는 뜻이다.
또 저 많은 코드들 사이에서 기능하도록 불리언을 다시 넣고 on off를 확인하고. 잘 될지는 자신이 없지만.
코드3
//필요한 요소 외에는 넣지 않았습니다.
//in GameManager
public bool canClick = true; //불리언으로 선언
public void Matched() //두 개를 다 열면 Matched() 실행
{
canClick = false;
if (firstCard.idx == secondCard.idx)
{
//두 카드가 서로 일치할 때 없앰
StartCoroutine(WaitClick()); //코루틴을 이용해 지연시킴
if (cardCount == 0)
{
//카드를 전부 소모하면 게임 종료화면
Time.timeScale = 0.0f;
}
}
else
{
//카드가 서로 불일치 하면 다시 덮음
StartCoroutine(WaitClick()); //마찬가지로 코루틴으로 기다려줌
}
firstCard= null;
secondCard= null;
}
IEnumerator WaitClick() //코루틴으로 부른 동안 처리할 일
{
yield return new WaitForSecondsRealtime(1.0f); //현실시간 1초 기다리고
canClick = true; //다시 클릭 가능하게 바꿔준다.
}
그런데 게임매니저를 수정한 것만으로는 해결되지 않는다.
사유: 카드를 여는 함수는 카드 스크립트에 있기 때문이다.
그래도 수정할 것은 많지 않다. 딱 하나만 추가하면 된다.
코드4
//card 스크립트에 있는 다른 사항은 적지 않음.
public void OnMouseDown() //버튼이 아닌 object에 박스콜라이더를 다는 형식으로 바꾸어, OnMouseDown을 사용
{
if (GameManager.Instance.canClick == true)OpenCard();
//GameManager의 canClick이 true일 때만 OpenCard함수를 실행할 수 있도록 지정
}
해냈다.
즉, Card 스크립트에만 넣음>정작 매치되었을 때 멈춰야하는데 그 순간이 없으니 지연이 느껴지지 않음.
GameManager에만 넣음> OpenCard를 담당하는 건 Card스크립트이기 때문에 막히지 않음
(지연은 하는데…뭘 지연하는데? 가 된다.)
스크립트 사이와 사이를 연결해주지 않으면 안되는 경우도 있던 것이다…
Q. 해결하신 걸 축하드립니다. 그런데 그 코루틴이 뭔데요?
A. Invoke랑 비슷한 겁니다. 그런데 이제 범용성이 좋은.
StartCoroutine(); 의 특징은, 해당 파트를 넣은 순간에 잠시 함수가 정지되고, 코루틴과 연결된 함수를 실행시킨다는 것이다.
비유하자면 목적지로 잘 가다가 다X소를 보고 어, 잠시만 기다려봐 나 다X소 좀 들렀다 올게. 하고 다녀오는 것이다.
하지만 저 StartCoroutine()은 혼자 쓰일 수 없다. 하단에 짝을 이룬 녀석이 있는 게 보인다.
코드3에 색을 칠한 것들을 좀 보자.
IEnumerator WaitClick() . //얘가 대충 다X소 역할이다. 다X소 WaitClick()
yield return new WaitForSecondsRealtime(1.0f); //얘는 다X소를 들리는 시간이다.
canClick = true; //얘는 필수요소는 아니고, 그 다X소에 들어간 상태에서 실행하는 다른 행동들이다.
끝나면 다시 돌아와서 읽어내기 시작한다.
StartCoroutine();은 반드시 IEnumerator 혹은 IEnumarable과 함께 쓰인다.
(둘의 차이점은, 죄송합니다. 아직 모릅니다.)
특징적으로는 yield return 조건( )이 보인다. 이건 코루틴을 쓸 때 IEnumerator안에서 쓸 수 있는데, 풀이하자면
'시간/할 거 다 됐으니까 이제 다시 돌아가자'이다. 즉, 조건을 만족하면 원래대로 되돌아가도록 시켜주는 역할이다.
코드 3에서는 조건이 현실시간 1초를 기다린 후 되돌아간다는 뜻이다.
즉, Matched()가 시작되자마자 canClick이 막혔던 것을, Matched()가 끝날 때즈음에 코루틴에 들어가 잠시 1초 대기했다가 다시 풀어주는 역할인 것.
이 yield return의 조건은 꽤 다양하다.
yield return null (조건이 없으므로 다음 Update 호출까지 기다림) 이나, new WaitForSeconds(이건 유니티 시간 1초) 등이 있다.
조건을 넣는 것도 있는데, 세세한 건 검색으로 찾아보자…. 다 적어두면 물론 좋겠지만, 오늘은 코루틴을 일일히 뜯어보는 시간이 아니기 때문에 여기서 끝낼 것이다.
4. 내일은 뭐하지?
씬 조작을 해볼 것이다.
단순히 씬을 넘기는 것은 할 수 있다. 하지만, 연결되는 것이 여러개의 씬이라면?!?!
정말 0부터 시작하는 씬 매니저 찾기 프로젝트. 내일 시작합니다.
'Unity_본캠프' 카테고리의 다른 글
[내일배움캠프 1주차] 1주차 정리 (1) | 2025.04.13 |
---|---|
[내일배움캠프 5일차] 쉬어갑시다? 코루틴 (2) | 2025.04.11 |
[내일배움캠프 4일차] 브금을 깔자 (1) | 2025.04.10 |
[내일배움캠프 2일차] Github (3) | 2025.04.08 |
[내일배움캠프 1일차] 카드 뒤집기 (3) | 2025.04.07 |