383 lines
15 KiB
TypeScript
383 lines
15 KiB
TypeScript
|
import { DisplayManager } from './displayManager';
|
||
|
import { _decorator, Component, Vec3, find, log} from 'cc';
|
||
|
import {ClientEvent} from '../framework/clientEvent';
|
||
|
import { Constant } from '../framework/constant';
|
||
|
import { GameState, Player, Channel, PropType} from './gameState';
|
||
|
import { PlayerLogic } from './playerLogic';
|
||
|
import { PropLogic } from './propLogic';
|
||
|
import { Util } from '../framework/util';
|
||
|
import { FrameInfo, PlayerInfo, RecvFrameMessage } from '../libs/GOBE';
|
||
|
import { GobeUtil, ROOM_TYPE, WIFI_TYPE } from './gobeUtil';
|
||
|
const { ccclass, property } = _decorator;
|
||
|
|
||
|
/**
|
||
|
* Predefined variables
|
||
|
* Name = LogicManager
|
||
|
* DateTime = Wed Sep 01 2021 17:31:10 GMT+0800 (中国标准时间)
|
||
|
* Author = yanli.huang
|
||
|
* FileBasename = logicManager.ts
|
||
|
* FileBasenameNoExtension = logicManager
|
||
|
* URL = db://assets/script/fight/logicManager.ts
|
||
|
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
|
||
|
*
|
||
|
*/
|
||
|
@ccclass('LogicManager')
|
||
|
export class LogicManager extends Component {
|
||
|
|
||
|
@property(PlayerLogic)
|
||
|
public playerLogic: PlayerLogic = null!;
|
||
|
|
||
|
@property(PropLogic)
|
||
|
public propLogic: PropLogic = null!;
|
||
|
|
||
|
public currentGameState: GameState = {} as GameState;
|
||
|
public get scriptDisplayManager () {
|
||
|
return find("display")?.getComponent(DisplayManager) as DisplayManager;
|
||
|
}
|
||
|
|
||
|
private _arrayGameState: {[index: number]: GameState} = [];
|
||
|
private _startGameTime: number = 0;
|
||
|
private _isGameing: boolean = false;
|
||
|
|
||
|
start () {
|
||
|
this._onGetRoomInfo();
|
||
|
this.playerLogic.init(this);
|
||
|
this.propLogic.init(this);
|
||
|
}
|
||
|
|
||
|
onEnable () {
|
||
|
ClientEvent.on(Constant.EVENT_NAME.ON_GAME_START, this._onStartGame, this);
|
||
|
ClientEvent.on(Constant.EVENT_NAME.ON_GAME_END, this._onEndGame, this);
|
||
|
ClientEvent.on(Constant.EVENT_NAME.CREATE_HAMMER, this._onCreateHammer, this);
|
||
|
}
|
||
|
|
||
|
onDisable () {
|
||
|
ClientEvent.off(Constant.EVENT_NAME.ON_GAME_START, this._onStartGame, this);
|
||
|
ClientEvent.off(Constant.EVENT_NAME.ON_GAME_END, this._onEndGame, this);
|
||
|
ClientEvent.off(Constant.EVENT_NAME.CREATE_HAMMER, this._onCreateHammer, this);
|
||
|
}
|
||
|
|
||
|
private _onEndGame(){
|
||
|
if(this._isGameing){
|
||
|
this._isGameing = false;
|
||
|
GobeUtil.instance.finishGame();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 设置第0帧数据
|
||
|
*/
|
||
|
public setDefaultGameState() {
|
||
|
this._arrayGameState = [];
|
||
|
this.playerLogic.reset();
|
||
|
this.propLogic.reset();
|
||
|
this.currentGameState.id = 0;
|
||
|
this.currentGameState.props = this.propLogic.initProps();
|
||
|
this.currentGameState.players = this.playerLogic.initPlayer();
|
||
|
this.currentGameState.frameTime = Date.now();
|
||
|
this.currentGameState.createHammerTime = Constant.GAME_TIME - Constant.HAMMER_TIME;
|
||
|
this._frameIndex = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 收到房间信息
|
||
|
*/
|
||
|
private _onGetRoomInfo() {
|
||
|
let playerList: PlayerInfo[] = GobeUtil.instance.roomPlayers;
|
||
|
let players: Array<Player> = this.currentGameState.players;
|
||
|
playerList.forEach((value: PlayerInfo, index: number) => {
|
||
|
var pIndex:number = 0;
|
||
|
if(!GobeUtil.instance.checkIsRoomOwner(value.playerId)){
|
||
|
pIndex = 1;
|
||
|
}
|
||
|
let player: Player = players[pIndex];
|
||
|
if (!player.channel) player.channel = {} as Channel;
|
||
|
player.channel.openId = value.playerId;
|
||
|
player.channel.name = value.customPlayerProperties as string;
|
||
|
player.channel.state = value.customPlayerStatus as number;
|
||
|
player.channel.delayTime = 0;
|
||
|
});
|
||
|
|
||
|
ClientEvent.dispatchEvent(Constant.EVENT_NAME.ON_GAME_READY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 开始帧同步操作
|
||
|
*/
|
||
|
private _onStartGame() {
|
||
|
this._isGameing = true;
|
||
|
this._startGameTime = JSON.parse(GobeUtil.instance.room.customRoomProperties)["time"];
|
||
|
this._arrayGameState[0] = Util.clone(this.currentGameState);
|
||
|
|
||
|
let gameState: GameState = this.currentGameState;
|
||
|
let players: Array<Player> = gameState.players;
|
||
|
this.playerLogic.updatePlayerNode(players);
|
||
|
}
|
||
|
/**
|
||
|
* 创建锤子
|
||
|
*
|
||
|
* @param hammerId
|
||
|
*/
|
||
|
private _onCreateHammer(pos:number[]){
|
||
|
this.currentGameState.props[this.propLogic.indexProp] =
|
||
|
this.propLogic.generateProp(new Vec3(pos[0], pos[1], pos[2]), 1, PropType.HAMMER);
|
||
|
this.propLogic.indexProp++;
|
||
|
}
|
||
|
|
||
|
public checkIsReCovery(){
|
||
|
if(GobeUtil.instance.isDisJoin){
|
||
|
this._handleAction(()=>{
|
||
|
this.scriptDisplayManager.updateStateRecovery(this.currentGameState);
|
||
|
this.playerLogic.updateStateRecovery();
|
||
|
this.scriptDisplayManager.updateProp(this.currentGameState);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 创建金币
|
||
|
*
|
||
|
* @param hammerId
|
||
|
*/
|
||
|
public onCreateCoin(pos:number[][]){
|
||
|
this.propLogic.createCoinServer(pos);
|
||
|
}
|
||
|
|
||
|
lateUpdate(dt: number): void {
|
||
|
if (GobeUtil.instance.room && GobeUtil.instance.roomType != ROOM_TYPE.START
|
||
|
|| !this._isGameing) {
|
||
|
// this.scriptDisplayManager.updateState(0.1, this.currentGameState, true);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this._handleAction();
|
||
|
|
||
|
var frameTime : number = GobeUtil.instance.time + GobeUtil.instance.serverTimeDis;
|
||
|
this.currentGameState.time = Math.floor(Constant.GAME_TIME - (frameTime - this._startGameTime) / 1000);
|
||
|
if (this.currentGameState.time <= 0) {
|
||
|
this._isGameing = false;
|
||
|
GobeUtil.instance.finishGame();
|
||
|
}
|
||
|
|
||
|
this.playerLogic.updateState();
|
||
|
this.scriptDisplayManager.updateOwnState(this.currentGameState, dt);
|
||
|
this.scriptDisplayManager.updateState(dt, this.currentGameState, false);
|
||
|
|
||
|
this._checkPlayerScoreLead();
|
||
|
//生成锤子
|
||
|
if (this.currentGameState.createHammerTime == 0) {
|
||
|
this.currentGameState.createHammerTime = this.currentGameState.time - Constant.HAMMER_TIME;
|
||
|
console.log("aaaaa", this.currentGameState.createHammerTime);
|
||
|
}
|
||
|
|
||
|
if((!GobeUtil.instance.isRoomOwnIn && !GobeUtil.instance.checkIsRoomOwner(GobeUtil.instance.ownPlayerId))
|
||
|
|| GobeUtil.instance.checkIsRoomOwner(GobeUtil.instance.ownPlayerId)){
|
||
|
if (this.currentGameState.time < this.currentGameState.createHammerTime) {
|
||
|
console.log("aaaaaa", this.currentGameState.time, this.currentGameState.createHammerTime);
|
||
|
this.currentGameState.createHammerTime = this.currentGameState.time - Constant.HAMMER_TIME;
|
||
|
GobeUtil.instance.createHammer(this.currentGameState.time - Constant.HAMMER_TIME);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 设置分数领先的玩家
|
||
|
*/
|
||
|
private _checkPlayerScoreLead () {
|
||
|
let maxScoreIdx = -1;
|
||
|
let maxScore: number = 0;
|
||
|
|
||
|
for (let idx in this.currentGameState.players) {
|
||
|
let player: Player = this.currentGameState.players[idx];
|
||
|
if (player.channel) {
|
||
|
if (maxScore < player.score) {
|
||
|
maxScore = player.score;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//初始分数都为零则不设置谁领先
|
||
|
if (maxScore === 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//筛选出分数相同的玩家
|
||
|
let arrMaxScorePlayer = this.currentGameState.players.filter((player: Player)=>{
|
||
|
return player.score === maxScore;
|
||
|
})
|
||
|
|
||
|
// 玩家分数得超越另一位才能标记分数领先
|
||
|
for (let index = 0; index < arrMaxScorePlayer.length; index++) {
|
||
|
const player = arrMaxScorePlayer[index];
|
||
|
if (player.isScoreLead) {
|
||
|
maxScoreIdx = player.id;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (maxScoreIdx === -1) {
|
||
|
maxScoreIdx = arrMaxScorePlayer[0].id;
|
||
|
}
|
||
|
|
||
|
this.currentGameState.players.forEach((player: Player)=>{
|
||
|
player.isScoreLead = player.id === maxScoreIdx;
|
||
|
})
|
||
|
}
|
||
|
|
||
|
private _frameIndex:number = 0;
|
||
|
|
||
|
private _isAiHit:boolean = false;
|
||
|
|
||
|
/**
|
||
|
* 处理玩家操作
|
||
|
* @param frame 帧数据
|
||
|
*/
|
||
|
private _handleAction(callback:Function = null) {
|
||
|
if(this._frameIndex > GobeUtil.instance.currFrame){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var frames : FrameInfo[] = [];
|
||
|
if(GobeUtil.instance.recvMap.has(this._frameIndex)){
|
||
|
frames = GobeUtil.instance.recvMap.get(this._frameIndex);
|
||
|
this._frameIndex ++;
|
||
|
}
|
||
|
else{
|
||
|
this._frameIndex ++;
|
||
|
}
|
||
|
|
||
|
for(var index:number = 0; index < frames.length; index ++){
|
||
|
let playerId: string = frames[index].playerId;
|
||
|
let players: Array<Player> = this.currentGameState.players;
|
||
|
let result = players.filter((value: Player) => {
|
||
|
return value.channel && value.channel.openId === playerId;
|
||
|
});
|
||
|
if (!result.length) return;
|
||
|
var msg:string = frames[index].data[0];
|
||
|
let data: {A: number, V: number, I: string, X: number, Z: number, AI: number, Y:number, MX:number, MY:number, T:number} = JSON.parse(msg);
|
||
|
switch(data.A) {
|
||
|
case Constant.ACTION.RUN:
|
||
|
this.scriptDisplayManager.updateRun(playerId, this.currentGameState);
|
||
|
break;
|
||
|
case Constant.ACTION.IDLE:
|
||
|
this.scriptDisplayManager.updateIdle(playerId, this.currentGameState);
|
||
|
break;
|
||
|
case Constant.ACTION.MOVE:
|
||
|
if(data.AI == 1){
|
||
|
players[Constant.AI_PLAYER].position = new Vec3(data.X, 0, data.Z);
|
||
|
players[Constant.AI_PLAYER].eulerAngles = new Vec3(0, data.V, 0);
|
||
|
this.playerLogic.move(Constant.AI_PLAYER, data.X, data.Z, data.V);
|
||
|
}else{
|
||
|
result[0].position = new Vec3(data.X, 0, data.Z);
|
||
|
result[0].eulerAngles = new Vec3(0, data.V, 0);
|
||
|
result[0].moveX = data.MX;
|
||
|
result[0].moveY = data.MY;
|
||
|
this.playerLogic.move(result[0].id, data.X, data.Z, data.V);
|
||
|
}
|
||
|
break;
|
||
|
case Constant.ACTION.STOP_MOVE:
|
||
|
this.playerLogic.stopMove(result[0], 0, 0, 0);
|
||
|
break;
|
||
|
case Constant.ACTION.HEART_BEAT:
|
||
|
result[0].channel.delayTime = data.V as number;
|
||
|
break;
|
||
|
case Constant.ACTION.HIT:
|
||
|
if(data.AI == 1){
|
||
|
this._isAiHit = true;
|
||
|
players[Constant.AI_PLAYER].attackPropType = PropType.HAMMER;
|
||
|
players[Constant.AI_PLAYER].eulerAngles = new Vec3(0, data.V, 0);
|
||
|
}else{
|
||
|
this._isAiHit = false;
|
||
|
result[0].attackPropType = PropType.HAMMER;
|
||
|
result[0].eulerAngles = new Vec3(0, data.V, 0);
|
||
|
}
|
||
|
break;
|
||
|
case Constant.ACTION.IS_ATTACK_ED:
|
||
|
if(this._isAiHit){
|
||
|
result[0].attackPropType = PropType.HAMMER_ED;
|
||
|
var coinCount:number = 0;
|
||
|
if(result[0].score > 10){
|
||
|
coinCount = 10;
|
||
|
result[0].score -= 10;
|
||
|
}
|
||
|
else{
|
||
|
coinCount = result[0].score;
|
||
|
result[0].score = 0;
|
||
|
}
|
||
|
|
||
|
this.propLogic.createCoinByHammer(coinCount, result[0].position);
|
||
|
}else{
|
||
|
players.filter((valueOther: Player) => {
|
||
|
if(valueOther.channel && valueOther.channel.openId != playerId){
|
||
|
valueOther.attackPropType = PropType.HAMMER_ED;
|
||
|
var coinCount:number = 0;
|
||
|
if(valueOther.score > 10){
|
||
|
coinCount = 10;
|
||
|
valueOther.score -= 10;
|
||
|
}
|
||
|
else{
|
||
|
coinCount = valueOther.score;
|
||
|
valueOther.score = 0;
|
||
|
}
|
||
|
|
||
|
if(valueOther.channel.openId != GobeUtil.instance.ownPlayerId){
|
||
|
this.propLogic.createCoinByHammer(coinCount, valueOther.position);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
break;
|
||
|
case Constant.ACTION.HAMMER:
|
||
|
var bool = this.propLogic.removePropId(data.V);
|
||
|
if(bool){
|
||
|
if(data.AI == 1){
|
||
|
players[Constant.AI_PLAYER].hammerCount = 1;
|
||
|
}else{
|
||
|
result[0].hammerCount = 1;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case Constant.ACTION.ICON:
|
||
|
var bool = this.propLogic.removePropId(data.V);
|
||
|
// if(bool){
|
||
|
if(data.AI == 1){
|
||
|
players[Constant.AI_PLAYER].score++;
|
||
|
}else{
|
||
|
result[0].score++;
|
||
|
}
|
||
|
// }
|
||
|
break;
|
||
|
case Constant.ACTION.CREATE_HAMMER:
|
||
|
console.log("aaaaa", data);
|
||
|
ClientEvent.dispatchEvent(Constant.EVENT_NAME.CREATE_HAMMER, [data.X, data.Y, data.Z]);
|
||
|
GobeUtil.instance.hammerIndex = data.V + 1;
|
||
|
this.currentGameState.createHammerTime = data.T;
|
||
|
break;
|
||
|
case Constant.ACTION.CREATE_ICON:
|
||
|
var info = JSON.parse(data.I);
|
||
|
ClientEvent.dispatchEvent(Constant.EVENT_NAME.CREATE_COIN, info["coin_pos"]);
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(callback){
|
||
|
callback();
|
||
|
}
|
||
|
|
||
|
this._handleAction(callback);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* [1] Class member could be defined like this.
|
||
|
* [2] Use `property` decorator if your want the member to be serializable.
|
||
|
* [3] Your initialization goes here.
|
||
|
* [4] Your update function goes here.
|
||
|
*
|
||
|
* Learn more about scripting: https://docs.cocos.com/creator/3.3/manual/zh/scripting/
|
||
|
* Learn more about CCClass: https://docs.cocos.com/creator/3.3/manual/zh/scripting/ccclass.html
|
||
|
* Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.3/manual/zh/scripting/life-cycle-callbacks.html
|
||
|
*/
|