import { _decorator, assetManager, Component, director, Label, Node, PhysicsSystem, Vec3, Animation, Prefab, instantiate, tween } from 'cc'; import { RoundBall } from './RoundBall'; import { PlayerController } from './PlayerController'; import { resLoader } from 'db://assets/core_tgx/base/utils/ResLoader'; import { ModuleDef } from 'db://assets/scripts/ModuleDef'; import { tgxUIAlert } from 'db://assets/core_tgx/tgx'; import { AreanNetMgr } from '../../scripts/AreanNetMgr'; import { RewardManager } from './RewardManager'; import { ScenePreloadManager } from 'db://assets/scripts/ScenePreloadManager'; const { ccclass, property } = _decorator; enum GameState { Playing, Paused, GameOver } @ccclass('BallGame') export class BallGame extends Component { /** * 游戏结束 */ private _isGameOver: boolean = false; @property({ type: Node }) guiNode: Node | null = null; public get isGameOver(): boolean { return this._isGameOver; } myBallNum: number = 10; opBallNum: number = 10; deadBallNum: number = 0; rndBallNum: number = 0; @property({ type: PlayerController, displayName: "角色控制" }) playerCtrl: PlayerController | null = null; @property({ type: RoundBall, displayName: "球控制" }) ballCtrl: RoundBall | null = null; @property({ type: Label, displayName: "我方弹珠数量" }) myBallNumLabel: Label | null = null; @property({ type: Label, displayName: "对方弹珠数量" }) opBallNumLabel: Label | null = null; @property({ type: Label, displayName: "放置弹珠数量" }) rndBallNumLabel: Label | null = null; @property({ type: Label, displayName: "击中弹珠数量" }) deadBallNumLabel: Label | null = null; @property(Node) PlaneNode: Node = null; @property(Animation) startAnim: Animation = null!; @property(Label) timerLabel: Label = null!; // 挂载到 timerNode 下的 Label 组件 private gameState: GameState = GameState.Playing; private countdownDuration: number = 120; // 2分钟 = 120秒 private countdownRemaining: number = 120; private isCountdownStarted: boolean = false; private startDelay: number = 0; // 开场动画结束后延迟1.5秒开始 start() { this.initPhysics(); this.initGameState(); this.playStartAnimation(); } private initPhysics() { const physics = PhysicsSystem.instance; physics.enable = true; physics.gravity = new Vec3(0, -10, 0); physics.allowSleep = false; } private initGameState() { this.myBallNum = 10; this.opBallNum = 10; this.deadBallNum = 0; this.rndBallNum = 0; this.PlaneNode.active = false; } private playStartAnimation() { if (this.startAnim) { this.startAnim.play("camera1"); this.startAnim.once(Animation.EventType.FINISHED, this.onStartAnimFinished, this); } } private onStartAnimFinished() { this.PlaneNode.active = true; // 延迟指定秒数后开始倒计时 this.scheduleOnce(() => { this.startCountdown(); }, this.startDelay); } private startCountdown() { this.isCountdownStarted = true; this.countdownRemaining = this.countdownDuration; this.updateTimerDisplay(); // 每秒更新一次 this.schedule(this.updateCountdown, 1); } private updateCountdown() { if (!this.isCountdownStarted || this.gameState !== GameState.Playing) return; this.countdownRemaining--; this.updateTimerDisplay(); if (this.countdownRemaining <= 0) { // 时间到,结束游戏 this.unschedule(this.updateCountdown); this.setGameOver(false); // 时间到算失败 } } private updateTimerDisplay() { if (!this.timerLabel) return; const minutes = Math.floor(this.countdownRemaining / 60); const seconds = this.countdownRemaining % 60; // 格式化为 "xx:xx" this.timerLabel.string = `${minutes < 10 ? '0' + minutes : minutes}:${seconds < 10 ? '0' + seconds : seconds}`; } AddBall() { console.log("添加球"); if (this.playerCtrl) { this.playerCtrl.AddBall(); } } public setGameOver(isWin: boolean) { this.isCountdownStarted = false; // 停止倒计时 this.unschedule(this.updateCountdown); if (!isWin) { resLoader.load(ModuleDef.Arean, 'common/prefabs/settlement', (err: Error | null, prefab: Prefab) => { if (!err && prefab) { const n = instantiate(prefab); this.guiNode.addChild(n); n.getComponent(Animation).play("showLose"); } }); } else { resLoader.load(ModuleDef.Arean, 'common/prefabs/settlement', (err: Error | null, prefab: Prefab) => { if (!err && prefab) { const n = instantiate(prefab); this.guiNode.addChild(n); n.getComponent(Animation).play("showWin"); } }); } this.scheduleOnce(() => { resLoader.load(ModuleDef.Arean, 'common/prefabs/settlement', (err: Error | null, prefab: Prefab) => { if (!err && prefab) { const n = instantiate(prefab); this.guiNode.addChild(n); n.getComponent(Animation).play("showSettlement"); // Lives从10滚动到8 const livesLabel = n.getChildByPath("settlementNode/Node/lives").getComponent(Label); let lives = { value: 4 }; tween(lives) .to(1, { value: 2 }, { easing: 'linear', onUpdate: () => { livesLabel.string = Math.floor(lives.value).toString(); } }) .start(); // Money从400w滚动到480w const moneyLabel = n.getChildByPath("settlementNode/Node/money").getComponent(Label); let money = { value: 452 }; tween(money) .to(1, { value: 454 }, { easing: 'linear', onUpdate: () => { moneyLabel.string = Math.floor(money.value) + "w"; } }) .start(); n.getChildByPath("settlementNode/btnOK/label").getComponent(Label).string = "Coming Soon"; n.getChildByPath("settlementNode/btnOK").on(Node.EventType.TOUCH_START, () => { if(isWin) { director.loadScene("lobby_arean"); } else { director.loadScene(director.getScene().name); } // 初始化奖励管理器 // RewardManager.instance.init(this.guiNode); // // 显示宝箱奖励 // RewardManager.instance.showRewardChest(() => { // // 奖励界面关闭后切换场景 // if (isWin) { // director.loadScene("lobby_arean"); // } else { // director.loadScene("lobby_arean"); // } // }); }); } }); }, 3); } public RestartGame() { this.myBallNum = 10; this.opBallNum = 10; this.deadBallNum = 0; this.rndBallNum = 0; this.refreshBallNum(); if (this.playerCtrl) { this.playerCtrl.resetGame(); } if (this.ballCtrl) { this.ballCtrl.resetGame(); } this.countdownRemaining = this.countdownDuration; this.isCountdownStarted = false; this.updateTimerDisplay(); } // update(deltaTime: number) { // if (this.playerCtrl) { // if (this.playerCtrl.IsMoveEnd()) { // if (this.ballCtrl && this.ballCtrl.isMoveEnd()) { // console.log("球移动结束"); // if (this.playerCtrl.AddBallEnd()) { // this.setGameOver(this.ballCtrl.isbegin); // this.RestGame(); // } else { // if (this.ballCtrl.isbegin) { // this.setGameOver(this.ballCtrl.isbegin); // this.RestGame(); // } // } // } // } // } // } public refreshBallNum() { scrollLabelToNumber(this.myBallNumLabel!, this.myBallNum); scrollLabelToNumber(this.opBallNumLabel!, this.opBallNum); scrollLabelToNumber(this.deadBallNumLabel!, this.deadBallNum); scrollLabelToNumber(this.rndBallNumLabel!, this.rndBallNum); } changeGameScene() { var bundle = assetManager.getBundle('level1'); if (bundle) { director.loadScene("scene/level1Scene"); } else { assetManager.loadBundle("level1", () => { director.loadScene("scene/level1Scene"); }) } } onClickBtnQuit() { tgxUIAlert.show(`是否确认退出 ? `, true).onClick(async b => { if (b) { AreanNetMgr.inst.sendMsg_exit(); } }); } } function scrollLabelToNumber(label: Label, targetNumber: number, duration: number = 0.3) { const startNumber = parseInt(label.string); // 获取当前 Label 上的数字 const startTime = Date.now(); // 记录开始时间 const updateNumber = () => { // 计算已经过去的时间比例 const elapsedTime = (Date.now() - startTime) / (duration * 1000); const progress = Math.min(elapsedTime, 1); // 限制在 [0, 1] 范围内 // 计算当前数字 const currentNumber = Math.round(startNumber + (targetNumber - startNumber) * progress); // 更新显示的数字 label.string = currentNumber.toString(); // 如果动画未结束,继续更新数字 if (progress < 1) { requestAnimationFrame(updateNumber); } }; // 开始更新数字 updateNumber(); }