[add] first
This commit is contained in:
69
assets/script/core/coinTipsManager.ts
Normal file
69
assets/script/core/coinTipsManager.ts
Normal 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);
|
||||
})
|
||||
|
||||
}
|
||||
}
|
12
assets/script/core/coinTipsManager.ts.meta
Normal file
12
assets/script/core/coinTipsManager.ts.meta
Normal 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": []
|
||||
}
|
||||
}
|
342
assets/script/core/displayManager.ts
Normal file
342
assets/script/core/displayManager.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
9
assets/script/core/displayManager.ts.meta
Normal file
9
assets/script/core/displayManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e542dff7-1894-4b59-8187-709cb194a914",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
587
assets/script/core/fighter.ts
Normal file
587
assets/script/core/fighter.ts
Normal 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
|
||||
*/
|
9
assets/script/core/fighter.ts.meta
Normal file
9
assets/script/core/fighter.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b2fbba2b-c2b0-4380-8eb7-f0d272ade8dc",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
108
assets/script/core/fighterModel.ts
Normal file
108
assets/script/core/fighterModel.ts
Normal 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});
|
||||
}
|
||||
}
|
||||
}
|
9
assets/script/core/fighterModel.ts.meta
Normal file
9
assets/script/core/fighterModel.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "2a13cc78-6c7b-455e-aaeb-4170b13db4b2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
44
assets/script/core/gameCamera.ts
Normal file
44
assets/script/core/gameCamera.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
assets/script/core/gameCamera.ts.meta
Normal file
12
assets/script/core/gameCamera.ts.meta
Normal 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": []
|
||||
}
|
||||
}
|
80
assets/script/core/gameState.ts
Normal file
80
assets/script/core/gameState.ts
Normal 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
|
||||
*/
|
9
assets/script/core/gameState.ts.meta
Normal file
9
assets/script/core/gameState.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "2ff802b0-9882-4a1e-8d6e-d89f43c9cb2c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
1374
assets/script/core/gobeUtil.ts
Normal file
1374
assets/script/core/gobeUtil.ts
Normal file
File diff suppressed because it is too large
Load Diff
9
assets/script/core/gobeUtil.ts.meta
Normal file
9
assets/script/core/gobeUtil.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "edfac376-3db6-4b20-9bc9-f4a1fbd9f477",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
382
assets/script/core/logicManager.ts
Normal file
382
assets/script/core/logicManager.ts
Normal 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
|
||||
*/
|
9
assets/script/core/logicManager.ts.meta
Normal file
9
assets/script/core/logicManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "549cbcf9-3d04-48ae-b0d0-e6316f112263",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
66
assets/script/core/meshHandle.ts
Normal file
66
assets/script/core/meshHandle.ts
Normal 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
|
||||
*/
|
9
assets/script/core/meshHandle.ts.meta
Normal file
9
assets/script/core/meshHandle.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0bf32029-154e-4cbb-a8f1-f7ef6dc7d286",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
268
assets/script/core/playerLogic.ts
Normal file
268
assets/script/core/playerLogic.ts
Normal 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
|
||||
*/
|
9
assets/script/core/playerLogic.ts.meta
Normal file
9
assets/script/core/playerLogic.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "2176aa66-110d-4749-adfb-9320453a99f2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
78
assets/script/core/propBase.ts
Normal file
78
assets/script/core/propBase.ts
Normal 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;
|
||||
}
|
||||
}
|
9
assets/script/core/propBase.ts.meta
Normal file
9
assets/script/core/propBase.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "933807d3-021c-45f6-9ab2-20f1dad58a83",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
377
assets/script/core/propLogic.ts
Normal file
377
assets/script/core/propLogic.ts
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
assets/script/core/propLogic.ts.meta
Normal file
9
assets/script/core/propLogic.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "1e5633ff-4f6b-4ff8-8beb-e0e259300ace",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
60
assets/script/core/virtualPlayer.ts
Normal file
60
assets/script/core/virtualPlayer.ts
Normal 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
|
||||
*/
|
9
assets/script/core/virtualPlayer.ts.meta
Normal file
9
assets/script/core/virtualPlayer.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "f0cd5f91-586d-49f2-9724-5bb012b1d2a8",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
Reference in New Issue
Block a user