import { _decorator, CCInteger, Component, Enum, EventTarget, instantiate, Node, ParticleSystem, Prefab, randomRangeInt, RigidBody2D, Vec2, Vec3, } from 'cc'; import { Ball } from './Ball'; import { EventType } from './Enums'; import { SoundManager } from './SoundManager'; import BEConnector from './BEConnector'; import { UIController } from './UIController'; import { LevelController } from './LevelController'; import Utilities from './Utilities/Utilities'; const { ccclass, property } = _decorator; window.addEventListener('message', (data) => { const { data: res } = data; const objectRes = Utilities.getJson(res); if (objectRes) { const { type, value } = objectRes; if (type === 'newTicket') { BEConnector.instance.numberTicket += value; GameplayController.Instance().OnRevive(); } } }); export enum GameState { MainMenu, StartGame, PlayGame, EndGame, } @ccclass('GameplayController') export class GameplayController extends Component { //#region Singleton private static instance: GameplayController; public static Instance(): GameplayController { if (!GameplayController.instance) { GameplayController.instance = new Node().addComponent(GameplayController); } return GameplayController.instance; } protected onLoad(): void { GameplayController.instance = this; } //#endregion //#region Properties @property(Prefab) private ballPrefab: Prefab; @property([Vec2]) private startPositions: Vec2[] = []; @property(UIController) public uiController: UIController = null; @property(LevelController) private levelController: LevelController = null; @property({ readonly: true, type: CCInteger }) public score: number = 0; @property({ readonly: true, type: CCInteger }) private streak: number = 0; @property({ readonly: true, type: CCInteger }) public highestStreak: number = 0; // @property({ readonly: true, type: CCInteger }) @property(CCInteger) private ball: number = 10; @property(CCInteger) private scoreToSpawnObstacle: number = 5; @property({ type: Enum(GameState) }) public currentGameState: GameState = GameState.MainMenu; @property(ParticleSystem) public particle: ParticleSystem = null; @property(CCInteger) public startGameCountDown: number = 3; @property([Node]) private randomEnemies: Node[] = []; @property(CCInteger) private maxRandomEnemies = 0; //#endregion private _currentRandomEnemies = 0; public eventMenuGame = new EventTarget(); private _currentBallsInGame = 0; public eventStartGame = new EventTarget(); public eventPlayGame = new EventTarget(); public eventEndGame = new EventTarget(); public eventSpawnObstacle = new EventTarget(); public eventUpdateScore = new EventTarget(); public eventUpdateStreak = new EventTarget(); public eventUpdateHighestStreak = new EventTarget(); public eventUpdateBall = new EventTarget(); protected start(): void { BEConnector.instance.authenticate(); this.ChangeGameState(GameState.MainMenu); this.randomEnemies.forEach((enemy) => (enemy.active = false)); } public SpawnBall(): Ball { if (this.currentGameState == GameState.EndGame) return; const ballClone = instantiate(this.ballPrefab); ballClone.setParent(this.node); let randonPos = randomRangeInt(0, this.startPositions.length); ballClone.setPosition(this.startPositions[randonPos].x, this.startPositions[randonPos].y, 0); const ball = ballClone.getComponent(Ball); ball.eventHitObstacle.on('HitObstacle', this.ObstacleHitControl, this); ball.eventGoal.on('Goal', this.GoalControl, this); this._currentBallsInGame++; return ball; } public SpawnBallInTime(time: number): void { if (this.ball <= 0) return; if (this.currentGameState == GameState.EndGame) return; this.spawnEnemies(); //this.unscheduleAllCallbacks(); console.log(GameState[this.currentGameState]); this.scheduleOnce(() => { const ball = this.SpawnBall(); let dir = randomRangeInt(-1, 2); while (dir == 0) { dir = randomRangeInt(-1, 2); } const force = new Vec2(dir, 1); ball.getComponent(RigidBody2D).applyLinearImpulse(force.multiply2f(3, 50), Vec2.ZERO, true); SoundManager.Instance().PlayOneShot(SoundManager.Instance().whistle); }, time); this.SetupObstacle(); } private spawnEnemies() { this._currentRandomEnemies = 0; this.randomEnemies.forEach((enemy) => { if (this._currentRandomEnemies >= this.maxRandomEnemies) return; const chance = randomRangeInt(0, 100) <= 50; enemy.active = chance; if (chance) this._currentRandomEnemies++; }); } //#region Events public AddScore(score: number): void { this.score += score; this.streak++; this.eventUpdateStreak.emit(EventType.UpdateStreak, this.streak); if (this.streak > 2) { let addBall = this.streak - 2; this.ball += addBall; } if (this.highestStreak < this.streak) { this.highestStreak = this.streak; this.eventUpdateHighestStreak.emit(EventType.UpdateHighestStreak, this.highestStreak); } this.eventUpdateBall.emit(EventType.UpdateBall, this.ball); this.eventUpdateScore.emit(EventType.UpdateScore, this.score); SoundManager.Instance().PlayOneShot(SoundManager.Instance().sfxGoal); } public LoseStreak(): void { this.streak = 0; this.eventUpdateStreak.emit(EventType.UpdateStreak, this.streak); } public ChangeGameState(newState: GameState): void { if (this.currentGameState == newState) return; this.currentGameState = newState; this.StateChangeHandle(); } private StateChangeHandle(): void { switch (this.currentGameState) { case GameState.MainMenu: this.eventMenuGame.emit(EventType.MainMenu); break; case GameState.StartGame: this.eventStartGame.emit(EventType.StartGame); this.SpawnBallInTime(this.startGameCountDown); this.levelController?.LevelUp(); BEConnector.instance.ticketMinus('auth'); break; case GameState.PlayGame: this.eventUpdateBall.emit(EventType.UpdateBall, this.ball); this.eventPlayGame.emit(EventType.PlayGame); break; case GameState.EndGame: this.eventEndGame.emit(EventType.EndGame); BEConnector.instance.postScoreToServer(this.score); break; } } public SetBall(ball: number): void { this.ball = ball; this.eventUpdateBall.emit(EventType.UpdateBall, this.ball); } //#endregion private SetupObstacle(): void { if (this.score < this.scoreToSpawnObstacle + 2) return; this.eventSpawnObstacle.emit('SpawnObstacle'); // this.harderObstacle.active = true; } private ObstacleHitControl(node: Node): void { node.active = false; this.scheduleOnce(function () { node.active = true; }, 3); } private GoalControl(positon: Vec3): void { const pos = positon; pos.z = this.particle.node.position.z; this.particle.node.setWorldPosition(pos); this.particle.play(); } public OnRevive(): void { this.uiController.ShutEndPnl(); this.ball += 5; this.eventUpdateBall.emit(EventType.UpdateBall, this.ball); this.SpawnBallInTime(1); } public updateCurrentBallsInGame(value: number) { this._currentBallsInGame += value; if (this._currentBallsInGame <= 0) { this.ball--; this.eventUpdateBall.emit(EventType.UpdateBall, this.ball); if (this.ball <= 0) this.ChangeGameState(GameState.EndGame); else this.SpawnBallInTime(1); } } }