[add] first

This commit is contained in:
2023-11-07 09:17:57 +08:00
commit 23924175a2
1102 changed files with 313997 additions and 0 deletions

12
assets/script/core.meta Normal file
View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "da2fa781-c694-476c-bf59-ad6fd00af7d1",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,69 @@
import { _decorator, Component, Node, Prefab, Vec3, LabelComponent, Tween } from "cc";
import {PoolManager} from "../framework/poolManager";
import {ClientEvent} from "../framework/clientEvent";
const { ccclass, property } = _decorator;
@ccclass("coinTipsManager")
export class coinTipsManager extends Component {
@property(Prefab)
pfCoinTips: Prefab = null!;
onEnable() {
ClientEvent.on('showCoinTips', this.showCoinTips, this);
}
onDisable() {
ClientEvent.off('showCoinTips', this.showCoinTips, this);
}
showCoinTips (coin: string, posWorld: Vec3) {
let tipsNode = PoolManager.instance.getNode(this.pfCoinTips, this.node);
let out = new Vec3();
//@ts-ignore
window.mainCamera.convertToUINode(posWorld, this.node, out);
tipsNode.setPosition(out);
let nodeNum = tipsNode.getChildByName('num');
if (nodeNum) {
nodeNum.getComponent(LabelComponent).string = coin;
}
//播放动画
tipsNode.setScale(0, 0, 0)
tipsNode['tweenMove'] = new Tween(tipsNode)
.to(0.3, {scale: new Vec3(1.2, 1.2, 1.2)})
.to(0.1, {scale: new Vec3(1, 1, 1)})
.by(0.6, {position: new Vec3(0, 100, 0)})
.union()
.call(()=>{
tipsNode['tweenMove'] = null;
PoolManager.instance.putNode(tipsNode);
})
.start();
}
/**
* 如果界面切换需要对tips进行回收
*/
recrycle () {
let arrChild: Node[] = [];
this.node.children.forEach((child: Node)=>{
arrChild.push(child);
});
arrChild.forEach((child: Node)=>{
//@ts-ignore
if (child['tweenMove']) {
//@ts-ignore
child['tweenMove'].stop();
//@ts-ignore
child['tweenMove'] = null;
}
PoolManager.instance.putNode(child);
})
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "03627329-603f-4643-9729-e1173bee741a",
"files": [],
"subMetas": {},
"userData": {
"moduleId": "project:///assets/script/fight/coinTipsManager.js",
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,342 @@
import { _decorator, Component, Node, Prefab, Animation } from 'cc';
import {ClientEvent} from '../framework/clientEvent';
import { UIManager } from '../framework/uiManager';
import { AudioManager } from '../framework/audioManager';
import {PoolManager} from '../framework/poolManager';
import { Constant } from '../framework/constant';
import { Fighter } from './fighter';
import { GameState, Player, Prop, PropType } from './gameState';
import { LogicManager } from './logicManager';
import { GobeUtil, WIFI_TYPE } from './gobeUtil';
import { ResourceUtil } from '../framework/resourceUtil';
import { PropBase } from './propBase';
import { GameCamera } from './gameCamera';
import { PlayerData } from '../framework/playerData';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = DisplayManager
* DateTime = Thu Sep 02 2021 10:12:26 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = displayManager.ts
* FileBasenameNoExtension = displayManager
* URL = db://assets/script/fight/displayManager.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
@ccclass('DisplayManager')
export class DisplayManager extends Component {
@property(LogicManager)
logicManager: LogicManager = null!;
@property(Node)
playerGroupNode: Node = null!;
@property(Node)
propGroupNode: Node = null!;
@property(Prefab)
coinPrefab: Prefab = null!;
@property(Prefab)
hammerPrefab: Prefab = null!;
@property(GameCamera)
cameraManager:GameCamera = null!;
@property(Node)
aiPosNode:Node = null!;
public dicPlayers: {[index: string]: Node} = {};
private _dicProps: {[index: number]: Node} = {};
private _isGameOver:boolean = false;
start () {
this.reset();
}
onEnable () {
ClientEvent.on(Constant.EVENT_NAME.ON_GAME_READY, this._onGameReady, this);
ClientEvent.on(Constant.EVENT_NAME.ON_GAME_END, this._onGameEnd, this);
ClientEvent.on(Constant.EVENT_NAME.ON_GAME_321, this._gameStart, this);
ClientEvent.on(Constant.EVENT_NAME.CREATE_COIN, this._onCreateCoin, this);
}
onDisable () {
ClientEvent.off(Constant.EVENT_NAME.ON_GAME_READY, this._onGameReady, this);
ClientEvent.off(Constant.EVENT_NAME.ON_GAME_END, this._onGameEnd, this);
ClientEvent.off(Constant.EVENT_NAME.ON_GAME_321, this._gameStart, this);
ClientEvent.off(Constant.EVENT_NAME.CREATE_COIN, this._onCreateCoin, this);
}
/**
* 创建金币
*
* @param hammerId
*/
private _onCreateCoin(pos:number[][]){
this.logicManager.onCreateCoin(pos);
this.dropCoin();
}
/**
* 显示初始场景
*/
private _init() {
this._isGameOver = false;
let keyArray: string[]= Object.keys(this.dicPlayers);
keyArray.forEach((element: string)=> {
PoolManager.instance.putNode(this.dicPlayers[parseInt(element)]);
delete this.dicPlayers[parseInt(element)];
});
keyArray= Object.keys(this._dicProps);
keyArray.forEach((element: string)=> {
PoolManager.instance.putNode(this._dicProps[parseInt(element)]);
delete this._dicProps[parseInt(element)];
});
let gameState: GameState = this.logicManager.currentGameState;
let props: Array<Prop> = gameState.props;
props.forEach((value: Prop, index: number) => {
this._dicProps[index] = this._createProp(value);
});
}
/**
* 创建道具节点
* @param value 道具数据
* @returns
*/
private _createProp(value: Prop) {
let prefab: Prefab = this.coinPrefab;
if (value.type === PropType.HAMMER) {
prefab = this.hammerPrefab;
}
let node: Node = PoolManager.instance.getNode(prefab, this.propGroupNode);
node.setPosition(value.position);
node.getComponent(PropBase)?.show(value);
return node;
}
public updateOwnState(gameState: GameState, dt:number){
let players: Array<Player> = gameState.players;
players.forEach((value: Player, index: number) => {
if(value.channel.openId == GobeUtil.instance.ownPlayerId){
let ndPlayer: Node = this.dicPlayers[index];
let scriptFighter: Fighter = ndPlayer.getComponent(Fighter) as Fighter;
scriptFighter.playMove(this.logicManager, dt, index == 0 ? this.dicPlayers[1] : this.dicPlayers[0], value);
}else if(GobeUtil.instance.isAi){
let ndPlayer: Node = this.dicPlayers[index];
let scriptFighter: Fighter = ndPlayer.getComponent(Fighter) as Fighter;
scriptFighter.playMoveAi(this.logicManager, dt, index == 0 ? this.dicPlayers[1] : this.dicPlayers[0], value);
}
});
}
public updateRun(playerId:string, gameState: GameState){
let players: Array<Player> = gameState.players;
players.forEach((value: Player, index: number) => {
if(value.channel.openId == playerId){
let ndPlayer: Node = this.dicPlayers[index];
let scriptFighter: Fighter = ndPlayer.getComponent(Fighter) as Fighter;
scriptFighter.playRun();
}
return;
});
}
public updateIdle(playerId:string, gameState: GameState){
let players: Array<Player> = gameState.players;
players.forEach((value: Player, index: number) => {
if(value.channel.openId == playerId){
let ndPlayer: Node = this.dicPlayers[index];
let scriptFighter: Fighter = ndPlayer.getComponent(Fighter) as Fighter;
scriptFighter.playIdle();
}
return;
});
}
public updateStateRecovery(gameState: GameState){
let players: Array<Player> = gameState.players;
players.forEach((value: Player, index: number) => {
let ndPlayer: Node = this.dicPlayers[index];
var value: Player = players[index];
if (ndPlayer) {
if (value.channel) {
ndPlayer.active = true;
let scriptFighter: Fighter = ndPlayer.getComponent(Fighter) as Fighter;
scriptFighter.updateStateRecovery(value);
} else if(ndPlayer){
ndPlayer.active = false;
}
}
});
}
public updateProp(gameState: GameState){
let props: Array<Prop> = gameState.props;
props.forEach((value: Prop, index: number) => {
let ndProp: Node = this._dicProps[index];
if (ndProp && !value.exist) {
PoolManager.instance.putNode(ndProp);
delete this._dicProps[index];
}
});
}
/**
* 更新场景状态
* @param deltaTime
*/
public updateState(deltaTime: number, gameState: GameState, isCheck:boolean) {
let players: Array<Player> = gameState.players;
players.forEach((value: Player, index: number) => {
let ndPlayer: Node = this.dicPlayers[index];
var value: Player = players[index];
if (ndPlayer) {
if (value.channel) {
ndPlayer.active = true;
let scriptFighter: Fighter = ndPlayer.getComponent(Fighter) as Fighter;
scriptFighter.updateState(deltaTime, value, isCheck);
} else if(ndPlayer){
ndPlayer.active = false;
}
}
});
let props: Array<Prop> = gameState.props;
props.forEach((value: Prop, index: number) => {
let ndProp: Node = this._dicProps[index];
if (ndProp && !value.exist) {
PoolManager.instance.putNode(ndProp);
delete this._dicProps[index];
}
if (!ndProp && value.exist && !value.dropPosition) {
this._dicProps[index] = this._createProp(value);
}
if (ndProp) {
let scriptProp = ndProp.getComponent(PropBase) as PropBase;
scriptProp?.updateState(deltaTime, value);
}
});
}
/**
* 开始游戏
*/
private _gameStart() {
this.logicManager.checkIsReCovery();
UIManager.instance.showDialog(Constant.PANEL_NAME.MEDIA_PANEL);
this.cameraManager.node.getComponent(Animation)?.play();
UIManager.instance.showDialog(Constant.PANEL_NAME.READY_GO, [()=>{
GobeUtil.instance.startGame();
AudioManager.instance.playMusic(Constant.AUDIO_NAME.BACKGROUND, true);
UIManager.instance.showDialog(Constant.PANEL_NAME.FIGHT_UI, [this]);
var isRoomOwner:boolean = GobeUtil.instance.checkIsRoomOwner(GobeUtil.instance.ownPlayerId)
if(isRoomOwner){
this.cameraManager.init(this.dicPlayers[0]);
}
else{
this.cameraManager.init(this.dicPlayers[1]);
}
this.cameraManager.startGame();
}]);
}
/**
* 重置游戏
*/
public reset() {
this.logicManager.setDefaultGameState();
this._init();
}
/**
* 游戏结束事件回调
*/
private _onGameEnd () {
if(this._isGameOver){
return;
}
this.cameraManager.finishGame();
this._isGameOver = true;
UIManager.instance.hideDialog(Constant.PANEL_NAME.FIGHT_UI);
AudioManager.instance.playSound(Constant.AUDIO_NAME.TIME_OUT);
let winner = -1;
let players: Player[] = this.logicManager.currentGameState.players;
if(players[0].score < players[1].score){
winner = 1;
}else if(players[0].score > players[1].score){
winner = 0;
}
for (const key in this.dicPlayers) {
if (Object.prototype.hasOwnProperty.call(this.dicPlayers, key)) {
const element = this.dicPlayers[key];
const scriptPlayer = element.getComponent(Fighter) as Fighter;
scriptPlayer.showFighterGameOverAni(winner == -1?true : winner === Number(key));
}
}
this.scheduleOnce(()=>{
UIManager.instance.hideDialog(Constant.PANEL_NAME.MESSAGE_PANEL);
UIManager.instance.hideDialog(Constant.PANEL_NAME.READY_GO);
UIManager.instance.hideDialog(Constant.PANEL_NAME.FIGHT_UI);
UIManager.instance.showTransitionBg(()=>{
UIManager.instance.showDialog(Constant.PANEL_NAME.GAME_OVER, [this, winner], ()=>{}, true);
});
}, 1.5)
}
/**
* 游戏开始事件回调
*/
private _onGameReady() {
let gameState: GameState = this.logicManager.currentGameState;
let players: Array<Player> = gameState.players;
players.forEach((value: Player, index: number) => {
if (value.channel) {
let playerPath = "player/girl";
if (GobeUtil.instance.checkIsRoomOwner(value.channel.openId)) {
playerPath = "player/boy";
}
ResourceUtil.loadModelRes(playerPath).then((pf: any)=>{
let ndPlayer: Node = PoolManager.instance.getNode(pf, this.playerGroupNode);
ndPlayer.setPosition(value.position);
ndPlayer.setScale(Constant.PLAYER_ORIGIN_SCALE, Constant.PLAYER_ORIGIN_SCALE, Constant.PLAYER_ORIGIN_SCALE);
ndPlayer.eulerAngles = value.eulerAngles;
ndPlayer.getComponent(Fighter)?.init(this, this.aiPosNode);
this.dicPlayers[index] = ndPlayer;
})
}
})
}
/**
* 显示被锤子击打后掉落的金币
*/
public dropCoin() {
let props: Array<Prop> = this.logicManager.currentGameState.props;
props.forEach((value: Prop, index: number) => {
let node: Node = this._dicProps[index];
if (!node && value.exist && value.dropPosition) {
this._dicProps[index] = this._createProp(value);
this._dicProps[index].getComponent(PropBase)?.drop(value.dropPosition);
}
});
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e542dff7-1894-4b59-8187-709cb194a914",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,587 @@
import { _decorator, Component, Node, SkinningModelComponent, ParticleSystemComponent, Vec3, Mat4, log } from 'cc';
import { ClientEvent }from '../framework/clientEvent';
import { AudioManager } from '../framework/audioManager';
import { PoolManager} from '../framework/poolManager';
import { ResourceUtil } from '../framework/resourceUtil';
import { Constant } from '../framework/constant';
import { DisplayManager } from './displayManager';
import { FighterModel } from './fighterModel';
import { Player, PropType} from './gameState';
import { EffectManager } from '../framework/effectManager';
import { Util } from '../framework/util';
import { PlayerData } from '../framework/playerData';
import { LogicManager } from './logicManager';
import { GobeUtil } from './gobeUtil';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = Player
* DateTime = Tue Sep 07 2021 12:38:14 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = player.ts
* FileBasenameNoExtension = player
* URL = db://assets/script/core/player.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
enum PlayType {
null,
idle,
run,
attack,
is_attack,
game_over,
}
let vec_0:Vec3 = new Vec3();
let vec_1:Vec3 = new Vec3();
let vec_2:Vec3 = new Vec3();
@ccclass('Fighter')
export class Fighter extends Component {
@property(Node)
public ndSocketCrown: Node = null!;//皇冠挂载节点
@property(SkinningModelComponent)
public model: SkinningModelComponent = null!;
@property(FighterModel)
public fighterModel: FighterModel = null!;
@property(Node)
public ndSocketWeapon: Node = null!;//武器挂载节点
private _aiPosNode:Node = null!; // ai点
public playerState: Player = null!;//玩家状态信息
private _ndCrown: Node = null!;//皇冠
private _ndHammer: Node = null!;//锤子
private _isPlayRunningEffect: boolean = false;
private _runEffect: Node = null!;
private _score: number = 0;
private _mat:Mat4 = new Mat4();
private _ndHammerTrial: Node = null!;//挂在锤子上的拖尾特效节点
private _parent: DisplayManager = null!;
private vec3_pos: Vec3 = new Vec3();
private vec3_angle: Vec3 = new Vec3();
private vec3_lastPos: Vec3 = new Vec3();
private vec3_pos_1: Vec3 = new Vec3();
private _moveIndex:number = 0;
private _playType:PlayType = PlayType.null;
public init(parent: DisplayManager, aiPosNode:Node) {
this._aiPosNode = aiPosNode;
this._parent = parent;
this._isPlayRunningEffect = false;
this._runEffect = null!;
this._score = 0;
this._aiPosIndex = 0;
this.playIdle();
if (!this._ndCrown) {
ResourceUtil.loadModelRes("crown/crown").then((pf: any)=>{
this._ndCrown = PoolManager.instance.getNode(pf, this.ndSocketCrown);
this.ndSocketCrown.active = false;
})
} else {
this.ndSocketCrown.active = false;
}
if (!this._ndHammer) {
ResourceUtil.loadModelRes("hammer/hammerProp").then((pf: any)=>{
this._ndHammer = PoolManager.instance.getNode(pf, this.ndSocketWeapon);
this._ndHammer.setPosition(0, 0, 0);
this.ndSocketWeapon.active = false;
this._hideHammerTrial();
})
} else {
this.ndSocketWeapon.active = false;
this._hideHammerTrial();
}
this.vec3_pos.set(0, 0, 0);
this.vec3_angle.set(0, 0, 0);
this.vec3_lastPos.set(0, 0, 0);
this.vec3_pos_1.set(0, 0, 0);
this._lastIndex = 0;
vec_0.set(50, 0, 0);
var index = Math.floor(Math.random() * Constant.AI_POS_INDEX[this._lastIndex].length);
this._nextIndex = Constant.AI_POS_INDEX[this._lastIndex][index];
vec_1.set(this._aiPosNode.children[this._nextIndex - 1].position);
var dis:number = Vec3.distance(vec_0, vec_1);
this._posPer = Constant.AI_SPEED / dis;
// console.log("1", this._nextIndex);
}
/**
* 隐藏锤子上的拖尾特效
*
* @private
* @memberof Fighter
*/
private _hideHammerTrial () {
if (!this._ndHammer) {
return;
}
if (!this._ndHammerTrial) {
this._ndHammerTrial = this._ndHammer.getChildByName("trail01") as Node;
}
if (this._ndHammerTrial && this._ndHammerTrial.active) {
this._ndHammerTrial.active = false;
}
}
/**
* 播放跑步效果
*/
public playRun() {
if(this._playType == PlayType.run){
return;
}
this._playType = PlayType.run;
if (!this.fighterModel.isRunning) {
this._isPlayRunningEffect = true;
//播放移动粒子特效
if (this._runEffect) {
this._runEffect.active = true;
let particle = this._runEffect.getComponentInChildren(ParticleSystemComponent) as ParticleSystemComponent;
particle.loop = true;
particle.clear();
particle.stop();
particle.play();
} else {
ResourceUtil.loadEffectRes("runningSmoke").then((pf: any)=>{
if (!this.fighterModel.isRunning) {
return; //已经没在跑了
}
this._runEffect = PoolManager.instance.getNode(pf, this.node);
this._runEffect.active = true;
let particle = this._runEffect.getComponentInChildren(ParticleSystemComponent) as ParticleSystemComponent;
particle.loop = true;
particle.clear();
particle.stop();
particle.play();
})
}
}
if (this.ndSocketWeapon.active) {
this.fighterModel.playAni(Constant.ANI_TYPE.RUN_1, true, false, ()=>{}, 1);
this._hideHammerTrial();
} else {
this.fighterModel.playAni(Constant.ANI_TYPE.RUN, true, false, ()=>{}, 1);
}
}
/**
* 攻击
* @param value
*/
public playAttack(value:Player, isActick:boolean) {
if(this._playType == PlayType.attack){
return;
}
this._playType = PlayType.attack;
value.hammerCount = 0;
value.attackPropType = PropType.NULL;
//使用锤子
AudioManager.instance.playSound(Constant.AUDIO_NAME.HIT);
this._ndHammerTrial.active = true;
EffectManager.instance.playTrail(this._ndHammerTrial);
this.fighterModel.isActick = isActick;
this.fighterModel.playAni(Constant.ANI_TYPE.ATTACK, false, false, ()=>{
this._hideHammerTrial();
this.ndSocketWeapon.active = false; //武器消失
this.playIdle();
}, 1);
}
/**
* 播放待机效果
*/
public playIdle() {
if(this._playType == PlayType.idle){
return;
}
this._playType = PlayType.idle;
this.fighterModel.playAni(Constant.ANI_TYPE.IDLE, true, false, ()=>{}, 2);
if (this._runEffect && this._isPlayRunningEffect) {
let particle2 = this._runEffect.getComponentInChildren(ParticleSystemComponent) as ParticleSystemComponent;
particle2.loop = false;
}
this._isPlayRunningEffect = false;
}
/**
* 移动
*/
public playMove(logicManager: LogicManager, dt:number, otherNode:Node, player:Player){
if(!(this._playType == PlayType.idle || this._playType == PlayType.run)){
return;
}
if(player.hammerCount > 0){
var distance:number = Vec3.distance(this.vec3_lastPos, otherNode.position);
if(distance < 5){
Vec3.subtract(this.vec3_pos_1, this.node.position, otherNode.position);
var angleY:number = Math.atan(this.vec3_pos_1.z/this.vec3_pos_1.x) * 180 / Math.PI;
if(this.vec3_pos_1.x < 0){
if(this.vec3_pos_1.z < 0){
angleY = 180 - angleY;
}else {
angleY = (angleY + 180) * -1;
}
}else{
angleY *= -1;
}
angleY-=90;
GobeUtil.instance.sendFrame({'A': Constant.ACTION.HIT, 'V': angleY});
this.vec3_angle.y = angleY;
this.node.eulerAngles = this.vec3_angle;
this.playAttack(player, true);
return;
}
}
var leftY:number = PlayerData.instance.getEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_LEFT_Y);
var leftX:number = PlayerData.instance.getEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_LEFT_X);
if (leftY == 0 && leftX == 0) {
if(this._playType != PlayType.idle){
this.vec3_angle.set(this.node.eulerAngles.clone());
this.vec3_lastPos.set(this.node.position.clone());
GobeUtil.instance.sendFrame({'A': Constant.ACTION.MOVE, 'V': this.vec3_angle.y, 'X': this.vec3_lastPos.x, 'Z': this.vec3_lastPos.z, 'MX': leftX, 'MY': leftY});
}
this.playIdle();
return;
}
this.playRun();
var angleY:number = Math.atan(leftX / leftY) * 180 / Math.PI;
if(leftY < 0){
angleY -= 180;
}
this.vec3_angle.y = 180 - angleY;
this.node.eulerAngles = this.vec3_angle;
this.vec3_lastPos.set(this.node.position.clone());
this.vec3_pos.set(this.node.position.clone());
var speed:number = 1 - (this.node.scale.x - 1) * Constant.MIN_SPEED_PERCENT;
this.vec3_pos.x += leftX * 0.2 * dt * 60 * speed;
this.vec3_pos.z -= leftY * 0.2 * dt * 60 * speed;
this._mat.m12 = this.vec3_pos.x;
this._mat.m13 = this.vec3_pos.y;
this._mat.m14 = this.vec3_lastPos.z;
if (!logicManager.playerLogic.intersectWithObstacle(this._mat, this.node.rotation, this.node.scale, this.node.parent?.scale)) {
this.vec3_lastPos.x = this.vec3_pos.x;
}
this._mat.m12 = this.vec3_lastPos.x;
this._mat.m13 = this.vec3_pos.y;
this._mat.m14 = this.vec3_pos.z;
if (!logicManager.playerLogic.intersectWithObstacle(this._mat, this.node.rotation, this.node.scale, this.node.parent?.scale)) {
this.vec3_lastPos.z = this.vec3_pos.z;
}
if(this._moveIndex == 0){
GobeUtil.instance.sendFrame({'A': Constant.ACTION.MOVE, 'V': this.vec3_angle.y, 'X': this.vec3_lastPos.x, 'Z': this.vec3_lastPos.z, 'MX': leftX, 'MY': leftY});
}
this.node.setPosition(this.vec3_lastPos);
this._moveIndex ++;
if(this._moveIndex > 4){
this._moveIndex = 0;
}
}
private _aiPosIndex:number = 0;
private _nextIndex:number = 0;
private _lastIndex:number = 0;
private _posPer:number = 0;
/**
* 移动
*/
public playMoveAi(logicManager: LogicManager, dt:number, otherNode:Node, player:Player){
if(!(this._playType == PlayType.idle || this._playType == PlayType.run)){
return;
}
if(player.hammerCount > 0){
var distance:number = Vec3.distance(this.vec3_lastPos, otherNode.position);
if(distance < 5){
Vec3.subtract(this.vec3_pos_1, this.node.position, otherNode.position);
var angleY:number = Math.atan(this.vec3_pos_1.z/this.vec3_pos_1.x) * 180 / Math.PI;
if(this.vec3_pos_1.x < 0){
if(this.vec3_pos_1.z < 0){
angleY = 180 - angleY;
}else {
angleY = (angleY + 180) * -1;
}
}else{
angleY *= -1;
}
angleY-=90;
GobeUtil.instance.sendFrame({'A': Constant.ACTION.HIT, 'V': angleY, 'AI': 1});
this.vec3_angle.y = angleY;
this.node.eulerAngles = this.vec3_angle;
this.playAttack(player, true);
return;
}
}
this.playRun();
var speed:number = 1 - (this.node.scale.x - 1) * Constant.MIN_SPEED_PERCENT;
this._aiPosIndex += this._posPer * speed;
if(this._aiPosIndex >= 1){
vec_0.set(vec_1);
var nextPos:number[] = [];
for(var index:number = 0; index < Constant.AI_POS_INDEX[this._nextIndex].length; index ++){
if(Constant.AI_POS_INDEX[this._nextIndex][index] != this._lastIndex){
nextPos.push(Constant.AI_POS_INDEX[this._nextIndex][index]);
}
}
this._lastIndex = this._nextIndex;
var index = Math.floor(Math.random() * nextPos.length);
this._nextIndex = nextPos[index];
vec_1.set(this._aiPosNode.children[this._nextIndex - 1].position);
this._aiPosIndex -= 1;
var dis:number = Vec3.distance(vec_0, vec_1);
this._posPer = Constant.AI_SPEED / dis;
}
// 坐标
Vec3.lerp(this.vec3_pos, vec_0, vec_1, this._aiPosIndex);
var leftX:number = vec_1.x - vec_0.x;
var leftY:number = vec_0.z - vec_1.z;
if(!(leftX == 0 && leftY == 0)){
var angleY:number = Math.atan(leftX / leftY) * 180 / Math.PI;
if(leftY < 0){
angleY -= 180;
}
this.vec3_angle.y = 180 - angleY;
this.node.eulerAngles = this.vec3_angle;
}
this.vec3_lastPos.set(this.node.position.clone());
this._mat.m12 = this.vec3_pos.x;
this._mat.m13 = this.vec3_pos.y;
this._mat.m14 = this.vec3_lastPos.z;
if (!logicManager.playerLogic.intersectWithObstacle(this._mat, this.node.rotation, this.node.scale, this.node.parent?.scale)) {
this.vec3_lastPos.x = this.vec3_pos.x;
}
this._mat.m12 = this.vec3_lastPos.x;
this._mat.m13 = this.vec3_pos.y;
this._mat.m14 = this.vec3_pos.z;
if (!logicManager.playerLogic.intersectWithObstacle(this._mat, this.node.rotation, this.node.scale, this.node.parent?.scale)) {
this.vec3_lastPos.z = this.vec3_pos.z;
}
if(this._moveIndex == 0){
GobeUtil.instance.sendFrame({'A': Constant.ACTION.MOVE, 'V': this.vec3_angle.y, 'X': this.vec3_lastPos.x, 'Z': this.vec3_lastPos.z, 'AI' : 1});
}
this.node.setPosition(this.vec3_lastPos);
this._moveIndex ++;
if(this._moveIndex > 4){
this._moveIndex = 0;
}
}
/**
* 断线重连
*
* @param value
*/
public updateStateRecovery(value: Player){
this.node.eulerAngles = value.eulerAngles;
this.node.setPosition(value.position);
//锤头显示
if (value.hammerCount && this.ndSocketWeapon.active === false) {
this.ndSocketWeapon.active = true;
} else if (value.hammerCount === 0 && this.ndSocketWeapon.active && !this.fighterModel.isAttacking){
this.ndSocketWeapon.active = false;
}
}
/**
* 根据帧数据更新玩家状态
* @param deltaTime
* @param value 玩家数据
*/
public updateState (deltaTime: number, value: Player, isCheck:boolean) {
if(!(this._playType == PlayType.idle || this._playType == PlayType.run)){
return;
}
this.playerState = value;
// 其他玩家移动
if(isCheck || value.channel.openId != GobeUtil.instance.ownPlayerId && !GobeUtil.instance.isAi){
var isAngle:boolean = false;
//玩家转向
if (!value.eulerAngles.equals(this.node.eulerAngles)) {
if(value.channel.openId != GobeUtil.instance.ownPlayerId){
this.node.eulerAngles = value.eulerAngles;
}
isAngle = true;
}
// var dis:number = Vec3.distance(value.position, this.node.position);
if(!(value.moveX == 0 && value.moveY == 0)){
Vec3.lerp(this.vec3_pos_1, this.node.position, value.position, 0.2);
this.node.setPosition(this.vec3_pos_1);
this.playRun();
}else if(isAngle){
this.playRun();
}else if (this._isPlayRunningEffect){
this.playIdle();
}
// 吃道具
if (value.attackPropType === PropType.HAMMER) {
this.node.setPosition(value.position);
this.playAttack(value, false);
}
}
if(value.attackPropType === PropType.HAMMER_ED){
value.attackPropType = PropType.NULL;
// 被锤子攻击
this.onHammerHit(value);
}
//得分tips
if (value.score > this._score) {
let num: number = value.score - this._score;
AudioManager.instance.playSound(Constant.AUDIO_NAME.GOLD);
ClientEvent.dispatchEvent(Constant.EVENT_NAME.ON_SHOW_COIN_TIPS, '+' + num, this.node.worldPosition.clone());
this._score = value.score;
}
//玩家大小
let size: number = (Constant.PLAYER_ORIGIN_SCALE + this._score * Constant.ADD_SIZE_PER_COIN);
size = size >= 2 ? 2 : size;
if (size !== this.node.scale.x) {
let targetSize = Util.lerp(size, this.node.scale.x, deltaTime * 10);
this.node.setScale(targetSize, targetSize, targetSize);
this._ndHammer.setScale(targetSize, targetSize, targetSize);
}
//皇冠显示
if (value.isScoreLead && !this.ndSocketCrown.active) {
this.ndSocketCrown.active = true;
} else if (!value.isScoreLead && this.ndSocketCrown.active) {
this.ndSocketCrown.active = false;
}
//锤头显示
if (value.hammerCount && this.ndSocketWeapon.active === false) {
this.ndSocketWeapon.active = true;
// 获得锤子切换动作
if(this._playType == PlayType.run){
this.fighterModel.playAni(Constant.ANI_TYPE.RUN_1, true, false, ()=>{}, 1);
this._hideHammerTrial();
}
} else if (value.hammerCount === 0 && this.ndSocketWeapon.active && !this.fighterModel.isAttacking){
// this.ndSocketWeapon.active = false;
}
}
/**
* 被锤子击中
*
* @param {Player} value
* @memberof Fighter
*/
public onHammerHit (value: Player) {
if(this._playType == PlayType.is_attack){
return;
}
this._playType = PlayType.is_attack;
EffectManager.instance.playEffect(this.node, "dizzyEff", true, true, 1);
this.fighterModel.playAni(Constant.ANI_TYPE.HIT, false, true, ()=>{
this.fighterModel.playAni(Constant.ANI_TYPE.DIZZY, false, false, ()=>{
this.playIdle();
}, 11);
}, 9);
// //更新分数
// let num: number = value.score - this._score;
// if (num !== 0) {
// ClientEvent.dispatchEvent(Constant.EVENT_NAME.ON_SHOW_COIN_TIPS, num, this.node.worldPosition.clone());
// }
// this._score = value.score;
// this._parent.dropCoin();
}
/**
* 击打特效
* @param posWorld 击打位置
* @param scale 击打范围
* @param endCb 击打回调函数
*/
private _playHitEffect (posWorld: Vec3, scale: number = 1, endCb?: Function) {
posWorld.y = 0.1;
EffectManager.instance.playParticle("hitNew1", posWorld, 0, scale, null, ()=>{
endCb && endCb();
});
}
/**
* 游戏结束时先观看3秒的人物胜利失败动画
*/
public showFighterGameOverAni (isWin: boolean = false) {
this._playType = PlayType.game_over;
if (isWin) {
this.fighterModel.playAni(Constant.ANI_TYPE.VICTORY, true, false, ()=>{}, 13);
} else {
this.fighterModel.playAni(Constant.ANI_TYPE.LOSE, false, false, ()=>{
this.fighterModel.playAni(Constant.ANI_TYPE.LOSE_1, true, false, ()=>{}, 15);
}, 14);
}
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b2fbba2b-c2b0-4380-8eb7-f0d272ade8dc",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,108 @@
import { _decorator, Component, SkeletalAnimationComponent, SkeletalAnimationState, AnimationClip, log } from 'cc';
import { Constant } from '../framework/constant';
import { GobeUtil } from './gobeUtil';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = FighterModel
* DateTime = Tue Sep 07 2021 13:36:57 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = FighterModel.ts
* FileBasenameNoExtension = FighterModel
* URL = db://assets/resources/package/prefab/ui/fight/playerModel.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
@ccclass('FighterModel')
export class FighterModel extends Component {
@property(SkeletalAnimationComponent)
public ani: SkeletalAnimationComponent = null!;
public isAniPlaying: boolean = false;//当前动画是否正在播放
//是否正在跑
public get isRunning () {
return this._aniType === Constant.ANI_TYPE.RUN && this.isAniPlaying === true;
}
//是否待机
public get isIdle () {
return this._aniType === Constant.ANI_TYPE.IDLE&& this.isAniPlaying === true;
}
//是否正在攻击
public get isAttacking () {
return this._aniType === Constant.ANI_TYPE.ATTACK && this.isAniPlaying === true;
}
//是否被击中
public get isHitting () {
return this._aniType === Constant.ANI_TYPE.HIT && this.isAniPlaying === true;
}
//是否眩晕
public get isDizzying () {
return this._aniType === Constant.ANI_TYPE.DIZZY && this.isAniPlaying === true;
}
private _aniType: string = "";//动画类型
private _aniState: SkeletalAnimationState = null!;//动画播放状态
public isActick:boolean = false;
/**
* 播放玩家动画
*
* @param {string} aniType 动画类型
* @param {boolean} [isLoop=false] 是否循环
* @param {boolean} [isSkipSameAni=false] 是否跳过同样的动画
* @param {Function} [callback] 回调函数
* @param {number} [callback] 调用播放动画的位置,方便用于测试
* @returns
* @memberof Player
*/
public playAni (aniType: string, isLoop: boolean = false, isSkipSameAni: boolean = false, callback?: Function, pos?: number) {
if(this._aniType == aniType){
return;
}
this._aniState = this.ani?.getState(aniType) as SkeletalAnimationState;
if (this._aniState && this._aniState.isPlaying) {
if (isSkipSameAni) {
this._aniState.time = 0;
this._aniState.sample();
} else {
return;
}
}
this._aniType = aniType;
this.ani?.play(aniType);
this.isAniPlaying = true;
if (this._aniState) {
if (isLoop) {
this._aniState.wrapMode = AnimationClip.WrapMode.Loop;
} else {
this._aniState.wrapMode = AnimationClip.WrapMode.Normal;
}
}
if (!isLoop) {
this.ani.once(SkeletalAnimationComponent.EventType.FINISHED, ()=>{
this.isAniPlaying = false;
callback && callback();
})
}
}
public attackPlayer(){
if(this.isActick){
this.isActick = false;
GobeUtil.instance.sendFrame({'A': Constant.ACTION.IS_ATTACK_ED});
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2a13cc78-6c7b-455e-aaeb-4170b13db4b2",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,44 @@
import { _decorator, Component, Node, CameraComponent, Vec3, Camera } from "cc";
const { ccclass, property } = _decorator;
let vec_1:Vec3 = new Vec3();
let vec_2:Vec3 = new Vec3();
@ccclass("GameCamera")
export class GameCamera extends Component {
@property(Camera)
camera:Camera = null!;
private _targetNode:Node = null;
private _isUpdate:boolean = false;
start () {
// Your initialization goes here.
window.mainCamera = this.camera.getComponent(CameraComponent);
}
public init(targetNode:Node): void {
this._targetNode = targetNode;
this.node.setPosition(this._targetNode.position);
this.node.setRotationFromEuler(0, 180, 0);
this.node.children[0].setRotationFromEuler(-60, -180, 0);
this.node.children[0].setPosition(0, 34, -17);
}
public startGame(){
this._isUpdate = true;
}
public finishGame(){
this._isUpdate = false;
}
update (deltaTime: number) {
if(this._isUpdate){
Vec3.lerp(vec_1, this.node.position, this._targetNode.position, 0.1);
this.node.setPosition(vec_1);
}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "3010456d-2f65-4f0c-a1d3-15a9db963641",
"files": [],
"subMetas": {},
"userData": {
"moduleId": "project:///assets/script/fight/gameCamera.js",
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,80 @@
import { _decorator, Vec3 } from 'cc';
/**
* Predefined variables
* Name = GameState
* DateTime = Wed Sep 01 2021 11:40:25 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = GameState.ts
* FileBasenameNoExtension = GameState
* URL = db://assets/script/fight/GameState.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
export enum PropType { //道具类型
NULL = 0,
COIN = 1, //金币
HAMMER = 2, //锤头
// IS_HAMMER = 2, //锤头
RAINING_COIN = 3, //金币雨
HAMMER_ED = 4, //被锤头攻击
}
export interface Channel{
openId: string, //玩家渠道id
name: string, //玩家昵称
headUrl: string, //玩家头像
state: number, //玩家状态
delayTime: number //延迟时间
}
export interface Player{ //道具信息
playId:number,
id: number, //道具信息
channel: Channel, //玩家渠道信息
position: Vec3, //玩家位置
eulerAngles: Vec3, //玩家旋转信息
score: number, //玩家积分
isShowReward: boolean,//是否奖励20个金币
isScoreLead: boolean,//是否分数领先
attackPos: Vec3 | null, //攻击位置
attackId: number, //攻击玩家id
attackPropType: PropType,//攻击的道具类型
hammerCount: number, //锤子可击打次数
dizzyTime: number, //眩晕时间
dizzyOverTime: number,//被榴莲或者锤子击中后眩晕结束时间frameTime大于这个玩家才能移动
moveX:number, // 手柄左右方向
moveY:number // 手柄上下方向
}
export interface Prop{ //道具信息
id: number, //道具id
position: Vec3,//道具位置
dropPosition: Vec3,//金币道具掉落位置
scale: number,//道具大小
exist: boolean,//是否展示
type: PropType,//道具类型
removed: boolean, // 移除
}
export interface GameState{
id: number, //逻辑帧标示符
time: number,//剩余时间
frameTime: number,//当前帧的时间
props: Array<Prop>,//道具信息
players: Array<Player>,//玩家信息
createHammerTime: number,//创建锤头的时间
createCoinTime: number, //创建金币的时间
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2ff802b0-9882-4a1e-8d6e-d89f43c9cb2c",
"files": [],
"subMetas": {},
"userData": {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "edfac376-3db6-4b20-9bc9-f4a1fbd9f477",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,382 @@
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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "549cbcf9-3d04-48ae-b0d0-e6316f112263",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,66 @@
import { _decorator, Component, Node, MeshRenderer } from 'cc';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = MeshHandle
* DateTime = Wed Sep 01 2021 17:11:20 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = meshHandle.ts
* FileBasenameNoExtension = meshHandle
* URL = db://assets/script/fight/meshHandle.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
@ccclass('MeshHandle')
export class MeshHandle extends Component {
@property({serializable: true})
_showMesh = true;
@property
set showMesh (value: boolean) {
this._showMesh = value;
this.handleMesh();
}
get showMesh () {
return this._showMesh;
}
start () {
if (typeof Editor === 'undefined') return;
this.handleMesh();
}
/**
* 障碍物碰撞范围显示
* @param node
*/
handleMesh (node: Node | null = null) {
node = node || this.node;
let meshRenderer = node.getComponent(MeshRenderer)
if (meshRenderer) {
meshRenderer.enabled = this._showMesh;
}
let children = node.children;
for (let i = 0, c = children.length; i < c; i++) {
this.handleMesh(children[i]);
}
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "0bf32029-154e-4cbb-a8f1-f7ef6dc7d286",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,268 @@
import { VirtualPlayer } from './virtualPlayer';
import { _decorator, Component, Node, Vec3, Prefab, Quat, ModelComponent, geometry, Mat4, math } from 'cc';
import { Constant } from '../framework/constant';
import { PoolManager } from '../framework/poolManager';
import { Player, PropType } from './gameState';
import { LogicManager } from './logicManager';
import { GobeUtil } from './gobeUtil';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = PlayerLogic
* DateTime = Thu Sep 09 2021 15:46:05 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = playerLogic.ts
* FileBasenameNoExtension = playerLogic
* URL = db://assets/script/core/playerLogic.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
let v3_1 = new Vec3();
let v3_2 = new Vec3();
@ccclass('PlayerLogic')
export class PlayerLogic extends Component {
@property(Prefab)
virtualPlayerPrefab: Prefab = null!;
@property(Node)
obstacleGroupNode: Node = null!;
private _dicPlayers: {[index: number]: Node} = {};//存放虚拟玩家节点的字典
private _dicScriptVirtualPlayers: {[index: number]: VirtualPlayer} = {};//存放虚拟玩家脚本的字典
private _parent: LogicManager = null!;
public init(parent: LogicManager) {
this._parent = parent;
}
/**
* 重置节点
*/
public reset() {
let keyArray: string[]= Object.keys(this._dicPlayers);
keyArray.forEach((element: string)=> {
PoolManager.instance.putNode(this._dicPlayers[parseInt(element)]);
delete this._dicPlayers[parseInt(element)];
});
}
/**
* 生成虚拟玩家
* @returns 虚拟玩家数据
*/
public initPlayer() {
let players: Array<Player>= [];
for(let i: number = 0; i < Constant.MAX_PLAYER; i++) {
let player: Player = {} as Player;
let pos: Vec3 = new Vec3(-50, 0, 0);
let eulerAngles: Vec3 = new Vec3(0, 90, 0);
switch (i) {
case 0:
break;
case 1:
pos.set(50, 0, 0);
eulerAngles.set(0, -90, 0);
break;
}
player.id = i;
player.position = pos;
player.eulerAngles = eulerAngles;
player.score = 0;
player.hammerCount = 0;
player.moveX = 0;
player.moveY = 0;
player.isShowReward = false;
player.isScoreLead = false;
players[i] = player;
let ndVirtualPlayer = PoolManager.instance.getNode(this.virtualPlayerPrefab, this.node);
ndVirtualPlayer.setPosition(pos);
ndVirtualPlayer.eulerAngles = eulerAngles;
this._dicPlayers[i] = ndVirtualPlayer;
let scriptVirtualPlayer = ndVirtualPlayer.getComponent(VirtualPlayer) as VirtualPlayer;
scriptVirtualPlayer.init(pos);
this._dicScriptVirtualPlayers[i] = scriptVirtualPlayer;
}
return players;
}
/**
* 处理虚拟玩家节点显示
* @param players 玩家数据
*/
public updatePlayerNode(players: Player[]) {
players.forEach((value: Player, index: number) => {
let playerNode: Node = this._dicPlayers[index];
if (value.channel) {
playerNode.active = true;
} else {
playerNode.active = false;
}
});
}
/**
* 玩家停止移动
* @param player
* @param horizontal
* @param vertical
* @param value
*/
public stopMove(player: Player, posX: number, posZ: number, angleY: number) {
this._dicScriptVirtualPlayers[player.id].playAction({action: Constant.ACTION.STOP_MOVE, posX: posX, posZ: posZ, angleY: angleY});
}
/**
* 玩家停止移动,并朝向敌人进行攻击
* @param player
* @param horizontal
* @param vertical
* @param value
*/
public stopMoveAndAttack(player: Player, posX: number, posZ: number, angleY: number) {
this._dicScriptVirtualPlayers[player.id].playAction({action: Constant.ACTION.IS_ATTACK_ED, posX: posX, posZ: posZ, angleY: angleY});
}
/**
* 玩家移动
* @param player 玩家数据
* @param horizontal 水平值
* @param vertical 垂直值
*/
public move(playerId: number, posX: number, posZ: number, angleY: number) {
this._dicScriptVirtualPlayers[playerId].playAction({action: Constant.ACTION.MOVE, posX: posX, posZ: posZ, angleY: angleY});
}
/**
* 更新玩家状态
*/
public updateStateRecovery () {
for (const i in this._dicScriptVirtualPlayers) {
if (Object.prototype.hasOwnProperty.call(this._dicScriptVirtualPlayers, i)) {
const scriptVirtualPlayer = this._dicScriptVirtualPlayers[i];
scriptVirtualPlayer.playActionRecovery();
}
}
}
/**
* 更新玩家状态
*/
public updateState () {
for (const i in this._dicScriptVirtualPlayers) {
if (Object.prototype.hasOwnProperty.call(this._dicScriptVirtualPlayers, i)) {
const scriptVirtualPlayer = this._dicScriptVirtualPlayers[i];
scriptVirtualPlayer.updateState(this._parent.currentGameState.players[i], this._parent);
}
}
}
/**
* 判断是否相交
* @returns
*/
public intersectWithObstacle(worldMatrix:Mat4, worldRotation:Quat, scale:Vec3, parentScale:Vec3) {
let modelArray: ModelComponent[] = this.obstacleGroupNode.getComponentsInChildren(ModelComponent);
let flag: boolean = false;
for(let i: number = 0; i < modelArray.length; i++) {
if (!modelArray[i].node.active) continue;
let model2: ModelComponent = modelArray[i];
let obb1: geometry.OBB = new geometry.OBB();
let obb2: geometry.OBB = new geometry.OBB();
obb1.halfExtents = Vec3.multiplyScalar(v3_1, scale, 0.5 * parentScale.x);
obb2.halfExtents = Vec3.multiplyScalar(v3_2, model2.node.scale, 0.5 * (model2.node.parent as Node).scale.x);
obb1.translateAndRotate(worldMatrix, worldRotation, obb1);
obb2.translateAndRotate(model2.node.worldMatrix, model2.node.worldRotation, obb2);
if (geometry.intersect.obbWithOBB(obb1, obb2)) {
return true;
}
}
return flag;
}
// /**
// * 处理攻击操作数据
// * @param player 攻击者数据
// * @returns
// */
// public checkAttack(player: Player) {
// if (!player.hammerCount) return;
// let enemy: Player = this.getNearestEnemy(player.channel.openId, player.position);
// if (!enemy || ((this._parent.currentGameState.frameTime - enemy.dizzyTime) < Constant.REVIVE_TIME * 1000)) return;
// let selfNode: Node = this._dicPlayers[player.id];
// //正前方3米处
// //半径为1米
// let hammerDistance = 3 * selfNode.scale.x;
// let hammerRange = 1 * selfNode.scale.x;
// let offset = enemy.position.clone().subtract(player.position).normalize();
// let posHammer = player.position.clone().add(offset.clone().multiplyScalar(hammerDistance));
// let dis = posHammer.clone().subtract(enemy.position).length();
// if (dis < hammerRange * 0.9 + Constant.INIT_COLLIDER_CIRCLE) {
// player.attackPos = posHammer.clone();
// player.attackPropType = PropType.HAMMER;
// let dis = posHammer.subtract(enemy.position).length();
// if (dis < hammerRange + Constant.INIT_COLLIDER_CIRCLE) {
// player.hammerCount--;
// player.attackId = enemy.id;
// enemy.dizzyTime = this._parent.currentGameState.frameTime;
// //设置眩晕结束时间,一秒攻击方动画播放秒数,一秒为受击动画播放秒数
// enemy.dizzyOverTime = this._parent.currentGameState.frameTime + Constant.DIZZY_TIME * 1000 + 1000;
// let num: number = Math.ceil(enemy.score / 2);
// num = num >= 20 ? 20 : num;
// enemy.score -= num;
// this._parent.propLogic.createCoinByHammer(num, enemy.position);
// }
// //朝向指定的敌人攻击
// GobeUtil.instance.sendFrame({'A': Constant.ACTION.IS_ATTACK_ED, 'I': enemy.channel.openId});
// }
// }
public getPlayerByIndex(index:number){
return this._dicPlayers[index];
}
/**
* 获取最近的其他玩家
* @param selfPlayerId
* @param position
* @returns
*/
public getNearestEnemy (selfPlayerId: string, position: Vec3) {
let sqr: number = math.bits.INT_MAX;
let nearestPlayer: Player = null!;
let players: Array<Player> = this._parent.currentGameState.players;
for (let pos in players) {
let player: Player = players[pos];
if (player.channel && player.channel.openId !== selfPlayerId) {
//判断距离
let lenSqr: number = Vec3.squaredDistance(player.position, position);
if (lenSqr < sqr) {
sqr = lenSqr;
nearestPlayer = player;
}
}
}
return nearestPlayer;
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2176aa66-110d-4749-adfb-9320453a99f2",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,78 @@
import { Prop } from './gameState';
import { _decorator, Component, Node, Tween, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = Coin2
* DateTime = Tue Sep 07 2021 11:07:17 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = coin2.ts
* FileBasenameNoExtension = coin2
* URL = db://assets/script/core/coin2.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
//道具基础类通用组件
@ccclass('PropBase')
export class PropBase extends Component {
protected _tween: Tween<Node> = null!;
protected _dropTween: Tween<Node> = null!;
protected _propInfo: Prop = null!;
protected _isDisappearEffShowing: boolean = false;//是否正在播放消失特效
protected _parentName: string = "";//父节点名字
protected _prop: Prop = null!;//道具状态信息
protected _disappearCb: Function = null!;//消失后执行的回调函数
protected _targetEuler: Vec3 = new Vec3(0, -360, 0);//目标角度
protected _oriEuler: Vec3 = new Vec3();//初始角度
onDisable () {
this.unscheduleAllCallbacks();
}
/**
* 展示道具
*
* @param {Prop} value 道具状态数据
* @memberof PropBase
*/
public show(value: Prop) {
this.node.eulerAngles = this._oriEuler;
if (this._tween) {
this._tween.stop();
this._tween = null!;
}
this._tween = new Tween(this.node)
.to(3 * value.scale, {eulerAngles: this._targetEuler})
.call(()=>{
this.node.eulerAngles = this._oriEuler;
})
.union()
.repeatForever()
.start();
this._propInfo = value;
this._parentName = this.node.parent?.name!;
this._isDisappearEffShowing = false;
}
/**
* 掉落动画
* @param posTarget 掉落位置
*/
public drop (posTarget: Vec3) {
let len: number = this.node.position.clone().subtract(posTarget).length();
this._dropTween = new Tween(this.node).to(len / 10, {position: posTarget}).call(()=>{
this._dropTween = null!;
this.node.setPosition(posTarget);
}).start();
}
public updateState (deltaTime: number, prop: Prop) {
this._prop = prop;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "933807d3-021c-45f6-9ab2-20f1dad58a83",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,377 @@
import { _decorator, Component, Node, Vec3, ModelComponent, geometry, Prefab, clamp } from 'cc';
import { PoolManager } from '../framework/poolManager';
import { Player, Prop, PropType } from './gameState';
import { LogicManager } from './logicManager';
import { Util } from '../framework/util';
import { Constant } from '../framework/constant';
import { EffectManager } from '../framework/effectManager';
import { GobeUtil } from './gobeUtil';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = PropLogic
* DateTime = Thu Sep 09 2021 15:45:54 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = propLogic.ts
* FileBasenameNoExtension = propLogic
* URL = db://assets/script/core/propLogic.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*/
let v3_1: Vec3 = new Vec3();
let v3_2: Vec3 = new Vec3();
let coinWorPos: Vec3 = new Vec3();
@ccclass('PropLogic')
export class PropLogic extends Component {
@property(Prefab)
virtualCoinPrefab: Prefab = null!;
@property(Prefab)
virtualHammerPrefab: Prefab = null!;
public indexProp: number = 0;
private _dicProps: {[index: number]: Node} = {};
private _parent: LogicManager = null!;
public init(parent: LogicManager) {
this._parent = parent;
}
/**
* 重置节点
*/
public reset() {
let keyArray: string[]= Object.keys(this._dicProps);
keyArray.forEach((element: string)=> {
PoolManager.instance.putNode(this._dicProps[parseInt(element)]);
delete this._dicProps[parseInt(element)];
});
}
/**
* 生成虚拟道具
* @returns 虚拟道具数据
*/
public initProps() {
let props: Array<Prop>= [];
this.indexProp = 0;
for (let idx: number = 0; idx < 36; idx++) {
let row = Math.floor(idx / 6);
let col = Math.floor(idx % 6);
if (row >= 2 && row <= 3 && col >= 2 && col <= 3) { //中间空出来
continue;
}
props[this.indexProp] = this.generateProp(new Vec3(-9 + col * 3.5, 1, 6 - row * 3));
this.indexProp++;
}
//两横
for (let idx: number= 0; idx < 7; idx++) {
props[this.indexProp] = this.generateProp(new Vec3(-18 + idx * 6, 1, -16));
this.indexProp++;
props[this.indexProp] = this.generateProp(new Vec3(-18 + idx * 6, 1, 14));
this.indexProp++;
}
//两横
for (let idx: number= 0; idx < 12; idx++) {
props[this.indexProp] = this.generateProp(new Vec3(-29 + idx * 5, 1, -24));
this.indexProp++;
props[this.indexProp] = this.generateProp(new Vec3(-29 + idx * 5, 1, 22.5));
this.indexProp++;
}
//两竖
for (let idx: number= 0; idx < 4; idx++) {
props[this.indexProp] = this.generateProp(new Vec3(-18, 1, -10 + idx * 6));
this.indexProp++;
props[this.indexProp] = this.generateProp(new Vec3(18, 1, -10 + idx * 6));
this.indexProp++;
}
//两竖
for (let idx: number= 0; idx < 5; idx++) {
props[this.indexProp] = this.generateProp(new Vec3(-29, 1, -10 + idx * 5));
this.indexProp++;
props[this.indexProp] = this.generateProp(new Vec3(29, 1, -10 + idx * 5));
this.indexProp++;
}
//两竖
for (let idx: number= 0; idx < 9; idx++) {
props[this.indexProp] = this.generateProp(new Vec3(-36, 1, -21 + idx * 5));
this.indexProp++;
props[this.indexProp] = this.generateProp(new Vec3(36, 1, -21 + idx * 5));
this.indexProp++;
}
return props;
}
/**
* 移除多余道具
* @param length 移除数值
*/
public removeOverProp(length: number) {
let keyArray = Object.keys(this._dicProps);
for(let i = length; i < keyArray.length; i++) {
if (this._dicProps[i]) {
PoolManager.instance.putNode(this._dicProps[i]);
delete this._dicProps[i];
}
}
}
/**
* 删除指定道具
*
* @memberof PropLogic
*/
public removePropId (propId: number) {
var prop:Prop = this._parent.currentGameState.props[propId];
if(prop){
prop.exist = false;
if(this._dicProps[prop.id]){
PoolManager.instance.putNode(this._dicProps[prop.id]);
delete this._dicProps[prop.id];
return true;
}
}
return false;
}
/**
* 删除指定道具
*
* @memberof PropLogic
*/
public removeProp (prop: Prop) {
PoolManager.instance.putNode(this._dicProps[prop.id]);
delete this._dicProps[prop.id];
prop.exist = false;
}
/**
* 生成道具数据
* @param pos 位置
* @param scale 大小
* @param type 类型
* @param belongOpenId 指定玩家才能拾取道具,为""则表示谁都可以拾取
* @param delay 延迟金币雨产生的金币会每隔150毫秒展示
* @returns
*/
public generateProp(pos: Vec3, scale: number = 1, type: PropType = PropType.COIN, belongOpenId: string = "", delay: number = 0) {
let prop: Prop = {} as Prop;
prop.id = this.indexProp;
prop.position = pos;
prop.scale = scale;
prop.exist = true;
prop.type = type;
this._dicProps[this.indexProp] = this._generatePropNode(prop) as Node;
return prop;
}
/**
* 生成道具节点
* @param prop 道具数据
* @returns
*/
private _generatePropNode(prop: Prop) {
let prefab: Prefab = this.virtualCoinPrefab;if (prop.type === PropType.HAMMER) {
prefab = this.virtualHammerPrefab;
}
let node: Node = PoolManager.instance.getNode(prefab, this.node);
node.setWorldPosition(prop.position);
return node;
}
/**
* 处理人物碰到道具
* @param player 玩家数据
* @param ndVirtualPlayer 玩家节点
*/
public handleProp(player: Player, ndVirtualPlayer: Node, isAi: boolean) {
let props: {[index: number]: Prop} = this._parent.currentGameState.props;
let keyPropsArray: Array<string> = Object.keys(this._dicProps);
let model1: ModelComponent = ndVirtualPlayer.getComponentInChildren(ModelComponent) as ModelComponent;
keyPropsArray.forEach((value: string) => {
let prop: Prop = props[parseInt(value)];
if (prop.type === PropType.HAMMER && player.hammerCount || prop.removed) {
return;
}
let ndProp: Node = this._dicProps[parseInt(value)];
let distance = Util.getTwoNodeXZLength(ndProp, ndVirtualPlayer);
if (distance >= 5) {
return;
}
let model2: ModelComponent = ndProp.getComponentInChildren(ModelComponent) as ModelComponent;
let obb1: geometry.OBB = new geometry.OBB();
let obb2: geometry.OBB = new geometry.OBB();
obb1.halfExtents = Vec3.multiplyScalar(v3_1, model1.node.scale, 0.5 * (model1.node.parent as Node).scale.x);
obb2.halfExtents = Vec3.multiplyScalar(v3_2, model2.node.scale, 0.5 * (model2.node.parent as Node).scale.x);
obb1.translateAndRotate(model1.node.worldMatrix, model1.node.worldRotation, obb1);
obb2.translateAndRotate(model2.node.worldMatrix, model2.node.worldRotation, obb2);
if (geometry.intersect.obbWithOBB(obb1, obb2)) {if (prop.type === PropType.HAMMER && player.hammerCount !== 0) {
return;
}
if (prop.type === PropType.HAMMER) {
prop.removed = true;
if(isAi){
GobeUtil.instance.sendFrame({'A': Constant.ACTION.HAMMER, 'V': prop.id, 'AI' : 1});
}else{
GobeUtil.instance.sendFrame({'A': Constant.ACTION.HAMMER, 'V': prop.id});
}
} else if (prop.type === PropType.COIN) {
if(this._dicProps[prop.id]){
prop.removed = true;
if(isAi){
GobeUtil.instance.sendFrame({'A': Constant.ACTION.ICON, 'V': prop.id, 'AI' : 1});
}else{
GobeUtil.instance.sendFrame({'A': Constant.ACTION.ICON, 'V': prop.id});
}
}else{
return;
}
}
}
});
}
/**
* 获取随机道具、金币掉落位置
* @param posWorld
* @returns
*/
public randomDropPos(posWorld: Vec3, propType: number, radius: number = 6) {
let posNew: Vec3 | null = new Vec3();
let i = 0;
let data: any;
if (propType === PropType.COIN) {
data = this.virtualCoinPrefab.data;
} else if (propType === PropType.HAMMER) {
data = this.virtualHammerPrefab.data;
}
do {
//范围逐渐扩大
let r_1 = (radius + i / 10);
let r_2 = (radius + i / 10);
let x = -r_1 + Math.random() * r_1 * 2;
let z = -r_2 + Math.random() * r_2 * 2;
x = x + posWorld.x;
z = z + posWorld.z;
//限制范围
x = clamp(x, -28, 28);
z = clamp(z, -24, 24);
posNew.set(x, 1, z);
i++;
//防止死循环
if (i >= 50) {
console.log("randomDropPos,posNew", posNew, "posWorld", posWorld, "propType", propType, "radius", radius);
posNew = null;
break;
}
} while (!!this._canPlaced(posNew, data));
return posNew;
}
/**
* 判断位置是否可放置
* @param pos 位置
* @param node 放置物体
* @returns
*/
private _canPlaced(pos: Vec3, node: Node) {
let modelArray: ModelComponent[] = this.node.parent?.getComponentsInChildren(ModelComponent) as ModelComponent[];
let flag: boolean = false;
let model1: ModelComponent = node.getComponentInChildren(ModelComponent) as ModelComponent;
node.setWorldPosition(pos);
for(let i: number = 0; i < modelArray.length; i++) {
if (!modelArray[i].node.active) continue;
let model2: ModelComponent = modelArray[i];
let obb1: geometry.OBB = new geometry.OBB();
let obb2: geometry.OBB = new geometry.OBB();
obb1.halfExtents = Vec3.multiplyScalar(v3_1, model1.node.scale, 0.5 *(model1.node.parent as Node).scale.x);
obb1.halfExtents.y *= 2;
obb2.halfExtents = Vec3.multiplyScalar(v3_2, model2.node.scale, 0.5 * (model2.node.parent as Node).scale.x);
obb1.translateAndRotate(model1.node.worldMatrix, model1.node.worldRotation, obb1);
obb2.translateAndRotate(model2.node.worldMatrix, model2.node.worldRotation, obb2);
if (geometry.intersect.obbWithOBB(obb1, obb2)) {
return true;
}
}
return flag;
}
/**
* 获取场景金币数
* @param props 道具数据
* @returns
*/
public getCoinNum(props: Prop[]) {
let result: Prop[] = props.filter((value: Prop) => {
return value.type === PropType.COIN && value.exist;
});
return result.length;
}
/**
* 获取场景锤头数
* @param props 道具数据
* @returns
*/
public getHammerNum(props: Prop[]) {
let result: Prop[] = props.filter((value: Prop) => {
return value.type === PropType.HAMMER && value.exist;
});
return result.length;
}
/**
* 生成被锤子打击后掉落的金币坐标
* @param num 金币数
* @param position 掉落位置
*/
public createCoinByHammer(num: number, position: Vec3, radius: number = 6) {
var pos:number[][] = [];
for(let i: number = 0; i < num; i++) {
let randomPos = this.randomDropPos(position, PropType.COIN, radius);
if (randomPos) {
pos.push([randomPos.x, randomPos.y, randomPos.z]);
}
}
GobeUtil.instance.createCoin(pos);
}
/**
* 创建金币
* @param pos
*/
public createCoinServer(pos:number[][]){
for(var index:number = 0; index < pos.length; index ++){
let prop: Prop = this.generateProp(new Vec3(pos[index][0], pos[index][1], pos[index][2]));
this._parent.currentGameState.props[this.indexProp] = prop;
prop.dropPosition = new Vec3(pos[index][0], pos[index][1], pos[index][2]);
this._dicProps[this.indexProp].setWorldPosition(prop.dropPosition);
this.indexProp++;
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "1e5633ff-4f6b-4ff8-8beb-e0e259300ace",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,60 @@
import { LogicManager } from './logicManager';
import { _decorator, Component, Vec3} from 'cc';
import { Player } from './gameState';
import { GobeUtil } from './gobeUtil';
const { ccclass } = _decorator;
@ccclass('VirtualPlayer')
export class VirtualPlayer extends Component {
private _curAngleY: number = 0;//当前Y分量旋转角度
private _vec3_0:Vec3 = new Vec3();
private _angle_0:Vec3 = new Vec3();
private _next_vec3_0:Vec3 = new Vec3();
init(pos:Vec3) {
this._curAngleY = 0;
this._vec3_0.set(pos);
}
/**
* 执行玩家行为
*
* @param {*} obj
* @memberof Player
*/
public playAction(obj: {action: number, posX: number, posZ: number, angleY: number}) {
this._curAngleY = obj.angleY;
this._vec3_0.set(obj.posX, 0, obj.posZ);
this._angle_0.set(0, this._curAngleY, 0);
}
public playActionRecovery () {
this.node.setRotationFromEuler(this._angle_0);
this.node.setPosition(this._vec3_0);
}
public updateState (player: Player, scriptLogicManager: LogicManager) {
Vec3.lerp(this._next_vec3_0, this.node.position, this._vec3_0, 0.2);
this.node.setRotationFromEuler(this._angle_0);
this.node.setPosition(this._next_vec3_0);
if(player.channel.openId == GobeUtil.instance.ownPlayerId){
scriptLogicManager.propLogic.handleProp(player, this.node, false);
}
else if(GobeUtil.instance.isAi){
scriptLogicManager.propLogic.handleProp(player, this.node, true);
}
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "f0cd5f91-586d-49f2-9724-5bb012b1d2a8",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "e032fa9d-83b0-48d4-adb2-4304f7de3de2",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,234 @@
import { _decorator, Node, AudioClip, AudioSource, director } from "cc";
import { StorageManager } from "./storageManager";
import { ResourceUtil } from "./resourceUtil";
import { Lodash } from './lodash';
const { ccclass, property } = _decorator;
interface AudioData {
source: AudioSource;
isMusic: boolean;
}
interface AudioDataMap {
[name: string]: AudioData;
}
@ccclass("AudioManager")
export class AudioManager {
private _persistRootNode: Node = null!;
private _audioSources: AudioSource[] = [];
static _instance: AudioManager;
dictWeaponSoundIndex: any = {};
static get instance() {
if (this._instance) {
return this._instance;
}
this._instance = new AudioManager();
return this._instance;
}
musicVolume: number = 0.8;
soundVolume: number = 1;
audios: AudioDataMap = {};
arrSound: AudioData[] = [];
init() {
if (this._persistRootNode) return; //避免切换场景初始化报错
this._persistRootNode = new Node('audio');
this.openAudio();
director.getScene()!.addChild(this._persistRootNode);
director.addPersistRootNode(this._persistRootNode)
this.musicVolume = this.getAudioSetting(true) ? 0.8 : 0;
this.soundVolume = this.getAudioSetting(false) ? 1 : 0;
}
private _getAudioSource(clip: AudioClip) {
let result: AudioSource | undefined;
for (let i = 0; i < this._audioSources.length; ++i) {
let audioSource = this._audioSources[i];
if (!audioSource.playing) {
result = audioSource;
break;
}
}
if (!result) {
result = this._persistRootNode.addComponent(AudioSource);
result.playOnAwake = false;
this._audioSources.push(result);
}
result.node.off(AudioSource.EventType.ENDED);
result.clip = clip;
result.currentTime = 0;
return result;
}
getAudioSetting(isMusic: boolean) {
let state;
if (isMusic) {
state = StorageManager.instance.getGlobalData('music');
} else {
state = StorageManager.instance.getGlobalData('sound');
}
return !state || state === 'true' ? true : false;
}
/**
* 播放音乐
* @param {String} name 音乐名称可通过Constant.AUDIO_MUSIC 获取
* @param {Boolean} loop 是否循环播放
*/
playMusic(name: string, loop: boolean) {
let path = 'audio/music/' + name;
ResourceUtil.loadRes(path, AudioClip, (err: any, clip: any) => {
let source = this._getAudioSource(clip);
let tmp: AudioData = {
source,
isMusic: true,
};
this.audios[name] = tmp;
source.volume = this.musicVolume;
source.loop = loop;
source.play();
});
}
/**
* 播放音效
* @param {String} name 音效名称可通过Constant.AUDIO_SOUND 获取
* @param {Boolean} loop 是否循环播放
*/
playSound(name: string, loop: boolean = false) {
if (!this.soundVolume) {
return;
}
//音效一般是多个的,不会只有一个
let path = 'audio/sound/';
ResourceUtil.loadRes(path + name, AudioClip, (err: any, clip: any) => {
let source = this._getAudioSource(clip);
let tmp: AudioData = {
source,
isMusic: false,
};
this.arrSound.push(tmp);
if (loop) {
this.audios[name] = tmp;
}
source.volume = this.soundVolume;
source.loop = loop;
source.play();
source.node.on(AudioSource.EventType.ENDED, () => {
Lodash.remove(this.arrSound, (obj: AudioData) => {
return obj.source === tmp.source;
});
});
});
}
stop(name: string) {
if (this.audios.hasOwnProperty(name)) {
let audio = this.audios[name];
audio.source.stop();
}
}
stopAll() {
for (const i in this.audios) {
if (this.audios.hasOwnProperty(i)) {
let audio = this.audios[i];
audio.source.stop();
}
}
}
getMusicVolume() {
return this.musicVolume;
}
setMusic(flag: number) {
this.musicVolume = flag;
for (let item in this.audios) {
if (this.audios.hasOwnProperty(item) && this.audios[item].isMusic) {
let audio = this.audios[item];
audio.source.volume = this.musicVolume;
}
}
}
//看广告时先将音乐暂停
pauseAll() {
for (let item in this.audios) {
if (this.audios.hasOwnProperty(item)) {
let audio = this.audios[item];
audio.source.pause();
}
}
}
resumeAll() {
for (let item in this.audios) {
if (this.audios.hasOwnProperty(item)) {
let audio = this.audios[item];
audio.source.play();
}
}
}
openMusic() {
this.setMusic(0.8);
StorageManager.instance.setGlobalData('music', 'true');
}
closeMusic() {
this.setMusic(0);
StorageManager.instance.setGlobalData('music', 'false');
}
openSound() {
this.setSound(1);
StorageManager.instance.setGlobalData('sound', 'true');
}
closeSound() {
this.setSound(0);
StorageManager.instance.setGlobalData('sound', 'false');
}
openAudio() {
this.openMusic();
this.openSound();
}
closeAudio() {
this.closeMusic();
this.closeSound();
}
setSound(flag: number) {
this.soundVolume = flag;
for (let item in this.audios) {
if (this.audios.hasOwnProperty(item) && !this.audios[item].isMusic) {
let audio = this.audios[item];
audio.source.volume = this.soundVolume;
}
}
for (let idx = 0; idx < this.arrSound.length; idx++) {
let audio = this.arrSound[idx];
audio.source.volume = this.soundVolume;
}
}
stopSingleSound(name: string) {
if (this.audios.hasOwnProperty(name) && !this.audios[name].isMusic) {
let audio = this.audios[name];
audio.source.stop();
}
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "5e2ec645-1091-441e-80a0-c7a9575581c1",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,80 @@
import { _decorator } from "cc";
const { ccclass, property } = _decorator;
@ccclass("ClientEvent")
export class ClientEvent {
private static _handlers: { [key: string]: any[] } = {};
/**
* 监听事件
* @param {string} eventName 事件名称
* @param {function} handler 监听函数
* @param {object} target 监听目标
*/
public static on (eventName: string, handler: Function, target: any) {
var objHandler: {} = {handler: handler, target: target};
var handlerList: Array<any> = ClientEvent._handlers[eventName];
if (!handlerList) {
handlerList = [];
ClientEvent._handlers[eventName] = handlerList;
}
for (var i = 0; i < handlerList.length; i++) {
if (!handlerList[i]) {
handlerList[i] = objHandler;
return i;
}
}
handlerList.push(objHandler);
return handlerList.length;
};
/**
* 取消监听
* @param {string} eventName 监听事件
* @param {function} handler 监听函数
* @param {object} target 监听目标
*/
public static off (eventName: string, handler: Function, target: any) {
var handlerList = ClientEvent._handlers[eventName];
if (!handlerList) {
return;
}
for (var i = 0; i < handlerList.length; i++) {
var oldObj = handlerList[i];
if (oldObj.handler === handler && (!target || target === oldObj.target)) {
handlerList.splice(i, 1);
break;
}
}
};
/**
* 分发事件
* @param {string} eventName 分发事件名
* @param {...any} params 分发事件参数
*/
public static dispatchEvent (eventName: string, ...args: any) {
var handlerList = ClientEvent._handlers[eventName];
var args1 = [];
var i;
for (i = 1; i < arguments.length; i++) {
args1.push(arguments[i]);
}
if (!handlerList) {
return;
}
for (i = 0; i < handlerList.length; i++) {
var objHandler = handlerList[i];
if (objHandler.handler) {
objHandler.handler.apply(objHandler.target, args1);
}
}
};
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e55dbcc1-367d-4d52-b87c-af9ceeb2f099",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,282 @@
import { Enum } from "cc";
export class Constant {
public static GAME_NAME = 'Coin';
public static GAME_VERSION = '1.0.1';
public static GAME_FRAME = 60; //游戏当前帧率
public static GAME_INIT_FRAME = 60; //游戏开发基础帧率
//本地缓存key值
public static LOCAL_CACHE = {
PLAYER: 'player', //玩家基础数据缓存,如金币砖石等信息,暂时由客户端存储,后续改由服务端管理
SETTINGS: 'settings', //设置相关,所有杂项都丢里面进去
DATA_VERSION: 'dataVersion', //数据版本
ACCOUNT: 'account', //玩家账号
// TMP_DATA: 'tmpData', //临时数据,不会存储到云盘
HISTORY: "history", //关卡通关数据
BAG: "bag", //玩家背包,即道具列表,字典类型
}
static PTM_RATIO = 1;
static GAME_OBJ_TYPE = { // 二进制位
PLAYER: 1,
COIN: 2
};
static ACTION = {
MOVE: 1,
STOP_MOVE: 2,//停止移动但是不转向敌人
GAME_START: 3,
GAME_OVER: 4,
READY: 5,
HEART_BEAT: 6,
UPDATE_POS: 8,
VIBRATE: 9,
RUN: 13,
IDLE: 14,
IS_ATTACK_ED: 12,//被攻击
HIT: 7,
ICON: 15,
HAMMER: 16,
CREATE_HAMMER: 17,
CREATE_ICON: 18,
}
static NETWORK_STATUS = {
COMMON_OFFLINE: 0,
COMMON_ONLINE: 1,
RELAY_OFFLINE: 2,
RELAY_ONLINE: 3,
}
static FRAME_SYNC_STATE = {
STOP: 0,
START: 1
}
static COIN_TYPE = Enum({
COIN: 1,
PROP: 2
});
static ADD_SIZE_PER_COIN = 0.03; //每1个金币 体积增加 5%
static MIN_SPEED_PERCENT = 0.2; //最低速度降低百分比
static INIT_MOVE_SPEED = 20; //初始移动速度
static GAME_TIME = 60; //游戏时间60 * 4秒
static MIN_PLAYER = 2;//玩家最少人数
static MAX_PLAYER = 2;//玩家最多人数
static EVENT_NAME = {
ON_GET_ROOM_INFO: 'onGetRoomInfo', //获取到房间信息
ON_RECV_SYNC:'onRecvSync', //帧同步数据
ON_GAME_READY: 'onGameReady', //游戏准备开始
ON_GAME_START: 'onGameStart', //开始游戏
ON_GAME_321: 'onGame321', //开始游戏
ON_GAME_END: 'onGameEnd', //结束游戏
ON_SHOW_COIN_TIPS: "showCoinTips", //显示金币提示
ON_OTHER_JOIN_ROOM: 'onOtherJoinRoom', //加入房间
SEND_MSG: 'sendMsg', //收到消息
SEND_MSG_HEIGHT: 'sendMsgHeight', //收到消息
SEND_VT: 'sendVt', //收到消息
OPEN_MEDIA: 'openMedia', //收到消息
OPEN_CHANNEL: 'openChannel', //收到消息
IS_TOUCH: 'is_touch', // 触摸
GAME_INIT: 'game_init',
INIT_MEDIA: 'init_media', // 语音准备
INIT_CHANNEL: 'init_channel', // channel准备
CREATE_HAMMER: 'create_hammer', // channel准备
CREATE_COIN: 'create_coin', // channel准备
DIS_JOIN: 'dis_join', // channel准备
OPEN_PGS: 'openPgs', // 开启社区
HUAWEI_LOGIN_MSG : 'huawei_login_msg', // 华为初始化
}
static PANEL_NAME = {
READY: 'fight/ready', //准备界面
GAME_OVER: 'fight/gameOver',//结算界面
FIGHT_UI: 'fight/fightUI', //结算界面
READY_GO: 'fight/readyGo', //结算界面
START_GAME: 'fight/startPanel', //开始游戏
SELECT_GAME: 'fight/selectPanel', //选择界面
TIP_PANEL: 'fight/tipPanel', //离开界面
JOIN_ROOM_PANEL: 'fight/joinRoomPanel', //加入房间
MATCH_PANEL: 'fight/matchPanel', //匹配界面
TRANSITION:'fight/transitionPanel', // 过度界面
TRANSITION_BG:'fight/transitionBgPanel', // 过度界面
MESSAGE_PANEL:'fight/messagePanel', // 消息面板
DOWNOFF_PANEL:'fight/downOffPanel', // 断线
MEDIA_PANEL:'fight/mediaPanel', // 对话
}
static SCENE_NAME = {
FIGHT : "fight",
START : "start",
SLECT : "select"
}
static AUDIO_NAME = {
BACKGROUND: 'background', //背景音乐
WIN: 'win', //胜利音效
GO: 'go', //游戏开始音效
TICK: 'tick', //倒计时音效
TIME_OUT: 'timeout', //时间到音效
GOLD: 'gold' ,//金币音效
HIT: 'hit', //击中音效
}
static EFFECT_NAME = {
RUNNING: 'running', //跑步特效
WIN: "leaveWinAni",
TRANSITION: "transition07", //过场动画
}
//道具类型
static PROP_TYPE = {
TO_SELF: "toSelf",//对己
TO_ENEMY: "toEnemy",//对敌人
}
//玩家动画类型
static ANI_TYPE = {
IDLE: 'idle',//普通待机
RUN: 'run',//空手跑
RUN_1: 'run1',//拿着锤子跑
VICTORY: "victory",//胜利
LOSE: "lose",//失败哭泣播放一次后播放lose1循环
LOSE_1: "lose1",//失败,哭泣循环
ATTACK: 'attack',//锤子攻击
HIT: "hit",//被击中先播放一次再播放dizzy循环
DIZZY: 'dizzy',//被击中眩晕
}
public static EASY_TOUCH = {
TOUCH_LEFT_X: 'touchLeftX', // 左手 x
TOUCH_LEFT_Y: 'touchLeftY', // 左右 y
TOUCH_RIGHT_X: 'touchRightX', // 右手 x
TOUCH_RIGHT_Y: 'touchRightY', // 右手 y
}
static PROP_DISAPPEAR_TIME = 10;//道具10秒后回收
static READY_PREFAB = {
GIRL_MODEL: "fight/girlUI", //ui上显示的女生模型
BOY_MODEL: "fight/boyUI", //ui上显示的男生模型
JOIN_EFFECT: "joinEff", //加入房间特效
VS_EFFECT: "vsAni" , //开始特效
}
static ROOM_TIPS = {
CREATE: "创建房间。。。",
WAITING: "请稍等,房主正在创建房间。。。",
LEAVE: "您的对手已经离开房间。。。",
IN_ROOM: "已在房间内。。。",
CREATE_ROOM_ERROR: "创建房间失败",
JOIN_ROOM_ERROR: "加入房间失败",
NO_ROOM_ID:"请输入正确的房间号",
LEAVE_ROOM_ERROR:"离开房间出错",
LEAVE_ROOM_MSG : "确认退出房间?",
LEAVE_ROOM_SUCCESS : "成功离开房间",
JOIN_ROOM_SUCCESS : "成功加入房间",
MATCH_ROOM_ERROR : "匹配房间出错",
PLAYER_LENGHT_ERROR : "长度需要大于2",
LEAVE_GAME : "是否退出游戏?",
INPUT_MSG : "请输入文字",
VT_ERROR:"未识别到语音",
PLAYER_LEAVE_1:"队友离开队伍,",
PLAYER_LEAVE_2:"秒游戏结束",
INIT_FAIL:"登录失败",
MEDIA_FAIL:"语音权限不足,语音未开启",
WORLD_LABEL:"世界频道",
ROOM_LABEL:"房间号:",
LOGIN_GAME_ERROR:"进入场景异常,请重试",
HUA_WEI_LOAGIN_ERROR:"华为登录失败,请改用普通账号登录"
}
static PLAYER_ORIGIN_SCALE = 1.5;//玩家初始缩放大小
static WORLD_ID = "cocosworldid00000"
static DIZZY_TIME = 1; //被榴莲击中后眩晕时间
static HAMMER_TIME = 15; //锤子生成时间每隔15秒
static AUTO_GEN_COIN = { //自动生成金币相关
SECOND_PER_TIMES: 1, //每多少秒触发一次
COIN_PER_TIMES: 1, //每次生成几个金币
START_NUM: 10, //金币数量小于指定个数,开始自动生成
END_NUM: 20 //金币数量大于指定个数,停止生成
}
static REVIVE_TIME = 0.5; //复活时间
static INIT_COLLIDER_CIRCLE = 0.8; //初始的人物碰撞矩形框
static HAMMER_TIMES = 1; //锤子可用次数
static AI_PLAYER_ID = "ai00000";
static AI_PLAYER = 1;
static HAMMER_POS:number[][]= [
[0, 0, 0],
[-28, 0, -25],
[28, 0, -25],
[23, 0, 23],
[-28, 0, 23]
];
static AI_SPEED : number = 0.22;
static AI_POS_INDEX : number[][] = [
[1, 26, 27, 19], // 初始化
[2, 26, 19], // Cube-001
[1, 3, 22], // Cube-002
[2, 4, 23], // 3
[3, 24, 5], // 4.......
[6, 25, 4], // 5
[5, 7, 20], //6 ..........
[25, 8, 23, 6], // 7
[10, 11, 18, 17], // 8
[23, 22], // 9
[13, 11, 18, 9], // 10
[10, 17, 12, 28], // 11
[11, 16, 13], // 12
[10, 12, 15], // 13
[13, 15, 16, 12], // 14
[18, 16, 28, 9], // 15
[15, 17, 28, 9], // 16
[18, 16, 28, 9], // 17
[15, 17, 28, 9], // 18
[1, 27, 20], // 19
[6, 21, 19], // 20
[7, 14, 22, 20], // 21
[23, 2, 14, 21, 2], // 22
[7, 8, 22, 3, 4], // 23
[25, 23], // 24
[7, 24], // 25 ..............
[27, 19, 22], // 26
[21, 26, 19], // 27
[7, 21], // 28
];
static HUAWEI_LOGIN = {
SIGN_IN_SUCCESS : 0, // 账号登录成功
INIT_SUCCESS : 10000, // 初始化成功
INIT_UNDER_AGE : 10001, // 未成年人登录
INIT_ERROR : 10002, // 初始化报错
SIGN_IN_ERROR : 10003, // 登录报错
NO_HUAWEI : 10004 // 非华为手机
}
static START_GAME :string = 'startGame';
static DISMISS :string = 'dismiss';
static START_GAME_TIME :string = 'start_game_time';
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b08f0f24-88e9-4403-b7ba-a9459aec09c0",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,628 @@
import { _decorator } from "cc";
const { ccclass, property } = _decorator;
var CELL_DELIMITERS = [",", ";", "\t", "|", "^"];
var LINE_DELIMITERS = ["\r\n", "\r", "\n"];
var getterCast = function(value: any, index: any, cast: any, d: any) {
if (cast instanceof Array) {
if (cast[index] === "number") {
return Number(d[index]);
} else if (cast[index] === "boolean") {
return d[index] === "true" || d[index] === "t" || d[index] === "1";
} else {
return d[index];
}
} else {
if (!isNaN(Number(value))) {
return Number(d[index]);
} else if (value == "false" || value == "true" || value == "t" || value == "f") {
return d[index] === "true" || d[index] === "t" || d[index] === "1";
} else {
return d[index];
}
}
};
var CSV = {
//
/* =========================================
* Constants ===============================
* ========================================= */
STANDARD_DECODE_OPTS: {
skip: 0,
limit: false,
header: false,
cast: false,
comment: ""
},
STANDARD_ENCODE_OPTS: {
delimiter: CELL_DELIMITERS[0],
newline: LINE_DELIMITERS[0],
skip: 0,
limit: false,
header: false
},
quoteMark: '"',
doubleQuoteMark: '""',
quoteRegex: /"/g,
/* =========================================
* Utility Functions =======================
* ========================================= */
assign: function () {
var args = Array.prototype.slice.call(arguments);
var base = args[0];
var rest = args.slice(1);
for (var i = 0, len = rest.length; i < len; i++) {
for (var attr in rest[i]) {
base[attr] = rest[i][attr];
}
}
return base;
},
map: function (collection: any, fn: Function) {
var results = [];
for (var i = 0, len = collection.length; i < len; i++) {
results[i] = fn(collection[i], i);
}
return results;
},
getType: function (obj: any) {
return Object.prototype.toString.call(obj).slice(8, -1);
},
getLimit: function (limit: any, len: any) {
return limit === false ? len : limit;
},
buildObjectConstructor: function(fields: any, sample: any, cast: any) {
return function(d: any) {
var object: any = new Object();
var setter = function(attr: any, value: any) {
return object[attr] = value;
};
if (cast) {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, cast, d));
});
} else {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, null, d));
});
}
// body.push("return object;");
// body.join(";\n");
return object;
};
},
buildArrayConstructor: function(fields: any, sample: any, cast: any) {
return function(d: any) {
var row = new Array(sample.length);
var setter = function(idx: any, value: any) {
return row[idx] = value;
};
if (cast) {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, cast, d));
});
} else {
fields.forEach(function(attr: any, idx: number) {
setter(attr, getterCast(sample[idx], idx, null, d));
});
}
return row;
};
},
frequency: function (coll: any, needle: any, limit: any) {
if (limit === void 0) limit = false;
var count = 0;
var lastIndex = 0;
var maxIndex = this.getLimit(limit, coll.length);
while (lastIndex < maxIndex) {
lastIndex = coll.indexOf(needle, lastIndex);
if (lastIndex === -1) break;
lastIndex += 1;
count++;
}
return count;
},
mostFrequent: function (coll: any, needles: any, limit: any) {
var max = 0;
var detected;
for (var cur = needles.length - 1; cur >= 0; cur--) {
if (this.frequency(coll, needles[cur], limit) > max) {
detected = needles[cur];
}
}
return detected || needles[0];
},
unsafeParse: function (text: any, opts: any, fn: any) {
var lines = text.split(opts.newline);
if (opts.skip > 0) {
lines.splice(opts.skip);
}
var fields;
var constructor;
function cells(lines: any) {
var line = lines.shift();
if (line.indexOf('"') >= 0) {// 含引号
// 找到这行完整的数据, 找到对称的双引号
var lastIndex = 0;
var findIndex = 0;
var count = 0;
while (lines.length > 0) {
lastIndex = line.indexOf('"', findIndex);
if (lastIndex === -1 && count % 2 === 0) break;
if (lastIndex !== -1) {
findIndex = lastIndex + 1;
count++;
} else {
line = line + opts.newline + lines.shift();
}
}
var list = [];
var item;
var quoteCount = 0;
var start = 0;
var end = 0;
var length = line.length;
for (var key in line) {
if (!line.hasOwnProperty(key)) {
continue;
}
let numKey = parseInt(key);
var value = line[key];
if (numKey === 0 && value === '"') {
quoteCount++;
start = 1;
}
if (value === '"') {
quoteCount++;
if (line[numKey - 1] === opts.delimiter && start === numKey) {
start++;
}
}
if (value === '"' && quoteCount % 2 === 0) {
if (line[numKey + 1] === opts.delimiter || numKey + 1 === length) {
end = numKey;
item = line.substring(start, end);
list.push(item);
start = end + 2;
end = start;
}
}
if (value === opts.delimiter && quoteCount % 2 === 0) {
end = numKey;
if (end > start) {
item = line.substring(start, end);
list.push(item);
start = end + 1;
end = start;
} else if (end === start) {
list.push("");
start = end + 1;
end = start;
}
}
}
end = length;
if (end >= start) {
item = line.substring(start, end);
list.push(item);
}
return list;
} else {
return line.split(opts.delimiter);
}
}
if (opts.header) {
if (opts.header === true) {
opts.comment = cells(lines); // 第一行是注释
opts.cast = cells(lines); // 第二行是数据类型
fields = cells(lines);
} else if (this.getType(opts.header) === "Array") {
fields = opts.header;
}
constructor = this.buildObjectConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
} else {
constructor = this.buildArrayConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
}
while (lines.length > 0) {
var row = cells(lines);
if (row.length > 1) {
fn(constructor(row), fields[0]);
}
}
return true;
},
safeParse: function (text: any, opts: any, fn: Function) {
var delimiter = opts.delimiter;
var newline = opts.newline;
var lines = text.split(newline);
if (opts.skip > 0) {
lines.splice(opts.skip);
}
return true;
},
encodeCells: function (line: any, delimiter: any, newline: any) {
var row = line.slice(0);
for (var i = 0, len = row.length; i < len; i++) {
if (row[i].indexOf(this.quoteMark) !== -1) {
row[i] = row[i].replace(this.quoteRegex, this.doubleQuoteMark);
}
if (row[i].indexOf(delimiter) !== -1 || row[i].indexOf(newline) !== -1) {
row[i] = this.quoteMark + row[i] + this.quoteMark;
}
}
return row.join(delimiter);
},
encodeArrays: function(coll: any, opts: any, fn: Function) {
var delimiter = opts.delimiter;
var newline = opts.newline;
if (opts.header && this.getType(opts.header) === "Array") {
fn(this.encodeCells(opts.header, delimiter, newline));
}
for (var cur = 0, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
fn(this.encodeCells(coll[cur], delimiter, newline));
}
return true;
},
encodeObjects: function (coll: any, opts: any, fn:Function) {
var delimiter = opts.delimiter;
var newline = opts.newline;
var header;
var row;
header = [];
row = [];
for (var key in coll[0]) {
header.push(key);
row.push(coll[0][key]);
}
if (opts.header === true) {
fn(this.encodeCells(header, delimiter, newline));
} else if (this.getType(opts.header) === "Array") {
fn(this.encodeCells(opts.header, delimiter, newline));
}
//@ts-ignore
fn(this.encodeCells(row, delimiter));
for (var cur = 1, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
row = [];
for (var key$1 = 0, len = header.length; key$1 < len; key$1++) {
row.push(coll[cur][header[key$1]]);
}
fn(this.encodeCells(row, delimiter, newline));
}
return true;
},
parse: function (text: any, opts: any, fn: Function) {
var rows: any;
if (this.getType(opts) === "Function") {
fn = opts;
opts = {};
} else if (this.getType(fn) !== "Function") {
rows = [];
fn = rows.push.bind(rows);
} else {
rows = [];
}
//@ts-ignore
opts = this.assign({}, this.STANDARD_DECODE_OPTS, opts);
//@ts-ignore
this.opts = opts;
if (!opts.delimiter || !opts.newline) {
var limit = Math.min(48, Math.floor(text.length / 20), text.length);
opts.delimiter = opts.delimiter || this.mostFrequent(text, CELL_DELIMITERS, limit);
opts.newline = opts.newline || this.mostFrequent(text, LINE_DELIMITERS, limit);
}
// modify by jl 由表自行控制不要含有双引号.提高解析效率
return this.unsafeParse(text, opts, fn) &&
(rows.length > 0 ? rows : true);
},
encode: function (coll: any, opts: any, fn: Function) {
var lines: any;
if (this.getType(opts) === "Function") {
fn = opts;
opts = {};
} else if (this.getType(fn) !== "Function") {
lines = [];
fn = lines.push.bind(lines);
}
//@ts-ignore
opts = this.assign({}, this.STANDARD_ENCODE_OPTS, opts);
if (opts.skip > 0) {
coll = coll.slice(opts.skip);
}
return (this.getType(coll[0]) === "Array" ? this.encodeArrays : this.encodeObjects)(coll, opts, fn) &&
(lines.length > 0 ? lines.join(opts.newline) : true);
}
};
@ccclass("CSVManager")
export class CSVManager {
/* class member could be defined like this */
static _instance: CSVManager;
static get instance () {
if (this._instance) {
return this._instance;
}
this._instance = new CSVManager();
return this._instance;
}
private _csvTables:any = {};
private _csvTableForArr:any = {};
private _tableCast:any = {};
private _tableComment:any = {};
addTable (tableName:string, tableContent:string, force?:boolean) {
if (this._csvTables[tableName] && !force) {
return;
}
let tableData: any = {};
let tableArr: any[] = [];
let opts = { header: true };
CSV.parse(tableContent, opts, function (row: any, keyName: string) {
tableData[row[keyName]] = row;
tableArr.push(row);
});
this._tableCast[tableName] = (CSV as any).opts.cast;
this._tableComment[tableName] = (CSV as any).opts.comment;
this._csvTables[tableName] = tableData;
this._csvTableForArr[tableName] = tableArr;
//this.csvTables[tableName].initFromText(tableContent);
}
/**
* 根据表名获取表的所有内容
* @param {string} tableName 表名
* @returns {object} 表内容
*/
getTableArr (tableName:string) {
return this._csvTableForArr[tableName];
}
/**
* 根据表名获取表的所有内容
* @param {string} tableName 表名
* @returns {object} 表内容
*/
getTable (tableName:string) {
return this._csvTables[tableName];
}
/**
* 查询一条表内容
* @param {string} tableName 表名
* @param {string} key 列名
* @param {any} value 值
* @returns {Object} 一条表内容
*/
queryOne (tableName:string, key:string, value:any) {
var table = this.getTable(tableName);
if (!table) {
return null;
}
if (key) {
for (var tbItem in table) {
if (!table.hasOwnProperty(tbItem)) {
continue;
}
if (table[tbItem][key] === value) {
return table[tbItem];
}
}
} else {
return table[value];
}
}
/**
* 根据ID查询一条表内容
* @param {string}tableName 表名
* @param {string}ID
* @returns {Object} 一条表内容
*/
queryByID (tableName:string, ID:string) {
//@ts-ignore
return this.queryOne(tableName, null, ID);
}
/**
* 查询key和value对应的所有行内容
* @param {string} tableName 表名
* @param {string} key 列名
* @param {any} value 值
* @returns {Object}
*/
queryAll (tableName:string, key:string, value:any) {
var table = this.getTable(tableName);
if (!table || !key) {
return null;
}
var ret: any = {};
for (var tbItem in table) {
if (!table.hasOwnProperty(tbItem)) {
continue;
}
if (table[tbItem][key] === value) {
ret[tbItem] = table[tbItem];
}
}
return ret;
}
/**
* 选出指定表里所有 key 的值在 values 数组中的数据,返回 Objectkey 为 ID
* @param {string} tableName 表名
* @param {string} key 列名
* @param {Array}values 数值
* @returns
*/
queryIn (tableName:string, key:string, values:Array<any>) {
var table = this.getTable(tableName);
if (!table || !key) {
return null;
}
var ret: any = {};
var keys = Object.keys(table);
var length = keys.length;
for (var i = 0; i < length; i++) {
var item = table[keys[i]];
if (values.indexOf(item[key]) > -1) {
ret[keys[i]] = item;
}
}
return ret;
}
/**
* 选出符合条件的数据。condition key 为表格的keyvalue 为值的数组。返回的objectkey 为数据在表格的IDvalue为具体数据
* @param {string} tableName 表名
* @param {any} condition 筛选条件
* @returns
*/
queryByCondition (tableName:string, condition: any) {
if (condition.constructor !== Object) {
return null;
}
var table = this.getTable(tableName);
if (!table) {
return null;
}
var ret: any = {};
var tableKeys = Object.keys(table);
var tableKeysLength = tableKeys.length;
var keys = Object.keys(condition);
var keysLength = keys.length;
for (var i = 0; i < tableKeysLength; i++) {
var item = table[tableKeys[i]];
var fit = true;
for (var j = 0; j < keysLength; j++) {
var key = keys[j];
fit = fit && (condition[key] === item[key]) && !ret[tableKeys[i]];
}
if (fit) {
ret[tableKeys[i]] = item;
}
}
return ret;
}
queryOneByCondition (tableName:string, condition: any) {
if (condition.constructor !== Object) {
return null;
}
var table = this.getTable(tableName);
if (!table) {
return null;
}
var keys = Object.keys(condition);
var keysLength = keys.length;
for (let keyName in table) {
var item = table[keyName];
var fit = true;
for (var j = 0; j < keysLength; j++) {
var key = keys[j];
fit = fit && (condition[key] === item[key]);
}
if (fit) {
return item;
}
}
return null;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d755406e-aa72-4b00-a89b-c15516b5ee4f",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,309 @@
import { _decorator, Node, Prefab, AnimationComponent, ParticleSystemComponent, Vec3, find, AnimationState, AnimationClip, director } from 'cc';
import { PoolManager } from './poolManager';
import { ResourceUtil } from './resourceUtil';
const { ccclass, property } = _decorator;
@ccclass('EffectManager')
export class EffectManager{
private _ndParent: Node = null!;
public get ndParent() {
if (!this._ndParent) {
let ndEffectParent = find("effectManager") as Node;
if (ndEffectParent) {
this._ndParent = ndEffectParent;
} else {
// console.warn("请在场景里添加effectManager节点");
this._ndParent = new Node("effectManager");
director.getScene()?.addChild(this._ndParent);
}
}
return this._ndParent;
}
static _instance: EffectManager;
static get instance () {
if (this._instance) {
return this._instance;
}
this._instance = new EffectManager();
return this._instance;
}
/**
* 播放动画
* @param {string} path 动画节点路径
* @param {string} aniName
* @param {vec3} worPos 世界坐标
* @param {boolean} isLoop 是否循环
* @param {boolean} isRecycle 是否回收
* @param {number} [scale=1] 缩放倍数
* @param {Function} [callback=()=>{}] 回调函数
*/
public playAni (path: string, aniName: string, worPos: Vec3 = new Vec3(), isLoop: boolean = false, isRecycle: boolean = false, scale: number = 1, callback: Function = ()=>{}) {
let childName: string = path.split("/")[1];
let ndEffect: Node | null = this.ndParent.getChildByName(childName);
let cb = ()=>{
ndEffect?.setScale(scale, scale, scale);
ndEffect?.setWorldPosition(worPos);
let ani: AnimationComponent= ndEffect?.getComponent(AnimationComponent) as AnimationComponent;
ani.play(aniName);
let aniState: AnimationState= ani.getState(aniName) as AnimationState;
if (aniState) {
if (isLoop) {
aniState.wrapMode = AnimationClip.WrapMode.Loop;
} else {
aniState.wrapMode = AnimationClip.WrapMode.Normal;
}
}
ani.once(AnimationComponent.EventType.FINISHED, ()=>{
callback && callback();
if (isRecycle && ndEffect) {
PoolManager.instance.putNode(ndEffect);
}
})
}
if (!ndEffect) {
ResourceUtil.loadEffectRes(path).then((prefab: unknown)=>{
ndEffect = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
ndEffect.setScale(scale, scale, scale);
ndEffect.setWorldPosition(worPos);
cb();
})
} else {
cb();
}
}
/**
* 移除特效
* @param {string} name 特效名称
* @param {Node}} ndParent 特效父节点
*/
public removeEffect (name: string, ndParent: Node = this.ndParent) {
let ndEffect: Node | null = ndParent.getChildByName(name);
if (ndEffect) {
let arrAni: AnimationComponent[] = ndEffect.getComponentsInChildren(AnimationComponent);
arrAni.forEach((element: AnimationComponent)=>{
element.stop();
})
let arrParticle: [] = ndEffect?.getComponentsInChildren(ParticleSystemComponent) as any;
arrParticle.forEach((element:ParticleSystemComponent)=>{
element?.clear();
element?.stop();
})
PoolManager.instance.putNode(ndEffect);
}
}
/**
* 播放粒子特效
* @param {string} path 特效路径
* @param {vec3}worPos 特效世界坐标
* @param {number} [recycleTime=0] 特效节点回收时间如果为0则使用默认duration
* @param {number} [scale=1] 缩放倍数
* @param {vec3} eulerAngles 特效角度
* @param {Function} [callback=()=>{}] 回调函数
*/
public playParticle (path: string, worPos: Vec3, recycleTime: number = 0, scale: number = 1, eulerAngles?: Vec3 | null, callback?: Function) {
ResourceUtil.loadEffectRes(path).then((prefab: any)=>{
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
ndEffect.setScale(scale, scale, scale);
ndEffect.setWorldPosition(worPos);
if (eulerAngles) {
ndEffect.eulerAngles = eulerAngles;
}
let maxDuration: number = 0;
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
arrParticle.forEach((item: ParticleSystemComponent)=>{
item.simulationSpeed = 1;
item?.clear();
item?.stop();
item?.play()
let duration: number= item.duration;
maxDuration = duration > maxDuration ? duration : maxDuration;
})
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
setTimeout(()=>{
if (ndEffect.parent) {
callback && callback();
PoolManager.instance.putNode(ndEffect);
}
}, seconds * 1000)
})
}
/**
* 播放节点下面的动画和粒子
*
* @param {Node} targetNode 特效挂载节点
* @param {string} effectPath 特效路径
* @param {boolean} [isPlayAni=true] 是否播放动画
* @param {boolean} [isPlayParticle=true] 是否播放特效
* @param {number} [recycleTime=0] 特效节点回收时间如果为0则使用默认duration
* @param {number} [scale=1] 缩放倍数
* @param {Vec3} [pos=new Vec3()] 位移
* @param {boolean} [isRecycle=true] 回收或者销毁
* @param {Function} [callback=()=>{}] 回调函数
* @returns
* @memberof EffectManager
*/
public playEffect (targetNode: Node, effectPath: string, isPlayAni: boolean = true, isPlayParticle: boolean = true, recycleTime: number = 0, scale: number = 1, pos?: Vec3 | null, eulerAngles?: Vec3 | null, isRecycle: boolean = true, callback?: Function | null) {
if (!targetNode || !targetNode.parent) {//父节点被回收的时候不播放
return;
}
ResourceUtil.loadEffectRes(effectPath).then((prefab: any)=>{
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, targetNode) as Node;
ndEffect.setScale(scale, scale, scale);
if (pos) {
ndEffect.setPosition(pos);
}
if (eulerAngles) {
ndEffect.eulerAngles = eulerAngles;
}
let maxDuration: number = 0;
if (isPlayAni) {
let arrAni: AnimationComponent[] = ndEffect.getComponentsInChildren(AnimationComponent);
if (arrAni.length) {
arrAni.forEach((element: AnimationComponent, idx: number)=>{
element?.play();
let aniName = element?.defaultClip?.name;
if (aniName) {
let aniState = element.getState(aniName);
if (aniState) {
aniState.time = 0;
aniState.sample();
let duration = aniState.duration;
maxDuration = duration > maxDuration ? duration : maxDuration;
aniState.speed = 1;
}
}
})
}
}
if (isPlayParticle) {
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
if (arrParticle.length) {
arrParticle.forEach((element:ParticleSystemComponent)=>{
element.simulationSpeed = 1;
element?.clear();
element?.stop();
element?.play()
let duration: number= element.duration;
maxDuration = duration > maxDuration ? duration : maxDuration;
})
}
}
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
setTimeout(()=>{
if (ndEffect.parent) {
callback && callback();
if (isRecycle) {
PoolManager.instance.putNode(ndEffect);
} else {
ndEffect.destroy();
}
}
}, seconds * 1000)
})
}
/**
* 播放节点上的粒子特效/托尾粒子特效
*
* @param {Node} ndParent
* @memberof EffectManager
*/
public playTrail (ndParent: Node, recycleTime:number = 0, callback?:Function, speed: number = 1) {
let maxDuration: number = 0;
if (!ndParent.active) {
ndParent.active = true;
}
let arrParticle: ParticleSystemComponent[]= ndParent.getComponentsInChildren(ParticleSystemComponent);
arrParticle.forEach((element:ParticleSystemComponent)=>{
element.simulationSpeed = speed;
element?.clear();
element?.stop();
element?.play();
let duration: number= element.duration;
maxDuration = duration > maxDuration ? duration : maxDuration;
})
if (callback) {
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
setTimeout(()=>{
callback();
}, seconds * 1000)
}
}
/**
* 播放道具消失特效
* @param {string} path 特效路径
* @param {vec3}worPos 特效世界坐标
* @param {Function} [callback=()=>{}] 回调函数
*/
public playDisappearEff (path: string, worPos: Vec3, cb: Function) {
ResourceUtil.loadEffectRes(path).then((prefab: any)=>{
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
ndEffect.setWorldPosition(worPos);
let maxDuration: number = 0;
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
arrParticle.forEach((item: ParticleSystemComponent)=>{
item.simulationSpeed = 1;
item?.clear();
item?.stop();
item?.play()
let duration: number= item.duration;
maxDuration = duration > maxDuration ? duration : maxDuration;
})
setTimeout(()=>{
if (ndEffect && ndEffect.parent) {
PoolManager.instance.putNode(ndEffect);
}
}, maxDuration * 1000)
cb && cb(()=>{
if (ndEffect && ndEffect.parent) {
PoolManager.instance.putNode(ndEffect);
}
});
})
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "554ba46f-7575-4269-965e-5c54afbc0a5e",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,141 @@
import { _decorator, resources } from "cc";
import { CSVManager } from "./csvManager";
import { ResourceUtil } from "./resourceUtil";
const { ccclass, property } = _decorator;
@ccclass("LocalConfig")
export class LocalConfig {
/* class member could be defined like this */
private static _instance: LocalConfig;
private _csvManager: CSVManager = new CSVManager();
static get instance () {
if (this._instance) {
return this._instance;
}
this._instance = new LocalConfig();
return this._instance;
}
private _callback: Function = new Function();
private _currentLoad: number = 0;
private _cntLoad: number = 0;
/**
* 加载配置文件
* @param {Function}cb 回调函数
*/
public loadConfig (cb: Function) {
this._callback = cb;
this._loadCSV();
}
private _loadCSV () {
//新增数据表 请往该数组中添加....
resources.loadDir("datas", (err: any, assets)=>{
if (err) {
return;
}
let arrCsvFiles = assets.filter((item: any)=>{
return item._native !== ".md";
})
this._cntLoad = arrCsvFiles.length;
//客户端加载
if (arrCsvFiles.length) {
arrCsvFiles.forEach((item, index, array)=> {
ResourceUtil.getTextData(item.name, (err: any, content: any) => {
this._csvManager.addTable(item.name, content);
this._tryToCallbackOnFinished();
});
});
} else {
this._tryToCallbackOnFinished();
}
})
}
/**
* 查询一条表内容
* @param {string} tableName 表名
* @param {string} key 列名
* @param {any} value 值
* @returns {Object} 一条表内容
*/
queryOne (tableName: string, key: string, value: any) {
return this._csvManager.queryOne(tableName, key, value);
}
/**
* 根据ID查询一条表内容
* @param {string}tableName 表名
* @param {string}ID
* @returns {Object} 一条表内容
*/
queryByID (tableName: string, ID: string) {
return this._csvManager.queryByID(tableName, ID);
}
/**
* 根据表名获取表的所有内容
* @param {string} tableName 表名
* @returns {object} 表内容
*/
getTable (tableName: string) {
return this._csvManager.getTable(tableName);
}
/**
* 根据表名获取表的所有内容
* @param {string} tableName 表名
* @returns {object} 表内容
*/
getTableArr (tableName: string) {
return this._csvManager.getTableArr(tableName);
}
/**
* 查询key和value对应的所有行内容
* @param {string} tableName 表名
* @param {string} key 列名
* @param {any} value 值
* @returns {Object}
*/
queryAll (tableName: string, key: string, value: any) {
return this._csvManager.queryAll(tableName, key, value);
}
//
/**
* 选出指定表里所有 key 的值在 values 数组中的数据,返回 Objectkey 为 ID
* @param {string} tableName 表名
* @param {string} key 列名
* @param {Array}values 数值
* @returns
*/
queryIn (tableName: string, key: string, values: any[]) {
return this._csvManager.queryIn(tableName, key, values);
}
/**
* 选出符合条件的数据。condition key 为表格的keyvalue 为值的数组。返回的objectkey 为数据在表格的IDvalue为具体数据
* @param {string} tableName 表名
* @param {any} condition 筛选条件
* @returns
*/
queryByCondition (tableName: string, condition: any) {
return this._csvManager.queryByCondition(tableName, condition);
}
private _tryToCallbackOnFinished () {
if (this._callback) {
this._currentLoad++;
if (this._currentLoad >= this._cntLoad) {
this._callback();
}
}
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "12fac499-8454-4621-86bb-cb188b5433a9",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,637 @@
import { _decorator } from "cc";
const { ccclass } = _decorator;
@ccclass("Lodash")
export class Lodash {
/* class member could be defined like this */
// dummy = '';
/**
* 遍历 collection集合元素返回 predicate断言函数第一个返回真值的第一个元素
* @param {any} collection 一个用来迭代的集合
* @param {Function} predicate 每次迭代调用的函数。
* @returns 返回匹配元素,否则返回 undefined。
*/
public static find (collection: any, predicate: Function) {
var result;
if (!Array.isArray(collection)) {
collection = Lodash._toArray(collection);
}
result = collection.filter(predicate);
if (result.length) {
return result[0];
}
return undefined;
}
/**
* 调用 iteratee 遍历 collection(集合) 中的每个元素
* @param {any} collection 一个用来迭代的集合
* @param {Function} iteratee 每次迭代调用的函数。
*/
public static forEach(collection: any, iteratee: any) {
if (!Array.isArray(collection)) {
var array = Lodash._toArrayKey(collection);
array.forEach(function (value: any, index: number, arr: any[]) {
var key1 = value['key'];
var value1 = value['value'];
iteratee(value1, key1, collection);
});
} else {
collection.forEach(iteratee);
}
}
/**
* 深度拷贝
* @param {any} sObj 拷贝的对象
* @returns
*/
public static cloneDeep(sObj: any) {
if (sObj === null || typeof sObj !== "object") {
return sObj;
}
let s: any = {};
if (sObj.constructor === Array) {
s = [];
}
for (let i in sObj) {
if (sObj.hasOwnProperty(i)) {
s[i] = Lodash.cloneDeep(sObj[i]);
}
}
return s;
}
/**
* 创建一个数组, value 是 iteratee迭代函数遍历 collection集合中的每个元素后返回的结果。
* @param {Array|Object} collection 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数用来转换key
* @returns {Array} 返回一个组成集合数组
*/
public static map(collection: any, iteratee: any) {
if (!Array.isArray(collection)) {
collection = Lodash._toArray(collection);
}
let arr: any[] = [];
collection.forEach(function (value: any, index: number, array: []) {
arr.push(iteratee(value, index, array));
});
return arr;
}
/**
*
* @param srcObj
* @returns
*/
private static _toArrayKey(srcObj: { [x: string]: any; hasOwnProperty: (arg0: string) => any; }) {
var resultArr = [];
// to array
for (var key in srcObj) {
if (!srcObj.hasOwnProperty(key)) {
continue;
}
resultArr.push({ key: key, value: srcObj[key] });
}
return resultArr;
}
private static _toArray(srcObj: any) {
let resultArr: any[] = [];
// to array
for (var key in srcObj) {
if (!srcObj.hasOwnProperty(key)) {
continue;
}
resultArr.push(srcObj[key]);
}
return resultArr;
}
/**
* 遍历 collection集合元素返回 predicate断言函数返回真值 的所有元素的数组。
* @param {Array|Object} collection 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数用来转换key
* @returns 返回一个新的过滤后的数组。
*/
public static filter(collection: any, iteratees: Function) {
if (!Array.isArray(collection)) {
collection = Lodash._toArray(collection);
}
return collection.filter(iteratees);
}
/**
* 执行深比较来确定两者的值是否相等。
* @param {any}x
* @param {any}y
* @returns {boolean} 如果 两个值完全相同,那么返回 true否则返回 false。
*/
public static isEqual(x: any, y: any): boolean {
var in1 = x instanceof Object;
var in2 = y instanceof Object;
if (!in1 || !in2) {
return x === y;
}
if (Object.keys(x).length !== Object.keys(y).length) {
return false;
}
for (var p in x) {
var a = x[p] instanceof Object;
var b = y[p] instanceof Object;
if (a && b) {
return Lodash.isEqual(x[p], y[p]);
} else if (x[p] !== y[p]) {
return false;
}
}
return true;
}
/**
* 接收一个要移除值的数组。
* @param {Array} array 修改的数组
* @param {Array} value 移除值的数组
* @param {Function} comparator comparator比较器调用每个元素。
* @returns
*/
public static pullAllWith(array: any[], value: any[], comparator: Function) {
value.forEach(function (item) {
var res = array.filter(function (n) {
return comparator(n, item);
});
res.forEach(function (item) {
var index = array.indexOf(item);
if (array.indexOf(item) !== -1) {
array.splice(index, 1);
}
});
});
return array;
}
/**
* 返回当前时间戳
* @returns
*/
public static now() {
return Date.now();
}
/**
* 接收一个要移除值的数组。
* @param {Array} array 修改的数组
* @param {Array} value 移除值的数组
* @returns
*/
public static pullAll(array: any[], value: any) {
value.forEach(function (item: any) {
var index = array.indexOf(item);
if (array.indexOf(item) !== -1) {
array.splice(index, 1);
}
});
return array;
}
/**
* 从右到左遍历集合中每一个元素的。
* @param {Array|Object} collection 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数
*/
public static forEachRight(collection: [] | {}, iteratee: Function) {
if (!Array.isArray(collection)) {
collection = Lodash._toArray(collection);
}
//@ts-ignore
for (var i = collection.length - 1; i >= 0; i--) {
//@ts-ignore
var ret = iteratee(collection[i]);
if (!ret) break;
}
}
/**
* 检查字符串string是否以 target 开头。
* @param {string} str 要检索的字符串。
* @param {string}target 要检查的字符串。
* @param {number}position 检索的位置。
* @returns
*/
public static startsWith(str: string, target: string, position: number) {
str = str.substr(position);
return str.startsWith(target);
}
/**
* 检查字符串string是否以 target 结束。
* @param {string} str 要检索的字符串。
* @param {string}target 要检查的字符串。
* @param {number}position 检索的位置。
* @returns
*/
public static endsWith(str: string, target: string, position: number) {
str = str.substr(position);
return str.endsWith(target);
}
/**
* 移除数组中predicate断言返回为真值的所有元素
* @param {Array} array 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数
* @returns
*/
public static remove(array: any[], predicate: Function) {
var result: any[] = [];
var indexes: any[] = [];
array.forEach(function (item, index) {
if (predicate(item)) {
result.push(item);
indexes.push(index);
}
});
Lodash._basePullAt(array, indexes);
return result;
}
private static _basePullAt(array: any[], indexes: any[]) {
var length = array ? indexes.length : 0;
var lastIndex = length - 1;
var previous;
while (length--) {
var index = indexes[length];
if (length === lastIndex || index !== previous) {
previous = index;
Array.prototype.splice.call(array, index, 1);
}
}
return array;
}
/**
* 返回第一个通过 predicate 判断为真值的元素的索引值
* @param {Array} array 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数
* @param {number} fromIndex 开始查找索引值
* @returns
*/
public static findIndex(array: any[], predicate: Function, fromIndex: number) {
array = array.slice(fromIndex);
var i;
if (typeof predicate === "function") {
for (i = 0; i < array.length; i++) {
if (predicate(array[i])) {
return i;
}
}
} else if (Array.isArray(predicate)) {
for (i = 0; i < array.length; i++) {
var key = predicate[0];
var vaule = true;
//@ts-ignore
if (predicate.length > 1) {
vaule = predicate[1];
}
if (array[i][key] === vaule) {
return i;
}
}
} else {
for (i = 0; i < array.length; i++) {
if (array[i] === predicate) {
return i;
}
}
}
return -1;
}
/**
* 创建一个新数组将array与任何数组 或 值连接在一起。
* @returns
*/
public static concat() {
var length = arguments.length;
if (!length) {
return [];
}
var array = arguments[0];
var index = 1;
while (index < length) {
array = array.concat(arguments[index]);
index++;
}
return array;
}
/**
* 检查 value 是否是原始Number数值型 或者 对象。
* @param {any }value
* @returns
*/
public static isNumber(value: any) {
return typeof value === 'number';
}
/**
* 返回首次 value 在数组array中被找到的 索引值
* @param {Array}array
* @param {any}value
* @param {number} fromIndex
* @returns
*/
public static indexOf(array: any[], value: any, fromIndex: number) {
array = array.slice(fromIndex);
return array.indexOf(value);
}
/**
* 将 array 中的所有元素转换为由 separator 分隔的字符串。
* @param {any} array 要转换的数组
* @param {string} separator 分隔元素。
* @returns
*/
public static join(array: any[], separator: string) {
if (array === null) return '';
var result = '';
array.forEach(function (item) {
result += item + separator;
});
return result.substr(0, result.length - 1);
}
/**
* 根据separator 拆分字符串string。
* @param {string} str 要转换的数组
* @param {RegExp|string} separator 分隔元素。
* @param {number} limit 限制结果的数量。
* @returns
*/
public static split(str: string, separator: RegExp|string, limit: number) {
return str.split(separator, limit);
}
/**
* 计算 array 中的最大值。 如果 array 是 空的或者假值将会返回 undefined。
* @param {Array}array
* @returns
*/
public static max(array: any[]) {
if (array && array.length) {
var result;
for (var i = 0; i < array.length; i++) {
if (i === 0) {
result = array[0];
} else if (result < array[i]) {
result = array[i];
}
}
return result;
}
return undefined;
}
/**
* 创建一个切片数组去除array前面的n个元素。n默认值为1。
* @param {Array}array : 要查询的数组。
* @param {number}n 要去除的元素个数。
* @returns
*/
public static drop(array: any[], n: number) {
var length = array === null ? 0 : array.length;
if (!length) {
return [];
}
return array.slice(n);
}
/**
* 将array递归为一维数组。
* @param {Array} arr
* @returns
*/
public static flattenDeep(arr: any[]): any {
return arr.reduce(function (prev: any[], cur: any[]) {
return prev.concat(Array.isArray(cur) ? Lodash.flattenDeep(cur) : cur);
}, [ ]);
}
/**
* 创建一个去重后的array数组副本。使用了SameValueZero 做等值比较。只有第一次出现的元素才会被保留。
* @param {Array} array
* @returns
*/
public static uniq(array: any[]) {
let result: any[] = [];
array.forEach(function (item) {
if (result.indexOf(item) === -1) {
result.push(item);
}
});
return result;
}
/**
* 检查 value 是否是 NaN。
* @param {any}value
* @returns
*/
public static isNaN(value: any) {
// An `NaN` primitive is the only value that is not equal to itself.
// Perform the `toStringTag` check first to avoid errors with some
// ActiveX objects in IE.
return Lodash.isNumber(value) && value !== +value;
}
/**
* 将数组array拆分成多个 size 长度的区块,并将这些区块组成一个新数组
* @param {Array}array
* @param {number}size
* @returns
*/
public static chunk(array: any[], size: number) {
var length = array === null ? 0 : array.length;
if (!length || size < 1) {
return [];
}
var result = [];
while (array.length > size) {
result.push(array.slice(0, size));
array = array.slice(size);
}
result.push(array);
return result;
}
/**
* 转换 value 为一个有限数字
* @param {any} value
* @returns
*/
public static toFinite(value: any) {
var INFINITY = 1 / 0;
var MAX_INTEGER = 1.7976931348623157e+308;
if (!value) {
return value === 0 ? value : 0;
}
value = Number(value);
if (value === INFINITY || value === -INFINITY) {
var sign = (value < 0 ? -1 : 1);
return sign * MAX_INTEGER;
}
return value === value ? value : 0;
}
/**
* 判断是否为对象
* @param {any}value
* @returns {boolean}
*/
public static isObject(value: any) {
var type = typeof value;
return value !== null && (type === 'object' || type === 'function');
}
public static MAX_SAFE_INTEGER = 9007199254740991;
/**
*
* @param value
* @returns
*/
public static isLength(value: any) {
return typeof value === 'number' &&
value > -1 && value % 1 === 0 && value <= Lodash.MAX_SAFE_INTEGER;
}
public static _isArrayLike(value: []) {
return value !== null && Lodash.isLength(value.length) /*&& !isFunction(value)*/;
}
/**
* 返回数组总符合条件的最大值
* @param {Array} array 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数
* @returns {Object} 返回最大值
*/
public static maxBy(array: any[], predicate: Function) {
if (array && array.length) {
var result;
var objResult;
for (var i = 0; i < array.length; i++) {
if (i === 0) {
result = predicate(array[0]);
objResult = array[0];
} else if (result < array[i]) {
result = (array[i]);
objResult = array[i];
}
}
return objResult;
}
return undefined;
}
/**
* 返回数组总符合条件的最小值
* @param {Array} array 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数
* @returns {Object} 返回最小值
*/
public static minBy(array: any[], predicate: Function) {
if (array && array.length) {
let result;
let objResult;
for (var i = 0; i < array.length; i++) {
if (i === 0) {
result = predicate(array[0]);
objResult = array[0];
} else if (result > array[i]) {
result = predicate(array[i]);
objResult = array[i];
}
}
return objResult;
}
return undefined;
}
/**
* 返回复合迭代函数的总和
* @param {Array|Object} collection 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数
* @returns {Object} 返回总和
*/
public static sumBy(collection: [] | {}, predicate: Function) {
let sum: number = 0;
for (let key in collection) {
//@ts-ignore
sum += predicate(collection[key]);
}
return sum;
}
/**
* 返回复合迭代函数的次数
* @param {Array|Object} collection 一个用来迭代的集合.
* @param {Function} predicate 一个迭代函数用来转换key
* @returns {Object} 返回一个组成集合对象
*/
public static countBy(collection: [] | {}, predicate: Function) {
let objRet: {[key: string]: number} = {};
for (let key in collection) {
let value: any = predicate(key);
if (objRet.hasOwnProperty(value)) {
objRet[value] += 1;
} else {
objRet[value] = 1;
}
}
return objRet;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a40a4a46-47a9-42aa-8d1c-a11d56e24025",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,247 @@
import { _decorator, Component, log } from "cc";
import { Constant } from "./constant";
import { StorageManager } from "./storageManager";
import { Util } from "./util";
const { ccclass, property } = _decorator;
@ccclass("PlayerData")
export class PlayerData extends Component {
static _instance: PlayerData;
public serverTime: number = 0;
public localTime: number = 0;
public static get instance () {
if (this._instance) {
return this._instance;
}
this._instance = new PlayerData();
return this._instance;
}
private _userId: string = '';
private _playerInfo: any = null;
private _history: any = null;
private _settings: any = null;
private _isNewBee: boolean = false; //默认非新手
private _dataVersion: string = '';
public get userId () {
return this._userId;
}
public set userId (v: string) {
this._userId = v;
}
public get settings () {
return this._settings;
}
public set settings (v: any) {
this._settings = v;
}
public get playerInfo () {
return this._playerInfo;
}
public get history () {
return this._history;
}
public get isNewBee () {
return this._isNewBee;
}
public set isNewBee (v: boolean) {
this._isNewBee = v;
}
/**
* 加上用户数据
*/
public loadGlobalCache() {
let userId: string = StorageManager.instance.getUserId();
if (userId) {
this._userId = userId;
}
}
public isInit:boolean = false;
/**
* 加载本地存储数据
*/
public loadFromCache() {
this.loadGlobalCache();
if (!this.userId) {
this.generateRandomAccount();
}
//读取玩家基础数据
this._playerInfo = this._loadDataByKey(Constant.LOCAL_CACHE.PLAYER);
this._history = this._loadDataByKey(Constant.LOCAL_CACHE.HISTORY);
this._settings = this._loadDataByKey(Constant.LOCAL_CACHE.SETTINGS);
}
/**
* 获取本地存储数据
* @param {string}keyName
* @returns
*/
private _loadDataByKey (keyName: any) {
let ret = {};
let str = StorageManager.instance.getConfigData(keyName);
if (str) {
try {
ret = JSON.parse(str);
} catch (e) {
ret = {};
}
}
return ret;
}
/**
* 创建角色数据
* @param loginData
*/
public createPlayerInfo(loginData?:any) {
this._playerInfo = {};
if (loginData) {
for (let key in loginData) {
this._playerInfo[key] = loginData[key];
}
}
this.savePlayerInfoToLocalCache();
}
/**
* 生成随机账户
* @returns
*/
public generateRandomAccount () {
this.userId = new Date().getTime() + "_" + Math.floor(Math.random() * 1000);
StorageManager.instance.setUserId(this._userId);
}
/**
* 存用户数据
* @param userId
*/
public saveAccount(userId: any) {
this._userId = userId;
StorageManager.instance.setUserId(userId);
}
/**
* 保存玩家数据
*/
public savePlayerInfoToLocalCache() {
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.PLAYER, JSON.stringify(this._playerInfo));
}
/**
* 保存玩家设置相关信息
*/
public saveSettingsToLocalCache () {
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.SETTINGS, JSON.stringify(this._settings));
StorageManager.instance.save();
}
/**
* 当数据同步完毕,即被覆盖的情况下,需要将数据写入到本地缓存,以免数据丢失
*/
public saveAll() {
StorageManager.instance.setConfigDataWithoutSave(Constant.LOCAL_CACHE.PLAYER, JSON.stringify(this._playerInfo));
StorageManager.instance.setConfigDataWithoutSave(Constant.LOCAL_CACHE.HISTORY, JSON.stringify(this._history));
StorageManager.instance.setConfigDataWithoutSave(Constant.LOCAL_CACHE.SETTINGS, JSON.stringify(this._settings));
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.DATA_VERSION, this._dataVersion);
}
/**
* 更新用户信息
* 例如钻石、金币、道具
* @param {String} key
* @param {Number} value
*/
public updatePlayerInfo(key:string, value: any) {
this._playerInfo[key] = value;
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.PLAYER, JSON.stringify(this._playerInfo));
}
/**
* 获取玩家杂项值
* @param {string} key
*/
public getSetting (key: string) {
if (!this._settings) {
return null;
}
if (!this._settings.hasOwnProperty(key)) {
return null;
}
return this._settings[key];
}
/**
* 设置玩家杂项值
* @param {string} key
* @param {*} value
*/
public setSetting (key: string, value: any) {
if (!this._settings) {
this._settings = {};
}
this._settings[key] = value;
this.saveSettingsToLocalCache();
}
/**
* 清除用户信息
*/
public clear () {
this._playerInfo = {};
this._settings = {};
this.saveAll();
}
// 触摸参数
private _easyTouchInfo: object = {};
/**
* 更新用户信息
* 例如钻石、金币、道具
* @param {String} key
* @param {Number} value
*/
public updateEasyTouchInfo (key: string, value: number): void {
this._easyTouchInfo[key] = value;
}
/**
* 触控
*
* @param {String} key
* @param {Number} value
*/
public getEasyTouchInfo (key: string) {
if (!this._easyTouchInfo.hasOwnProperty(key)) {
this._easyTouchInfo[key] = 0;
}
return this._easyTouchInfo[key];
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e5927076-94ef-42ea-8e5e-2e0d8d99c281",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,103 @@
import { _decorator, Prefab, Node, instantiate, NodePool } from "cc";
const { ccclass, property } = _decorator;
@ccclass("PoolManager")
export class PoolManager {
private _dictPool: any = {}
private _dictPrefab: any = {}
static _instance: PoolManager;
static get instance() {
if (this._instance) {
return this._instance;
}
this._instance = new PoolManager();
return this._instance;
}
/**
* 根据预设从对象池中获取对应节点
*/
public getNode(prefab: Prefab, parent: Node) {
let name = prefab.name;
//@ts-ignore
if (!prefab.position) {
//@ts-ignore
name = prefab.data.name;
}
this._dictPrefab[name] = prefab;
let node: Node = null!;
if (this._dictPool.hasOwnProperty(name)) {
//已有对应的对象池
let pool = this._dictPool[name];
if (pool.size() > 0) {
node = pool.get();
} else {
node = instantiate(prefab);
}
} else {
//没有对应对象池,创建他!
let pool = new NodePool();
this._dictPool[name] = pool;
node = instantiate(prefab);
}
node.parent = parent;
node.active = true;
return node;
}
/**
* 将对应节点放回对象池中
*/
public putNode(node: Node) {
if (!node) {
return;
}
let name = node.name;
let pool = null;
if (this._dictPool.hasOwnProperty(name)) {
//已有对应的对象池
pool = this._dictPool[name];
} else {
//没有对应对象池,创建他!
pool = new NodePool();
this._dictPool[name] = pool;
}
pool.put(node);
}
/**
* 根据名称,清除对应对象池
*/
public clearPool(name: string) {
if (this._dictPool.hasOwnProperty(name)) {
let pool = this._dictPool[name];
pool.clear();
}
}
/**
* 预生成对象池
* @param prefab
* @param nodeNum
* 使用——PoolManager.instance.prePool(prefab, 40);
*/
public prePool(prefab: Prefab, nodeNum: number) {
const name = prefab.name;
let pool = new NodePool();
this._dictPool[name] = pool;
for (let i = 0; i < nodeNum; i++) {
const node = instantiate(prefab);
pool.put(node);
}
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e4ab64f9-ff55-42a8-afd5-9fe51c00334c",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,302 @@
import { _decorator, Prefab, Node, SpriteComponent, SpriteFrame, ImageAsset, resources, error, Texture2D, instantiate, isValid, find, TextAsset, JsonAsset, assetManager } from "cc";
const { ccclass } = _decorator;
@ccclass("ResourceUtil")
export class ResourceUtil {
/**
* 加载资源
* @param url 资源路径
* @param type 资源类型
* @param cb 回调
* @method loadRes
*/
public static loadRes (url: string, type: any, cb: Function = ()=>{}) {
resources.load(url, (err: any, res: any)=>{
if (err) {
error(err.message || err);
cb(err, res);
return;
}
cb && cb(null, res);
})
}
/**
* 加载资源
* @param url 资源路径
* @param type 资源类型
* @method loadRes
*/
public static loadResType (url: string, type: any) {
return new Promise((resolve, reject) => {
resources.load(url, type, (err: any, res: any) => {
if (err) {
error(err.message || err);
reject && reject(err)
return;
}
resolve && resolve(res);
})
})
}
/**
* 获取特效prefab
* @param modulePath 路径
* @returns
*/
public static loadEffectRes (modulePath: string) {
return new Promise((resolve, reject)=>{
this.loadRes(`prefab/effect/${modulePath}`, Prefab, (err: any, prefab: Prefab)=>{
if (err) {
console.error('effect load failed', modulePath);
reject && reject();
return;
}
resolve && resolve(prefab);
})
})
}
/**
* 获取模型数据
* @param modulePath 模型路径
* @returns
*/
public static loadModelRes (modulePath: string) {
return new Promise((resolve, reject)=>{
this.loadRes(`prefab/model/${modulePath}`, Prefab, (err: any, prefab: Prefab)=>{
if (err) {
console.error("model load failed", modulePath);
reject && reject();
return;
}
resolve && resolve(prefab);
})
})
}
/**
* 获取多模型数据
* @param path 资源路径
* @param arrName 资源名称
* @param progressCb 过程回调函数
* @param completeCb 完成回调函数
*/
public static loadModelResArr (path: string ,arrName: Array<string>, progressCb: any, completeCb: any) {
let arrUrls = arrName.map((item)=>{
return `${path}/${item}`;
})
resources.load(arrUrls, Prefab, progressCb, completeCb);
}
/**
* 获取贴图资源
* @param path 贴图路径
* @returns
*/
public static loadSpriteFrameRes(path: string) {
return new Promise((resolve, reject)=>{
this.loadRes(path, SpriteFrame, (err: any, img: ImageAsset)=>{
if (err) {
console.error('spriteFrame load failed!', path, err);
reject && reject();
return;
}
let texture = new Texture2D();
texture.image = img;
let sf = new SpriteFrame();
sf.texture = texture;
resolve && resolve(sf);
})
})
}
/**
* 获取贴图资源
* @param path 贴图路径
* @returns
*/
public static loadSpriteFrameURL(url: string, sprite: SpriteComponent) {
assetManager.loadRemote(url, (err: any, img: ImageAsset)=>{
if (err) {
console.error('spriteFrame load failed!', url, err);
return;
}
let texture = new Texture2D();
texture.image = img;
let sf = new SpriteFrame();
sf.texture = texture;
sprite.spriteFrame = sf;
})
}
/**
* 获取关卡数据
* @param level 关卡
* @param cb 回调函数
*/
public static getMap (level: number, cb: Function) {
let levelStr: string = 'map';
//前面补0
if (level >= 100) {
levelStr += level;
} else if (level >= 10) {
levelStr += '0' + level;
} else {
levelStr += '00' + level;
}
this.loadRes(`map/config/${levelStr}`, null, (err: {}, txtAsset: any)=>{
if (err) {
cb(err, txtAsset);
return;
}
let content: string = '';
if (txtAsset._file) {
//@ts-ignore
if (window['LZString']) {
//@ts-ignore
content = window['LZString'].decompressFromEncodedURIComponent(txtAsset._file);
}
var objJson = JSON.parse(content);
cb(null, objJson);
} else if (txtAsset.text) {
//@ts-ignore
if (window['LZString']) {
//@ts-ignore
content = window['LZString'].decompressFromEncodedURIComponent(txtAsset.text);
}
var objJson = JSON.parse(content);
cb(null, objJson);
} else if (txtAsset.json) {
cb(null, txtAsset.json);
} else {
cb('failed');
}
});
}
/**
* 获取关卡数据
* @param type 关卡类型
* @param arrName 资源名称
* @param progressCb 过程回调函数
* @param completeCb 完成回调函数
*/
public static getMapObj(type: string, arrName: Array<string>, progressCb?:any, completeCb?:any) {
let arrUrls: string[] = [];
for (let idx = 0; idx < arrName.length; idx++) {
arrUrls.push(`map/${type}/${arrName[idx]}`)
}
resources.load(arrUrls, Prefab, progressCb, completeCb);
}
/**
* 获取UI prefab
* @param prefabPath prefab路径
* @param cb 回调函数
*/
public static getUIPrefabRes (prefabPath: string, cb?: Function) {
this.loadRes("prefab/ui/" + prefabPath, Prefab, cb);
}
/**
* 创建ui界面
* @param path ui路径
* @param cb 回调函数
* @param parent 父节点
*/
public static createUI (path: string, cb?: Function, isTip?:boolean) {
this.getUIPrefabRes(path, function (err: {}, prefab: Prefab) {
if (err) return;
let node: Node = instantiate(prefab);
node.setPosition(0, 0, 0);
var parent:Node = null;
if(isTip){
parent = find("Canvas/ui/tip") as Node;
}else{
parent = find("Canvas/ui/dislog") as Node;
}
parent.addChild(node);
cb && cb(null, node);
});
}
/**
* 获取json数据
* @param fileName 文件名
* @param cb 回调函数
*/
public static getJsonData (fileName: string, cb: Function) {
this.loadRes("datas/" + fileName, null, function (err: any, content: JsonAsset) {
if (err) {
error(err.message || err);
return;
}
if (content.json) {
cb(err, content.json);
} else {
cb('failed!!!');
}
});
}
/**
* 获取文本数据
* @param fileName 文件名
* @param cb 回调函数
*/
public static getTextData (fileName:string, cb: Function) {
this.loadRes("datas/" + fileName, null, function (err: any, content: TextAsset) {
if (err) {
error(err.message || err);
return;
}
let text: string = content.text;
cb(err, text);
});
}
/**
* 设置精灵贴图
* @param path 资源路径
* @param sprite 精灵
* @param cb 回调函数
*/
public static setSpriteFrame (path: string, sprite: SpriteComponent, cb: Function) {
this.loadRes(path + '/spriteFrame', SpriteFrame, (err: any, spriteFrame: SpriteFrame)=> {
if (err) {
console.error('set sprite frame failed! err:', path, err);
cb(err);
return;
}
if (sprite && isValid(sprite)) {
sprite.spriteFrame = spriteFrame;
cb(null);
}
});
}
public static getEffectPrefab (effectName: string, cb: Function) {
this.loadRes(`prefab/effect/${effectName}/${effectName}`, Prefab, cb);
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "7844ed5b-3b06-4afb-b24c-62310d414e6f",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,213 @@
import { _decorator, sys, log, native } from "cc";
import { Util } from './util';
const { ccclass, property } = _decorator;
@ccclass("StorageManager")
export class StorageManager {
private static _instance: StorageManager;
public static get instance () {
if (this._instance) {
return this._instance;
}
this._instance = new StorageManager();
this._instance.start();
return this._instance;
}
private _jsonData: {[key: string]: any} = {};
private _path: any = null;
private KEY_CONFIG: string = 'template';
private _markSave: boolean = false;
private _saveTimer: number = -1;
start () {
this._jsonData = {
"userId": "",
};
this._path = this._getConfigPath();
var content;
if (sys.isNative) {
var valueObject = native.fileUtils.getValueMapFromFile(this._path);
content = valueObject[this.KEY_CONFIG];
} else {
content = sys.localStorage.getItem(this.KEY_CONFIG);
}
log("content", content);
if (content && content.length) {
if (content.startsWith('@')) {
content = content.substring(1);
content = Util.decrypt(content);
}
try {
//初始化操作
var jsonData = JSON.parse(content);
log("content1", jsonData);
this._jsonData = jsonData;
}catch (excepaiton) {
}
}
}
/**
* 存储配置文件,不保存到本地
* @param {string}key 关键字
* @param {any}value 存储值
*/
setConfigDataWithoutSave (key: string, value: any) {
let account: string = this._jsonData.userId;
if (this._jsonData[account]) {
this._jsonData[account][key] = value;
} else {
console.error("no account can not save");
}
this.save();
}
/**
* 存储配置文件,保存到本地
* @param {string}key 关键字
* @param {any}value 存储值
*/
setConfigData (key: string, value: any) {
this.setConfigDataWithoutSave(key, value);
this._markSave = true; //标记为需要存储,避免一直在写入,而是每隔一段时间进行写入
}
/**
* 根据关键字获取数值
* @param {string} key 关键字
* @returns
*/
getConfigData (key: string) {
let account: string = this._jsonData.userId;
if (this._jsonData[account]) {
var value = this._jsonData[account][key];
return value ? value : "";
} else {
log("no account can not load");
return "";
}
}
/**
* 设置全局数据
* @param {string} key 关键字
* @param {any}value 存储值
* @returns
*/
public setGlobalData (key:string, value: any) {
this._jsonData[key] = value;
this.save();
}
/**
* 获取全局数据
* @param {string} key 关键字
* @returns
*/
public getGlobalData (key:string) {
return this._jsonData[key];
}
/**
* 设置用户唯一标示符
* @param {string} userId 用户唯一标示符
* @param {any}value 存储值
* @returns
*/
public setUserId (userId:string) {
this._jsonData.userId = userId;
if (!this._jsonData[userId]) {
this._jsonData[userId] = {};
}
this.save();
}
/**
* 获取用户唯一标示符
* @returns {string}
*/
public getUserId () {
return this._jsonData.userId;
}
/**
* 定时存储
* @returns
*/
public scheduleSave () {
if (!this._markSave) {
return;
}
this.save();
}
/**
* 标记为已修改
*/
public markModified () {
this._markSave = true;
}
/**
* 保存配置文件
* @returns
*/
public save () {
// 写入文件
var str = JSON.stringify(this._jsonData);
let zipStr = '@' + Util.encrypt(str);
this._markSave = false;
if (!sys.isNative) {
var ls = sys.localStorage;
ls.setItem(this.KEY_CONFIG, zipStr);
return;
}
var valueObj: any = {};
valueObj[this.KEY_CONFIG] = zipStr;
native.fileUtils.writeValueMapToFile(valueObj, this._path);
}
/**
* 获取配置文件路径
* @returns 获取配置文件路径
*/
private _getConfigPath () {
let platform: any= sys.platform;
let path: string = "";
if (platform === sys.OS.WINDOWS) {
path = "src/conf";
} else if (platform === sys.OS.LINUX) {
path = "./conf";
} else {
if (sys.isNative) {
path = native.fileUtils.getWritablePath();
path = path + "conf";
} else {
path = "src/conf";
}
}
return path;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "56893e3c-6d22-46c9-8a35-d9619ae9e789",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,287 @@
import { _decorator, Node, find, isValid} from "cc";
import { ResourceUtil } from "./resourceUtil";
import { PoolManager } from "./poolManager";
import { Tips } from "../ui/common/tips";
import { Constant } from "./constant";
import { TransitionPanel } from "../ui/fight/transition_panel";
import { TransitionBgPanel } from "../ui/fight/transition_bg_panel";
const { ccclass, property } = _decorator;
const SHOW_STR_INTERVAL_TIME = 800;
@ccclass("UIManager")
export class UIManager {
private _dictSharedPanel: any = {}
private _dictLoading: any = {}
private _arrPopupDialog: any = []
private _showTipsTime: number = 0
private static _instance: UIManager;
public static get instance() {
if (this._instance) {
return this._instance;
}
this._instance = new UIManager();
return this._instance;
}
/**
* 检查当前界面是否正在展示
* @param panelPath
*/
public isDialogVisible(panelPath: string) {
if (!this._dictSharedPanel.hasOwnProperty(panelPath)) {
return false;
}
let panel = this._dictSharedPanel[panelPath];
return isValid(panel) && panel.active && panel.parent;
}
/**
* 显示单例界面
* @param {String} panelPath
* @param {Array} args
* @param {Function} cb 回调函数,创建完毕后回调
*/
public showDialog(panelPath: string, args?: any, cb?: Function, isTip?:boolean) {
if (this._dictLoading[panelPath]) {
return;
}
let idxSplit = panelPath.lastIndexOf('/');
let scriptName = panelPath.slice(idxSplit + 1);
if (!args) {
args = [];
}
if (this._dictSharedPanel.hasOwnProperty(panelPath)) {
let panel = this._dictSharedPanel[panelPath];
if (isValid(panel)) {
var parent = null;
if(isTip){
parent = find("Canvas/ui/tip");
}else{
parent = find("Canvas/ui/dislog");
}
panel.parent = parent;
panel.active = true;
let script = panel.getComponent(scriptName);
let script2 = panel.getComponent(scriptName.charAt(0).toUpperCase() + scriptName.slice(1));
if (script && script.show) {
script.show.apply(script, args);
cb && cb(script);
} else if (script2 && script2.show) {
script2.show.apply(script2, args);
cb && cb(script2);
} else {
throw `查找不到脚本文件${scriptName}`;
}
return;
}
}
this._dictLoading[panelPath] = true;
ResourceUtil.createUI(panelPath, (err: any, node: any) => {
//判断是否有可能在显示前已经被关掉了?
let isCloseBeforeShow = false;
if (!this._dictLoading[panelPath]) {
//已经被关掉
isCloseBeforeShow = true;
}
this._dictLoading[panelPath] = false;
if (err) {
console.error(err);
return;
}
this._dictSharedPanel[panelPath] = node;
let script: any = node.getComponent(scriptName);
let script2: any = node.getComponent(scriptName.charAt(0).toUpperCase() + scriptName.slice(1));
if (script && script.show) {
script.show.apply(script, args);
cb && cb(script);
} else if (script2 && script2.show) {
script2.show.apply(script2, args);
cb && cb(script2);
} else {
throw `查找不到脚本文件${scriptName}`;
}
if (isCloseBeforeShow) {
//如果在显示前又被关闭,则直接触发关闭掉
this.hideDialog(panelPath);
}
}, isTip);
}
/**
* 隐藏单例界面
* @param {String} panelPath
* @param {fn} callback
*/
public hideDialog(panelPath: string, callback?: Function) {
if (this._dictSharedPanel.hasOwnProperty(panelPath)) {
let panel = this._dictSharedPanel[panelPath];
if (panel && isValid(panel)) {
let ani = panel.getComponent('animationUI');
if (ani) {
ani.close(() => {
panel.parent = null;
if (callback && typeof callback === 'function') {
callback();
}
});
} else {
panel.parent = null;
if (callback && typeof callback === 'function') {
callback();
}
}
} else if (callback && typeof callback === 'function') {
callback();
}
}
this._dictLoading[panelPath] = false;
}
/**
* 将弹窗加入弹出窗队列
* @param {string} panelPath
* @param {string} scriptName
* @param {*} param
*/
public pushToPopupSeq(panelPath: string, scriptName: string, param: any) {
let popupDialog = {
panelPath: panelPath,
scriptName: scriptName,
param: param,
isShow: false
};
this._arrPopupDialog.push(popupDialog);
this._checkPopupSeq();
}
/**
* 将弹窗加入弹出窗队列
* @param {number} index
* @param {string} panelPath
* @param {string} scriptName
* @param {*} param
*/
public insertToPopupSeq(index: number, panelPath: string, param: any) {
let popupDialog = {
panelPath: panelPath,
param: param,
isShow: false
};
this._arrPopupDialog.splice(index, 0, popupDialog);
}
/**
* 将弹窗从弹出窗队列中移除
* @param {string} panelPath
*/
public shiftFromPopupSeq(panelPath: string) {
this.hideDialog(panelPath, () => {
if (this._arrPopupDialog[0] && this._arrPopupDialog[0].panelPath === panelPath) {
this._arrPopupDialog.shift();
this._checkPopupSeq();
}
})
}
/**
* 检查当前是否需要弹窗
*/
private _checkPopupSeq() {
if (this._arrPopupDialog.length > 0) {
let first = this._arrPopupDialog[0];
if (!first.isShow) {
this.showDialog(first.panelPath, first.param);
this._arrPopupDialog[0].isShow = true;
}
}
}
/**
* 显示提示
* @param {String} content
* @param {Function} cb
*/
public showTips(content: string | number, callback?: Function) {
let str = String(content);
let next = () => {
this._showTipsAni(str, callback);
}
var now = Date.now();
if (now - this._showTipsTime < SHOW_STR_INTERVAL_TIME) {
var spareTime = SHOW_STR_INTERVAL_TIME - (now - this._showTipsTime);
setTimeout(() => {
next();
}, spareTime);
this._showTipsTime = now + spareTime;
} else {
next();
this._showTipsTime = now;
}
}
/**
* 内部函数
* @param {String} content
* @param {Function} cb
*/
private _showTipsAni(content: string, callback?: Function) {
ResourceUtil.getUIPrefabRes('common/tips', function (err: any, prefab: any) {
if (err) {
return;
}
let tipsNode = PoolManager.instance.getNode(prefab, find("Canvas") as Node);
let tipScript = tipsNode.getComponent(Tips) as Tips;
tipScript.show(content, callback);
});
}
public showTransition(sceneName:string) {
ResourceUtil.getUIPrefabRes(Constant.PANEL_NAME.TRANSITION, function (err: any, prefab: any) {
if (err) {
return;
}
let transitionNode = PoolManager.instance.getNode(prefab, find('') as Node);
let transitionScript = transitionNode.getComponent(TransitionPanel) as TransitionPanel;
transitionScript.show(sceneName);
});
}
public showTransitionBg(callback:Function) {
ResourceUtil.getUIPrefabRes(Constant.PANEL_NAME.TRANSITION_BG, function (err: any, prefab: any) {
if (err) {
return;
}
let transitionNode = PoolManager.instance.getNode(prefab, find('Canvas/ui/tip') as Node);
let transitionScript = transitionNode.getComponent(TransitionBgPanel) as TransitionBgPanel;
transitionScript.show(callback);
});
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "f9384158-0e9e-46aa-85be-0adac295add4",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "4c8ec73a-d4c0-402c-8394-d4ae97d04575",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,902 @@
import { _decorator, Component, JsonAsset, Node, randomRange } from "cc";
import { ResourceUtil } from "./resourceUtil";
import { PlayerData } from "./playerData";
const { ccclass, property } = _decorator;
@ccclass("Util")
export class Util {
/**
* !#zh 拷贝object。
*/
/**
* 深度拷贝
* @param {any} sObj 拷贝的对象
* @returns
*/
public static clone(sObj: any) {
if (sObj === null || typeof sObj !== "object") {
return sObj;
}
let s: { [key: string]: any } = {};
if (sObj.constructor === Array) {
s = [];
}
for (let i in sObj) {
if (sObj.hasOwnProperty(i)) {
s[i] = this.clone(sObj[i]);
}
}
return s;
}
/**
* 将object转化为数组
* @param { any} srcObj
* @returns
*/
public static objectToArray(srcObj: { [key: string]: any }) {
let resultArr: any[] = [];
// to array
for (let key in srcObj) {
if (!srcObj.hasOwnProperty(key)) {
continue;
}
resultArr.push(srcObj[key]);
}
return resultArr;
}
/**
* !#zh 将数组转化为object。
*/
/**
* 将数组转化为object。
* @param { any} srcObj
* @param { string} objectKey
* @returns
*/
public static arrayToObject(srcObj: any, objectKey: string) {
let resultObj: { [key: string]: any } = {};
// to object
for (var key in srcObj) {
if (!srcObj.hasOwnProperty(key) || !srcObj[key][objectKey]) {
continue;
}
resultObj[srcObj[key][objectKey]] = srcObj[key];
}
return resultObj;
}
/**
* 根据权重,计算随机内容
* @param {arrany} weightArr
* @param {number} totalWeight 权重
* @returns
*/
public static getWeightRandIndex(weightArr: [], totalWeight: number) {
let randWeight: number = Math.floor(Math.random() * totalWeight);
let sum: number = 0;
for (var weightIndex: number = 0; weightIndex < weightArr.length; weightIndex++) {
sum += weightArr[weightIndex];
if (randWeight < sum) {
break;
}
}
return weightIndex;
}
/**
* 从n个数中获取m个随机数
* @param {Number} n 总数
* @param {Number} m 获取数
* @returns {Array} array 获取数列
*/
public static getRandomNFromM(n: number, m: number) {
let array: any[] = [];
let intRd: number = 0;
let count: number = 0;
while (count < m) {
if (count >= n + 1) {
break;
}
intRd = this.getRandomInt(0, n);
var flag = 0;
for (var i = 0; i < count; i++) {
if (array[i] === intRd) {
flag = 1;
break;
}
}
if (flag === 0) {
array[count] = intRd;
count++;
}
}
return array;
}
/**
* 获取随机整数
* @param {Number} min 最小值
* @param {Number} max 最大值
* @returns
*/
public static getRandomInt(min: number, max: number) {
let r: number = Math.random();
let rr: number = r * (max - min + 1) + min;
return Math.floor(rr);
}
/**
* 获取字符串长度
* @param {string} render
* @returns
*/
public static getStringLength(render: string) {
let strArr: string = render;
let len: number = 0;
for (let i: number = 0, n = strArr.length; i < n; i++) {
let val: number = strArr.charCodeAt(i);
if (val <= 255) {
len = len + 1;
} else {
len = len + 2;
}
}
return Math.ceil(len / 2);
}
/**
* 判断传入的参数是否为空的Object。数组或undefined会返回false
* @param obj
*/
public static isEmptyObject(obj: any) {
let result: boolean = true;
if (obj && obj.constructor === Object) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
result = false;
break;
}
}
} else {
result = false;
}
return result;
}
/**
* 判断是否是新的一天
* @param {Object|Number} dateValue 时间对象 todo MessageCenter 与 pve 相关的时间存储建议改为 Date 类型
* @returns {boolean}
*/
public static isNewDay(dateValue: any) {
// todo是否需要判断时区
var oldDate: any = new Date(dateValue);
var curDate: any = new Date();
var oldYear = oldDate.getYear();
var oldMonth = oldDate.getMonth();
var oldDay = oldDate.getDate();
var curYear = curDate.getYear();
var curMonth = curDate.getMonth();
var curDay = curDate.getDate();
if (curYear > oldYear) {
return true;
} else {
if (curMonth > oldMonth) {
return true;
} else {
if (curDay > oldDay) {
return true;
}
}
}
return false;
}
/**
* 获取对象属性数量
* @param {object}o 对象
* @returns
*/
public static getPropertyCount(o: Object) {
var n, count = 0;
for (n in o) {
if (o.hasOwnProperty(n)) {
count++;
}
}
return count;
}
/**
* 返回一个差异化数组将array中diff里的值去掉
* @param array
* @param diff
*/
public static difference(array: [], diff: any) {
let result: any[] = [];
if (array.constructor !== Array || diff.constructor !== Array) {
return result;
}
let length = array.length;
for (let i: number = 0; i < length; i++) {
if (diff.indexOf(array[i]) === -1) {
result.push(array[i]);
}
}
return result;
}
public static _stringToArray(string: string) {
// 用于判断emoji的正则们
var rsAstralRange = '\\ud800-\\udfff';
var rsZWJ = '\\u200d';
var rsVarRange = '\\ufe0e\\ufe0f';
var rsComboMarksRange = '\\u0300-\\u036f';
var reComboHalfMarksRange = '\\ufe20-\\ufe2f';
var rsComboSymbolsRange = '\\u20d0-\\u20ff';
var rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;
var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
var rsFitz = '\\ud83c[\\udffb-\\udfff]';
var rsOptVar = '[' + rsVarRange + ']?';
var rsCombo = '[' + rsComboRange + ']';
var rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')';
var reOptMod = rsModifier + '?';
var rsAstral = '[' + rsAstralRange + ']';
var rsNonAstral = '[^' + rsAstralRange + ']';
var rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}';
var rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]';
var rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*';
var rsSeq = rsOptVar + reOptMod + rsOptJoin;
var rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
var hasUnicode = function (val: string) {
return reHasUnicode.test(val);
};
var unicodeToArray = function (val: string) {
return val.match(reUnicode) || [];
};
var asciiToArray = function (val: string) {
return val.split('');
};
return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string);
}
// 模拟传msg的uuid
public static simulationUUID() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
public static trim(str: string) {
return str.replace(/(^\s*)|(\s*$)/g, "");
}
/**
* 判断当前时间是否在有效时间内
* @param {String|Number} start 起始时间。带有时区信息
* @param {String|Number} end 结束时间。带有时区信息
*/
public static isNowValid(start: string| number, end: string| number) {
var startTime = new Date(start);
var endTime = new Date(end);
var result = false;
if (startTime.getDate() + '' !== 'NaN' && endTime.getDate() + '' !== 'NaN') {
var curDate = new Date();
result = curDate < endTime && curDate > startTime;
}
return result;
}
/**
* 返回相隔天数
* @param start
* @param end
* @returns
*/
public static getDeltaDays(start: any, end: any) {
start = new Date(start);
end = new Date(end);
let startYear: number = start.getFullYear();
let startMonth: number = start.getMonth() + 1;
let startDate: number = start.getDate();
let endYear: number = end.getFullYear();
let endMonth: number = end.getMonth() + 1;
let endDate: number = end.getDate();
start = new Date(startYear + '/' + startMonth + '/' + startDate + ' GMT+0800').getTime();
end = new Date(endYear + '/' + endMonth + '/' + endDate + ' GMT+0800').getTime();
let deltaTime = end - start;
return Math.floor(deltaTime / (24 * 60 * 60 * 1000));
}
/**
* 获取数组最小值
* @param array 数组
* @returns
*/
public static getMin(array: number[]) {
let result: number = null!;
if (array.constructor === Array) {
let length = array.length;
for (let i = 0; i < length; i++) {
if (i === 0) {
result = Number(array[0]);
} else {
result = result > Number(array[i]) ? Number(array[i]) : result;
}
}
}
return result;
}
/**
* 格式化两位小数点
* @param time
* @returns
*/
public static formatTwoDigits(time: number) {
//@ts-ignore
return (Array(2).join(0) + time).slice(-2);
}
/**
* 根据格式返回时间
* @param date 时间
* @param fmt 格式
* @returns
*/
public static formatDate(date: Date, fmt: string) {
let o: any = {
"M+": date.getMonth() + 1, //月份
"d+": date.getDate(), //日
"h+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (let k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
/**
* 获取格式化后的日期(不含小时分秒)
*/
public static getDay() {
let date: Date = new Date();
return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
}
/**
* 格式化名字XXX...
* @param {string} name 需要格式化的字符串
* @param {number}limit
* @returns {string} 返回格式化后的字符串XXX...
*/
public static formatName(name: string, limit: number) {
limit = limit || 6;
var nameArray = this._stringToArray(name);
var str = '';
var length = nameArray.length;
if (length > limit) {
for (var i = 0; i < limit; i++) {
str += nameArray[i];
}
str += '...';
} else {
str = name;
}
return str;
}
/**
* 格式化钱数超过10000 转换位 10K 10000K 转换为 10M
* @param {number}money 需要被格式化的数值
* @returns {string}返回 被格式化的数值
*/
public static formatMoney(money: number) {
let arrUnit: string[] = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'B', 'N', 'D'];
let strValue: string = '';
for (let idx: number = 0; idx < arrUnit.length; idx++) {
if (money >= 10000) {
money /= 1000;
} else {
strValue = Math.floor(money) + arrUnit[idx];
break;
}
}
if (strValue === '') {
strValue = Math.floor(money) + 'U'; //超过最大值就加个U
}
return strValue;
}
/**
* 格式化数值
* @param {number}value 需要被格式化的数值
* @returns {string}返回 被格式化的数值
*/
public static formatValue(value: number) {
let arrUnit: string[] = [];
let strValue: string = '';
for (let i = 0; i < 26; i++) {
arrUnit.push(String.fromCharCode(97 + i));
}
for (let idx: number = 0; idx < arrUnit.length; idx++) {
if (value >= 10000) {
value /= 1000;
} else {
strValue = Math.floor(value) + arrUnit[idx];
break;
}
}
return strValue;
}
/**
* 根据剩余秒数格式化剩余时间 返回 HH:MM:SS
* @param {Number} leftSec
*/
public static formatTimeForSecond(leftSec: number, withoutHours: boolean = false, withoutMinutes: boolean = false, withoutSeconds: boolean = false) {
let timeStr: string = '';
let sec: number = leftSec % 60;
let leftMin: number = Math.floor(leftSec / 60);
leftMin = leftMin < 0 ? 0 : leftMin;
let hour: number = Math.floor(leftMin / 60);
let min: number = leftMin % 60;
if (!withoutHours) {
if (hour > 0) {
timeStr += hour > 9 ? hour.toString() : '0' + hour;
timeStr += ':';
} else {
timeStr += '00:';
}
}
if (!withoutMinutes) {
timeStr += min > 9 ? min.toString() : '0' + min;
timeStr += ':';
}
if (!withoutSeconds) {
// timeStr += ':';
timeStr += sec > 9 ? sec.toString() : '0' + sec;
}
return timeStr;
}
/**
* 根据剩余毫秒数格式化剩余时间 返回 HH:MM:SS
*
* @param {Number} ms
*/
public static formatTimeForMillisecond(ms: number): Object {
let second: number = Math.floor(ms / 1000 % 60);
let minute: number = Math.floor(ms / 1000 / 60 % 60);
let hour: number = Math.floor(ms / 1000 / 60 / 60);
return { 'hour': hour, 'minute': minute, 'second': second };
}
/**
* 将数组内容进行随机排列
* @param {Array}arr 需要被随机的数组
* @returns
*/
public static rand(arr: []): [] {
let arrClone = this.clone(arr);
// 首先从最大的数开始遍历,之后递减
for (let i: number = arrClone.length - 1; i >= 0; i--) {
// 随机索引值randomIndex是从0-arrClone.length中随机抽取的
const randomIndex: number = Math.floor(Math.random() * (i + 1));
// 下面三句相当于把从数组中随机抽取到的值与当前遍历的值互换位置
const itemIndex: number = arrClone[randomIndex];
arrClone[randomIndex] = arrClone[i];
arrClone[i] = itemIndex;
}
// 每一次的遍历都相当于把从数组中随机抽取不重复的一个元素放到数组的最后面索引顺序为len-1,len-2,len-3......0
return arrClone;
}
/**
* 获得开始和结束两者之间相隔分钟数
*
* @static
* @param {number} start
* @param {number} end
* @memberof Util
*/
public static getOffsetMimutes(start: number, end: number) {
let offSetTime: number = end - start;
let minute: number = Math.floor((offSetTime % (1000 * 60 * 60)) / (1000 * 60));
return minute;
}
/**
* 返回指定小数位的数值
* @param {number} num
* @param {number} idx
*/
public static formatNumToFixed(num: number, idx: number = 0) {
return Number(num.toFixed(idx));
}
/**
* 用于数值到达另外一个目标数值之间进行平滑过渡运动效果
* @param {number} targetValue 目标数值
* @param {number} curValue 当前数值
* @param {number} ratio 过渡比率
* @returns
*/
public static lerp(targetValue: number, curValue: number, ratio: number = 0.25) {
let v: number = curValue;
if (targetValue > curValue) {
v = curValue + (targetValue - curValue) * ratio;
} else if (targetValue < curValue) {
v = curValue - (curValue - targetValue) * ratio;
}
return v;
}
/**
* 数据解密
* @param {String} str
*/
public static decrypt(b64Data: string) {
let n: number = 6;
if (b64Data.length % 2 === 0) {
n = 7;
}
let decodeData = '';
for (var idx = 0; idx < b64Data.length - n; idx += 2) {
decodeData += b64Data[idx + 1];
decodeData += b64Data[idx];
}
decodeData += b64Data.slice(b64Data.length - n + 1);
decodeData = this._base64Decode(decodeData);
return decodeData;
}
/**
* 数据加密
* @param {String} str
*/
public static encrypt(str: string) {
let b64Data = this._base64encode(str);
let n: number = 6;
if (b64Data.length % 2 === 0) {
n = 7;
}
let encodeData: string = '';
for (let idx = 0; idx < (b64Data.length - n + 1) / 2; idx++) {
encodeData += b64Data[2 * idx + 1];
encodeData += b64Data[2 * idx];
}
encodeData += b64Data.slice(b64Data.length - n + 1);
return encodeData;
}
//public method for encoding
/**
* base64加密
* @param {string}input
* @returns
*/
private static _base64encode(input: string) {
let keyStr: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
let output: string = "", chr1: number, chr2: number, chr3: number, enc1: number, enc2: number, enc3: number, enc4: number, i: number = 0;
input = this._utf8Encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
keyStr.charAt(enc1) + keyStr.charAt(enc2) +
keyStr.charAt(enc3) + keyStr.charAt(enc4);
}
return output;
}
/**
* utf-8 加密
* @param string
* @returns
*/
private static _utf8Encode(string: string) {
string = string.replace(/\r\n/g, "\n");
let utftext: string = "";
for (let n: number = 0; n < string.length; n++) {
let c: number = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
/**
* utf-8解密
* @param utftext
* @returns
*/
private static _utf8Decode(utftext: string) {
let string = "";
let i: number = 0;
let c: number = 0;
let c1: number = 0;
let c2: number = 0;
let c3: number = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
/**
* base64解密
* @param {string}input 解密字符串
* @returns
*/
private static _base64Decode(input: string) {
let keyStr: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
let output: string = "";
let chr1: number;
let chr2: number;
let chr3: number;
let enc1: number;
let enc2: number;
let enc3: number;
let enc4: number;
let i: number = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = this._utf8Decode(output);
return output;
}
/**
* 获取当前机型性能是否为低端机
*/
public static checkIsLowPhone(): Boolean {
//@ts-ignore
if (window.wx) {
//微信性能数值参考:https://developers.weixin.qq.com/minigame/dev/guide/performance/perf-benchmarkLevel.html
let nowBenchmarkLevel: number = -1; //nowBenchmarkLevel = -1性能未知
//@ts-ignore
const sys = window.wx.getSystemInfoSync();
const isIOS = sys.system.indexOf('iOS') >= 0;
if (isIOS) {
//微信不支持IO性能等级
const model = sys.model;
// iPhone 5s 及以下 设定为超低端机
const ultraLowPhoneType = ['iPhone1,1', 'iPhone1,2', 'iPhone2,1', 'iPhone3,1', 'iPhone3,3', 'iPhone4,1', 'iPhone5,1', 'iPhone5,2', 'iPhone5,3', 'iPhone5,4', 'iPhone6,1', 'iPhone6,2'];
// iPhone 6 ~ iPhone SE 设定为超低端机
const lowPhoneType = ['iPhone6,2', 'iPhone7,1', 'iPhone7,2', 'iPhone8,1', 'iPhone8,2', 'iPhone8,4'];
// iPhone 7 ~ iPhone X 设定为中端机
const middlePhoneType = ['iPhone9,1', 'iPhone9,2', 'iPhone9,3', 'iPhone9,4', 'iPhone10,1', 'iPhone10,2', 'iPhone10,3', 'iPhone10,4', 'iPhone10,5', 'iPhone10,6'];
// iPhone XS 及以上 设定为高端机
const highPhoneType = ['iPhone11,2', 'iPhone11,4', 'iPhone11,6', 'iPhone11,8', 'iPhone12,1', 'iPhone12,3', 'iPhone12,5', 'iPhone12,8'];
for (let i = 0; i < ultraLowPhoneType.length; i++) {
if (model.indexOf(ultraLowPhoneType[i]) >= 0)
nowBenchmarkLevel = 5;
}
for (let i = 0; i < lowPhoneType.length; i++) {
if (model.indexOf(lowPhoneType[i]) >= 0)
nowBenchmarkLevel = 10;
}
for (let i = 0; i < middlePhoneType.length; i++) {
if (model.indexOf(middlePhoneType[i]) >= 0)
nowBenchmarkLevel = 20;
}
for (let i = 0; i < highPhoneType.length; i++) {
if (model.indexOf(highPhoneType[i]) >= 0)
nowBenchmarkLevel = 30;
}
} else {
nowBenchmarkLevel = sys.benchmarkLevel;
}
if (nowBenchmarkLevel < 22) { //22的具体参数可参考微信官方
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* 获取两个节点坐标在xz轴的距离
*
* @static
* @param {Node} ndA
* @param {Node} ndB
* @param {boolean} [isLocal=false] 是否为本地坐标,反之为世界坐标
* @return {*}
* @memberof util
*/
public static getTwoNodeXZLength(ndA: Node, ndB: Node, isLocal: boolean = false) {
const aX = isLocal ? ndA.position.x : ndA.worldPosition.x;
const aZ = isLocal ? ndA.position.z : ndA.worldPosition.z;
const bX = isLocal ? ndB.position.x : ndB.worldPosition.x;
const bZ = isLocal ? ndB.position.z : ndB.worldPosition.z;
return this.getTwoPosXZLength(aX, aZ, bX, bZ);
}
/**
* 获取两个坐标在xz轴的距离
*
* @static
* @param {number} aX
* @param {number} aZ
* @param {number} bX
* @param {number} bZ
* @return {*}
* @memberof util
*/
public static getTwoPosXZLength(aX: number, aZ: number, bX: number, bZ: number) {
const x = aX - bX;
const z = aZ - bZ;
return Math.sqrt(x * x + z * z);
}
public static distance (x: number, y: number, z: number) {
return Math.sqrt(x * x + y * y + z * z);
}
/**
* 生成随机名字
*
* @static
* @returns
* @memberof Util
*/
public static createRandomName () {
let name = "";
for (let j = 0; j < Math.round(Math.random() * 3) + 1; j++) {
name += String.fromCharCode(Math.round(Math.random() * 26) + 97);
name += String.fromCharCode(Math.round(Math.random() * 20901) + 19968);
//打乱name
if (Math.random() > 0.5) {
name = name.split("").reverse().join("");
}
}
return name;
}
/**
* 随机名字
*
* @param staticId
*/
public static async randomName (staticId:number) {
let names: any = await ResourceUtil.loadResType("jsons/names", JsonAsset);
var firsnames = names.json.firstnames;
var boyNames = names.json.boyNames;
var girlNames = names.json.girlNames;
let lastName: string = '';
if (staticId == 0) {
lastName = boyNames[Math.floor(randomRange(0, 1) * boyNames.length)];
} else {
lastName = girlNames[Math.floor(randomRange(0, 1) * girlNames.length)];
}
let firstName = firsnames[Math.floor(randomRange(0, 1) * firsnames.length)];
var playerName = firstName + lastName;
return playerName;
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "5123890b-1801-4188-ba33-de0c5cc31b47",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,15 @@
import { _decorator, Component, Node, BatchingUtility } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('StaticBatch')
export class StaticBatch extends Component {
@property([Node])
needBatches: Node[] = [];
start () {
this.needBatches.forEach((node)=>{
BatchingUtility.batchStaticModel(node, this.node);
})
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d5c7efbb-b2b1-4245-941f-009be3c9110a",
"files": [],
"subMetas": {},
"userData": {
"moduleId": "project:///assets/script/framework/util/staticBatch.js",
"simulateGlobals": []
}
}

12
assets/script/libs.meta Normal file
View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "bb7d5e2c-11e4-4219-9efe-b6e5ba8eabf3",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

1339
assets/script/libs/GOBE.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "75274edb-b9b0-4f0b-8c3b-ed91d7752144",
"files": [],
"subMetas": {},
"userData": {}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
{
"ver": "4.0.23",
"importer": "javascript",
"imported": true,
"uuid": "886bc5ef-680b-4c31-9df0-b7ab34423449",
"files": [
".js"
],
"subMetas": {},
"userData": {
"isPlugin": true,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": true
}
}

12
assets/script/ui.meta Normal file
View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "442e604a-ef7b-40cf-9951-e7839a9c95a8",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "86163c02-256d-4232-952f-2f9c3c03ab0a",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,29 @@
import { _decorator, Component, LabelComponent, Vec3, UITransform, Size, isValid, AnimationComponent } from 'cc';
import {PoolManager} from '../../framework/poolManager';
const { ccclass, property } = _decorator;
@ccclass('Tips')
export class Tips extends Component {
@property(LabelComponent)
lbTips: LabelComponent = null!;
targetPos: any;
show (content: string, callback?: Function) {
this.targetPos = new Vec3(0, 0, 0);
this.node.setPosition(this.targetPos);
this.lbTips.string = content;
let size: Size = this.lbTips.node.getComponent(UITransform)?.contentSize as Size;
if (!isValid(size)) {
PoolManager.instance.putNode(this.node);
return;
}
this.node.getComponent(UITransform)?.setContentSize(size.width + 100 < 240 ? 240 : size.width + 100, size.height + 30);
let animation: AnimationComponent = this.node.getComponent(AnimationComponent) as AnimationComponent;
animation.play();
animation.once(AnimationComponent.EventType.FINISHED, () => {
callback && callback();
PoolManager.instance.putNode(this.node);
})
}
}

View File

@@ -0,0 +1,11 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a91d7339-e96d-451b-8be6-e1c5dbf91132",
"files": [],
"subMetas": {},
"userData": {
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "8c8ec3c3-e63c-49f2-a4b8-0dd46b0eaa4a",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,158 @@
import { _decorator, Component, Node, CCInteger, Vec3 } from 'cc';
import { Constant } from '../../framework/constant';
import { Util } from '../../framework/util';
import { PlayerData } from '../../framework/playerData';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = easyTouch
* DateTime = Wed May 11 2022 14:12:44 GMT+0800 (中国标准时间)
* Author = yu_meng123
* FileBasename = easyTouch.ts
* FileBasenameNoExtension = easyTouch
* URL = db://assets/script/game/easyTouch.ts
* ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
*
*/
@ccclass('EasyTouch')
export class EasyTouch extends Component {
@property(Node)
centerCircleNode: Node = null!;
@property(Node)
directionNode: Node = null!;
@property(CCInteger)
bgLength: number = 0;
@property
isLeftTouch: boolean = false;
private _vec3_1: Vec3 = new Vec3();
private _lastPos: Vec3 = new Vec3();
private _vec3_Angle: Vec3 = new Vec3(0, 0, 0);
private _lastX: number = 0;
private _lastY: number = 0;
start () {
this.directionNode.active = false;
setTimeout(() => {
this._lastPos.set(this.node.position);
});
}
public startTouch (x: number, y: number) {
this.node.setPosition(new Vec3(x, y));
this.directionNode.active = false;
}
public endTouch () {
this.node.setPosition(this._lastPos);
this.directionNode.active = false;
// 左手
if (this.isLeftTouch) {
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_LEFT_X, 0);
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_LEFT_Y, 0);
}
// 右手
else {
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_RIGHT_X, 0);
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_RIGHT_Y, 0);
}
}
/**
* 移动
*
* @param x
* @param y
*/
public moveTouch (x: number, y: number) {
var dis = Math.sqrt(x * x + y * y);
if (dis > this.bgLength) {
var per: number = this.bgLength / dis;
x = per * x;
y = per * y;
this._vec3_1.set(x, y, 0);
this.centerCircleNode.setPosition(this._vec3_1);
}
else {
this._vec3_1.set(x, y, 0);
this.centerCircleNode.setPosition(this._vec3_1);
}
var z: number = Math.atan(x / y) * 180 / Math.PI;
if (y < 0) {
z -= 180;
}
this._vec3_Angle.set(0, 0, z * -1);
this.directionNode.eulerAngles = this._vec3_Angle;
this.directionNode.active = true;
// 左手
if (this.isLeftTouch) {
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_LEFT_X, x / this.bgLength);
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_LEFT_Y, y / this.bgLength);
}
// 右手
else {
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_RIGHT_X, x / this.bgLength);
PlayerData.instance.updateEasyTouchInfo(Constant.EASY_TOUCH.TOUCH_RIGHT_Y, y / this.bgLength);
}
}
/**
* 设置 上次便移的点
* @param x
* @param y
*/
public setLastXY (x: number, y: number) {
this._lastX = x;
this._lastY = y;
}
/**
* 通过数值更改位置
*
* @param x
* @param y
*/
public moveTouchByXY (x: number, y: number) {
x = Math.ceil(x * 10) * 0.1;
y = Math.ceil(y * 10) * 0.1;
this._lastX = Util.lerp(this._lastX, x, 0.1);
this._lastY = Util.lerp(this._lastY, y, 0.1);
this._vec3_1.set(this._lastX * this.bgLength, this._lastY * this.bgLength, 0);
this.centerCircleNode.setPosition(this._vec3_1);
var z: number = Math.atan(x / y) * 180 / Math.PI;
if (y < 0) {
z -= 180;
}
this._vec3_Angle.set(0, 0, z * -1);
this.directionNode.eulerAngles = this._vec3_Angle;
}
}
/**
* [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.4/manual/zh/scripting/
* Learn more about CCClass: https://docs.cocos.com/creator/3.4/manual/zh/scripting/decorator.html
* Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.4/manual/zh/scripting/life-cycle-callbacks.html
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2ab5d37b-dce3-45ce-b8c6-247477bb702f",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,140 @@
import { _decorator, Touch, input, Input, view, EventTouch, Vec2, Component } from 'cc';
import { Constant } from '../../framework/constant';
import { EasyTouch } from './easy_touch';
import { ClientEvent } from '../../framework/clientEvent';
const { ccclass, property } = _decorator;
@ccclass('EasyTouchPanel')
export class EasyTouchPanel extends Component {
// 左 横杆
@property(EasyTouch)
leftEasyTouch: EasyTouch = null!;
@property(EasyTouch)
rightEasyTouch: EasyTouch = null!;
// 移动位置
private _startLeftMoveX: number = 0;
// 移动坐标
private _startLeftMoveY: number = 0;
// 移动位置
private _startRightMoveX: number = 0;
// 移动坐标
private _startRightMoveY: number = 0;
// 屏幕宽
private _canvasMidWidth: number = 0;
// 屏幕高
private _canvasMidHeight: number = 0;
private _leftTouchId: number = -1;
private _rightTouchId: number = -1;
start () {
let size = view.getVisibleSize();
let width = Math.round(size.width);
let height = Math.round(size.height);
this._canvasMidWidth = width * 0.5;
this._canvasMidHeight = height * 0.5;
}
onEnable () {
ClientEvent.on(Constant.EVENT_NAME.GAME_INIT, this._init, this);
input.on(Input.EventType.TOUCH_START, this._onTouchStart, this);
input.on(Input.EventType.TOUCH_MOVE, this._onTouchMove, this);
input.on(Input.EventType.TOUCH_END, this._onTouchEnd, this);
}
onDisable () {
input.off(Input.EventType.TOUCH_START, this._onTouchStart, this);
input.off(Input.EventType.TOUCH_MOVE, this._onTouchMove, this);
input.off(Input.EventType.TOUCH_END, this._onTouchEnd, this);
}
/**
* 鼠标触摸
* @param event
*/
private _onTouchStart (event: EventTouch) {
var touch: Touch = event.touch;
var touchX: number = touch.getUIStartLocation().x;
var touchY: number = touch.getUIStartLocation().y;
// 屏幕左边
if (touchX < this._canvasMidWidth) {
this._startLeftMoveX = touchX;
this._startLeftMoveY = touchY;
this._leftTouchId = touch.getID();
this.leftEasyTouch.startTouch(touchX - this._canvasMidWidth, touchY - this._canvasMidHeight);
}
else {
this._startRightMoveX = touchX;
this._startRightMoveY = touchY;
this._rightTouchId = touch.getID();
this.rightEasyTouch.startTouch(touchX - this._canvasMidWidth, touchY - this._canvasMidHeight);
}
}
/**
* 鼠标触摸
* @param event
*/
private _onTouchMove (event: EventTouch) {
var touchs: Touch[] = event.getTouches();
for (var index: number = 0; index < touchs.length; index++) {
var touch: Touch = touchs[index];
var vec2: Vec2 = touch.getUILocation();
if (touch.getID() == this._leftTouchId) {
this.leftEasyTouch.moveTouch(touch.getUILocation().x - this._startLeftMoveX, touch.getUILocation().y - this._startLeftMoveY);
}
else if (touch.getID() == this._rightTouchId) {
this.rightEasyTouch.moveTouch(vec2.x - this._startRightMoveX, vec2.y - this._startRightMoveY);
}
}
}
private _init(){
this._leftTouchId = -1;
this.leftEasyTouch.endTouch();
this.leftEasyTouch.moveTouchByXY(
0,
0
);
}
/**
* 鼠标触摸
* @param event
*/
private _onTouchEnd (event: EventTouch) {
var touch: Touch = event.touch;
var touchId: number = touch.getID();
if (touchId == this._leftTouchId) {
this._leftTouchId = -1;
this.leftEasyTouch.endTouch();
this.leftEasyTouch.moveTouchByXY(
0,
0
);
}
else {
this._rightTouchId = -1;
this.rightEasyTouch.endTouch();
this.rightEasyTouch.moveTouchByXY(
0,
0
);
}
if (this._leftTouchId == -1 && this._rightTouchId == -1) {
// 双手都移开屏幕
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e1f2a28c-3bf2-49c7-91b1-c5c641bb0edd",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "25fcc73d-99be-4f5b-8e35-2ea1cdf93fb6",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,19 @@
import { _decorator, Component } from 'cc';
import { UIManager } from '../../framework/uiManager';
import { Constant } from '../../framework/constant';
import { GobeUtil } from '../../core/gobeUtil';
const { ccclass, property } = _decorator;
@ccclass('DownOffPanel')
export class DownOffPanel extends Component {
show(){
}
onCancel(){
GobeUtil.instance.leaveGame();
UIManager.instance.showTransition(Constant.SCENE_NAME.SLECT)
}
}

View File

@@ -0,0 +1 @@
{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"83f5cf78-decc-42fa-bfbb-99ef5ca1fb7d","files":[],"subMetas":{},"userData":{}}

View File

@@ -0,0 +1,121 @@
import { _decorator, Component, Node, LabelComponent, SpriteFrame, SpriteComponent} from 'cc';
import { GameState, Player } from '../../core/gameState';
import { GobeUtil, ROOM_TYPE } from '../../core/gobeUtil';
import {Util} from '../../framework/util';
import { Constant } from '../../framework/constant';
import { ClientEvent } from '../../framework/clientEvent';
import { ResourceUtil } from '../../framework/resourceUtil';
import { DisplayManager } from '../../core/displayManager';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = FightUI2
* DateTime = Mon Sep 06 2021 15:55:45 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = fightUI2.ts
* FileBasenameNoExtension = fightUI2
* URL = db://assets/script/ui/fight/fightUI2.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
const MODEL_BOY: number = 0;//蓝色房主
const MODEL_GIRL: number = 1;
@ccclass('FightUI')
export class FightUI extends Component {
@property([LabelComponent])
public aryPlayerDelay: LabelComponent[] = [];
@property([LabelComponent])
public aryPlayerScore: LabelComponent[] = [];
@property([Node])
public aryPlayerNode: Node[] = [];
@property([SpriteComponent])
public aryPlayerHead: SpriteComponent[] = [];
@property([SpriteFrame])
public aryHead: SpriteFrame[] = [];
@property(LabelComponent)
public lbCountDown: LabelComponent = null!;
@property([Node])
public ringNode: Node[] = [];
private _parent: DisplayManager = null!;
show(parent: DisplayManager) {
this.lbCountDown.string = Util.formatTimeForSecond(60, true);
this._parent = parent;
let gameState: GameState = this._parent.logicManager.currentGameState;
let players: Array<Player> = gameState.players;
for (let idx = 0; idx < players.length; idx++) {
let player: Player = players[idx];
if (!player.channel) {
this.aryPlayerNode[idx].active = false;
} else {
this.aryPlayerNode[idx].active = true;
let i = MODEL_BOY;
if (!GobeUtil.instance.checkIsRoomOwner(player.channel.openId)) {
i = MODEL_GIRL;
}
if (player.channel.headUrl && player.channel.headUrl.length) {
ResourceUtil.loadSpriteFrameURL(player.channel.headUrl, this.aryPlayerHead[i]);
} else {
this.aryPlayerHead[i].spriteFrame = this.aryHead[i];
}
}
}
var isRoomOwner:boolean = GobeUtil.instance.checkIsRoomOwner(GobeUtil.instance.ownPlayerId);
this.ringNode[0].active = isRoomOwner;
this.ringNode[1].active = !isRoomOwner;
ClientEvent.dispatchEvent(Constant.EVENT_NAME.GAME_INIT);
}
private _updatePlayerState() {
if (GobeUtil.instance.room
&& GobeUtil.instance.roomType != ROOM_TYPE.START) {
return;
}
let gameState: GameState = this._parent.logicManager.currentGameState;
let players: Array<Player> = gameState.players;
for (let idx = 0; idx < players.length; idx++) {
let player: Player = players[idx];
if (player.channel) {
let i = MODEL_BOY;
if (!GobeUtil.instance.checkIsRoomOwner(player.channel.openId)) {
i = MODEL_GIRL;
}
this.aryPlayerScore[i].string = `${player.score}`;
// this.aryPlayerDelay[i].string = `${player.channel.delayTime}ms`;
}
}
let curTime = gameState.time > 0 ? gameState.time : 0;
if(curTime > Constant.GAME_TIME){
curTime = Constant.GAME_TIME;
}
this.lbCountDown.string = Util.formatTimeForSecond(curTime, true);
}
lateUpdate (deltaTime: number) {
this._updatePlayerState();
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "65e1e7b6-dc46-4def-8d19-0198b4d4215a",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,224 @@
import { _decorator, Component, Node, LabelComponent, SpriteComponent, SpriteFrame, Prefab, AnimationComponent, AnimationClip, Animation, sys } from 'cc';
import { DisplayManager } from '../../core/displayManager';
import { FighterModel } from '../../core/fighterModel';
import { UIManager } from '../../framework/uiManager';
import { AudioManager } from '../../framework/audioManager';
import { Constant } from '../../framework/constant';
import { Player } from '../../core/gameState';
import { ResourceUtil } from '../../framework/resourceUtil';
import { PoolManager } from '../../framework/poolManager';
import { GobeUtil, WIFI_TYPE } from '../../core/gobeUtil';
const { ccclass, property } = _decorator;
/**
* Predefined variables
* Name = GameOver2
* DateTime = Wed Sep 08 2021 19:12:52 GMT+0800 (中国标准时间)
* Author = yanli.huang
* FileBasename = gameOver2.ts
* FileBasenameNoExtension = gameOver2
* URL = db://assets/script/ui/fight/gameOver2.ts
* ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
*
*/
const MODEL_BOY: number = 0;
const MODEL_GIRL: number = 1;
@ccclass('gameOver')
export class GameOver extends Component {
@property([Node])
aryNodeWin: Node[] = [];
@property([LabelComponent])
aryLbScore: LabelComponent[] = [];
@property([LabelComponent])
aryLbName: LabelComponent[] = [];
@property([SpriteComponent])
arySpIcon: SpriteComponent[] = [];
@property([SpriteFrame])
aryHead: SpriteFrame[] = [];
@property(Node)
leftNode: Node = null!;
@property(Node)
rightNode: Node = null!;
@property(Animation)
winAni: Animation = null!;
@property(Node)
btnAgc: Node = null!;
private _parent: DisplayManager = null!;
private _girlNode: Node | null = null;
private _boyNode: Node | null = null;
onDisable () {
this._cleanModel();
this.winAni.stop();
this.winAni.node.active = false;
UIManager.instance.hideDialog(Constant.PANEL_NAME.FIGHT_UI);
}
public show (parent: DisplayManager, winner: number) {
this.winAni.stop();
this.winAni.node.active = false;
this._parent = parent;
let players: Player[] = parent.logicManager.currentGameState.players;
if(players.length < 2){
return;
}
AudioManager.instance.stop(Constant.AUDIO_NAME.BACKGROUND);
AudioManager.instance.playSound(Constant.AUDIO_NAME.WIN);
for (let pos in players) {
let player: Player = players[pos];
if (player.channel) {
let i = MODEL_BOY;
if (!GobeUtil.instance.checkIsRoomOwner(player.channel.openId)) {
i = MODEL_GIRL;
}
if (parseInt(pos) === winner) {
this.winAni.node.setPosition(this.aryNodeWin[i].position);
this.winAni.node.active = true;
let aniStateIn = this.winAni.getState("leaveWinAniIn");
if (aniStateIn) {
aniStateIn.time = 0;
aniStateIn.sample();
this.winAni.play("leaveWinAniIn");
aniStateIn.wrapMode = AnimationClip.WrapMode.Normal;
}
this.winAni.once(AnimationComponent.EventType.FINISHED, ()=>{
let aniStateIdle = this.winAni.getState("leaveWinAniIdle");
if (aniStateIdle) {
aniStateIdle.time = 0;
aniStateIdle.sample();
this.winAni.play("leaveWinAniIdle");
aniStateIdle.wrapMode = AnimationClip.WrapMode.Loop;
}
})
}
this._showModel(i, winner == -1 ? true : parseInt(pos) === winner);
this.aryLbScore[i].string = player.score + '';
this.aryLbName[i].string = player.channel.name;
if (player.channel.headUrl && player.channel.headUrl.length) {
ResourceUtil.loadSpriteFrameURL(player.channel.headUrl, this.arySpIcon[i]);
} else {
this.arySpIcon[i].spriteFrame = this.aryHead[i];
}
}
}
GobeUtil.instance.leaveRoom();
// 开启内置社区
this.btnAgc.active = GobeUtil.instance.isOpenPgs && GobeUtil.instance.isHwLogin;
}
/**
* 重新开始
*/
onAgainBtnClick() {
UIManager.instance.showDialog(Constant.PANEL_NAME.MATCH_PANEL, [], ()=>{}, true);
if(GobeUtil.instance.wifiType == WIFI_TYPE.WIFI){
GobeUtil.instance.matchRoom(()=>{
UIManager.instance.hideDialog(Constant.PANEL_NAME.MATCH_PANEL);
UIManager.instance.hideDialog(Constant.PANEL_NAME.GAME_OVER);
UIManager.instance.showDialog(Constant.PANEL_NAME.READY, [true]);
this._parent.reset();
}, ()=>{
UIManager.instance.showTips(Constant.ROOM_TIPS.MATCH_ROOM_ERROR);
UIManager.instance.hideDialog(Constant.PANEL_NAME.MATCH_PANEL);
});
}else{
GobeUtil.instance.createRoomAI(()=>{
UIManager.instance.hideDialog(Constant.PANEL_NAME.MATCH_PANEL);
UIManager.instance.hideDialog(Constant.PANEL_NAME.GAME_OVER);
UIManager.instance.showDialog(Constant.PANEL_NAME.READY, [true]);
this._parent.reset();
}, ()=>{
UIManager.instance.showTips(Constant.ROOM_TIPS.MATCH_ROOM_ERROR);
UIManager.instance.hideDialog(Constant.PANEL_NAME.MATCH_PANEL);
})
}
}
/**
* 离开场景
*/
onClickLeave(){
if(!GobeUtil.instance.isChangeWifiType){
UIManager.instance.showDialog(Constant.PANEL_NAME.TIP_PANEL, [Constant.ROOM_TIPS.LEAVE_GAME, ()=>{
GobeUtil.instance.leaveGame();
UIManager.instance.hideDialog(Constant.PANEL_NAME.GAME_OVER);
UIManager.instance.showTransition(Constant.SCENE_NAME.SLECT);
}],()=>{},true);
}else{
this._parent.reset();
UIManager.instance.showTips(Constant.ROOM_TIPS.LEAVE_ROOM_SUCCESS);
UIManager.instance.hideDialog(Constant.PANEL_NAME.GAME_OVER);
UIManager.instance.showTransition(Constant.SCENE_NAME.SLECT);
}
}
onClickAgc(){
GobeUtil.instance.forumPagePublish();
GobeUtil.instance.leaveRoom();
}
private _showModel (idx: number, isWin: boolean) {
let prefabName: string = Constant.READY_PREFAB.BOY_MODEL;
let parent: Node = this.leftNode;
if (idx === MODEL_GIRL) {
parent = this.rightNode;
prefabName = Constant.READY_PREFAB.GIRL_MODEL;
}
if ((idx === MODEL_GIRL? this._girlNode : this._boyNode) === null) {
ResourceUtil.getUIPrefabRes(prefabName, (err: {}, prefab: Prefab) =>{
if ((idx === MODEL_GIRL? this._girlNode : this._boyNode) === null) {
let node: Node = PoolManager.instance.getNode(prefab, parent);
let fighterModel: FighterModel = node.getComponent(FighterModel) as FighterModel;
if (isWin) {
fighterModel.playAni(Constant.ANI_TYPE.VICTORY, true, false, ()=>{}, 13);
} else {
fighterModel.playAni(Constant.ANI_TYPE.LOSE, false, false, ()=>{
fighterModel.playAni(Constant.ANI_TYPE.LOSE_1, true, false, ()=>{}, 15);
}, 14);
}
if (idx === MODEL_GIRL) {
this._girlNode = node;
} else {
this._boyNode = node;
}
}
});
}
}
private _cleanModel () {
PoolManager.instance.putNode(this._girlNode as Node);
this._girlNode = null;
PoolManager.instance.putNode(this._boyNode as Node);
this._boyNode = null!;
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "7da34920-bf2e-4647-bda1-7254ca048096",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,47 @@
import { _decorator, Component, EditBox } from 'cc';
import { GobeUtil } from '../../core/gobeUtil';
import { UIManager } from '../../framework/uiManager';
import { Constant } from '../../framework/constant';
const { ccclass, property } = _decorator;
@ccclass('JoinRoomPanel')
export class JoinRoomPanel extends Component {
@property(EditBox)
editBox:EditBox = null!;
private _callback:Function = null!;
show(callback:Function){
this.editBox.string = "";
this._callback = callback;
}
onJoinRoom(){
if(this.editBox.string == ""){
UIManager.instance.showTips(Constant.ROOM_TIPS.NO_ROOM_ID);
return;
}
GobeUtil.instance.joinRoom(
this.editBox.string,
()=>{
UIManager.instance.showDialog(Constant.PANEL_NAME.READY);
UIManager.instance.showTips(Constant.ROOM_TIPS.JOIN_ROOM_SUCCESS);
UIManager.instance.hideDialog(Constant.PANEL_NAME.JOIN_ROOM_PANEL);
this._callback && this._callback();
}, (error:any)=>{
UIManager.instance.showTips(Constant.ROOM_TIPS.NO_ROOM_ID);
}
);
}
onClose(){
UIManager.instance.hideDialog(Constant.PANEL_NAME.JOIN_ROOM_PANEL);
}
}

View File

@@ -0,0 +1 @@
{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"4c16c5ba-22e0-4464-9371-a28da4ebcf8d","files":[],"subMetas":{},"userData":{}}

View File

@@ -0,0 +1,22 @@
import { _decorator, Component, Label } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('MatchPanel')
export class MatchPanel extends Component {
@property(Label)
txtTip: Label = null!;
private _matchTime:number = 0;
show(){
this._matchTime = 0;
}
protected update(dt: number): void {
this._matchTime += dt;
this.txtTip.string = "当前等待时长为" + Math.floor(this._matchTime) + "秒"
}
}

View File

@@ -0,0 +1 @@
{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"580ef00b-12b3-4ef6-90fd-b8614b8fd5cb","files":[],"subMetas":{},"userData":{}}

View File

@@ -0,0 +1,164 @@
import { _decorator, Component, Node} from 'cc';
import { GobeUtil } from '../../core/gobeUtil';
import { Constant } from '../../framework/constant';
import { ClientEvent } from '../../framework/clientEvent';
import { UIManager } from '../../framework/uiManager';
const { ccclass, property } = _decorator;
@ccclass('MediaPanel')
export class MediaPanel extends Component {
@property(Node)
public mediaOpen:Node = null!;
@property(Node)
public mediaClose:Node = null!;
@property(Node)
public micClose:Node = null!;
@property(Node)
public micOpen:Node = null!;
@property(Node)
public noMessageOpen:Node = null!;
@property(Node)
public messageClose:Node = null!;
@property(Node)
public messageOpen:Node = null!;
private _isOpenMessage:boolean = false; // message界面开启
private _isFirstOpenM:boolean = true; // 是否第一次开启
onEnable(): void {
ClientEvent.on(Constant.EVENT_NAME.SEND_MSG, this._onSendMsg, this);
ClientEvent.on(Constant.EVENT_NAME.OPEN_MEDIA, this._openMedia, this);
ClientEvent.on(Constant.EVENT_NAME.OPEN_CHANNEL, this._openChannel, this);
}
onDisable(): void {
ClientEvent.off(Constant.EVENT_NAME.SEND_MSG, this._onSendMsg, this);
ClientEvent.off(Constant.EVENT_NAME.OPEN_MEDIA, this._openMedia, this);
ClientEvent.off(Constant.EVENT_NAME.OPEN_CHANNEL, this._openChannel, this);
}
private _openMedia(){
if(GobeUtil.instance.isOpenMedia){
this.mediaClose.active = true;
this.mediaOpen.active = false;
this.micClose.active = true;
this.micOpen.active = false;
}else{
this.mediaClose.active = false;
this.mediaOpen.active = false;
this.micClose.active = false;
this.micOpen.active = false;
}
}
private _openChannel(){
if(GobeUtil.instance.isChannelId){
this.noMessageOpen.active = true;
this.messageClose.active = false;
this.messageOpen.active = false;
}
else{
this.noMessageOpen.active = false;
this.messageClose.active = false;
this.messageOpen.active = false;
}
}
show() {
this._isFirstOpenM = true;
this.mediaClose.active = false;
this.mediaOpen.active = false;
this.micClose.active = false;
this.micOpen.active = false;
this.noMessageOpen.active = false;
this.messageClose.active = false;
this.messageOpen.active = false;
}
/**
* 打开语音
*/
public onClickOpenMedia(){
GobeUtil.instance.mediaMuteAllPlayers(true);
this.mediaClose.active = false;
this.mediaOpen.active = true;
}
/**
* 关闭语音
*/
public onClickCloseMedia(){
GobeUtil.instance.mediaMuteAllPlayers(false);
this.mediaClose.active = true;
this.mediaOpen.active = false;
}
/**
* 开启四周音
*/
public onOpenMic(){
GobeUtil.instance.mediaEnableMic(true);
this.micClose.active = false;
this.micOpen.active = true;
}
/**
* 关闭四周音
*/
public onCloseMic(){
GobeUtil.instance.mediaEnableMic(false);
this.micClose.active = true;
this.micOpen.active = false;
}
public onOpenMessage(){
this._isOpenMessage = true;
UIManager.instance.showDialog(Constant.PANEL_NAME.MESSAGE_PANEL, [this._isFirstOpenM]);
this.messageClose.active = true;
this.noMessageOpen.active = false;
this.messageOpen.active = false;
this._isFirstOpenM = false;
}
public onCloseMessage(){
this._isOpenMessage = false;
UIManager.instance.hideDialog(Constant.PANEL_NAME.MESSAGE_PANEL);
this.messageClose.active = false;
this.noMessageOpen.active = true;
this.messageOpen.active = false;
}
private _onSendMsg(msg:string){
if(msg != "" && !this._isOpenMessage){
this.noMessageOpen.active = false;
this.messageOpen.active = true;
}
}
}
/**
* [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
*/

View File

@@ -0,0 +1 @@
{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"5cde5ed2-e0f8-4872-834b-5847b3cf7232","files":[],"subMetas":{},"userData":{}}

View File

@@ -0,0 +1,81 @@
import { _decorator, Component, Label, Node, UITransform } from 'cc';
import { GobeUtil } from '../../core/gobeUtil';
import { ClientEvent } from '../../framework/clientEvent';
import { Constant } from '../../framework/constant';
const { ccclass, property } = _decorator;
@ccclass('MessageItem')
export class MessageItem extends Component {
@property(Node)
headBoy: Node = null!;
@property(Node)
headGirl: Node = null!;
@property(UITransform)
messageUITF:UITransform = null!;
@property(Node)
msgTxtNode:Node = null!;
@property(Label)
nameTxt:Label = null!;
// @property(UITransform)
msgTxtUITF:UITransform = null!;
// @property(Label)
msgTxt:Label = null!;
public show(msg:object){
if(this.msgTxtUITF == null){
this.msgTxtUITF = this.msgTxtNode.getComponent(UITransform);
}
if(this.msgTxt == null){
this.msgTxt = this.msgTxtNode.getComponent(Label);
}
this.nameTxt.string = msg["sendId"];
if(msg["isOwn"]){
if(GobeUtil.instance.room == null){
this.headBoy.active = false;
this.headGirl.active = true;
}
else if( GobeUtil.instance.checkIsRoomOwner(GobeUtil.instance.ownPlayerId)){
this.headBoy.active = true;
this.headGirl.active = false;
}else{
this.headBoy.active = false;
this.headGirl.active = true;
}
}else{
if(GobeUtil.instance.room == null){
this.headBoy.active = true;
this.headGirl.active = false;
}
else if(GobeUtil.instance.checkIsRoomOwner(GobeUtil.instance.ownPlayerId)){
this.headBoy.active = false;
this.headGirl.active = true;
}else{
this.headBoy.active = true;
this.headGirl.active = false;
}
}
this.msgTxt.string = msg["content"];
setTimeout(()=>{
var height:number = this.msgTxtUITF.contentSize.height;
this.messageUITF.setContentSize(291, height + 10);
if(height < 60){
height = 60;
}
ClientEvent.dispatchEvent(Constant.EVENT_NAME.SEND_MSG_HEIGHT, height + 50);
}, 100);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "0a4ba360-91b5-48bf-a783-66863300129a",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,258 @@
import { _decorator, Component, EditBox, Label, Node, Prefab, ProgressBar, ScrollView, UITransform } from 'cc';
import { UIManager } from '../../framework/uiManager';
import { Constant } from '../../framework/constant';
import { GobeUtil } from '../../core/gobeUtil';
import { ClientEvent } from '../../framework/clientEvent';
import { PoolManager } from '../../framework/poolManager';
import { MessageItem } from './message_item';
const { ccclass, property } = _decorator;
@ccclass('MessagePanel')
export class MessagePanel extends Component {
@property(Node)
content: Node = null!;
@property(Prefab)
leftPrefab:Prefab = null!;
@property(Prefab)
rightPrefab:Prefab = null!;
@property(Node)
startNode:Node = null!;
@property(Node)
inputNode:Node = null!;
@property(EditBox)
editBox:EditBox = null!;
private _currY:number = -45;
@property(Node)
voiceInputNode:Node = null!;
@property(Node)
voiceNode:Node = null!;
@property(ProgressBar)
bar:ProgressBar = null!;
@property(Label)
barTxt:Label = null!;
@property(Label)
inputTxt:Label = null!;
@property(UITransform)
inputSpUIF:UITransform = null!;
@property(UITransform)
inputTxtUIF:UITransform = null!;
@property(ScrollView)
scrollView:ScrollView = null!;
@property(Label)
labelTxt:Label = null!;
// 上一条显示完全
private _isMsgShow:boolean = false;
show(isClear:boolean){
this.startNode.active = true;
this.inputNode.active = false;
this.voiceInputNode.active = false;
this.voiceNode.active = false;
if(GobeUtil.instance.room == null
|| GobeUtil.instance.room.players.length < 2){
this.labelTxt.string = Constant.ROOM_TIPS.WORLD_LABEL;
}else{
this.labelTxt.string = Constant.ROOM_TIPS.ROOM_LABEL + GobeUtil.instance.room.roomCode;
}
if(isClear){
this._clearItem();
this._currY = -45;
}
this._onSendMsg();
}
protected onEnable(): void {
ClientEvent.on(Constant.EVENT_NAME.SEND_MSG, this._onSendMsg, this);
ClientEvent.on(Constant.EVENT_NAME.SEND_MSG_HEIGHT, this._onSendMsgHeight, this);
ClientEvent.on(Constant.EVENT_NAME.SEND_VT, this._onSendVT, this);
}
protected onDisable(): void {
ClientEvent.off(Constant.EVENT_NAME.SEND_MSG, this._onSendMsg, this);
ClientEvent.off(Constant.EVENT_NAME.SEND_MSG_HEIGHT, this._onSendMsgHeight, this);
ClientEvent.off(Constant.EVENT_NAME.SEND_VT, this._onSendVT, this);
}
public onControlIM(){
this.startNode.active = true;
this.inputNode.active = false;
this.voiceInputNode.active = false;
this.editBox.string = "";
}
public onStartIM(){
this.startNode.active = false;
this.inputNode.active = true;
}
public onClickInput(){
if(this.editBox.string == ""){
UIManager.instance.showTips(Constant.ROOM_TIPS.INPUT_MSG);
return;
}
GobeUtil.instance.sendTextMsg(this.editBox.string);
this.editBox.string = "";
this.voiceNode.active = false;
this.voiceInputNode.active = false;
this.inputNode.active = false;
this.startNode.active = true;
}
public onClickVInput(){
if(this.inputTxt.string == ""){
UIManager.instance.showTips(Constant.ROOM_TIPS.INPUT_MSG);
return;
}
GobeUtil.instance.sendTextMsg(this.inputTxt.string);
this.inputTxt.string = "";
this.voiceNode.active = false;
this.voiceInputNode.active = false;
this.inputNode.active = false;
this.startNode.active = true;
}
/**
* 显示msg
*/
private _onSendMsg(){
if(this._isMsgShow){
return
}
if(GobeUtil.instance.msgLst.length > 0){
this._isMsgShow = true;
var msg:object = GobeUtil.instance.msgLst[0];
if(msg["isOwn"]){
var rightN:Node = PoolManager.instance.getNode(this.rightPrefab, this.content);
rightN.setPosition(45, this._currY, 0);
rightN.getComponent(MessageItem).show(msg);
}else{
var rightN:Node = PoolManager.instance.getNode(this.leftPrefab, this.content);
rightN.setPosition(45, this._currY, 0);
rightN.getComponent(MessageItem).show(msg);
}
GobeUtil.instance.msgLst.splice(0, 1);
}
}
/**
* 更新height
* @param height
*/
private _onSendMsgHeight(height:number){
this._isMsgShow = false;
this._currY -= height - 10;
this.content.getComponent(UITransform)?.setContentSize(424, this._currY * -1);
if(this._currY < -570){
this.scrollView.scrollToBottom();
}
this._onSendMsg();
}
protected update(dt: number): void {
if(this._isRecording){
this._recordTime += dt;
this.bar.progress = this._recordTime * 0.2;
this.barTxt.string = this._recordTime.toFixed(2) + "秒";
if(this._recordTime >= 5){
this.onStopVoice();
}
}
}
private _onSendVT(msg:string){
if(msg == ""){
UIManager.instance.showTips(Constant.ROOM_TIPS.VT_ERROR);
this.voiceNode.active = false;
this.voiceInputNode.active = false;
this.inputNode.active = false;
this.startNode.active = true;
this._isEffectRecording = false;
return;
}
if(this._isEffectRecording){
this.voiceNode.active = false;
this.voiceInputNode.active = true;
this.inputTxt.string = msg;
setTimeout(()=>{
this.inputSpUIF.setContentSize(314, this.inputTxtUIF.contentSize.height + 7);
});
}
this._isEffectRecording = false;
}
private _isRecording:boolean = false;
private _isEffectRecording = false;
private _recordTime:number = 0;
public onClickStartVoice(){
this.voiceNode.active = true;
this.startNode.active = false;
GobeUtil.instance.startRecordAudioToText();
this._isRecording = true;
this._isEffectRecording = true;
this._recordTime = 0;
}
public onCancelVoice(){
GobeUtil.instance.stopRecordAudioToText();
this.voiceNode.active = false;
this.voiceInputNode.active = false;
this.startNode.active = true;
this._isRecording = false;
this._isEffectRecording = false;
}
public onStopVoice(){
GobeUtil.instance.stopRecordAudioToText();
this._isRecording = false;
}
private _clearItem(){
var count:number = this.content.children.length;
for(var index:number = count - 1; index > -1; index --){
PoolManager.instance.putNode(this.content.children[index]);
}
}
}

View File

@@ -0,0 +1 @@
{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"6c443359-2382-4c41-a90c-0c535f26bdfc","files":[],"subMetas":{},"userData":{}}

View File

@@ -0,0 +1,26 @@
import { _decorator, Component, AnimationComponent} from "cc";
import { AudioManager } from "../../framework/audioManager";
import { Constant } from "../../framework/constant";
const { ccclass, property } = _decorator;
@ccclass("readyGo")
export class readyGo extends Component {
@property(AnimationComponent)
ani: AnimationComponent = null!;
show (callback: Function) {
this.ani.play();
this.ani.once(AnimationComponent.EventType.FINISHED, ()=>{
callback && callback();
});
}
tick () {
AudioManager.instance.playSound(Constant.AUDIO_NAME.TICK);
}
go () {
AudioManager.instance.playSound(Constant.AUDIO_NAME.GO);
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "041fedc3-6584-4e8d-847b-40c0b81e9e5d",
"files": [],
"subMetas": {},
"userData": {
"moduleId": "project:///assets/script/ui/fight/readyGo.js",
"simulateGlobals": []
}
}

View File

@@ -0,0 +1,156 @@
import { _decorator, Component, JsonAsset, Label, randomRange, Node } from 'cc';
import { GobeUtil, WIFI_TYPE } from '../../core/gobeUtil';
import { UIManager } from '../../framework/uiManager';
import { Constant } from '../../framework/constant';
import { PlayerData } from '../../framework/playerData';
import { ClientEvent } from '../../framework/clientEvent';
import { ResourceUtil } from '../../framework/resourceUtil';
import { Util } from '../../framework/util';
const { ccclass, property } = _decorator;
@ccclass('SelectPanel')
export class SelectPanel extends Component {
@property(Label)
txtName:Label = null!;
@property(Label)
txtCoin:Label = null!;
@property(Node)
btnStrategy:Node = null!;
@property(Node)
btnCommunity:Node = null!;
@property(Node)
btnShare:Node = null!;
show(){
if(PlayerData.instance.playerInfo["playerName"] == ""){
var staticId = PlayerData.instance.playerInfo["playerName"];
// 随机名字
Util.randomName(staticId).then((playerName:string)=>{
this.txtName.string = playerName;
PlayerData.instance.updatePlayerInfo("playerName", playerName);
})
}else{
this.txtName.string = PlayerData.instance.playerInfo["playerName"];
}
UIManager.instance.showDialog(Constant.PANEL_NAME.MEDIA_PANEL);
if(!PlayerData.instance.isInit){
PlayerData.instance.isInit = true;
GobeUtil.instance.startMedia(GobeUtil.instance.openId);
GobeUtil.instance.startForumPage();
}else{
GobeUtil.instance.joinTeamRoom(Constant.WORLD_ID);
GobeUtil.instance.joinGroupChannel(Constant.WORLD_ID);
}
// 开启 分享
this._onOpenPgs();
}
protected onEnable(): void {
ClientEvent.on(Constant.EVENT_NAME.INIT_MEDIA, this._onInitMedia, this);
ClientEvent.on(Constant.EVENT_NAME.INIT_CHANNEL, this._onSendChannel, this);
ClientEvent.on(Constant.EVENT_NAME.OPEN_PGS, this._onOpenPgs, this);
}
protected onDisable(): void {
ClientEvent.off(Constant.EVENT_NAME.INIT_MEDIA, this._onInitMedia, this);
ClientEvent.off(Constant.EVENT_NAME.INIT_CHANNEL, this._onSendChannel, this);
ClientEvent.off(Constant.EVENT_NAME.OPEN_PGS, this._onOpenPgs, this);
UIManager.instance.hideDialog(Constant.PANEL_NAME.MEDIA_PANEL);
}
/**
* 开启分享
*/
private _onOpenPgs(){
this.btnCommunity.active = GobeUtil.instance.isOpenPgs;
this.btnStrategy.active = GobeUtil.instance.isOpenPgs && GobeUtil.instance.isHwLogin;
this.btnShare.active = GobeUtil.instance.isOpenPgs && GobeUtil.instance.isHwLogin;
}
private _onInitMedia(){
GobeUtil.instance.joinTeamRoom(Constant.WORLD_ID);
}
private _onSendChannel(){
GobeUtil.instance.joinGroupChannel(Constant.WORLD_ID);
}
public onOpenForumPage(){
GobeUtil.instance.openForumPage();
}
public onForumPageCheckScene(){
GobeUtil.instance.forumPageCheckScene();
}
public onForumPagePublish(){
GobeUtil.instance.forumPagePublish();
}
/**
* 人机模式
*/
onCreateRoomAi(){
GobeUtil.instance.createRoomAI(()=>{
UIManager.instance.showDialog(Constant.PANEL_NAME.READY);
},()=>{
UIManager.instance.showTips(Constant.ROOM_TIPS.CREATE_ROOM_ERROR);
});
}
/**
* 创建room
*/
onCreateRoom(){
GobeUtil.instance.createRoom(()=>{
UIManager.instance.showDialog(Constant.PANEL_NAME.READY);
},()=>{
UIManager.instance.showTips(Constant.ROOM_TIPS.CREATE_ROOM_ERROR);
});
}
/**
* 加入room
*/
onJoinRoom(){
UIManager.instance.showDialog(Constant.PANEL_NAME.JOIN_ROOM_PANEL,[()=>{
// UIManager.instance.hideDialog(Constant.PANEL_NAME.SELECT_GAME);
}]);
}
/**
* 随机匹配
*/
onMatchRoom(){
UIManager.instance.showDialog(Constant.PANEL_NAME.MATCH_PANEL);
GobeUtil.instance.matchRoom(()=>{
UIManager.instance.showDialog(Constant.PANEL_NAME.READY);
UIManager.instance.showTips(Constant.ROOM_TIPS.JOIN_ROOM_SUCCESS);
UIManager.instance.hideDialog(Constant.PANEL_NAME.MATCH_PANEL);
},()=>{
// UIManager.instance.showTips(Constant.ROOM_TIPS.MATCH_ROOM_ERROR);
// UIManager.instance.hideDialog(Constant.PANEL_NAME.MATCH_PANEL);
});
}
/**
* 退出账号
*/
onLeaveClient(){
UIManager.instance.showDialog(Constant.PANEL_NAME.TIP_PANEL, [Constant.ROOM_TIPS.LEAVE_GAME, ()=>{
GobeUtil.instance.leaveGame();
UIManager.instance.hideDialog(Constant.PANEL_NAME.SELECT_GAME);
UIManager.instance.showDialog(Constant.PANEL_NAME.START_GAME);
}]);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "fc853374-496a-482b-9248-79fdb6694f89",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,142 @@
import { _decorator, Node, Component, Animation, sp, sys, log} from 'cc';
import { UIManager } from '../../framework/uiManager';
import { Constant } from '../../framework/constant';
import { GobeUtil, WIFI_TYPE } from '../../core/gobeUtil';
import { PlayerData } from '../../framework/playerData';
import { Util } from '../../framework/util';
import { ClientEvent } from '../../framework/clientEvent';
const { ccclass, property } = _decorator;
@ccclass('StartPanel')
export class StartPanel extends Component {
@property(sp.Skeleton)
startSk:sp.Skeleton = null!;
@property(Node)
btnNode:Node = null!;
@property(Node)
btnNodeHw:Node = null!;
@property(Animation)
loadAni:Animation = null!;
private _isClick:boolean = false;
show(){
this.loadAni.node.active = false;
this.loadAni.stop();
this.startSk.setAnimation(0, 'start', false);
this.startSk.addAnimation(0, 'idle', true);
this.btnNode.active = false;
this.btnNodeHw.active = false;
setTimeout(()=>{
this.btnNode.active = true;
if(GobeUtil.instance.isHwInit){
this.btnNodeHw.active = true;
}
}, 1500);
if(!GobeUtil.instance.isHwInit){
GobeUtil.instance.initHuawei();
}
}
protected onEnable(): void {
ClientEvent.on(Constant.EVENT_NAME.HUAWEI_LOGIN_MSG, this._initSuccess, this);
}
protected onDisable(): void {
ClientEvent.off(Constant.EVENT_NAME.HUAWEI_LOGIN_MSG, this._initSuccess, this);
}
private _initSuccess(code:number, msg:string){
// 账号登录
if(code == Constant.HUAWEI_LOGIN.SIGN_IN_SUCCESS){
GobeUtil.instance.isHwLogin = true;
this._loginGame();
}else if(code == Constant.HUAWEI_LOGIN.INIT_SUCCESS){
// 华为初始化
this.btnNodeHw.active = true;
}
else if(code == Constant.HUAWEI_LOGIN.INIT_UNDER_AGE){
}
else if(code == Constant.HUAWEI_LOGIN.INIT_ERROR){
}
else if(code == Constant.HUAWEI_LOGIN.SIGN_IN_ERROR){
UIManager.instance.showTips(Constant.ROOM_TIPS.HUA_WEI_LOAGIN_ERROR);
this.loadAni.node.active = false;
this.loadAni.stop();
this._isClick = false;
}
}
/**
* 开始游戏
*
* @returns
*/
public onStartGameHW(){
if(this._isClick){
return;
}
this._isClick = true;
this.loadAni.node.active = true;
this.loadAni.play();
GobeUtil.instance.hwSignIn();
}
/**
* 开始游戏
*
* @returns
*/
public onStartGame(){
if(this._isClick){
return;
}
this._isClick = true;
this.loadAni.node.active = true;
this.loadAni.play();
this._loginGame();
}
/**
* 登录游戏
*/
private _loginGame(){
if(!GobeUtil.instance.isChangeWifiType){
GobeUtil.instance.createRoomAI(()=>{
UIManager.instance.showDialog(Constant.PANEL_NAME.READY);
},()=>{
UIManager.instance.showTips(Constant.ROOM_TIPS.CREATE_ROOM_ERROR);
});
}else{
// 登录
var playerId:string = PlayerData.instance.playerInfo['playerId'];
GobeUtil.instance.initSDK(playerId, (successInit:boolean)=>{
if(successInit){
UIManager.instance.showDialog(Constant.PANEL_NAME.SELECT_GAME);
UIManager.instance.hideDialog(Constant.PANEL_NAME.START_GAME);
}else{
UIManager.instance.showTips(Constant.ROOM_TIPS.LOGIN_GAME_ERROR);
}
this.loadAni.node.active = false;
this.loadAni.stop();
this._isClick = false;
});
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "f65802ea-e53a-4068-83de-f11ac45391a9",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,31 @@
import { _decorator, Component, Label} from 'cc';
import { UIManager } from '../../framework/uiManager';
import { Constant } from '../../framework/constant';
const { ccclass, property } = _decorator;
@ccclass('TipPanel')
export class TipPanel extends Component {
@property(Label)
txtTip: Label = null!;
private _callback:Function = null!;
show(tip:string, callback:Function){
this.txtTip.string = tip;
this._callback = callback;
}
onOk(){
if(this._callback){
this._callback();
}
UIManager.instance.hideDialog(Constant.PANEL_NAME.TIP_PANEL);
}
onCancel(){
UIManager.instance.hideDialog(Constant.PANEL_NAME.TIP_PANEL);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a8b69cad-378a-4e50-97bd-da72b7d3b802",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,38 @@
import { _decorator, Component, AnimationComponent, director } from 'cc';
import { PoolManager } from '../../framework/poolManager';
const { ccclass, property } = _decorator;
@ccclass('TransitionBgPanel')
export class TransitionBgPanel extends Component {
private static TRANSITION_IN: string = 'transitionIn';
private static TRANSITION_OUT: string = 'transitionOut';
@property(AnimationComponent)
animation: AnimationComponent = null!;
show (callback:Function) {
director.addPersistRootNode(this.node);
this.animation.play(TransitionBgPanel.TRANSITION_IN);
this.animation.once(AnimationComponent.EventType.FINISHED, () => {
this.animation.play(TransitionBgPanel.TRANSITION_OUT);
this.animation.once(AnimationComponent.EventType.FINISHED, () => {
director.removePersistRootNode(this.node);
PoolManager.instance.putNode(this.node);
callback && 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
*/

View File

@@ -0,0 +1 @@
{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"6c0e1633-e119-474b-9755-70d8f46d705e","files":[],"subMetas":{},"userData":{}}

View File

@@ -0,0 +1,58 @@
import { _decorator, Component, AnimationComponent, director } from 'cc';
import { PoolManager } from '../../framework/poolManager';
import { ClientEvent } from '../../framework/clientEvent';
import { Constant } from '../../framework/constant';
const { ccclass, property } = _decorator;
@ccclass('TransitionPanel')
export class TransitionPanel extends Component {
private static TRANSITION_IN: string = 'transitionIn';
private static TRANSITION_OUT: string = 'transitionOut';
@property(AnimationComponent)
animation: AnimationComponent = null!;
private _loadSceneOver: boolean = false;
private _sceneName: string = '';
show (sceneName: string) {
this._sceneName = sceneName;
director.addPersistRootNode(this.node);
this._loadSceneOver = false;
this.animation.play(TransitionPanel.TRANSITION_IN);
director.preloadScene(Constant.SCENE_NAME.SLECT, () => {
this._loadSceneOver = true;
this._transitionOut();
});
}
private _transitionOut () {
if (this._loadSceneOver) {
var self = this;
director.loadScene(this._sceneName, ()=>{
self.animation.play(TransitionPanel.TRANSITION_OUT);
self.animation.once(AnimationComponent.EventType.FINISHED, () => {
director.removePersistRootNode(self.node);
PoolManager.instance.putNode(self.node);
ClientEvent.dispatchEvent(Constant.EVENT_NAME.ON_GAME_321);
});
});
}
}
}
/**
* [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
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "958f129c-362a-437a-a2a0-92a5a63d3a31",
"files": [],
"subMetas": {},
"userData": {}
}

Some files were not shown because too many files have changed in this diff Show More