import { _decorator, geometry, Node, Camera, view, EventTouch, Prefab, instantiate, v3, tween, RigidBody, MeshRenderer, Vec3, find, input, Input, Tween, PhysicsSystem, physics, PhysicsSystem2D, EPhysics2DDrawFlags, director } from 'cc'; import { ComponentEx } from '../../core/component/ComponentEx'; import Utils from '../../core/utils/Utils'; import { TileItem } from './TileItem'; import GameConst, { ITEM_TYPE } from '../../core/common/GameConst'; import WindowManager from '../../core/manager/WindowManager'; import { DrawStarLayer } from './gameui/DrawStarLayer'; import GameEvent from '../../core/event/GameEvent'; import MsgHints from '../../core/utils/MsgHints'; import Data from '../../core/manager/Data'; import BusyLoadingManager, { BUSY_TYPE } from '../../core/manager/BusyLoadingManager'; import { Main } from './Main'; import levelsData from 'db://assets/data/levelsData'; import platformSystem from 'db://assets/platform/platformSystem'; import { constants } from 'db://assets/data/constants'; import audioManager from 'db://assets/manager/audioManager'; import { utils } from 'db://assets/data/utils'; const { Ray } = geometry; const { ccclass, property, executeInEditMode } = _decorator; @ccclass('GameNode') export class GameNode extends ComponentEx { @property({type: Node,tooltip:"底部的盘子"}) public plate: Node = null; public collectpos: Vec3[] = []; public collectTiles: Node[] = []; public allTiles: Node[] = []; public optionTiles: Node[] = []; public start() { setTimeout(() => { this.initWall(); this.collectpos = []; this.GetNode("collectbox").children.map(a => { this.collectpos.push(a.worldPosition); a.active = false; }) }, 100); GameEvent.Instance().register(this, GameConst.CLEAR_ALL_BOX, () => { console.log("清空盒子") this.lock=false setTimeout(() => { for (let i = 0; i < this.collectTiles.length; ++i) { this.pushBask(this.collectTiles[i].name); } this.collectTiles.map(a => { a.destroy(); }) this.collectTiles = []; }, 500); }) //提示 GameEvent.Instance().register(this, GameConst.USE_ITEM_HINT,this.prompt.bind(this)) } onEnable() { input.on(Input.EventType.TOUCH_START, this.onTouchStart, this); input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this); input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this); } onDisable() { input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this); input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this); } moveToRightPos() { //移动到正确位置 this.collectTiles.map((a, i) => { let tileItem = a.getComponent(TileItem) Tween.stopAllByTarget(a) tween(a).to(0.3, { worldPosition: this.collectpos[i].clone(), worldScale: v3(1, 1, 1) }).call(() => { tileItem.auto_rotation = true; if (tileItem.removed) { utils.remove(this.optionTiles,a); tween(a).to(0.25, { worldPosition: tileItem.removedPos }, { easing: 'backIn' }).call(async () => { //最中央的播放移除特效 if (tileItem.playRmovedEff) { //增加星星 let pos = this.GetNode("Main Camera").getComponent(Camera).convertToUINode(a.worldPosition, find("Canvas")); let node_ani = await Utils.playSkAni("effect_hecheng", "effect", find("Canvas"), pos); audioManager.playOneShot(constants.audios.starCollect); platformSystem.platform.vibrateShort(); Utils.flyAnim(ITEM_TYPE.Star, node_ani, Main.Instance()._GameUI.starNode, 1, 0, (b) => { if (b) { node_ani.destroy(); Main.Instance()._GameUI.star++; } }); } a.destroy() this.moveToRightPos() this.checkResult() }).start() } }).start(); }) } chooseTile(tile: Node) { let chooseName = tile.name; this.optionTiles.push(tile); //删除点击对象从列表 tile.getComponent(TileItem).destoryCollider() for (var i = 0; i < this.allTiles.length; ++i) { if (this.allTiles[i] == tile) { this.allTiles.splice(i, 1); break; } } //插入 let bInsert = false; for (var i = this.collectTiles.length - 1; i >= 0; --i) { if (this.collectTiles[i].name == chooseName) { this.collectTiles.splice(i + 1, 0, tile); bInsert = true; break; } } if (!bInsert) { this.collectTiles.push(tile); } this.moveToRightPos() //检测要删除的 let tmp = this.collectTiles.filter(a => { return a.name == chooseName; }) if (tmp.length == 3) { for (var i = this.collectTiles.length - 1; i >= 0; --i) { if (this.collectTiles[i].name == chooseName) { let delNode = this.collectTiles[i]; delNode.getComponent(TileItem).removed = true this.collectTiles.splice(i, 1); delNode.getComponent(TileItem).removedPos = tmp[1].worldPosition if (delNode == tmp[1]) delNode.getComponent(TileItem).playRmovedEff = true } } } this.checkResult() } lock=false checkResult() { if(this.lock)return //检测胜利和失败 if (this.collectTiles.length >= 7) { this.lock=true if (!WindowManager.ins.isShow("OutOfBoxLayer")) WindowManager.ins.open("OutOfBoxLayer"); } else if (this.collectTiles.length == 0 && this.allTiles.length == 0) { this.lock=true WindowManager.ins.open("DrawStarLayer").then((com: DrawStarLayer) => { com.setStar(Main.Instance()._GameUI.star); }) } } private touchTileItem: TileItem = null; onTouchStart(event: EventTouch) { if (Main.Instance()._GameUI.pasue) return; if (Data.user.useMagnet) return; if (this.allTiles.length == 0) return; if (this.collectTiles.length >= 7) { return; } const p = event.getLocation(); let camera = this.GetNode("Main Camera").getComponent(Camera); const r = new Ray(); camera?.screenPointToRay(p.x, p.y, r); let b = PhysicsSystem.instance.raycastClosest(r, 1) if (b) { let collider = PhysicsSystem.instance.raycastClosestResult.collider; console.log(collider.node.name, collider.getComponent(RigidBody).group); let item = collider.node.parent.getComponent(TileItem); if (item) { item.enableCollider = false; let pos = item.node.getWorldPosition(); pos.y += 0.3; item.node.setWorldPosition(pos); this.touchTileItem = item; } } } onTouchEnd(event: EventTouch) { if (Main.Instance()._GameUI.pasue) return; if (Data.user.useMagnet) return; if (!this.touchTileItem) return; if (this.allTiles.length == 0) return; if (this.collectTiles.length >= 7) { return; } const p = event.getLocation(); let camera = this.GetNode("Main Camera").getComponent(Camera); const r = new Ray(); camera?.screenPointToRay(p.x, p.y, r); let b = PhysicsSystem.instance.raycastClosest(r, 1); if (b) { let collider = PhysicsSystem.instance.raycastClosestResult.collider; let item = collider.node.parent.getComponent(TileItem); if (item && item == this.touchTileItem) { platformSystem.platform.vibrateShort(); this.chooseTile(item.node); this.touchTileItem = null; audioManager.playOneShot(constants.audios.tap); }else { this.touchTileItem.enableCollider = true; } } } onTouchMove(event: EventTouch) { if (Main.Instance()._GameUI.pasue) return; if (Data.user.useMagnet) return; if (this.allTiles.length == 0) return; if (this.collectTiles.length >= 7) { return; } const p = event.getLocation(); let camera = this.GetNode("Main Camera").getComponent(Camera); const r = new Ray(); camera?.screenPointToRay(p.x, p.y, r); let b = PhysicsSystem.instance.raycastClosest(r, 1) if (b) { let collider = PhysicsSystem.instance.raycastClosestResult.collider let item = collider.node.parent.getComponent(TileItem); if (item) { if (this.touchTileItem && item == this.touchTileItem) { }else { if (this.touchTileItem) this.touchTileItem.enableCollider = true; item.enableCollider = false; let pos = item.node.getWorldPosition(); pos.y += 0.3; // console.log("切换") item.node.setWorldPosition(pos); this.touchTileItem = item; } } else { if (this.touchTileItem) { // console.log("无目标") this.touchTileItem.enableCollider = true; this.touchTileItem = null; } } } } initWall() { if (!PhysicsSystem.instance) return; const OFFSET = 25; let camera = this.GetNode("Main Camera").getComponent(Camera); const r = new Ray(); let size = view.getCanvasSize(); //左边墙 camera?.screenPointToRay(OFFSET, size.height / 2, r); if (PhysicsSystem.instance.raycastClosest(r)) { const result = PhysicsSystem.instance.raycastClosestResult; this.GetNode("PlaneLeft").setWorldPosition(result.hitPoint); } //右边墙 camera?.screenPointToRay(size.width - OFFSET, size.height / 2, r); if (PhysicsSystem.instance.raycastClosest(r)) { const result = PhysicsSystem.instance.raycastClosestResult; this.GetNode("PlaneRight").setWorldPosition(result.hitPoint); } //上边墙 camera?.screenPointToRay(size.width / 2, size.height - OFFSET * 4, r); if (PhysicsSystem.instance.raycastClosest(r)) { const result = PhysicsSystem.instance.raycastClosestResult; this.GetNode("PlaneTop").setWorldPosition(result.hitPoint); } let minx = this.GetNode("PlaneLeft").worldPosition.x; let maxx = this.GetNode("PlaneRight").worldPosition.x; let scale = (maxx - minx) / 8.461091041564941; this.GetNode("bottom").scale = v3(scale, scale, scale); //格子位置 camera?.screenPointToRay(size.width / 2, 10, r); if (PhysicsSystem.instance.raycastClosest(r)) { const result = PhysicsSystem.instance.raycastClosestResult; //result.hitPoint let p: Vec3 = new Vec3(result.hitPoint.x,4,result.hitPoint.z); this.GetNode("bottom").setWorldPosition(p); } //下边墙 this.GetNode("PlaneDown").setWorldPosition(this.GetNode("bottom").worldPosition.add3f(0, 0, -2.5 * scale)); } async createTiles() { let Margin = 0 let minx = this.GetNode("PlaneLeft").worldPosition.x + Margin; let maxx = this.GetNode("PlaneRight").worldPosition.x - Margin; let maxz = this.GetNode("PlaneDown").worldPosition.z + Margin; let minz = this.GetNode("PlaneTop").worldPosition.z - Margin; let obj = levelsData.getCurLevelInfo(); //数量 let tileCount = Math.floor(obj.count / 3); // if (Data.user.lv == 1) tileCount = 2; // tiles = Utils.shuffle(tiles); let tilepools = [];// 30 /2 = 15 let count1 = Math.floor(tileCount / 2); let count2 = tileCount - count1; //1从解锁池选一半 let OpenItems:Array = levelsData.getDeblockDatas(); for (let i = Data.user.openIndex - 1; i >= 0; --i) { tilepools.push(OpenItems[i]); count1--; if (count1 == 0) { break; } } console.log("解锁取", tileCount - (count2 + count1), "标准取", tileCount - (tileCount - (count2 + count1))) //2从标准池选一半 let ItemNames:Array = levelsData.getNormModelDatas(); for(let k = count2 + count1 - 1; k >= 0; --k) { tilepools.push(ItemNames[k]); } tilepools = Utils.shuffle(tilepools); Main.Instance()._GameUI.pasue = true; BusyLoadingManager.ins.addBusy(BUSY_TYPE.RES); for (let i = 0; i < tileCount; i++) { let ret = await levelsData.LoadItemPrefabByName(tilepools[i]) as Prefab; if (!ret) continue; //获取节点下的 MeshRenderer 组件 设置阴影投射模式 (ret.data.getComponentInChildren(MeshRenderer) as MeshRenderer).shadowCastingMode = MeshRenderer.ShadowCastingMode.ON; for (let j = 0; j < 3; j++) { const globalIndex = (i * 3 + j) % 9; let lnode = this.GetNode(`l${globalIndex}`); tween(this.node).delay(j * 0.03).call(() => { let nomal_node: Node = instantiate(ret); nomal_node.name = ret.name; let tile = nomal_node.addComponent(TileItem); let rigid = tile.addCollider(); nomal_node.scale = v3(1.25, 1.25, 1.25) if (Data.user.lv == 1) { nomal_node.setWorldPosition(lnode.getWorldPosition()); nomal_node.parent = this.node; this.allTiles.push(nomal_node); }else{ let p = v3(Utils.getRandomInt(minx / 2, maxx / 2), Utils.getRandom(12, 15), Utils.getRandomInt(minz / 2, maxz / 2)); nomal_node.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300)) nomal_node.setWorldPosition(p); nomal_node.parent = this.node; rigid.applyImpulse(v3(0, 3, 0)) this.allTiles.push(nomal_node); } }).start() } if (i == tileCount - 1) { BusyLoadingManager.ins.removeBusy(BUSY_TYPE.RES); Main.Instance()._GameUI.pasue = false; } } setTimeout(() => { if (Data.user.useMagnet) { Main.Instance()._GameUI.pasue = true; Data.user.magnet--; let p = this.GetNode("magnet").worldPosition; this.GetNode("magnet").worldPosition = v3(-10, p.y, p.z); tween(this.GetNode("magnet")).to(0.5, { worldPosition: v3(0, p.y, p.z) }).call(async () => { let arr = []; for (var i = this.allTiles.length - 1; i >= 0; --i) { let pick = false; let item = this.allTiles[i]; let tmp: Node = arr[0]; if(tmp){ if (tmp.name == item.name && arr.length < 3) { arr.push(item); pick = true; } }else{ arr.push(item); pick = true; } if(pick) { let tile: TileItem = this.allTiles[i].getComponent(TileItem); tile.destoryCollider(); this.GetNode("magnet_content").addChild(tile.node); tween(tile.node).to(0.5, { worldPosition: this.GetNode(arr.length % 2 ? "m_left" : "r_left").worldPosition }).start(); this.allTiles.splice(i, 1); console.log("删除", tile.name, this.allTiles.length) } } Data.user.useMagnet = false; }).delay(1.5).to(0.5, { worldPosition: v3(10, p.y, p.z) }).call(() => { this.GetNode("magnet_content").removeAllChildren(); Main.Instance()._GameUI.pasue = false; if (Data.user.useTime && Data.user.time > 0) GameEvent.Instance().dispatch(GameConst.USE_ITEM_TIME) }).start(); }else { if (Data.user.useTime && Data.user.time > 0){ GameEvent.Instance().dispatch(GameConst.USE_ITEM_TIME)} } }, 2000); } /** * 提示 */ restart() { this.allTiles.map(a => a.destroy()); this.allTiles = []; Main.Instance()._GameUI.star = 0; this.collectTiles.map(a => a.destroy()); this.collectTiles = []; this.createTiles(); this.lock=false } /**移除*/ public remove(){ if (this.optionTiles.length === 0 || this.lock) return; // 获取最后一个收集的物品 const lastItem = this.optionTiles.pop(); if (!lastItem) return; utils.remove(this.collectTiles,lastItem); const tile = lastItem.getComponent(TileItem); tile.removed = false; tile.auto_rotation = false; //播放撤销动画 Tween.stopAllByTarget(lastItem); //const globalIndex = Math.floor(Math.random() * 9); let lnode = this.GetNode(`l${4}`); let p:Vec3 = lnode.position.clone(); tween(tile.node) .to(0.35, { worldPosition: new Vec3(p.x,p.y + 1,p.z), worldScale: v3(1.25, 1.25, 1.25) }) .call(() => { tile.addCollider(); tile.enableCollider = true; this.allTiles.push(lastItem); //向上施加力 然后在向下重力效果 tile.rigid.applyImpulse(v3(0, 3, 0)) this.moveToRightPos(); // 重新排列收集框中的物品 }) .start(); } /**乱序*/ public mess(){ if(this.allTiles.length === 0 || this.lock) return; this.allTiles.forEach((item, index) => { const tileItem = item.getComponent(TileItem); tileItem.auto_rotation = false; tileItem.enableCollider = true; Tween.stopAllByTarget(item); tween(item) .to(0.3, { worldPosition: this.GetNode("l4").worldPosition.clone().add(v3(0, 1, 0)), worldScale: v3(1.25, 1.25, 1.25) }) .call(() => { const rigid = tileItem.addCollider(); rigid.applyImpulse(v3( Utils.getRandom(-3, 3), Utils.getRandom(5, 8), Utils.getRandom(-3, 3) )); item.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300)) }) .start(); }); //audioManager.playOneShot(constants.audios.shuffle); platformSystem.platform.vibrateShort(); } /**凑齐*/ public prompt(){ if(this.collectTiles.length <= 0)return; let obj = {} for (var i = 0; i < this.collectTiles.length; ++i) { let name = this.collectTiles[i].name; if (!obj[name]) obj[name] = 0; obj[name]++; } let hint_succ = false; let bFind = false; let hint_name = "" for (const key in obj) { if (obj[key] == 2) { hint_name = key; bFind = true; break; } } //找到两个一样 if (bFind) { console.log("找到两个一样") for (let i = 0; i < this.allTiles.length; ++i) { if (this.allTiles[i].name == hint_name) { this.chooseTile(this.allTiles[i]); break; } } hint_succ = true; }else { if (this.collectTiles.length >= 5) { MsgHints.show("未找到合适物品"); return }else { hint_name = this.collectTiles[0] ? this.collectTiles[0].name : this.allTiles[0].name; let lsit = this.allTiles.filter(a => { return a.name == hint_name; }) lsit.map((a, i) => { setTimeout(() => { this.chooseTile(a); }, 350 * i); }) hint_succ = true; } } if (hint_succ) { Data.user.hint--; } } //放回场景中 async pushBask(name: string) { let Margin = 0; let maxz = this.GetNode("PlaneDown").worldPosition.z + Margin; let minz = this.GetNode("PlaneTop").worldPosition.z - Margin; let minx = this.GetNode("PlaneLeft").worldPosition.x + Margin; let maxx = this.GetNode("PlaneRight").worldPosition.x - Margin; let ret = await levelsData.LoadItemPrefabByName(name) as Prefab; let nomal_node: Node = instantiate(ret); nomal_node.name = name; let tile = nomal_node.addComponent(TileItem); let rigid = tile.addCollider(); nomal_node.scale = v3(1.25,1.25, 1.25) nomal_node.parent = this.node; rigid.applyImpulse(v3(0, 3, 0)) let p = v3(minx + (maxx - minx) / 2, Utils.getRandom(12, 15), minz + (maxz - minz) / 2); nomal_node.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300)) nomal_node.setWorldPosition(p); this.allTiles.push(nomal_node); } }