| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- import { Label, dragonBones, instantiate } from 'cc';
- import { find } from 'cc';
- import { _decorator, Component, Node } from 'cc';
- import { v3 } from 'cc';
- import { Charactor } from './Charactor/Charactor';
- import { GameEventEnum, GameSystemInputType } from './GameStruct';
- import { CharactorAI } from './Charactor/CharactorAI';
- import { JCMGO } from '../ThirdParty/JCMGO';
- import { BuiltinMatchInfos } from './View/GameMatchView';
- const { ccclass, property } = _decorator;
- @ccclass('GameMode')
- export class GameMode extends Component {
- protected onLoad(): void {
- //监听处理游戏开始
- window.gm.node.on(GameEventEnum.GameStart, this.handleGameStart.bind(this));
- //监听处理游戏结束
- window.gm.node.on(GameEventEnum.GameEnd, this.handleGameEnd.bind(this));
- //监听匹配结束
- window.gm.node.on(GameEventEnum.MatchEnd, () => {
- //显示游戏角色
- find("Canvas/CharactorGroup").active = true;
- });
- }
- protected start(): void {
- this.initLines();
- //显示匹配界面
- find("Canvas-001/GameMatchView").active = true;
- }
- protected lateUpdate(): void {
- this.updateFollowCamera();
- this.uploadInputs();
- }
- handleGameStart() {
- this.displayReadyGo();
- //打开游戏UI界面
- find("Canvas-001/GameModeView").active = true;
- //ai判断
- for (let i = 0; i < window.gm.state.aiFlags.length; i++) {
- if ( window.gm.state.aiFlags[i]) {
- this.getCharactorNode(i).addComponent(CharactorAI);
- }
- }
- }
- handleGameEnd() {
- //关闭游戏UI界面
- find("Canvas-001/GameModeView").active = false;
- //打开结算界面
- find("Canvas-001/GameSettleView").active = true;
- //关闭socket
- window.gm.socketPlayer.close();
- }
- /**初始化-起跑线/终点 */
- private initLines() {
- let startLine = find("Canvas/BandGroup/Start");
- let endLine = instantiate(startLine);
- endLine.name = "End";
- endLine.position = endLine.position.add(v3(window.gm.config.endPointDistance));
- find("Canvas/BandGroup").addChild(endLine);
- }
- /**更新相机跟随 */
- private updateFollowCamera() {
- let bgGroupNode = this.getBGGroupNode();
- let cameraNode = this.getCameraNode();
- let charactorNode = this.getCharactorNode(window.gm.state.myPlayerIndex);
- //相机跟随我控制的角色
- cameraNode.position = cameraNode.position.set(charactorNode.position.x, cameraNode.position.y)
- //根据相机位置,动态补充背景
- while (cameraNode.position.x >= bgGroupNode.children[1].position.x) {
- bgGroupNode.children[0].setPosition(
- bgGroupNode.children[0].position.add(v3(720))
- )
- bgGroupNode.children[0].setSiblingIndex(1);
- }
- }
- /**显示ReadyGo动画 */
- private displayReadyGo() {
- let dp = find("Canvas-001/ReadyGoDisplay").getComponent(dragonBones.ArmatureDisplay);
- dp.node.active = true;
- dp.addEventListener(dragonBones.EventObject.COMPLETE, () => {
- dp.node.destroy();
- }, this);
- window.gm.node.emit(GameEventEnum.ReadyGo);
- }
- //========================获取节点========================
- private _cameraNode: Node;
- private getCameraNode() {
- if (!this._cameraNode) this._cameraNode = find("Canvas/Camera");
- return this._cameraNode;
- }
-
- private _bgGroupNode: Node;
- private getBGGroupNode() {
- if (!this._bgGroupNode) {
- this._bgGroupNode = find("Canvas/BGGroup");
- if (this._bgGroupNode.children.length == 1) {
- this._bgGroupNode.addChild(instantiate(this._bgGroupNode.children[0]))
- }
- }
- return this._bgGroupNode;
- }
- private _charactorGroup: Node;
- public getCharactor(index: number) {
- if (!this._charactorGroup) this._charactorGroup = find("Canvas/CharactorGroup")
- return this._charactorGroup.children[index].getComponent(Charactor);
- }
- public getCharactorNode(index: number) {
- if (!this._charactorGroup) this._charactorGroup = find("Canvas/CharactorGroup")
- return this._charactorGroup.children[index];
- }
- //========================游戏逻辑处理(逻辑/渲染已分离)========================
- /**处理进入房间 */
- handleEnterRoom(data: JCMGO.RoomAddPlayerBst) {
- if (data.isSelf) window.gm.state.myPlayerIndex = data.playerIndex;
- }
- /**处理匹配完成 */
- handleMatchComplete(data: JCMGO.RoomEndMatchingBst) {
- JCMGO.ExactMath.setSeed(data.timestamp);
- let aiInfoIndexes = [];
- for (let i = 0; i < BuiltinMatchInfos.aiPlayerInfos.length; i++) aiInfoIndexes.push(i);
- aiInfoIndexes.sort(() => JCMGO.ExactMath.sub(0.5, JCMGO.ExactMath.random()))
- window.gm.state.matchPlayerInfos = new Array(window.gm.config.maxMembers);
- for (let i = 0; i < window.gm.state.matchPlayerInfos.length; i++) {
- let playerInfo = data.roomInfo.playerInfos[i];
- if (!playerInfo) { //这个索引位没有真人,就分配个ai
- playerInfo = BuiltinMatchInfos.aiPlayerInfos[aiInfoIndexes.shift()];
- window.gm.state.aiFlags[i] = true;
- } else {
- window.gm.state.aiFlags[i] = false;
- }
- window.gm.state.matchPlayerInfos[i] = JCMGO.ObjectUtils.merge({}, playerInfo) as MatchPlayerInfo;
- }
- window.gm.node.emit(GameEventEnum.MatchEnd);
- }
- handleFrameSyncStart() {
- window.gm.state.isFrameSyncStarted = true;
- window.gm.node.emit(GameEventEnum.GameStart);
- }
- /**上传帧输入 */
- public uploadInputs() {
- if (!window.gm.state.isFrameSyncStarted || window.gm.state.authGameSystemState.gameOver) return;
- //本地预测时间间隔(最终还是以服务器下发的为准)
- let nowTime = Date.now();
- if (window.gm.state.lastUploadTime === 0) window.gm.state.lastUploadTime = nowTime;
- //模拟本地预测帧并更新状态
- let moniFrame = window.gm.socketPlayer.moniServerFrame({sign: window.gm.state.lastSign.toString(), dt: nowTime - window.gm.state.lastUploadTime});
- window.gm.state.lastUploadTime = nowTime;
- window.gm.state.localMoniFrames.push(moniFrame);
- this.handleInputs(window.gm.state.gameSystemState, moniFrame.inputs as GameSystemInput[], moniFrame.dt);
- //上传帧输入到服务器
- window.gm.socketPlayer.uploadInputs(window.gm.state.lastSign.toString());
- window.gm.state.lastSign++;
- //清除缓存的帧输入
- window.gm.socketPlayer.clearInputs();
- }
- /**处理服务器下发的帧数据 */
- public handleRecvFrame(frame: JCMGO.Frame) {
- //更新权威状态
- this.handleInputs(window.gm.state.authGameSystemState, frame.inputs as GameSystemInput[], frame.dt);
- //移除已经被服务器认证的本地帧
- for (let i = window.gm.state.localMoniFrames.length - 1; i >= 0; i--) {
- let localFrame = window.gm.state.localMoniFrames[i];
- if (parseInt(localFrame.sign) <= parseInt(frame.sign)) {
- window.gm.state.localMoniFrames.splice(i, 1);
- }
- }
- //当前状态回滚到权威状态
- window.gm.state.gameSystemState = JCMGO.ObjectUtils.merge({}, window.gm.state.authGameSystemState) as GameSystemState;
- //预测并更新当前状态
- window.gm.state.localMoniFrames.forEach((frame: JCMGO.Frame) => {
- this.handleInputs(window.gm.state.gameSystemState, frame.inputs as GameSystemInput[], frame.dt)
- });
- // find("Canvas-001/DebugUI/Label").getComponent(Label).string = JSON.stringify(
- // window.gm.state.authGameSystemState.gameOver ? window.gm.state.authGameSystemState : window.gm.state.gameSystemState,
- // null, "\t");
- }
- /**处理帧输入 */
- private handleInputs(state: GameSystemState, inputs: GameSystemInput[], dt: number) {
- if (state.gameOver) return;
- //计时
- state.time = JCMGO.ExactMath.add(state.time, dt);
- //判断readygo是否完成
- if (!state.readyComplete) {
- if (state.time > 1600) {
- state.readyComplete = true;
- } else {
- return;
- }
- }
- //处理玩家输入
- if (inputs instanceof Array) {
- inputs.forEach((input: GameSystemInput) => {
- if (input.type === GameSystemInputType.PlayerAcc) {
- let ps = state.playerStates.find(v => v.index === input.playerIndex);
- if (ps) {
- ps.speedX = JCMGO.ExactMath.add(ps.speedX, window.gm.config.acc);
- ps.lastAccTime = state.time;
- ps.accCount++;
- }
- return;
- }
- });
- }
- //===========================处理游戏逻辑======================
- //更新玩家状态
- state.playerStates.forEach(ps => {
- //如果超过1秒没加速,就开始减速
- if (JCMGO.ExactMath.sub(state.time, ps.lastAccTime) > window.gm.config.decGap) {
- ps.speedX = JCMGO.ExactMath.add(
- ps.speedX,
- JCMGO.ExactMath.mul(window.gm.config.dec, JCMGO.ExactMath.div(dt, 1000))
- );
- if (ps.speedX < 0) ps.speedX = 0;
- }
- //更新位置
- ps.moveX = JCMGO.ExactMath.add(
- ps.moveX,
- JCMGO.ExactMath.mul(ps.speedX, JCMGO.ExactMath.div(dt, 1000))
- );
- });
- //判断是否有玩家获胜,游戏结束
- let winners: PlayerState[] = [];
- for (const ps of state.playerStates) {
- if (ps.moveX >= window.gm.config.endPointDistance) {
- winners.push(ps);
- }
- }
- if (winners.length > 0) {
- winners.sort((a, b) => b.moveX - a.moveX);
- state.winPlayerIndex = winners[0].index;
- state.gameOver = true;
- this.emitGameEnd();
- }
- }
- private _emitedGameEnd = false;
- private emitGameEnd() {
- if (this._emitedGameEnd) return;
- if (window.gm.state.authGameSystemState.gameOver) {
- this._emitedGameEnd = true;
- window.gm.node.emit(GameEventEnum.GameEnd);
- }
- }
- }
|