pinball/assets/_Game/Scripts/Manager/GameManager.ts

371 lines
12 KiB
TypeScript
Raw Normal View History

2024-03-27 04:00:23 -07:00
import {
_decorator,
AudioClip,
2024-05-27 02:19:31 -07:00
CCInteger,
Color,
2024-03-27 04:00:23 -07:00
EPhysics2DDrawFlags,
2024-05-27 02:19:31 -07:00
Node,
2024-03-27 04:00:23 -07:00
PhysicsSystem2D,
2024-05-27 02:19:31 -07:00
Prefab,
Quat,
randomRangeInt,
SpriteFrame,
2024-05-27 02:19:31 -07:00
Vec2,
Vec3,
2024-03-27 04:00:23 -07:00
} from 'cc';
2024-05-27 02:19:31 -07:00
import BEConnector from '../API/BEConnector';
import Timer, { TimerType } from '../Base/Timer';
import BoosterType from '../Enum/BoosterType';
2024-03-06 10:08:30 -08:00
import GameState from '../Enum/GameState';
2024-03-07 03:15:08 -08:00
import ScoreType from '../Enum/ScoreType';
2024-03-12 01:50:54 -07:00
import TimeConfig from '../Enum/TimeConfig';
2024-05-27 02:19:31 -07:00
import { FloatingText } from '../Environments/FloatingText';
import GameEvent from '../Events/GameEvent';
import { Ball } from '../GamePlay/Ball';
import ObjectPool from '../Pool/ObjectPool';
2024-03-28 20:35:44 -07:00
import Singleton from '../Singleton';
2024-05-27 02:19:31 -07:00
import Utilities from '../Utilities';
import AudioManager from './AudioManager';
import { EventManger } from './EventManger';
import { StickerManager } from './StickerManager';
2024-03-06 01:28:01 -08:00
const { ccclass, property } = _decorator;
2024-03-26 00:28:59 -07:00
window.addEventListener('message', (data) => {
const { data: res } = data;
const objectRes = Utilities.getJson(res);
if (objectRes) {
const { type, value } = objectRes;
if (type === 'newTicket') {
2024-04-26 00:48:20 -07:00
BEConnector.numberTicket += value;
2024-03-26 00:28:59 -07:00
GameManager.instance.gameRelive();
}
}
});
2024-03-27 04:00:23 -07:00
class Booster {
public type: BoosterType;
public time: number;
public runningTime: number = 0;
constructor(type: BoosterType, time: number) {
this.type = type;
this.time = time;
}
}
2024-03-06 01:28:01 -08:00
@ccclass('GameManager')
2024-03-28 20:35:44 -07:00
export class GameManager extends Singleton<GameManager>() {
@property({ visible: true })
private _colliderDebug: boolean = false;
2024-03-06 03:09:17 -08:00
@property({ type: Prefab, visible: true })
private _ballPrefab: Prefab;
2024-03-08 03:07:41 -08:00
@property({ type: Prefab, visible: true })
private _floatingScoreText: Prefab;
@property({ type: Node, visible: true })
2024-04-23 03:36:31 -07:00
private _topContainer: Node;
2024-03-21 01:59:08 -07:00
@property({ type: Node, visible: true })
private _ballHolder: Node;
2024-03-07 03:15:08 -08:00
@property({ visible: true })
2024-03-06 10:08:30 -08:00
private _ballSpawnPosition: Vec3;
@property({ type: CCInteger, visible: true })
2024-03-29 04:24:58 -07:00
private readonly _timePlay = 120;
2024-04-03 02:43:18 -07:00
@property({ type: SpriteFrame, visible: true })
private _clockIcon: SpriteFrame;
2024-04-03 02:43:18 -07:00
@property({ type: AudioClip, visible: true })
private _boosterActiveSound: AudioClip;
2024-03-10 20:46:50 -07:00
@property({ type: AudioClip, visible: true })
private _startSound: AudioClip;
@property({ type: AudioClip, visible: true })
2024-04-03 02:43:18 -07:00
private _ballOutSound: AudioClip;
@property({ type: AudioClip, visible: true })
2024-03-10 20:46:50 -07:00
private _backgroundMusic: AudioClip;
2024-04-03 02:43:18 -07:00
@property({ type: AudioClip, visible: true })
private _gameOverMusic: AudioClip;
2024-03-06 10:08:30 -08:00
2024-03-06 03:09:17 -08:00
private _ballPool: ObjectPool;
2024-03-08 03:07:41 -08:00
private _FloatingScorePool: ObjectPool;
2024-03-10 20:46:50 -07:00
private _gameState: GameState;
2024-05-27 02:19:31 -07:00
private _timer: Timer = new Timer(TimerType.countDown);
2024-03-27 04:00:23 -07:00
private _boostersActive: Booster[] = [];
2024-03-11 04:12:22 -07:00
2024-03-07 03:15:08 -08:00
private _score = 0;
2024-03-26 00:28:59 -07:00
private isReplayed = false;
2024-03-10 03:12:55 -07:00
private _isMultiBall = false;
2024-04-21 19:04:58 -07:00
private _warningTime = false;
2024-03-10 03:12:55 -07:00
private _currentBallInGame = 0;
private _isWaitingUpdateScore = false;
public get isWaitingUpdateScore() {
return this._isWaitingUpdateScore;
}
2024-03-10 03:12:55 -07:00
2024-04-23 03:36:31 -07:00
public get topContainer() {
return this._topContainer;
}
2024-03-10 03:12:55 -07:00
public get score() {
return this._score;
}
2024-03-06 01:28:01 -08:00
2024-03-29 04:24:58 -07:00
public get gameTime() {
return this._timePlay;
}
public get gameState() {
return this._gameState;
}
2024-03-06 03:09:17 -08:00
protected onLoad(): void {
2024-03-28 20:35:44 -07:00
super.onLoad();
2024-03-07 03:15:08 -08:00
this._ballPool = new ObjectPool(this._ballPrefab, 10, true, Ball);
2024-03-08 03:07:41 -08:00
this._FloatingScorePool = new ObjectPool(this._floatingScoreText, 10, true);
2024-04-26 00:48:20 -07:00
BEConnector.getGameData();
2024-03-28 20:35:44 -07:00
if (this._colliderDebug) PhysicsSystem2D.instance.debugDrawFlags = EPhysics2DDrawFlags.Shape;
2024-03-06 03:09:17 -08:00
}
2024-03-10 20:46:50 -07:00
protected start(): void {
this.changeGameState(GameState.Init);
2024-03-06 10:08:30 -08:00
}
2024-03-12 01:50:54 -07:00
protected update(dt: number): void {
if (this._gameState != GameState.Playing) return;
2024-03-27 04:00:23 -07:00
for (let i = 0; i < this._boostersActive.length; i++) {
const booster = this._boostersActive[i];
booster.runningTime += dt;
if (booster.runningTime >= booster.time) {
this._boostersActive.splice(i, 1);
2024-04-24 04:05:06 -07:00
if (this._boostersActive.length == 0) {
2024-05-27 02:19:31 -07:00
AudioManager.setPlayRateBGM(1);
2024-04-24 04:05:06 -07:00
}
2024-03-27 04:00:23 -07:00
EventManger.instance.emit(GameEvent.BoosterDisable, booster.type);
}
}
2024-03-12 01:50:54 -07:00
}
2024-03-26 00:28:59 -07:00
private async changeGameState(state: GameState) {
2024-03-06 10:08:30 -08:00
this._gameState = state;
EventManger.instance.emit(GameEvent.GameStateChange, this._gameState);
2024-04-26 00:48:20 -07:00
let ticket = 0;
2024-03-26 00:28:59 -07:00
switch (state) {
case GameState.Init:
2024-04-26 00:48:20 -07:00
BEConnector.authenticate();
2024-03-26 00:28:59 -07:00
break;
2024-04-03 02:43:18 -07:00
case GameState.Ready:
break;
2024-03-26 00:28:59 -07:00
case GameState.Playing:
2024-03-29 04:24:58 -07:00
this.countTime();
2024-04-26 00:48:20 -07:00
ticket = await BEConnector.ticketMinus('auth');
EventManger.instance.emit(GameEvent.TicketUpdate, ticket);
2024-03-26 00:28:59 -07:00
break;
case GameState.GameOver:
break;
case GameState.End:
break;
case GameState.Relive:
2024-04-26 00:48:20 -07:00
ticket = await BEConnector.ticketMinus('revive');
EventManger.instance.emit(GameEvent.TicketUpdate, ticket);
2024-03-26 00:28:59 -07:00
break;
default:
throw new Error(`Argument Out Of Range Exception: ${GameState[state]}`);
}
2024-03-06 10:08:30 -08:00
}
2024-03-27 04:00:23 -07:00
public addScore(
2024-03-26 20:04:28 -07:00
score: number,
type: ScoreType,
position: Vec3,
opts?: { scaleMin?: number; scaleMax?: number; duration?: number },
) {
this._score += score;
const floatingScore = this._FloatingScorePool.get(FloatingText, this._topContainer);
floatingScore.show(
`+${score}`,
position,
score >= 100 ? opts?.scaleMax || 1 : opts?.scaleMin || 1,
opts?.duration || 1,
);
EventManger.instance.emit(GameEvent.Score, [this._score, score, type, position]);
}
public async addScoreWithWaiting(
score: number,
type: ScoreType,
position: Vec3,
predicate: () => boolean,
2024-03-26 20:04:28 -07:00
opts: { scaleMin: number; scaleMax: number; duration: number },
) {
this._isWaitingUpdateScore = true;
await Utilities.waitUntil(predicate);
2024-03-07 03:15:08 -08:00
this._score += score;
2024-04-23 03:36:31 -07:00
const floatingScore = this._FloatingScorePool.get(FloatingText, this._topContainer);
2024-03-26 20:04:28 -07:00
floatingScore.show(`+${score}`, position, score >= 100 ? opts.scaleMax : opts.scaleMin, opts.duration);
2024-04-04 04:27:04 -07:00
EventManger.instance.emit(GameEvent.Score, [this._score, score, type, position]);
this._isWaitingUpdateScore = false;
2024-03-10 03:12:55 -07:00
}
2024-03-29 04:24:58 -07:00
private async countTime() {
while (this._gameState == GameState.Playing) {
2024-05-27 02:19:31 -07:00
if (this._timer.time <= 0) {
this._timer.time = 0;
this._timer.stopCount();
2024-03-29 04:24:58 -07:00
this.gameOver();
}
2024-05-27 02:19:31 -07:00
if (!this._warningTime && this._timer.time <= 10) {
2024-04-21 19:04:58 -07:00
this._warningTime = true;
EventManger.instance.emit(GameEvent.WarningTime, true);
}
2024-05-27 02:19:31 -07:00
EventManger.instance.emit(GameEvent.TimeUpdate, this._timer.timeRound);
2024-03-29 04:24:58 -07:00
await Utilities.delay(1);
}
}
2024-03-10 03:12:55 -07:00
private setCurrentBallInGame(value: number) {
this._currentBallInGame += value;
2024-05-01 19:33:07 -07:00
if (value > 0 && this._currentBallInGame >= 2) {
2024-04-01 19:26:53 -07:00
this._isMultiBall = true;
EventManger.instance.emit(GameEvent.MultiBall, true);
this._ballPool.listActive.forEach((ball) => ball.getComponent(Ball).playMultiBallEffect());
2024-03-10 03:12:55 -07:00
}
if (this._currentBallInGame <= 0) {
if (this._isMultiBall) {
this._isMultiBall = false;
EventManger.instance.emit(GameEvent.MultiBall, false);
}
}
2024-03-07 03:15:08 -08:00
}
2024-04-03 02:43:18 -07:00
public spawnBall(throwBall: boolean, playStartSound: boolean = true): Ball {
2024-03-12 01:50:54 -07:00
if (this._gameState != GameState.Playing) return;
2024-05-27 02:19:31 -07:00
if (playStartSound) AudioManager.playSfx(this._startSound);
2024-03-10 03:12:55 -07:00
this.setCurrentBallInGame(1);
2024-04-03 02:43:18 -07:00
const ball = this._ballPool.get(Ball, this._ballHolder);
2024-03-28 20:35:44 -07:00
ball.init(this._boostersActive.length > 0);
2024-03-21 01:59:08 -07:00
ball.node.setRotation(Quat.IDENTITY);
2024-03-06 10:08:30 -08:00
ball.node.setPosition(this._ballSpawnPosition);
2024-03-10 03:12:55 -07:00
if (!throwBall) return ball;
2024-03-06 10:08:30 -08:00
let dir = randomRangeInt(-1, 2);
while (dir == 0) {
dir = randomRangeInt(-1, 2);
}
const force = new Vec2(dir, 1);
2024-03-07 03:15:08 -08:00
ball.throwBall(force.multiply2f(1, 40));
2024-03-06 10:08:30 -08:00
return ball;
}
2024-03-07 09:45:13 -08:00
public async ballOut() {
2024-03-10 03:12:55 -07:00
this.setCurrentBallInGame(-1);
if (this._currentBallInGame <= 0) {
2024-03-12 01:50:54 -07:00
EventManger.instance.emit(GameEvent.BallOut, null);
2024-05-27 02:19:31 -07:00
AudioManager.playSfx(this._ballOutSound);
2024-04-24 04:05:06 -07:00
this.DisableAllBooster();
2024-03-12 01:50:54 -07:00
await Utilities.delay(TimeConfig.DelayPLay);
2024-03-10 03:12:55 -07:00
this.spawnBall(true);
2024-03-06 10:08:30 -08:00
}
2024-03-07 03:15:08 -08:00
}
2024-03-08 03:07:41 -08:00
public async goal(bonusScore: number, position: Vec3) {
2024-03-26 20:04:28 -07:00
this.addScore(this._isMultiBall ? bonusScore * 2 : bonusScore, ScoreType.Goal, position, {
scaleMin: 2,
scaleMax: 3,
duration: 1,
});
2024-03-10 03:12:55 -07:00
this.setCurrentBallInGame(-1);
if (this._currentBallInGame <= 0) {
2024-03-12 01:50:54 -07:00
await Utilities.delay(TimeConfig.DelayGoal);
2024-03-10 03:12:55 -07:00
this.spawnBall(true);
}
2024-03-07 03:15:08 -08:00
}
2024-03-12 01:50:54 -07:00
public async destroyEnvironmentObject(bonusScore: number, position: Vec3, bonusTime?: number) {
if (bonusScore) {
2024-03-27 04:00:23 -07:00
this.addScore(bonusScore, ScoreType.DestroyObject, position, {
2024-03-26 20:04:28 -07:00
scaleMin: 1.5,
scaleMax: 2,
duration: 0.7,
});
2024-03-12 01:50:54 -07:00
await Utilities.delay(0.3);
}
if (bonusTime) {
this.addTime(bonusTime);
2024-04-23 03:36:31 -07:00
const floatingScore = this._FloatingScorePool.get(FloatingText, this._topContainer);
floatingScore.show(`+${bonusTime}`, position, 1.5, 1, this._clockIcon);
2024-03-12 01:50:54 -07:00
}
}
public addTime(time: number) {
2024-05-27 02:19:31 -07:00
this._timer.time += time;
if (this._warningTime && this._timer.time > 10) {
2024-04-25 02:23:23 -07:00
this._warningTime = false;
EventManger.instance.emit(GameEvent.WarningTime, false);
}
2024-05-27 02:19:31 -07:00
EventManger.instance.emit(GameEvent.TimeUpdate, this._timer.timeRound);
2024-03-06 10:08:30 -08:00
}
public async gameOver() {
2024-03-29 04:24:58 -07:00
this._ballPool.releaseAll();
2024-04-24 04:05:06 -07:00
this.DisableAllBooster();
2024-05-27 02:19:31 -07:00
AudioManager.playBGM(this._gameOverMusic);
StickerManager.instance.showLabel('TIME UP!!!', { color: new Color('#ed3a18'), outLineColor: Color.WHITE });
2024-04-26 00:48:20 -07:00
BEConnector.gameScore = this.score;
2024-03-26 00:28:59 -07:00
if (this.isReplayed) {
this.changeGameState(GameState.End);
return;
}
this.isReplayed = true;
2024-03-12 01:50:54 -07:00
this.changeGameState(GameState.GameOver);
2024-03-10 20:46:50 -07:00
}
2024-04-03 02:43:18 -07:00
public Ready() {
2024-05-27 02:19:31 -07:00
AudioManager.playBGM(this._backgroundMusic);
2024-04-03 02:43:18 -07:00
this.changeGameState(GameState.Ready);
}
2024-03-12 01:50:54 -07:00
public async play() {
2024-05-27 02:19:31 -07:00
this._timer.time = this._timePlay;
2024-03-10 20:46:50 -07:00
this._score = 0;
this._currentBallInGame = 0;
this._isMultiBall = false;
this.changeGameState(GameState.Playing);
2024-03-12 01:50:54 -07:00
await Utilities.delay(TimeConfig.DelayPLay);
2024-05-27 02:19:31 -07:00
this._timer.startCount();
2024-03-10 20:46:50 -07:00
this.spawnBall(true);
2024-03-10 03:12:55 -07:00
}
2024-03-26 00:28:59 -07:00
public async gameRelive() {
this.changeGameState(GameState.Relive);
2024-05-27 02:19:31 -07:00
this._timer.time = this._timePlay;
2024-03-26 00:28:59 -07:00
this._currentBallInGame = 0;
this._isMultiBall = false;
2024-05-27 02:19:31 -07:00
AudioManager.playBGM(this._backgroundMusic);
2024-03-26 00:28:59 -07:00
this.changeGameState(GameState.Playing);
await Utilities.delay(TimeConfig.DelayPLay);
2024-05-27 02:19:31 -07:00
this._timer.startCount();
2024-03-26 00:28:59 -07:00
this.spawnBall(true);
2024-03-06 01:28:01 -08:00
}
2024-03-27 04:00:23 -07:00
2024-04-24 04:05:06 -07:00
private DisableAllBooster() {
for (let i = 0; i < this._boostersActive.length; i++) {
const booster = this._boostersActive[i];
EventManger.instance.emit(GameEvent.BoosterDisable, booster.type);
}
this._boostersActive = [];
2024-05-27 02:19:31 -07:00
AudioManager.setPlayRateBGM(1);
2024-04-24 04:05:06 -07:00
}
public async ActiveBooster(type: BoosterType, time: number, displayName: string) {
2024-03-27 04:00:23 -07:00
//check booster already active
for (let i = 0; i < this._boostersActive.length; i++) {
const booster = this._boostersActive[i];
if (booster.type == type) return;
}
this._boostersActive.push(new Booster(type, time));
EventManger.instance.emit(GameEvent.BoosterActive, [type, displayName]);
2024-05-27 02:19:31 -07:00
AudioManager.playSfx(this._boosterActiveSound);
AudioManager.setPlayRateBGM(1.25);
2024-03-27 04:00:23 -07:00
}
2024-03-06 01:28:01 -08:00
}