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= []; 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 = 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++; } } }