123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612 |
- import { _decorator, geometry, Node, Camera, screen, EventTouch, instantiate, v3, tween, MeshRenderer, Vec3, find, input, Input, Tween, PhysicsSystem, RigidBody, Prefab, math } from 'cc';
- import { TileItem } from './TileItem';
- import { Main } from './Main';
- import { ResUtil } from '../core/utils/ResUtil';
- import { ComponentEx } from '../core/component/ComponentEx';
- import { audioMgr } from '../core/manager/AudioManager';
- import BusyLoadingManager, { BUSY_TYPE } from '../core/manager/BusyLoadingManager';
- import Data from '../core/manager/Data';
- import WindowManager from '../core/manager/WindowManager';
- import MsgHints from '../core/utils/MsgHints';
- import Utils from '../core/utils/Utils';
- import { DrawStarLayer } from '../gameui/DrawStarLayer';
- import { eventEmitter } from '../core/event/EventEmitter';
- import platformSystem from '../platform/platformSystem';
- import { GameConst, ITEM_TYPE } from '../core/common/GameConst';
- import { levelsData } from '../user/LevelsData';
- import i18n from '../core/i18n/runtime-scripts/LanguageData';
- const { Ray } = geometry;
- const { ccclass, property, executeInEditMode } = _decorator;
- @ccclass('GameNode')
- export class GameNode extends ComponentEx {
- public lock: boolean = false;
- 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);
- eventEmitter.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);
- })
- //提示
- eventEmitter.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);
- tileItem.auto_rotation = true;
- // tileItem.isMoving = true;
- // this.parabolicMovementWithScale(a,this.collectpos[i].clone(),10,0.15,a.scale.clone(),v3(1, 1, 1),
- // (n: Node) => {
- tween(a).to(0.25, { worldPosition: this.collectpos[i].clone(), worldScale: v3(1, 1, 1) }).call(() => {
- if (tileItem.removed) {
- Utils.remove(this.optionTiles,a);
- tween(a).to(0.2, { worldPosition: tileItem.removedPos }, { easing: 'backIn' }).call(async () => {
- // tileItem.isMoving = false;
- //最中央的播放移除特效
- if (tileItem.playRmovedEff) {
- //增加星星
- let pos = this.GetNode("Main Camera").getComponent(Camera).convertToUINode(a.worldPosition, find("Canvas"));
- let node_ani = await ResUtil.playSkAni("spine/effect_hecheng", "effect", find("Canvas"), pos);
- audioMgr.playOneShot(GameConst.audios.starCollect);
- platformSystem.platform.vibrateShort();
- Utils.flyAnim(ITEM_TYPE.Star, node_ani, Main.I._GameUI.starNode, 1, 0, (b) => {
- if (b) {
- Main.I._GameUI.star++;
- }
- });
- }
- a.destroy();
- this.moveToRightPos()
- this.checkResult()
- }).start()
- }
- }).start();
- // }
- // );
- })
- }
-
- chooseTile(tile: Node) {
- let chooseName = tile.name;
- this.optionTiles.push(tile);
- let tileItem:TileItem = tile.getComponent(TileItem);
- // if(tileItem.isMoving)return;
- tileItem.destoryCollider();
- for (var i = 0; i < this.allTiles.length; ++i) {
- if (this.allTiles[i] == tile) {
- this.allTiles.splice(i, 1);
- break;
- }
- }
- //计算目标位置
- let targetPos: Vec3;
- let bInsert = false;
- for (var i = this.collectTiles.length - 1; i >= 0; --i) {
- if (this.collectTiles[i].name == chooseName) {
- targetPos = this.collectpos[i + 1]?.clone() || this.collectpos[this.collectpos.length - 1].clone();
- this.collectTiles.splice(i + 1, 0, tile);
- bInsert = true;
- break;
- }
- }
- if (!bInsert) {
- targetPos = this.collectpos[this.collectTiles.length]?.clone() || this.collectpos[0].clone();
- this.collectTiles.push(tile);
- }
- this.moveToRightPos()
- //动画完成后执行原有逻辑
- let tmp = this.collectTiles.filter(a =>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();
- }
- 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.I._GameUI.star);
- })
- }
- }
- private touchTileItem: TileItem = null;
- onTouchStart(event: EventTouch) {
- if (Main.I._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.I._GameUI.pasue) return;
- if (Data.user.useMagnet) return;
- if (!this.touchTileItem) return;
- if(this.touchTileItem.isMoving){
- 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;
- audioMgr.playOneShot(GameConst.audios.tap);
- }else {
- this.touchTileItem.enableCollider = true;
- }
- }
- }
- onTouchMove(event: EventTouch) {
- if (Main.I._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;
- 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 = screen.windowSize;
- //左边墙
- 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);
- let names:Array<string> = levelsData.getModesNames();
- let tilepools = Utils.getRandomElements(names,obj.kind);
- tilepools = Utils.extendArray(tilepools,tileCount);
- Main.I._GameUI.pasue = true;
- BusyLoadingManager.ins.addBusy(BUSY_TYPE.RES);
- for (let i = 0; i < tileCount; i++) {
- for (let j = 0; j < 3; j++) {
- const globalIndex = (i * 3 + j) % 9;
- let lnode = this.GetNode(`l${globalIndex}`);
- setTimeout(async ()=>{
- let nomal_node:Node = await ResUtil.loadModelPrefabName(tilepools[i]);
- nomal_node.getComponentInChildren(MeshRenderer).shadowCastingMode = MeshRenderer.ShadowCastingMode.ON;
- 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);
- }
- },j * 0.03 * 1000);
- }
- if (i == tileCount - 1) {
- BusyLoadingManager.ins.removeBusy(BUSY_TYPE.RES);
- Main.I._GameUI.pasue = false;
- }
- }
- setTimeout(() => {
- if (Data.user.useMagnet) {
- Main.I._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.I._GameUI.pasue = false;
- if (Data.user.useTime && Data.user.time > 0)
- eventEmitter.dispatch(GameConst.USE_ITEM_TIME)
- }).start();
- }else {
- if (Data.user.useTime && Data.user.time > 0){
- eventEmitter.dispatch(GameConst.USE_ITEM_TIME)}
- }
- }, 2000);
- }
- /**
- * 提示
- */
- restart() {
- this.allTiles.map(a => a.destroy());
- this.allTiles = [];
- Main.I._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(GameConst.audios.shuffle);
- platformSystem.platform.vibrateShort();
- }
- /**凑齐*/
- public prompt(){
- if(Data.user.hint <= 0){
- MsgHints.show(i18n("main.凑齐道具不足"))
- return;
- }
- 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(i18n("main.未找到合适物品"));
- 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 nomal_node = await ResUtil.loadModelPrefabName(name);
- 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);
- }
- /**
- * 抛物线运动工具(带缩放动画)
- * @param node 要移动的节点
- * @param startPos 起始坐标(世界坐标)
- * @param endPos 目标坐标(世界坐标)
- * @param height 抛物线最高点高度(相对于起点)
- * @param duration 动画时长(秒)
- * @param startScale 起始缩放(默认原始大小)
- * @param endScale 目标缩放(默认原始大小)
- * @param onComplete 完成回调
- */
- public parabolicMovementWithScale(
- n:Node,
- endPos: Vec3,
- height: number = 2,
- duration: number = 1.5,
- startScale: Vec3 = Vec3.ONE,
- endScale: Vec3 = Vec3.ONE,
- onComplete?: (n:Node) => void
- ){
- console.log("抛物开始....");
- let startPos: Vec3 = n.position.clone();
- if(startPos.z.toFixed(2) == endPos.z.toFixed(2)) {
- console.log("z周线位置抛物....回调了");
- tween(n).to(0.25, { worldPosition: endPos.clone(), worldScale: v3(1, 1, 1) }).call(() => {
- onComplete?.(n);
- }).start();
- }else{
- //初始化节点状态
- n.setWorldPosition(startPos.clone());
- n.setScale(startScale);
- //计算抛物线顶点
- const midPoint = new Vec3(
- (startPos.x + endPos.x) / 2,
- Math.max(startPos.y, endPos.y) + height,
- (startPos.z + endPos.z) / 2
- );
- //创建组合动画
- return tween(n)
- .to(duration,
- {
- worldPosition: endPos,
- worldScale: endScale
- },{
- onUpdate: (target: Node, ratio: number) => {
- //1. 计算抛物线位置
- const t = ratio;
- const invT = 1 - t;
- const tempPos = new Vec3();
- // XZ轴线性插值
- Vec3.lerp(tempPos, startPos, endPos, t);
- //Y轴抛物线计算
- const y = invT * invT * startPos.y
- + 2 * invT * t * midPoint.y
- + t * t * endPos.y;
- //2. 计算当前缩放比例
- const currentScale = new Vec3();
- Vec3.lerp(currentScale, startScale, endScale, t);
- //更新节点状态
- target.worldPosition = new Vec3(tempPos.x, y, tempPos.z);
- target.setScale(currentScale);
- }
- }
- )
- .call(() => {//最终确保缩放精确
- n.setScale(endScale);
- console.log("不相同的位置抛物....回调了");
- onComplete?.(n);
- })
- .start();
- }
-
- }
- }
|