1. 게임 오버 패널 만들기
사진과 같이 게임 오버 패널을 만들어주고 비활성화 상태로 한다.
패널 안에는 게임 화면을 검은색 반투명 처리하는 스프라이트와 게임을 다시 시작할 수 있는 버튼 등도 추가해준다.
기본 레이아웃을 만들면 흰색 박스가 만들어지는데, 흰색을 검은색으로 바꾸고 알파 값을 128로 낮춰서 반투명 스프라이트를 만들었다.
다른 방법은 빈 노드에 스프라이트 컴포넌트를 붙이고 Sprite Frame, Type, Size Mode를 사진과 같이 설정하면 된다.
@property(cc.Node)
gameOverPanel:cc.Node = null;
만든 게임 오버 패널을 GameScene 스크립트에 연결해준다.
스크립트에서는 라이프가 0 이하가 되어서 게임 오버 됐는지, 일시정지 버튼을 눌렀는지 체크해서 이 노드를 활성화하고
이 노드 안의 재시작 버튼을 누르면 노드를 비활성화하는 로직을 구현한다.
2. 게임 오버 조건 체크
DropFish()
{
this.life--;
this.lifeLabel.string = "X" + this.life;
if(this.life == 0)
{
this.gameOverPanel.active = true;
if (cc.sys.localStorage.getItem("best_score") < this.score)
cc.sys.localStorage.setItem("best_score", this.score);
cc.director.pause();
}
}
DropFish 함수에서 라이프를 차감하니까 그 밑에 바로 조건을 체크하는 코드를 추가한다.
게임 오버 노드를 활성화하고, 로컬 DB에 베스트 기록을 저장한다. 그리고 cc.director.pause를 실행해서 게임을 일시 정지시킨다.
이후에는 update 같은 cc.Node의 생명 주기 함수들과 cc.Node가 가지고 있는 runAction 등의 함수가 실행되지 않게 된다.
함수 설명을 보면은 이러하다.
"디렉터의 시간을 일시 중지하고 게임 로직 실행만 포함합니다. 렌더링 프로세스나 이벤트 관리자를 일시 중지하지 않습니다. 렌더링, 오디오 및 이벤트를 포함한 전체 게임을 일시 중지하려면 cc.game.pause를 사용하세요"
정확한 이해를 하기 위해서는 학습이 더 필요하겠지만
게임을 멈추는 함수는 cc.director.puase와 cc.game.pause가 있고 서로 멈추는 범위가 다르다는 걸 알 수 있다.
스크립트에서 cc.game.pause를 써보니 게임이 멈추긴 하는데 화면이 계속 번쩍거리는 현상이 있다.
설명에서 말하는 '중지하지 않는 렌더링 프로세스'는 화면 더블 버퍼링 같은 기능을 포함하는 듯하다.
그리고 이벤트 관리자를 중지하지 않는다는 얘기는 이벤트 리스너는 동작을 한다는 것이다.
ButtonClick()
{
console.log("click~");
}
게임이 멈추고 게임 오버 노드가 활성화되면 나오는 버튼의 클릭 이벤트 리스트에 로그를 찍는 함수를 추가해준다.
실제로 그 버튼을 클릭해보면 로그가 찍히고, 게임이 멈춰도 이벤트 리스너는 동작하는 것을 알 수 있다.
버튼 클릭 이벤트에 게임을 재개시키는 코드를 넣어도 문제가 발생하지 않는다.
3. 게임 재시작
TitleScene에서 게임 시작 버튼에 붙여줬던 StartGameButton 스크립트를 재사용하는 방법을 택했다.
GameOverPanel 안의 재시작 버튼에도 StartGameButton 스크립트를 붙여준다.
// StartGameButton.ts
const {ccclass, property} = cc._decorator;
@ccclass
export default class StartGameButton extends cc.Component {
start () {
this.node.on("click", this.StartGame, this);
}
StartGame()
{
cc.director.loadScene("GameScene");
if (cc.director.isPaused())
cc.director.resume();
}
}
기존 코드에 게임 일시 정지를 풀어주는 코드를 추가한다.
resume을 하지 않으면 씬이 다시 로드가 돼도 start나 update 같은 노드의 라이프 사이클 함수들이 실행되지 않는다.
사실 씬을 새로 불러오는 것으로 게임을 재시작하는 것은 그다지 명쾌하지 않다.
씬을 파괴하고 다시 로드하는 것과, 여러 변수들을 초기값으로 초기화하는 것을 비교하면
후자가 코드량과 체크해야 할 부분이 많긴 해도 속도면에서 빠를 것이다.
이 게임같이 GameScene에 별거 없을 때는 차이가 느껴지지 않겠지만.
@ccclass
export default class StartGameButton extends cc.Component {
restartCallback:cc.ActionInstant;
start () {
this.node.on("click", this.StartGame, this);
}
StartGame()
{
// GameScene에서의 StartGameButton
if (this.restartCallback != null)
{
cc.director.resume();
this.node.runAction(this.restartCallback);
}
// TitleScene에서의 StartGameButton
else
{
cc.director.loadScene("GameScene");
}
}
}
먼저 StartGameButton 스크립트의 StartGame 함수를 위와 같이 수정한다.
this.restartCallback은 GameScene에서만 초기화해줄 것이고 TitleScene에서는 null로 둘 것이다.
this.restartCallback의 null 체크로 이 버튼이 어떤 씬에서의 스타트 버튼인지 구분할 수 있다.
start() {
this.InitFishPool();
this.InitStatus();
this.InitRestartButton();
}
InitRestartButton()
{
var button = this.gameOverPanel.getChildByName("StartGameButton");
button.getComponent(StartGameButton).restartCallback = cc.callFunc(this.RestartGame, this);
}
RestartGame()
{
this.InitStatus();
this.gameOverPanel.active = false;
this.fishPool.forEach(pool => {
pool.forEach(fish => {
if (fish.active)
fish.getComponent(Fish).RemoveFish();
});
});
}
GameScene 스크립트에서는 StartGameButton의 restartCallback을 GameScene의 게임 재시작 함수로 초기화한다.
게임 재시작 함수는 Status 변수들을 초기화하고, 게임 오버 패널을 비활성화한다.
그리고 일시정지된 상태로 화면에 보이는 물고기들을 모두 오브젝트 풀에 반납한다.
콜백 함수를 초기화할 때 언제나 주의해야 할 점은 cc.callFunc의 두 번째 파라미터인 selectorTarget을 꼭 신경 써야 한다.
selectorTarget을 this(GameScene)로 지정해주지 않으면, RestartGame 함수가 실행될 때
함수 안에서의 this는 StartGameButton이 된다. 이 콜백 함수를 가지고 있는 객체는 StartGameButton 이니까.
StartGameButton.InitStatus 함수는 존재하지 않으므로 에러가 난다.
'Cocos Creator' 카테고리의 다른 글
[예제 게임] GameScene #5 (스프라이트 로드와 교체) (0) | 2021.06.07 |
---|---|
[예제 게임] GameScene #4 (오디오 매니저) (0) | 2021.06.04 |
[예제 게임] GameScene #2 (UI 배치, 클릭 이벤트, 스코어 갱신) (0) | 2021.06.01 |
[예제 게임] GameScene #1 (오브젝트 풀링) (0) | 2021.06.01 |
[예제 게임] 씬 전환과 버튼 클릭 이벤트 (0) | 2021.05.31 |