diff --git a/assets/Script/Block.ts b/assets/Script/Block.ts index 2e9dfc2..113c65d 100644 --- a/assets/Script/Block.ts +++ b/assets/Script/Block.ts @@ -274,35 +274,44 @@ export default class Block extends cc.Component { // Cocos生命周期 - onLoad方法 // 在组件加载时调用,用于初始化成员变量和获取组件引用 // ============================================ + // ============================================ + // Cocos生命周期 - onLoad方法 + // 在组件加载时调用,用于初始化成员变量和获取组件引用 + // 何时调用:方块节点被创建并加载到场景时自动调用 + // 初始化内容:粘合偏移量、粘合节点数组、地板块队伍数组、变色块颜色数组等 + // ============================================ onLoad() { this.stacking = cc.v2(0, 0); - // 初始化粘合偏移量为(0,0) + // 初始化粘合偏移量为(0,0) - 用于计算粘合块与主方块的位置关系 this.adhesive = cc.v2(0, 0); - // 初始化可移动地板块坐标偏移数组为空数组 + // 初始化可移动地板块坐标偏移数组为空数组 - 存储地板移动时的位置变化量 this.floorOffset = []; - // 初始化粘合方块节点数组为空数组 + // 初始化粘合方块节点数组为空数组 - 存储与当前方块粘合在一起的所有其他方块 this.adhesiveNode = []; - // 初始化可移动地板块队伍数组为空数组 + // 初始化可移动地板块队伍数组为空数组 - 存储同一队伍的所有可移动地板块 this.teamBlocks = []; - // 初始化变色块颜色变化数组为空数组 + // 初始化变色块颜色变化数组为空数组 - 存储颜色变化序列 this.colorArray = []; - // 初始化粘合方块数组为空数组 + // 初始化粘合方块数组为空数组 - 存储粘合在一起的所有方块引用 this.adhesiveArray = []; - // 初始化可移动地板块移动状态为false + // 初始化可移动地板块移动状态为false - 防止地板块移动时产生冲突 this.moveFloorPd = false; - // 初始化变色方块节点为null + // 初始化变色方块节点为null - 存储变色块的节点引用 this.colorNode = null; - // 获取多边形碰撞器组件 + // 获取多边形碰撞器组件 - 用于检测方块之间的碰撞 this.collider = this.node.getComponent(cc.PolygonCollider); - // 初始化方块已消除状态为false(未消除) + // 初始化方块已消除状态为false(未消除) - 消除后不再参与游戏逻辑 this.over = false; - // 初始化碰撞检测状态为false(未检测) + // 初始化碰撞检测状态为false(未检测) - 防止重复碰撞检测 this.checkCollision = false; } // ============================================ // Cocos生命周期 - start方法 // 在组件第一次激活时调用,通常用于初始化一些依赖其他组件的数据 + // 何时调用:方块节点第一次激活时(第一次显示前)自动调用 + // 与onLoad区别:onLoad在节点加载时调用,start在第一次激活时调用 + // 当前实现为空,因为方块初始化主要在init方法中完成 // ============================================ start() { @@ -312,6 +321,9 @@ export default class Block extends cc.Component { // JSON深拷贝方法 // 功能:将对象转为JSON字符串再转回,实现深拷贝(完全独立的副本) // 用途:避免修改配置时影响原始数据 + // 为什么用深拷贝:因为方块配置是共享的,修改其中一个方块的配置不应影响其他方块 + // 参数obj:需要拷贝的对象 + // 返回值:深拷贝后的新对象 // ============================================ jsonDeepClone(obj: T): T { return JSON.parse(JSON.stringify(obj)); @@ -320,12 +332,13 @@ export default class Block extends cc.Component { // ============================================ // 方块初始化方法 // 功能:初始化方块的各种属性和状态,包括类型、颜色、位置、特效等 + // 调用时机:方块创建后立即调用,是方块启动的入口方法 // 参数说明: - // - block_Info: 方块的配置信息对象,包含类型、颜色、ID等 - // - posX: 方块在地图网格中的X坐标(可选) - // - posY: 方块在地图网格中的Y坐标(可选) - // - node: 方块关联的节点,用于粘合块等(可选) - // - createAd: 是否创建粘合块的图片效果(可选) + // - block_Info: 方块的配置信息对象,包含type(类型)、color(颜色)、id(ID)等 + // - posX: 方块在地图网格中的X坐标(可选),用于地图定位 + // - posY: 方块在地图网格中的Y坐标(可选),用于地图定位 + // - node: 方块关联的节点,用于粘合块等特殊方块(可选) + // - createAd: 是否创建粘合块的图片效果(可选),true时会创建粘合视觉效果 // ============================================ //createAd 为是否创建粘合快图片 init(block_Info, posX, posY, node, createAd) { @@ -447,7 +460,15 @@ export default class Block extends cc.Component { } - //创建粘合方块 + // ============================================ + // 创建粘合方块方法 + // 功能:为粘合块创建与其他方块的连接效果(粘合链/粘合线) + // 何时调用:当方块类型为粘合块(BlockType.粘合块)时,在init方法中延时200ms后调用 + // 视觉效果:在两个粘合的方块之间显示一条连接线/链 + // createAd参数:是否创建粘合图片效果,true会创建视觉上的粘合连接 + // 原理:遍历目标节点的子节点(top/down/left/right),找到相邻的碰撞块, + // 然后在相邻位置添加粘合效果节点 + // ============================================ createNianHe(createAd) { const posOffset = cc.v2( this.node.x - this.block_Info.node.x, @@ -480,7 +501,27 @@ export default class Block extends cc.Component { - //初始化方块类型 + // ============================================ + // 初始化方块类型特效方法 + // 功能:根据方块类型(block_Info.type)创建对应的特效子节点 + // 例如:钥匙块显示钥匙图标、锁块显示锁图标、星星块显示星星等 + // 何时调用:在init方法中调用,位于initColor之后 + // 特效类型包括: + // - 炸弹块(BlockType.炸弹块):在方块上显示炸弹 + // - 消除炸弹块(BlockType.消除炸弹块):显示有次数限制的炸弹 + // - 星星块(BlockType.星星块):显示星星图标 + // - 钥匙块(BlockType.钥匙块):显示钥匙图标 + // - 第二钥匙块(BlockType.第二钥匙块):显示橙色钥匙 + // - 门钥匙(BlockType.门钥匙):显示门钥匙图标 + // - 上锁块(BlockType.上锁块):显示锁图标 + // - 第二上锁块(BlockType.第二上锁块):显示橙色锁 + // - 冻结块(BlockType.冻结块):显示冰冻效果图标 + // - 水平块(BlockType.水平块):显示水平限制箭头 + // - 垂直块(BlockType.垂直块):显示垂直限制箭头 + // - 叠加块上(BlockType.叠加块上):设置叠加块上层的位置和缩放 + // - 问号块(BlockType.问号块):显示问号图标和计时器 + // - 开关块(block_Info.lock):根据lock状态显示开或锁的图标 + // ============================================ initType() { if (MapConroler && MapConroler._instance) { let posConfig = cc.fx.GameConfig.PROP_INFO[this.block_Info.block]; @@ -655,13 +696,18 @@ export default class Block extends cc.Component { } } - //初始化方块颜色 // ============================================ - // 初始化方块颜色显示 - // 功能:根据方块的颜色和类型,设置方块的精灵图显示 - // 参数说明: - // - change: 是否是变色块切换颜色(true表示正在切换颜色) - // 颜色命名规则:颜色值 + "color" + 方块类型编号,如"1color2"表示黄色2号方块 + // 初始化方块颜色显示方法 + // 功能:根据方块的颜色(color)和类型(block_Info.block),设置方块的精灵图显示 + // 何时调用:在init方法中调用,设置方块的外观颜色 + // 颜色命名规则:颜色值 + "color" + 方块类型编号 + // 例如:"1color2"表示黄色2号方块,"0color2"表示暗灰色2号方块 + // change参数说明:是否为变色块切换颜色(true表示正在切换颜色) + // 特殊处理: + // - 暗灰色(color=11):使用"0color"作为名称 + // - 问号块:不需要初始化颜色 + // - 变色块:使用colorArray数组的第一个颜色作为当前颜色 + // - 叠加变色块:显示变色效果节点 // ============================================ initColor(change) { // 根据颜色和方块类型拼接精灵图名称,格式:颜色值 + "color" + 方块block编号 @@ -765,7 +811,13 @@ export default class Block extends cc.Component { } } - //改变变色块颜色 + // ============================================ + // 改变变色块颜色方法 + // 功能:切换变色块到下一个颜色 + // 何时调用:当需要改变变色块颜色时调用(例如消除后通知变色块变色) + // 原理:将colorArray数组的第一个元素移到末尾,然后重新初始化颜色显示 + // 注意:只有类型为变色块或配置中有colorArray的方块才会变色 + // ============================================ changeBlockColor() { if (this.type == BlockType.变色块 || (this.block_Info.colorArray != undefined && this.block_Info.colorArray != null)) { if (this.colorArray && this.colorArray.length > 0) { @@ -781,7 +833,20 @@ export default class Block extends cc.Component { } } - //创建粘合快连接处 + // ============================================ + // 创建粘合块连接效果方法 + // 功能:在两个粘合块之间创建视觉上的连接线(锁链效果) + // 何时调用:当粘合块createAd为true时调用,或者当另一个粘合块的zIndex大于当前块时调用 + // 视觉效果:在相邻的粘合块之间显示一条锁链/连接线 + // 算法: + // 1. 遍历当前方块的所有格子位置(allBlocks) + // 2. 遍历目标方块(被粘合的方块)的所有格子位置 + // 3. 找到在X轴或Y轴相邻的格子对(相差1个格子) + // 4. 根据相邻方向(left/right/up/down)添加对应方向的粘合效果 + // 特殊处理: + // - 可移动地板块(adhesiveNode)需要设置为透明 + // - 收集花瓣方块(adhesiveNode)也需要设置为透明 + // ============================================ createAdhesive() { MapConroler._instance.adhesiveBlock.push(this); let box = []; @@ -835,7 +900,17 @@ export default class Block extends cc.Component { } - //具体添加粘合快锁链方法 + // ============================================ + // 添加粘合效果方法 + // 功能:具体添加一个粘合连接效果节点 + // 参数说明: + // - diraction: 粘合的方向,可选值:"left"(左边)、"right"(右边)、"up"(上方)、"down"(下方) + // - box: 粘合效果应该添加到的格子位置(相对于方块自身的坐标) + // 视觉效果:根据方向创建水平或垂直的锁链图案 + // - left/right:水平锁链,显示在左边或右边 + // - up/down:垂直锁链,显示在上方或下方 + // 锁链位置计算:基于格子尺寸(120)和方块锚点偏移计算 + // ============================================ addAdhesive(diraction, box) { let pos = cc.v2(box.x - this.posX, box.y - this.posY); let adhesive = cc.instantiate(MapConroler._instance.Block_Prop[10]); @@ -864,7 +939,14 @@ export default class Block extends cc.Component { } - //删除粘合快连接处 + // ============================================ + // 删除粘合块连接效果方法 + // 功能:删除当前方块的所有粘合连接效果 + // 何时调用:当粘合块被消除或需要断开粘合时调用 + // 视觉效果:移除所有粘合锁链节点 + // 参数action:未使用(可能是历史遗留参数) + // 同时播放"adhesive"音效 + // ============================================ removeAdhesive(action) { if (this.adhesiveNode.length > 0) { cc.fx.AudioManager._instance.playEffect("adhesive", null); @@ -875,7 +957,13 @@ export default class Block extends cc.Component { } } - //减少粘合快连接处 + // ============================================ + // 减少粘合块连接效果方法 + // 功能:减少粘合块连接效果的使用次数 + // 何时调用:当地板块(adhesiveNode)需要减少粘合效果时调用 + // 与removeAdhesive区别:reduce是减少使用次数,remove是直接删除 + // 注意:如果方块有floor和floorTime属性,则不减少粘合效果 + // ============================================ reduceAdhesive() { if (this.block_Info.floor && this.block_Info.floorTime) { return; @@ -888,7 +976,17 @@ export default class Block extends cc.Component { } } - //删除所有粘合快连接处 + // ============================================ + // 删除所有粘合块连接方法 + // 功能:断开与目标节点的粘合关系,删除所有粘合连接 + // 何时调用:当粘合块需要解除与另一个方块的粘合关系时调用 + // 参数type:是否播放动画效果 + // 处理逻辑: + // 1. 遍历所有粘合节点(adhesiveNode) + // 2. 调用每个节点的remove方法 + // 3. 清空adhesiveNode数组 + // 4. 将被粘合节点的引用置空 + // ============================================ removeAllAdhesive(type) { if (this.block_Info.node) { this.removeAdhesive(type); @@ -899,7 +997,18 @@ export default class Block extends cc.Component { } - //删除特殊粘合快连接处 + // ============================================ + // 删除特殊粘合块连接方法 + // 功能:删除特殊的粘合块连接(与removeAllAdhesive略有不同) + // 与removeAllAdhesive区别:这个方法同时恢复当前块和被粘合块的普通状态 + // 何时调用:当需要彻底断开粘合并恢复两个方块为普通状态时调用 + // 处理逻辑: + // 1. 移除当前块的粘合效果 + // 2. 移除被粘合块的粘合效果 + // 3. 恢复被粘合块为普通状态 + // 4. 恢复当前块为普通状态 + // 5. 清除被粘合块的引用 + // ============================================ removeSpecailAdhesive() { if (this.block_Info.node) { this.removeAdhesive(false); @@ -912,7 +1021,24 @@ export default class Block extends cc.Component { } } - //方块落点 + // ============================================ + // 方块落下处理方法(核心移动逻辑) + // 功能:处理方块触摸结束后的落下逻辑,判断是否消除 + // 参数说明: + // - point: 落点位置(世界坐标) + // - type: 是否是模拟模式(true=正常消除,false=模拟检测) + // - Simulate: 模拟结果,包含jg(是否能消除)和direction(消除方向) + // 处理流程: + // 1. 将世界坐标转换为网格坐标 + // 2. 找到最近的地图格子作为落点 + // 3. 检查障碍物(锁块、地板、花瓣接收块等),如果有则直接返回 + // 4. 如果Simulate有效,判断能否消除并执行相应动作 + // 5. 否则调用checkPass检查是否能通过 + // 6. 根据结果执行消除动画或保持位置 + // 注意事项: + // - 叠加块需要同时移动上部分 + // - 粘合块需要同时移动被粘合的块 + // ============================================ blockFall(point, type, Simulate) { if (this.over == true) return; // // 假设 MapConroler 有网格信息,这里简单示例 @@ -994,7 +1120,21 @@ export default class Block extends cc.Component { } - //模拟方块落点 + // ============================================ + // 模拟方块落下并判断是否能消除方法 + // 功能:模拟方块落下到指定位置,判断是否能成功消除 + // 参数point:落点位置的世界坐标 + // 返回值:包含两个属性 + // - jg: boolean 是否能消除(false表示不能消除,true表示能消除) + // - direction: number 消除方向(0-上,1-下,2-左,3-右) + // 算法: + // 1. 将世界坐标转换为网格坐标 + // 2. 检查网格坐标是否越界 + // 3. 检查目标位置是否有障碍物(锁块、地板、花瓣接收块等) + // 4. 如果有障碍物,恢复原位并返回不能消除 + // 5. 如果没有障碍物,调用checkPass检查是否能通过 + // 用途:在touchEnd时调用,判断方块是否能被消除 + // ============================================ blockFallSimulate(point) { let Simulate = { jg: false, @@ -1061,7 +1201,15 @@ export default class Block extends cc.Component { } } - //移除方块碰撞 + // ============================================ + // 移除方块碰撞器方法 + // 功能:删除方块的碰撞检测子节点(left/right/top/down/tan_xxx等) + // 何时调用:在方块被消除时调用,移除碰撞检测相关节点 + // 碰撞节点说明: + // - left/right/top/down:方块四个方向的碰撞区域 + // - tan_up_right/tan_up_left/tan_down_right/tan_down_left:角落碰撞区域 + // 注意事项:这些节点是方块的子节点,需要在消除动画播放前销毁 + // ============================================ removeBoxCollider() { for (let i = 0; i < this.node.children.length; i++) { if (this.node.children[i].name == "left" || this.node.children[i].name == "right" || this.node.children[i].name == "top" || this.node.children[i].name == "down" @@ -1073,7 +1221,29 @@ export default class Block extends cc.Component { - //移除方块动画 + // ============================================ + // 方块消除动画播放方法 + // 功能:播放方块消除时的各种动画效果 + // 参数说明: + // - diraction: 消除方向(0-上,1-下,2-左,3-右) + // - type: 消除类型(true=正常触摸消除,false=道具消除) + // 动画效果包括: + // 1. 禁用触摸事件监听 + // 2. 根据消除方向调整节点尺寸(向上消除增大高度,向下消除减小高度等) + // 3. 添加遮罩组件 + // 4. 根据不同方块类型播放不同动画: + // - 叠加块下:播放叠加分离动画 + // - 粘合块:移除粘合效果 + // - 星星块:播放星星音效 + // - 炸弹块:销毁炸弹 + // - 钥匙块:播放钥匙音效 + // - 加时间块:增加游戏时间 + // - 变色块:触发颜色变化 + // 5. 播放通用消除动画(子节点向消除方向移动) + // 6. 播放音效和震动效果 + // 7. 延时后隐藏并移除节点 + // 8. 延时检测游戏是否结束 + // ============================================ removeAction(diraction, type) { this.node.off(cc.Node.EventType.TOUCH_START); this.node.off(cc.Node.EventType.TOUCH_MOVE); @@ -1235,7 +1405,27 @@ export default class Block extends cc.Component { } - //点击事件 + // ============================================ + // 触摸开始事件处理方法 + // 功能:处理玩家手指按下方块的事件 + // 触发时机:玩家手指触碰方块并开始拖动时 + // 参数event:触摸事件对象,包含触摸位置等信息 + // 处理流程: + // 1. 检查游戏是否结束(this.over或gameOver),如果是则直接返回 + // 2. 获取触摸点的世界坐标 + // 3. 检查多边形碰撞器是否存在 + // 4. 处理可移动地板块的限制(如果floorMove为false则不能移动) + // 5. 使用cc.Intersection.pointInPolygon判断触摸点是否在方块多边形内 + // 6. 如果在多边形内: + // a. 如果是锤子模式,直接调用eliminate2消除并返回 + // b. 如果是锁块/冻结块/问号块等特殊方块,根据规则处理 + // c. 否则设置触摸状态为true,记录触摸位置,设置层级等 + // d. 播放音效,调用downDoor处理门的升降 + // 7. 如果不在多边形内,设置isTouch为false并返回false + // 重要标志: + // - this.isTouch:标记方块是否正在被触摸拖动 + // - this.relative_Position:记录手指相对于方块中心的位置 + // ============================================ touchStart(event) { if (this.over || MapConroler._instance.gameOver) return; // 返回世界坐标 @@ -1387,7 +1577,31 @@ export default class Block extends cc.Component { } - //点击结束事件 + // ============================================ + // 触摸结束事件处理方法 + // 功能:处理玩家手指离开方块的事件 + // 触发时机:玩家手指从方块上松开时 + // 参数event:触摸事件对象 + // 处理流程: + // 1. 如果游戏已结束则直接返回 + // 2. 初始化模拟结果对象Simulate {jg: false, direction: 0} + // 3. 如果方块正在被触摸(isTouch为true): + // a. 调用resetStartPos检测是否有块在障碍物上 + // b. 如果检测到障碍,调用blockFallSimulate模拟能否消除 + // c. 如果不能消除,回归原始位置 + // d. 如果能消除,设置Simulate的jg和direction + // 4. 重置触摸相关状态: + // - touchPoint置空 + // - touchDelta归零 + // - checkCollision重置 + // - isTouch设为false + // - zIndex恢复原始层级 + // 5. 处理特殊方块: + // - 粘合块需要同时处理被粘合的块 + // - 地板块队伍需要同时处理队友 + // 6. 调用blockFall执行真正的落下逻辑 + // 7. 如果是粘合块,还要处理被粘合块的落下 + // ============================================ touchEnd(event) { if (MapConroler._instance.gameOver) { return; @@ -1486,7 +1700,25 @@ export default class Block extends cc.Component { } - //点击移动事件 + // ============================================ + // 触摸移动事件处理方法 + // 功能:处理玩家手指在方块上移动的事件 + // 触发时机:玩家手指在方块上拖动时持续触发 + // 参数event:触摸事件对象,包含当前触摸位置和增量信息 + // 处理流程: + // 1. 如果游戏已结束,处理方块归位逻辑 + // 2. 如果游戏未结束且方块正在被触摸(isTouch为true): + // a. 获取触摸点位置 + // b. 计算手指相对位置:delta = 触摸点位置 - 方块位置 + 相对偏移 + // c. 限制移动速度(最大速度为maxSpeed,防止穿透) + // d. 将delta保存到touchDelta,供update方法使用 + // 速度限制说明: + // - 最大速度为300像素每帧 + // - 超出限制的增量会被截断 + // 注意事项: + // - 实际移动在update方法中执行,这里只记录触摸增量 + // - 移动速度限制防止方块穿透障碍物 + // ============================================ touchMove(event: cc.Event.EventTouch) { if (MapConroler._instance.gameOver) { if (this.isTouch == true) { @@ -1548,7 +1780,21 @@ export default class Block extends cc.Component { } } - //重置位置 + // ============================================ + // 重置方块起始位置方法 + // 功能:检测方块当前位置是否有效,如果无效则需要回归原位 + // 返回值:boolean - true表示需要回归原位,false表示位置有效 + // 检测逻辑: + // 1. 检查stickWallArray是否为空(如果没有障碍墙,直接返回false) + // 2. 收集需要检测的方块列表: + // - 当前方块自身 + // - 粘合块(block_Info.node) + // - 地板块队伍(teamBlocks) + // 3. 遍历每个方块的所有格子位置 + // 4. 调用judgeStick检测每个位置是否有效 + // 5. 如果有任何位置无效,返回true表示需要回归原位 + // 用途:在touchEnd时调用,判断方块是否需要回归原位而不是消除 + // ============================================ resetStartPos() { if (MapConroler._instance) { if (MapConroler._instance.stickWallArray.length == 0) return false; @@ -1606,11 +1852,44 @@ export default class Block extends cc.Component { return jg; } - //超出限制判断 + // ============================================ + // 超出限制判断方法(未实现) + // 功能:判断方块是否超出了移动限制 + // 参数说明: + // - stepx: X轴移动步长 + // - stepy: Y轴移动步长 + // 注意事项:当前方法体为空,可能是预留的方法 + // ============================================ exceeds(stepx, stepy) { } - //道具魔棒消除 + // ============================================ + // 道具魔法棒消除方法 + // 功能:处理魔法棒道具消除方块的逻辑 + // 触发时机:玩家使用魔法棒道具点击方块时调用 + // 参数type:消除类型(未使用,可能是历史遗留) + // 处理流程: + // 1. 清除所有定时器,防止重复执行 + // 2. 设置游戏暂停状态 + // 3. 如果是魔法模式(ismagic): + // a. 延时200ms后创建魔法特效动画 + // b. 如果是冻结块,减少2次冻结计数 + // c. 如果是锁块,减少1次锁计数 + // d. 如果是地板块,减少1次地板计数 + // 4. 延时950ms后: + // a. 减少游戏方块计数 + // b. 调用special_Treatment处理特殊消除 + // c. 处理花瓣移动 + // 5. 延时1200ms后执行最终消除: + // a. 移除地图方块信息 + // b. 判断游戏胜负 + // c. 根据不同方块类型处理(叠加块/炸弹块/星星块等) + // d. 播放相应音效 + // e. 调用nextLevel进入下一关 + // f. 标记over=true并隐藏节点 + // g. 调用checkColor检查颜色门 + // 6. 延时1900ms后检测游戏是否结束 + // ============================================ eliminate(type) { clearTimeout(this.scheduleCallback2); @@ -1747,7 +2026,33 @@ export default class Block extends cc.Component { } - //道具锤子消除 + // ============================================ + // 道具锤子消除方法 + // 功能:处理锤子道具消除方块的逻辑 + // 触发时机:玩家使用锤子道具点击方块时调用 + // 与eliminate(魔法棒)的区别:锤子消除有更长的动画和震动效果 + // 处理流程: + // 1. 清除定时器 + // 2. 设置暂停状态,标记被锤子消除 + // 3. 如果是锤子模式(ishammer): + // a. 计算锤子落点位置(根据方块锚点anchorX不同而不同) + // b. 延时300ms后播放锤子音效 + // c. 调用startHammer在落点显示锤子动画 + // d. 如果是锁块,减少1次锁计数 + // e. 如果是地板块,减少1次地板计数 + // 4. 处理冻结块:减少2次冻结计数 + // 5. 处理锁块:减少1次锁计数 + // 6. 延时1000ms后执行最终消除(与魔法棒不同的延时) + // a. 减少游戏方块计数 + // b. 调用special_Treatment处理特殊消除 + // c. 处理花瓣移动 + // d. 移除地图方块信息 + // e. 根据不同方块类型处理 + // f. 调用nextLevel进入下一关 + // g. 标记over=true并隐藏节点 + // h. 调用checkColor检查颜色门 + // 7. 延时1500ms后检测游戏是否结束 + // ============================================ eliminate2() { clearTimeout(this.scheduleCallback2); let self = this; @@ -1997,7 +2302,26 @@ export default class Block extends cc.Component { let cm: any = cc.director.getCollisionManager(); cm.update(); } - //恢复成一般方块 + // ============================================ + // 恢复成普通方块方法 + // 功能:将特殊类型方块恢复为普通块(type=0) + // 参数说明: + // - posX: 方块在地图网格中的X坐标 + // - posY: 方块在地图网格中的Y坐标 + // - type: 是否恢复碰撞块显示(true=恢复,false=不恢复) + // 何时调用: + // - 粘合块解除粘合时 + // - 叠加块上分离时 + // - 消除后需要恢复配对方块时 + // 处理逻辑: + // 1. 将type设置为0(普通块) + // 2. 隐藏变色效果节点 + // 3. 清除被粘合节点引用 + // 4. 重置位置和层级 + // 5. 根据type决定是否恢复碰撞块显示 + // 6. 重新注册触摸事件监听 + // 7. 创建新的hit节点(用于显示高亮效果) + // ============================================ restoreNomal(posX, posY, type) { this.type = 0; @@ -2045,7 +2369,16 @@ export default class Block extends cc.Component { this.hit.active = false; } - //冻结状态恢复为常规状态 + // ============================================ + // 解除冻结状态方法 + // 功能:将冻结块恢复为普通块 + // 何时调用:当冻结块的冻结时间耗尽时调用 + // 处理逻辑: + // 1. 将type和block_Info.type都设置为0(普通块) + // 2. 根据当前color重新计算精灵图名称 + // 3. 更新icon子节点的精灵图显示 + // 注意:冻结块的冰冻效果是叠加在方块上的,冰冻效果消失后方块变为普通块 + // ============================================ resetFreeze() { this.type = 0; this.block_Info.type = 0; @@ -2064,7 +2397,21 @@ export default class Block extends cc.Component { } - //地板铺盖状态恢复为常态 + // ============================================ + // 解除地板块覆盖状态方法 + // 功能:将地板块恢复为普通方块状态 + // 何时调用:当地板覆盖效果结束,需要将方块恢复为普通状态时调用 + // 前提条件:方块必须有floor、floorTime属性,且类型不是叠加块上 + // 处理逻辑: + // 1. 清除floor相关属性(floor、floorTime、floorMove、floorOffset) + // 2. 销毁floor和moveFloor子节点 + // 3. 如果有粘合节点,恢复其透明度 + // 4. 处理地板块队伍,重置每个成员的显示 + // 5. 恢复teamBlocks数组为空 + // 6. 恢复icon节点显示 + // 7. 如果是冻结块,恢复冰冻效果透明度 + // 8. 如果是叠加变色块,恢复变色效果 + // ============================================ resetFloor() { if (this.block_Info.floor == null && this.block_Info.floorTime == null && this.type != BlockType.叠加块上) return; @@ -2138,7 +2485,17 @@ export default class Block extends cc.Component { } } - //问号状态恢复成普通颜色 + // ============================================ + // 问号块颜色恢复方法 + // 功能:将问号块恢复为普通颜色方块 + // 何时调用:当问号块的计时结束,需要将颜色恢复时调用 + // 处理逻辑: + // 1. 将type设置为0(普通块) + // 2. 调用initColor重新初始化颜色显示 + // 3. 如果配置中有vertical属性,恢复为垂直块类型 + // 4. 如果配置中有horizontal属性,恢复为水平块类型 + // 注意:问号块是随机效果的方块,时间结束后会变成对应的颜色 + // ============================================ resetQuestionColor() { this.type = 0; this.initColor(false); @@ -2152,6 +2509,17 @@ export default class Block extends cc.Component { } } + // ============================================ + // 切换开关状态方法 + // 功能:切换方块开关的锁定/解锁状态 + // 何时调用:当玩家触碰到开关方块时调用 + // 处理逻辑: + // - 如果当前是锁定状态(lock=true),切换为解锁状态(lock=false) + // - 如果当前是解锁状态(lock=false),切换为锁定状态(lock=true) + // 视觉效果:切换lock子节点的颜色 + // - 解锁状态:青色(0, 200, 255) + // - 锁定状态:黑色(0, 0, 0) + // ============================================ changeSwitch() { if (this.block_Info.lock != undefined) { if (this.block_Info.lock) { @@ -2164,7 +2532,23 @@ export default class Block extends cc.Component { } } - //初始化方块子块 + // ============================================ + // 初始化方块形状子块坐标方法 + // 功能:根据block_Info.block的值,初始化方块的形状坐标数组(allBlocks) + // 为什么要这个方法:方块不是只有一个格子大小,可能由多个格子组成(如L形、T形等) + // allBlocks数组说明: + // - 数组中每个元素是一个cc.Vec2坐标 + // - 坐标是相对于方块自身左上角的偏移量 + // - 例如:L形方块可能是[cc.v2(0,0), cc.v2(0,1), cc.v2(1,1)] + // 方块形状编号(block值)说明: + // - block0: 单格子方块 + // - block1: 横向2格子(向左延伸) + // - block2: 竖向2格子(向上延伸) + // - block3: 横向3格子 + // - block4: 竖向3格子 + // - block5-22: 各种复杂形状(L形、T形、十字形等) + // 注意事项:坐标系统是Y轴向上的,需要注意方向的对应关系 + // ============================================ initBlocks() { this.allBlocks = []; @@ -2321,7 +2705,19 @@ export default class Block extends cc.Component { } } - //设置地图方块信息 + // ============================================ + // 设置地图方块信息方法 + // 功能:将当前方块的信息注册到地图网格系统中 + // 为什么要设置:地图需要知道每个格子被哪个方块占据,用于碰撞检测和消除判定 + // 处理逻辑: + // 1. 遍历方块的所有格子位置(allBlocks) + // 2. 计算每个格子在地图中的绝对坐标:x = posX + 相对x, y = posY + 相对y + // 3. 将地图网格中对应位置的block_Id设置为当前方块的uuid + // 用途: + // - 碰撞检测时检查目标位置是否被其他方块占据 + // - 消除时清空地图格子信息 + // - 判断方块能否移动到某个位置 + // ============================================ setMapBlock() { if (this.allBlocks.length > 0) { for (let i = 0; i < this.allBlocks.length; i++) { @@ -2334,7 +2730,16 @@ export default class Block extends cc.Component { } } - //检查地图块是否有伸缩杆 + // ============================================ + // 检查地图块是否有伸缩杆方法 + // 功能:检查方块当前位置的地图格子上是否有伸缩杆 + // 参数说明: + // - posX: 方块在地图中的X坐标 + // - posY: 方块在地图中的Y坐标 + // 返回值:boolean - true表示有伸缩杆,false表示没有 + // 处理逻辑:遍历方块的所有格子,检查每个格子位置的地图是否有stick子节点且active为true + // 用途:判断方块是否能够消除(如果下方有伸缩杆则不能消除) + // ============================================ judgeMapBlock(posX, posY) { let jg = false; if (this.allBlocks.length > 0) { @@ -2352,7 +2757,20 @@ export default class Block extends cc.Component { return jg; } - //移除地图方块信息 + // ============================================ + // 移除地图方块信息方法 + // 功能:将当前方块的信息从地图网格系统中移除 + // 何时调用: + // - 方块被消除时 + // - 方块移动到新位置前(先移除旧位置信息) + // 处理逻辑: + // 1. 检查posX和posY是否为0,如果是则直接返回(方块从未设置过位置) + // 2. 检查allBlocks数组是否存在且有元素 + // 3. 遍历方块的所有格子位置 + // 4. 计算每个格子在地图中的绝对坐标 + // 5. 将地图网格中对应位置的block_Id清空(设置为空字符串) + // 与setMapBlock关系:setMapBlock是注册,removeMapBlock是注销 + // ============================================ removeMapBlock() { if (this.posX == 0 && this.posY == 0) { return; @@ -2376,7 +2794,24 @@ export default class Block extends cc.Component { } } - //叠加块,位置差异,校准位置 + // ============================================ + // 获取叠加块偏移位置方法 + // 功能:获取叠加块上部分相对于下部分的位置偏移 + // 为什么要这个方法:叠加块是由上下两部分组成的,上部分需要偏移到正确的位置 + // 返回值:cc.Vec2类型的位置偏移量 + // 方块名称对应偏移量说明: + // - block0: (-21, 22) + // - block1: (-36, 23) + // - block2: (-18, 40) + // - block3: (-59, 25) + // - block4: (-19, 57) + // - block5: (-36, 38) + // - block6: (-19, 97) + // - block7: (-19, 61) + // - block8: (-55, 24) + // - 其他方块... + // 注意事项:不同形状的方块有不同的偏移量,这个是预定义在代码中的 + // ============================================ getStackingPos() { switch (this.node.name) { case "block0": @@ -2428,7 +2863,24 @@ export default class Block extends cc.Component { } } - //更新位置 + // ============================================ + // Cocos Engine Update 方法(每帧调用) + // 功能:每帧更新方块的位置和状态 + // 何时调用:游戏运行期间每帧自动调用(约60帧/秒) + // 这是游戏的核心更新循环,处理方块的实时移动和碰撞 + // 主要处理内容: + // 1. 处理触摸移动(如果isTouch为true且touchDelta大于0) + // 2. 限制移动速度,防止穿透 + // 3. 处理移动方向限制(水平块只能左右移动,垂直块只能上下移动) + // 4. 调用LQCollideSystem.update_logic进行碰撞检测 + // 5. 处理叠加块跟随(叠加块上跟随下部分移动) + // 6. 处理粘合块跟随(粘合块移动时,其粘合的块也跟随移动) + // 7. 处理地板块队伍移动(队伍中一个移动,其他也跟着移动) + // 碰撞检测说明: + // - moveLeft/moveRight/moveUp/moveDown表示该方向是否可以移动 + // - moveX/moveY表示综合移动状态 + // - checkCollision标记是否正在进行碰撞检测 + // ============================================ update(dt: number) { if (this.isTouch && this.touchDelta.mag() > 0) { //this.moveLeft = this.moveRight = this.moveUp = this.moveDown = true; @@ -2633,7 +3085,20 @@ export default class Block extends cc.Component { } } - //精细更改 点击高亮位置 + // ============================================ + // 设置高亮效果位置方法 + // 功能:设置方块被点击时显示的高亮效果(hit节点)的位置 + // 为什么要这个方法:不同形状的方块,高亮效果的位置不同 + // 方块形状与高亮位置对应关系(block值 -> 位置): + // - block0: (15, -20) + // - block1: (13, -17.5) + // - block2: (15, -16) + // - block4: (12, -18) + // - block6: (15, -14) + // - block7: (17, -9) + // - 其他形状... + // hit节点说明:hit是方块的子节点,用于显示方块被选中时的高亮效果 + // ============================================ setHitPosition() { this.hit.setPosition(13, -16); switch (this.block_Info.block) { @@ -2700,7 +3165,18 @@ export default class Block extends cc.Component { } } - // 边角弹开 避免卡死 + // ============================================ + // 边角弹开方法 + // 功能:当方块碰到角落时,弹开一点距离避免卡死 + // 参数name:角落名称 + // - "tan_down_left":左下角 + // - "tan_up_right":右上角 + // - "tan_down_right":右下角 + // - "tan_up_left":左上角 + // 弹开距离:每个方向1.5像素 + // 为什么需要这个方法:当方块移动到角落位置时,可能因为碰撞检测问题卡住, + // 这个方法让方块稍微弹开一点,避免完全卡死无法移动 + // ============================================ Bounce(name) { let distance = 1.5; if (name == "tan_down_left") { @@ -2721,7 +3197,24 @@ export default class Block extends cc.Component { } } - //创建单个方块效果 + // ============================================ + // 创建单个魔法特效方法 + // 功能:为方块创建一个魔法特效节点(骨骼动画) + // 参数说明: + // - blockPos: 方块的位置(相对于方块自身的坐标) + // - index: 特效的索引(用于命名和调试) + // - blockSize: 格子大小(默认120) + // - baseOffset: 基础偏移量 + // 何时调用:在createLabelsForBlocksWithCustomDelay中循环调用 + // 处理逻辑: + // 1. 创建特效节点并添加sp.Skeleton骨骼动画组件 + // 2. 计算特效的实际位置(世界坐标) + // 3. 将世界坐标转换为Canvas的本地坐标 + // 4. 设置最高层级(zIndex=9999)确保在最上层 + // 5. 添加到Canvas节点下 + // 6. 播放动画 + // 7. 3秒后自动清理节点 + // ============================================ createSingleBlockEffect(blockPos: any, index: number, blockSize: number, baseOffset: cc.Vec2) { const effectNode = new cc.Node(`magic_effect_${index}`); @@ -2770,7 +3263,18 @@ export default class Block extends cc.Component { } - // 播放魔法动画的辅助方法 + // ============================================ + // 播放魔法动画辅助方法 + // 功能:播放骨骼动画并设置完成回调 + // 参数说明: + // - skeletonComponent: 骨骼动画组件 + // - index: 动画索引(用于调试) + // 处理逻辑: + // 1. 检查动画"play"是否存在于Spine资源中 + // 2. 设置动画为"play",不循环播放 + // 3. 监听动画完成事件 + // 4. 动画完成后移除节点并销毁 + // ============================================ playMagicAnimation(skeletonComponent: sp.Skeleton, index: number) { try { // 检查动画是否存在 @@ -2797,7 +3301,13 @@ export default class Block extends cc.Component { } } - // 清理 + // ============================================ + // 清理魔法特效方法 + // 功能:清理当前方块上所有残留的魔法特效节点 + // 何时调用:在createLabelsForBlocksWithCustomDelay之前调用,确保清理旧的特效 + // 处理逻辑:遍历方块的所有子节点,移除所有以"magic_effect_"开头的节点 + // 注意:这些特效节点是在Canvas下,不是在方块节点下,但通过name来识别 + // ============================================ clearPreviousEffects() { const children = this.node.children; for (let i = children.length - 1; i >= 0; i--) { @@ -2809,7 +3319,22 @@ export default class Block extends cc.Component { } } - //设置地板块 + // ============================================ + // 设置地板块方法 + // 功能:为方块添加地板覆盖效果 + // 何时调用:当方块有floor和floorTime属性时,在initType中调用 + // 地板块说明:地板是一种覆盖效果,会覆盖在方块上方 + // 处理逻辑: + // 1. 隐藏方块的icon和change_color节点(被地板覆盖) + // 2. 根据floorMove属性决定创建普通地板还是移动地板 + // 3. 遍历allBlocks,在每个格子位置创建地板节点 + // 4. 设置地板的位置、大小和层级 + // 5. 初始化地板的持续时间(floorTime) + // 特殊处理: + // - 如果是冻结块,地板透明度设为0 + // - 如果是叠加块上,隐藏地板节点 + // - 如果是叠加块下,隐藏主方块图标 + // ============================================ setFloor() { // console.log("设置地板块", this.type); this.node.getChildByName("change_color").active = false; @@ -2854,13 +3379,33 @@ export default class Block extends cc.Component { } } - //设置团队块块 + // ============================================ + // 设置地板块队伍方法 + // 功能:将多个相关的地板块组织成一个队伍 + // 参数teamBlocks:包含所有队友方块的数组 + // 为什么要队伍:一个地板块移动时,同队伍的其他人也要一起移动 + // 队伍成员说明:队伍中的所有地板块会作为一个整体一起移动 + // ============================================ setTeamBlocks(teamBlocks) { // console.log("自己的類型::", this.block_Info.block, teamBlocks); this.teamBlocks = teamBlocks; } - //设置可移动地板块的朝向 + // ============================================ + // 设置可移动地板块朝向方法 + // 功能:根据周围方块情况,设置移动地板的显示方向 + // 朝向类型: + // - 0:水平方向(heng) + // - 1:垂直方向(shu) + // - 2:十字方向(两种方向都有) + // 算法说明: + // 1. 计算自己所有格子位置 + // 2. 计算其他地板块的所有格子位置 + // 3. 合并所有位置作为"其他方块"集合 + // 4. 对于每个地板格子,检查上下左右是否有其他方块 + // 5. 根据上下左右是否有邻居,设置对应的朝向 + // 用途:让移动地板块看起来与周围方块连接更自然 + // ============================================ setFloorSprite() { //其他块的位置 let otherBlocks = []; @@ -2920,7 +3465,21 @@ export default class Block extends cc.Component { // this.node.getChildByName("moveFloor").getComponent("Floor").setSpriteFrame(2); } - //增加可移动地板块每个块的限制移动 + // ============================================ + // 设置移动地板限制方法 + // 功能:为队友地板块设置移动限制和碰撞克隆 + // 何时调用:当需要设置移动地板的移动限制时调用 + // 处理逻辑: + // 1. 调用setFloorSprite设置地板朝向 + // 2. 如果队伍少于2个方块,直接返回 + // 3. 遍历队伍中除自己外的其他地板块: + // a. 计算自己与队友的位置偏移量(floorOffset) + // b. 克隆队友的碰撞块(left/right/top/down)作为自己的碰撞块 + // c. 设置克隆碰撞块的data_string为"-2"(表示是移动地板碰撞块) + // 4. 延时100ms后设置moveFloorPd为true(允许地板移动) + // 碰撞块克隆说明:队友的碰撞块被克隆到当前方块上, + // 这样移动时不会与队友发生碰撞 + // ============================================ setMoveFloor() { this.setFloorSprite(); if (this.teamBlocks.length < 2) { @@ -2963,7 +3522,22 @@ export default class Block extends cc.Component { // console.log(this.block_Info.floor, this.block_Info.block); } - //魔法棒道具使用,动画 + // ============================================ + // 魔法棒特效创建方法 + // 功能:为方块创建分批次延迟的魔法特效动画 + // 何时调用:当使用魔法棒道具时,在eliminate方法中调用 + // 参数delayBetweenBlocks:每批次特效之间的延迟时间(默认0.1秒) + // 处理逻辑: + // 1. 检查allBlocks是否存在 + // 2. 调用clearPreviousEffects清理旧的特效 + // 3. 根据方块名称(block0-block22)定义创建顺序createOrder + // 4. 按照createOrder定义的批次顺序创建特效 + // 5. 每批次之间有delayBetweenBlocks的延迟 + // createOrder说明:定义了每个方块形状特效的创建顺序 + // 例如:block5的createOrder为[[0], [1,3], [2]] + // 表示先创建索引0的特效,然后同时创建索引1和3的特效,最后创建索引2的特效 + // 视觉效果:实现特效从某个位置开始,依次向外扩散的效果 + // ============================================ createLabelsForBlocksWithCustomDelay(delayBetweenBlocks: number = 0.1) { if (!this.allBlocks || this.allBlocks.length === 0) { console.warn("allBlocks 数组为空或未定义"); @@ -3143,7 +3717,16 @@ export default class Block extends cc.Component { }); } - //创建花 + // ============================================ + // 创建花瓣效果方法 + // 功能:根据花瓣类型创建发送或接收花瓣效果 + // 何时调用:在init方法中,根据flowerSend或flowerReceive属性调用 + // flowerType说明: + // - 0:不是花瓣方块 + // - 1:是发送花瓣方块(会发射花瓣) + // - 2:是接收花瓣方块(会收集花瓣) + // 注意:一个方块可以同时是发送和接收花瓣(flowerType == 2) + // ============================================ createFlower() { if (this.flowerType == 1) { this.createFlowerSend(); @@ -3156,7 +3739,17 @@ export default class Block extends cc.Component { this.createFlowerReceive(); } } - //创建发送花 + // ============================================ + // 创建发送花瓣方法 + // 功能:为发送花瓣方块创建花瓣发射效果 + // 何时调用:当flowerType为1(发送)或2(同时发送和接收)时调用 + // 处理逻辑: + // 1. 获取方块的位置配置信息 + // 2. 创建花瓣发送节点并设置父节点 + // 3. 解析flowerSend字符串获取花瓣颜色序列 + // 4. 根据颜色序列激活对应的花瓣并设置精灵图 + // 例如:flowerSend为"135"表示依次发射颜色1、3、5的花瓣 + // ============================================ createFlowerSend() { let posConfig = cc.fx.GameConfig.PROP_INFO[this.block_Info.block]; let flowerSend = cc.instantiate(MapConroler._instance.Block_Prop[17]); @@ -3173,7 +3766,19 @@ export default class Block extends cc.Component { petal.getComponent(cc.Sprite).spriteFrame = (this.flower_SpriteFrame._spriteFrames[flowerName]); } } - //创建接受花 + // ============================================ + // 创建接收花瓣方法 + // 功能:为接收花瓣方块创建花瓣收集效果 + // 何时调用:当flowerType为2(同时发送和接收)时调用 + // 处理逻辑: + // 1. 创建花瓣盖板节点(flowerFloor),显示在原方块图标上方 + // 2. 设置花瓣盖板的精灵图(根据方块形状) + // 3. 创建花瓣接收节点(flowerReceive) + // 4. 设置接收节点的背景颜色 + // 5. 解析flowerReceive字符串获取需要收集的花瓣序列 + // 6. 根据序列激活对应的花瓣并设置精灵图 + // 注意:花瓣接收节点有6个花瓣槽位(petal0-5) + // ============================================ createFlowerReceive() { //创建花瓣盖板 let flowerFloor = new cc.Node(); @@ -3204,14 +3809,33 @@ export default class Block extends cc.Component { } - //花瓣转移 + // ============================================ + // 转移花瓣方法 + // 功能:当发送花瓣方块被消除时,触发花瓣转移 + // 何时调用:当发送花瓣方块被消除时调用 + // 处理逻辑: + // 1. 解析flowerSend字符串获取花瓣颜色序列 + // 2. 调用MapConroler的moveFlower方法执行花瓣移动动画 + // 注意:只有flowerType为1(发送)或2(同时发送和接收)的方块才会执行此方法 + // ============================================ moveFlower() { if (this.flowerType == 1) { let flowerSendArray = this.block_Info.flowerSend.toString().split('').map(Number); MapConroler._instance.moveFlower(flowerSendArray); } } - //花瓣移动 + // ============================================ + // 移除花瓣效果方法 + // 功能:移除方块上的花瓣效果(发送和接收) + // 何时调用:当花瓣方块需要移除花瓣效果时调用 + // 处理逻辑: + // 1. 重置flowerType为0 + // 2. 调用resetFloor重置地板效果 + // 3. 如果是粘合块,恢复粘合节点透明度 + // 4. 如果配置中有flowerSend,恢复flowerType为1 + // 5. 隐藏并移除flowerFloor节点 + // 6. 隐藏并移除flowerReceive节点 + // ============================================ removeFlower() { this.flowerType = 0; this.resetFloor(); @@ -3234,7 +3858,18 @@ export default class Block extends cc.Component { } - //花瓣接收 + // ============================================ + // 添加花瓣方法 + // 功能:为接收花瓣方块添加收集到的花瓣 + // 参数number:要添加的花瓣数量 + // 何时调用:当花瓣移动到接收方块时调用 + // 处理逻辑: + // 1. 找到flowerReceive节点 + // 2. 找到第一个未激活的花瓣槽位(petal0-5) + // 3. 依次激活花瓣槽位,设置对应颜色 + // 4. 如果所有槽位都填满,调用removeFlower移除花瓣效果 + // 注意:花瓣接收节点有6个槽位,最多接收6个花瓣 + // ============================================ addFlower(number) { if (this.node.getChildByName("flowerReceive")) { @@ -3270,6 +3905,17 @@ export default class Block extends cc.Component { } } + // ============================================ + // Cocos组件销毁方法 + // 功能:当方块节点被销毁时调用,用于清理定时器 + // 何时调用:当方块节点从场景中移除并销毁时自动调用 + // 为什么需要:方块使用了setTimeout定时器,需要在销毁时清理 + // 否则定时器回调可能会访问已销毁的节点导致错误 + // 清理内容: + // - scheduleCallback:第一个定时器回调 + // - scheduleCallback2:第二个定时器回调 + // - scheduleCallback3:第三个定时器回调 + // ============================================ onDestroy() { if (this.scheduleCallback) clearTimeout(this.scheduleCallback); if (this.scheduleCallback2) clearTimeout(this.scheduleCallback2); diff --git a/assets/Script/JiaZai.ts b/assets/Script/JiaZai.ts index 3f838c5..bae380c 100644 --- a/assets/Script/JiaZai.ts +++ b/assets/Script/JiaZai.ts @@ -126,6 +126,23 @@ export default class JiaZai extends cc.Component { private guideInProgress: boolean = false; // LIFE-CYCLE CALLBACKS: + // ============================================ + // Cocos生命周期 - onLoad方法 + // 功能:场景加载时初始化游戏主界面 + // 何时调用:HomeScene场景节点加载到场景时自动调用 + // 主要功能: + // 1. 初始化游戏配置信息 + // 2. 预加载各种活动预制体(action_bundle) + // 3. 预加载商店预制体(shop) + // 4. 初始化音频系统 + // 5. 检测新手礼包、月卡等状态 + // 6. 处理好友邀请和分享逻辑 + // 7. 判断是首次进入还是返回游戏 + // 8. 预加载游戏场景 + // 特殊处理: + // - 开发版/体验版/正式版显示不同的编辑框 + // - 网页版给予大量金币和道具 + // ============================================ onLoad() { //@ts-ignore // wx.getStorageInfo({ @@ -381,6 +398,20 @@ export default class JiaZai extends cc.Component { // }); } + // ============================================ + // 创建图标方法 + // 功能:在主界面创建多圈图标装饰 + // 何时调用:在onLoad中被调用(已注释掉) + // 图标布局: + // - 中心圈:1个图标 + // - 第1圈:8个图标 + // - 第2圈:16个图标 + // - 第3圈:24个图标 + // - 第4圈:32个图标 + // 图标大小:130x130像素 + // 位置计算:根据屏幕中心点和角度均匀分布 + // zIndex设置:根据Y坐标设置层级,形成遮挡效果 + // ============================================ createIcon() { if (!this.icon) return; @@ -428,7 +459,15 @@ export default class JiaZai extends cc.Component { } } - //监听后台 + // ============================================ + // 监听游戏前后台切换方法 + // 功能:注册微信小游戏的onShow和onHide事件监听 + // 何时调用:在onLoad中调用 + // 平台判断:仅在微信小游戏环境中生效(通过wx是否存在判断) + // 监听事件: + // - onShow:游戏从后台切换到前台 + // - onHide:游戏从前台切换到后台 + // ============================================ onGames() { //@ts-ignore if (typeof wx !== 'undefined') { @@ -449,6 +488,17 @@ export default class JiaZai extends cc.Component { } } + + // ============================================ + // 游戏隐藏回调方法 + // 功能:游戏切入后台时执行的清理操作 + // 何时调用:游戏切换到后台时(微信onHide事件触发) + // 主要功能: + // 1. 重置首次启动标志 + // 2. 停止体力计时 + // 3. 停止倒计时 + // 4. 停止能量时间 + // ============================================ onGameHide() { // console.log("执行onGameHide", cc.fx.GameConfig.GM_INFO.min_Time); if (this.isFirstLaunch != null && this.isFirstLaunch != undefined) this.isFirstLaunch = false; @@ -462,6 +512,17 @@ export default class JiaZai extends cc.Component { } + // ============================================ + // 游戏显示回调方法 + // 功能:游戏从后台切换到前台时执行的逻辑 + // 何时调用:游戏切换到前台时(微信onShow事件触发) + // 主要功能: + // 1. 处理分享奖励逻辑(分享超过2秒可获得奖励) + // 2. 更新体力显示 + // 3. 更新关卡等级显示 + // 4. 更新金币显示 + // 5. 刷新体力值和倒计时 + // ============================================ onGameShow() { // console.log("执行开始游戏gameshow"); if (this.shareIng == true) { @@ -513,6 +574,21 @@ export default class JiaZai extends cc.Component { } + // ============================================ + // Cocos生命周期 - start方法 + // 功能:场景首次激活时初始化UI和业务逻辑 + // 何时调用:场景第一次激活时自动调用(在onLoad之后) + // 主要功能: + // 1. 更新体力显示 + // 2. 获取并显示关卡等级 + // 3. 获取并显示金币数量 + // 4. 设置体力信息 + // 5. 播放入场动画 + // 6. 上传关卡数据到云端 + // 7. 检查新手礼包 + // 8. 检查各种奖励状态 + // 9. 检查月卡过期状态 + // ============================================ start() { // //console.log("已经进入Home界面"); // //console.log("金币",cc.fx.GameConfig.GM_INFO.coin); @@ -630,7 +706,17 @@ export default class JiaZai extends cc.Component { // }); } - // 适配pad + // ============================================ + // 适配Pad方法 + // 功能:根据屏幕比例调整UI布局适配Pad设备 + // 何时调用:在start中被调用 + // 适配内容: + // 1. 获取适配缩放比例 + // 2. 获取屏幕和设计分辨率尺寸 + // 3. 计算X和Y方向的缩放比例 + // 4. 使用较小缩放比例确保不变形 + // 5. 调整UI元素的宽度和位置 + // ============================================ setAdaptation() { const hmScale = cc.fx.GameTool.adaptation() if (hmScale == 1) return; @@ -711,11 +797,23 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 检查每日任务方法 + // 功能:从服务器获取每日任务信息 + // 何时调用:在onLoad中调用 + // 回调处理:获取每日任务数据用于更新任务状态显示 + // ============================================ checkDailyQuests() { cc.fx.GameTool.getDailyQuestsInfo((data) => { }) } + // ============================================ + // 打开头像方法 + // 功能:显示玩家头像界面 + // 何时调用:玩家点击头像按钮时调用 + // 主要功能:实例化并显示头像预制体 + // ============================================ openAvatar() { if (!JiaZai.cachedAvatarPrefab) { console.log('Avatar prefab is not loaded yet.'); @@ -758,6 +856,12 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 关闭头像方法 + // 功能:隐藏并销毁头像界面 + // 何时调用:玩家关闭头像弹窗时调用 + // 主要功能:从父节点移除并销毁头像节点 + // ============================================ closeAvatar() { // console.log("最终头像:", cc.fx.GameConfig.GM_INFO.useravatarIcon); // console.log("最终头像框:", cc.fx.GameConfig.GM_INFO.useravaterkuang); @@ -795,7 +899,15 @@ export default class JiaZai extends cc.Component { cc.fx.GameTool.setUserAvatar(); } - // 打开heath弹窗,创建预制体并启动自己的倒计时 + // ============================================ + // 打开体力弹窗方法 + // 功能:创建体力预制体并显示,同时启动体力倒计时 + // 何时调用:玩家点击体力不足提示或体力耗尽时调用 + // 主要功能: + // 1. 创建体力预制体 + // 2. 启动体力倒计时 + // 3. 处理不同的按钮来源(干扰按钮等) + // ============================================ openHeath(event?: cc.Event, customEventData?: string) { // EventTouch EventCustom let eventName = ""; let btnName = "" @@ -863,7 +975,16 @@ export default class JiaZai extends cc.Component { } - // 弹窗倒计时 + // ============================================ + // 体力弹窗倒计时方法 + // 功能:启动体力弹窗的倒计时器 + // 何时调用:打开体力弹窗时调用 + // 主要功能: + // 1. 先停止之前的倒计时 + // 2. 每秒执行一次回调 + // 3. 更新剩余时间显示 + // 4. 时间归零时停止倒计时并关闭弹窗 + // ============================================ startHeathTimeCutDown(timeLabelNode?: cc.Node) { this.stopHeathTimeCutDown(); this.heathScheduleCallback = function () { @@ -886,13 +1007,30 @@ export default class JiaZai extends cc.Component { this.schedule(this.heathScheduleCallback, 1); } + // ============================================ + // 停止体力弹窗倒计时方法 + // 功能:停止体力弹窗的倒计时器 + // 何时调用:体力恢复满或关闭弹窗时调用 + // 主要功能: + // 1. 取消定时回调 + // 2. 清空回调引用 + // ============================================ stopHeathTimeCutDown() { if (this.heathScheduleCallback) { this.unschedule(this.heathScheduleCallback); this.heathScheduleCallback = null; } } - //开始倒计时 恢复体力 + // ============================================ + // 体力恢复倒计时方法 + // 功能:启动体力恢复的倒计时器 + // 何时调用:进入主界面或体力消耗后调用 + // 主要功能: + // 1. 每秒执行一次回调 + // 2. 检测体力是否已满 + // 3. 体力恢复后更新显示 + // 4. 体力满时停止倒计时 + // ============================================ startTimeCutDown() { this.stopTimeCutDown(); this.scheduleCallback = function () { @@ -928,7 +1066,14 @@ export default class JiaZai extends cc.Component { }.bind(this); this.schedule(this.scheduleCallback, 1); } - // 停止倒计时 恢复体力 + // ============================================ + // 停止体力恢复倒计时方法 + // 功能:停止体力恢复的倒计时器 + // 何时调用:体力已满或不需要继续恢复时调用 + // 主要功能: + // 1. 取消定时回调 + // 2. 清空回调引用 + // ============================================ stopTimeCutDown() { if (this.scheduleCallback) { this.unschedule(this.scheduleCallback); @@ -936,6 +1081,15 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 开始无限膂力倒计时方法 + // 功能:启动无限体力时间监控 + // 何时调用:当有无限体力时调用 + // 主要功能: + // 1. 先停止之前的计时器 + // 2. 每秒检查一次无限体力剩余时间 + // 3. 无限体力时间到期后关闭显示并更新状态 + // ============================================ startPowerTime() { this.stopPowerTime(); if (this.scheduleCallback2) { @@ -978,7 +1132,15 @@ export default class JiaZai extends cc.Component { }.bind(this); this.schedule(this.scheduleCallback2, 1); } - + // ============================================ + // 停止无限体力倒计时方法 + // 功能:停止无限体力时间监控 + // 何时调用:无限体力时间到期或不需要时调用 + // 主要功能: + // 1. 刷新体力状态 + // 2. 取消定时回调 + // 3. 清空回调引用 + // ============================================ stopPowerTime() { cc.fx.GameTool.getUserPowerTime(); if (this.scheduleCallback2) { @@ -987,6 +1149,15 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 上传数据到云存储方法 + // 功能:将玩家关卡数据上传到微信云存储 + // 何时调用:进入游戏或关卡变化时调用 + // 上传数据: + // - level:当前关卡等级 + // - coin:当前金币数量 + // 平台判断:仅在微信小游戏环境中生效 + // ============================================ uploadToCloud(level: number) { //@ts-ignore if (typeof wx !== 'undefined') { @@ -1001,7 +1172,17 @@ export default class JiaZai extends cc.Component { } } - + // ============================================ + // 设置体力信息方法 + // 功能:更新体力显示状态 + // 何时调用:体力变化时调用 + // 参数说明:type=true表示需要启动体力恢复计时 + // 主要功能: + // 1. 体力满时检查是否有无限体力 + // 2. 更新体力进度条显示 + // 3. 体力不满时启动恢复计时 + // 4. 更新体力标签显示 + // ============================================ setHealthInfo(type) { if (cc.fx.GameConfig.GM_INFO.hp >= cc.fx.GameConfig.GM_INFO.hp_Max) { if (cc.fx.GameConfig.GM_INFO.userPowerTime != 0) { @@ -1063,7 +1244,15 @@ export default class JiaZai extends cc.Component { } } - // 最大关卡后第一次进入关卡弹窗 + // ============================================ + // 进入游戏方法 + // 功能:检测是否首次到达最高关卡并弹出提示 + // 何时调用:点击进入游戏时调用 + // 主要功能: + // 1. 检测是否到达最大关卡 + // 2. 首次到达时显示特殊提示 + // 3. 处理特殊情况弹窗 + // ============================================ enterGame() { let recordInfinity = cc.fx.StorageMessage.getStorage("EndLevelPop"); // console.log("已经最大关卡 弹窗提示", recordInfinity, cc.fx.GameTool.maxLevel()) @@ -1083,10 +1272,23 @@ export default class JiaZai extends cc.Component { } } + // 关闭最大关卡弹窗 specialTipsClose() { this.node.getChildByName("Load").getChildByName("specialTips").active = false; } + // ============================================ + // 开始游戏方法 + // 功能:处理点击开始游戏按钮的核心逻辑 + // 何时调用:点击开始游戏按钮时调用 + // 主要功能: + // 1. 重置游戏数据 + // 2. 播放按钮音效 + // 3. 检测版本和平台 + // 4. 判断体力是否足够 + // 5. 体力足够则加载并切换场景 + // 6. 体力不足则弹出体力不足提示 + // ============================================ startGame() { if (cc.fx.GameConfig.GM_INFO.otherLevel == 0) { cc.fx.GameConfig.GM_INFO.allOutTradeNo = []; @@ -1228,7 +1430,15 @@ export default class JiaZai extends cc.Component { } - //打开商店 + // ============================================ + // 打开商店方法 + // 功能:创建并显示商店界面 + // 何时调用:点击商店按钮时调用 + // 主要功能: + // 1. 实例化商店预制体 + // 2. 设置父节点和位置 + // 3. 播放按钮音效 + // ============================================ openShop(event?: cc.Event, customEventData?: string) { if (!JiaZai.cachedShopPrefab) { cc.error('Shop prefab is not loaded yet.'); @@ -1279,6 +1489,7 @@ export default class JiaZai extends cc.Component { }) } + //打开奖励弹窗 openRewardWindow(data, month?: number) { if (!JiaZai.cachedRewardPrefab) { cc.error('Reward prefab is not loaded yet.'); @@ -1353,6 +1564,16 @@ export default class JiaZai extends cc.Component { } + // ============================================ + // 领取分享奖励方法 + // 功能:处理分享奖励的领取逻辑 + // 何时调用:分享成功后调用 + // 主要功能: + // 1. 重置分享状态 + // 2. 增加分享次数 + // 3. 发送奖励到服务器 + // 4. 成功后打开每日任务界面 + // ============================================ getShareReward() { this.shareIng = false; if (cc.fx.GameConfig.GM_INFO.tasks.share.value < cc.fx.GameConfig.GM_INFO.tasks.share.target) { @@ -1376,6 +1597,15 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 打开每日任务方法 + // 功能:创建并显示每日任务界面 + // 何时调用:点击任务按钮或分享成功后调用 + // 参数说明: + // - event:点击事件 + // - customEventData:自定义事件数据 + // - share:是否来自分享回调 + // ============================================ openDailyQuests(event?: cc.Event, customEventData?: string, share?: boolean) { let eventName = ""; let btnName = "" @@ -1459,32 +1689,56 @@ export default class JiaZai extends cc.Component { }) } - // 关闭商店 + // ============================================ + // 关闭商店方法 + // 功能:隐藏商店界面 + // 何时调用:点击关闭按钮或完成购买时调用 + // ============================================ closeShop() { if (this.shopNode) { this.shopNode.active = false; } } - + // ============================================ + // 关闭排名方法 + // 功能:隐藏排名界面 + // 何时调用:点击关闭按钮时调用 + // ============================================ closeRank() { this.node.getChildByName("Rank").active = false; } - + // ============================================ + // 打开排名方法 + // 功能:显示排名界面 + // 何时调用:点击排名按钮时调用 + // ============================================ openRank() { this.node.getChildByName("Rank").active = true; } - + // ============================================ + // 打开奖励方法 + // 功能:显示奖励界面 + // 何时调用:点击奖励按钮时调用 + // ============================================ openReward() { this.node.getChildByName("Reward").active = true; } - + // 点击商店 clickShop() { // 假设已经获取到了 userId 和 productId } - + // ============================================ + // 打开暂停方法 + // 功能:显示暂停菜单界面 + // 何时调用:点击暂停按钮时调用 + // 主要功能: + // 1. 播放按钮音效 + // 2. 显示暂停节点 + // 3. 显示玩家OpenID + // ============================================ openPause() { cc.fx.AudioManager._instance.playEffect("anniu_little", null); //console.log(cc.fx.GameConfig.GM_INFO); @@ -1495,12 +1749,25 @@ export default class JiaZai extends cc.Component { this.node.getChildByName("Pause").active = true; this.node.getChildByName("Pause").getChildByName("openID").getComponent(cc.Label).string = cc.fx.GameConfig.GM_INFO.openid; } - + // ============================================ + // 关闭暂停方法 + // 功能:隐藏暂停菜单界面 + // 何时调用:点击继续按钮时调用 + // ============================================ closePause() { cc.fx.AudioManager._instance.playEffect("anniu_little", null); this.node.getChildByName("Pause").active = false; } - + // ============================================ + // 打开设置方法 + // 功能:显示设置界面 + // 何时调用:点击设置按钮时调用 + // 防抖处理:0.3秒内禁止重复点击 + // 主要功能: + // 1. 播放按钮音效 + // 2. 显示设置节点 + // 3. 播放设置动画 + // ============================================ openSet() { const now = Date.now(); if (now - this.lastPauseClickTime < 300) { @@ -1521,27 +1788,55 @@ export default class JiaZai extends cc.Component { this.setUi.active = false; } } - + // ============================================ + // 关闭奖励方法 + // 功能:隐藏奖励界面 + // 何时调用:点击关闭按钮时调用 + // ============================================ closeReward() { this.node.getChildByName("Reward").active = false; } + // ============================================ + // 打开体力界面方法 + // 功能:显示体力购买界面 + // 何时调用:点击体力按钮时调用 + // ============================================ openStamina() { this.node.getChildByName("Stamina").active = true; } - + // ============================================ + // 关闭体力界面方法 + // 功能:隐藏体力购买界面 + // 何时调用:点击关闭按钮时调用 + // ============================================ closeStamina() { this.node.getChildByName("Stamina").active = false; } - + // ============================================ + // 更新金币显示方法 + // 功能:将当前金币数量转换为图片显示 + // 何时调用:金币变化时调用 + // 主要功能: + // 1. 获取当前金币数量 + // 2. 使用数字转图片工具显示 + // ============================================ updateCoin() { //console.log("主页更新金币", cc.fx.GameConfig.GM_INFO.coin); // NumberToImage.numberToImageNodes(cc.fx.GameConfig.GM_INFO.coin, 30, 15, "coin_", this.coin, true); if (this.coin) NumberToImage.numberToImageNodes5(cc.fx.GameConfig.GM_INFO.coin, 30, 15, "Black", this.coin, true); } - + // ============================================ + // 获取订单方法 + // 功能:检查是否有未处理的订单进行补发 + // 何时调用:进入主界面时调用 + // 平台判断:仅在微信小游戏或头条小游戏环境中生效 + // 主要功能: + // 1. 获取支付订单 + // 2. 处理补发逻辑 + // ============================================ getOrder() { //@ts-ignore if ((typeof wx !== 'undefined' && wx !== null) || (typeof tt !== 'undefined' && tt !== null)) { @@ -1678,13 +1973,28 @@ export default class JiaZai extends cc.Component { } } - + // ============================================ + // 打开加载界面方法 + // 功能:显示加载界面并播放旋转动画 + // 何时调用:开始加载资源时调用 + // 主要功能: + // 1. 显示加载节点 + // 2. 播放loading旋转动画 + // ============================================ openLoad() { this.node.getChildByName("Loading").active = true; this.node.getChildByName("Loading").getChildByName("load").stopAllActions(); this.node.getChildByName("Loading").getChildByName("load").runAction(cc.rotateTo(2, 1080).repeatForever()); } - + // ============================================ + // 打开加载界面2方法 + // 功能:显示加载界面(带每日任务状态检测) + // 何时调用:开始加载资源时调用 + // 主要功能: + // 1. 显示加载节点 + // 2. 播放loading旋转动画 + // 3. 加载完成后检测是否显示每日任务 + // ============================================ openLoad2() { this.node.getChildByName("Loading").active = true; this.node.getChildByName("Loading").getChildByName("load").stopAllActions(); @@ -1696,13 +2006,33 @@ export default class JiaZai extends cc.Component { } }, 5000); } - + // ============================================ + // 关闭加载界面方法 + // 功能:隐藏加载界面 + // 何时调用:加载完成时调用 + // ============================================ closeLoad() { this.node.getChildByName("Loading").active = false; } + + + // ============================================ + // 关闭加载界面2方法 + // 功能:隐藏加载界面 + // 何时调用:加载完成时调用 + // ============================================ closeLoad2() { this.node.getChildByName("Loading").active = false; } + // ============================================ + // 更新体力方法 + // 功能:更新体力显示状态 + // 何时调用:体力变化时调用 + // 主要功能: + // 1. 检测无限体力状态 + // 2. 体力未满时启动恢复计时 + // 3. 更新体力标签显示 + // ============================================ updatePower() { if (cc.fx.GameConfig.GM_INFO.userPowerTime != 0) { let nowTime = Math.floor(Date.now() / 1000); @@ -1733,8 +2063,11 @@ export default class JiaZai extends cc.Component { } } - //月卡 - //打开界面 + // ============================================ + // 打开月卡方法 + // 功能:显示月卡购买界面 + // 何时调用:点击月卡按钮时调用 + // ============================================ openMonthCard() { this.openMonthlyCard(); // this.monthCard.active = true; @@ -1750,6 +2083,15 @@ export default class JiaZai extends cc.Component { // }) } + // ============================================ + // 打开通行证方法 + // 功能:创建并显示通行证预制体 + // 何时调用:点击通行证按钮或满足条件时调用 + // 参数说明: + // - event:点击事件 + // - customEventData:自定义事件数据 + // ============================================ + // 打开通行证弹窗 openStarter_pack(event?: cc.Event, customEventData?: string) { if (!JiaZai.cachedActionPrefab) { let eventName = ""; @@ -1820,13 +2162,25 @@ export default class JiaZai extends cc.Component { wx.offHide(this.onHideListener); } } - + // ============================================ + // 关闭通行证方法 + // 功能:隐藏通行证界面 + // 何时调用:点击关闭按钮时调用 + // ============================================ closeStarter_pack() { if (this.actionpNode) { this.actionpNode.active = false; } } - + // ============================================ + // 开始通行证倒计时方法 + // 功能:启动通行证时间监控 + // 何时调用:打开通行证界面时调用 + // 主要功能: + // 1. 先停止之前的计时器 + // 2. 每秒检查一次通行证剩余时间 + // 3. 到期后停止计时 + // ============================================ startStarter_pack() { this.stopStarter_pack(); if (this.scheduleCallback3) { @@ -1868,7 +2222,11 @@ export default class JiaZai extends cc.Component { }.bind(this); this.schedule(this.scheduleCallback3, 1); } - + // ============================================ + // 停止通行证倒计时方法 + // 功能:停止通行证时间监控 + // 何时调用:通行证到期或不需要时调用 + // ============================================ stopStarter_pack() { if (this.scheduleCallback3) { this.unschedule(this.scheduleCallback3); @@ -1876,6 +2234,15 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 打开分享方法 + // 功能:处理分享逻辑并显示加载 + // 何时调用:点击分享按钮时调用 + // 主要功能: + // 1. 显示加载界面 + // 2. 获取分享信息(昵称、头像、关卡) + // 3. 调用分享接口 + // ============================================ openShare() { console.log("打开加载2"); this.openLoad(); @@ -1953,7 +2320,15 @@ export default class JiaZai extends cc.Component { } }) } - + // ============================================ + // 领取月卡奖励方法 + // 功能:检查并领取月卡每日奖励 + // 何时调用:进入主界面时调用 + // 主要功能: + // 1. 获取月卡奖励状态 + // 2. 更新体力上限 + // 3. 处理月卡过期逻辑 + // ============================================ rewarded() { Utils.monthGetReward((data) => { if (data.data == null) { @@ -2000,8 +2375,14 @@ export default class JiaZai extends cc.Component { }) } - - //缓存弹窗 + // ============================================ + // 月卡信息缓存方法 + // 功能:检查并缓存月卡信息,使用缓存控制弹窗显示 + // 何时调用:在onLoad中调用 + // 主要功能: + // 1. 获取月卡状态 + // 2. 使用缓存控制每天只弹一次月卡弹窗 + // ============================================ monthH() { // return; //如果没有充值月卡,每天弹一次月卡弹窗用缓存实现 @@ -2032,7 +2413,13 @@ export default class JiaZai extends cc.Component { } - //检查是否弹出新手礼包 + // ============================================ + // 检查新手礼包方法 + // 功能:检测是否需要弹出新手礼包 + // 何时调用:在onLoad中调用 + // 触发条件:关卡达到15级后检测 + // 主要功能:使用缓存控制每天只弹一次 + // ============================================ checkStarter_pack() { // return; //如果没有充值新手礼包,每天弹一次新手礼包 @@ -2133,7 +2520,15 @@ export default class JiaZai extends cc.Component { } - //获取有没有分享信息 + // ============================================ + // 获取分享信息方法 + // 功能:从微信启动参数中获取分享人的关卡和UID + // 何时调用:在onLoad中调用 + // 主要功能: + // 1. 获取启动参数 + // 2. 解析分享人信息 + // 3. 保存分享人数据 + // ============================================ getShareInfo() { // 检查微信小游戏启动参数 if (cc.sys.platform === cc.sys.WECHAT_GAME) { @@ -2165,11 +2560,18 @@ export default class JiaZai extends cc.Component { } } } - + // 关闭月卡奖励弹窗 onCardReward() { this.getcard.active = false; } - + // ============================================ + // 设置音乐方法 + // 功能:设置游戏音乐开关状态 + // 何时调用:在onLoad中调用 + // 主要功能: + // 1. 获取微信用户设置 + // 2. 设置音乐开关状态 + // ============================================ setFirstMusic() { const group = cc.fx.GameTool.setWechatGameGroup(2); if (group == 0) { @@ -2187,7 +2589,15 @@ export default class JiaZai extends cc.Component { } - //检测当日是否有分享行为,用不用主动获取分享关卡信息 + // ============================================ + // 检测分享方法 + // 功能:检测当日是否有分享行为 + // 何时调用:在onLoad中调用 + // 主要功能: + // 1. 获取缓存的分享信息 + // 2. 检测是否超过24小时 + // 3. 更新分享状态 + // ============================================ checkShare() { const otherInfo = cc.fx.StorageMessage.getStorage("otherLevel"); // console.log("分享信息:", otherInfo); @@ -2248,7 +2658,12 @@ export default class JiaZai extends cc.Component { } - //购买月卡 + // ============================================ + // 购买月卡方法 + // 功能:调用支付接口购买月卡 + // 何时调用:点击购买月卡按钮时调用 + // 参数说明:id为月卡类型ID + // ============================================ buyMonthCard(id) { Utils.setMonthlyCard(0, (data) => { // console.log("购买月卡", data.code); @@ -2290,12 +2705,22 @@ export default class JiaZai extends cc.Component { // update (dt) {} } + // ============================================ + // 设置分享信息方法 + // 功能:调用SDK分享到好友 + // 何时调用:需要分享时调用 + // ============================================ setShareInfo() { // console.log("设置分享信息"); MiniGameSdk.API.shareAppToFriends(); } - //检查任务列表 + // ============================================ + // 检查任务列表方法 + // 功能:获取并更新任务状态显示 + // 何时调用:在onLoad中调用 + // 主要功能:更新任务红点和进度显示 + // ============================================ checkTasks() { let top = this.node.getChildByName("Load").getChildByName("Top"); top.getChildByName("day").getChildByName("red").active = false; @@ -2334,6 +2759,12 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 打开胜利弹窗方法 + // 功能:显示胜利界面 + // 何时调用:游戏胜利时调用 + // 触发条件:连胜显示开关打开且关卡>=17级 + // ============================================ openWin() { if (this.winStreakShow == false || cc.fx.GameConfig.GM_INFO.level < 17) { return; @@ -2359,7 +2790,11 @@ export default class JiaZai extends cc.Component { } this.openWinStreak(); } - //打开连胜活动 + // ============================================ + // 打开连胜活动方法 + // 功能:创建并显示连胜活动预制体 + // 何时调用:点击连胜活动按钮时调用 + // ============================================ openWinStreak(event?: cc.Event, customEventData?: string) { let eventName = ""; let btnName = "" @@ -2419,6 +2854,14 @@ export default class JiaZai extends cc.Component { this.winStreakNode.getComponent("WinStreak").init(); } } + // ============================================ + // 检查通行证购买状态方法 + // 功能:检测是否需要补发通行证 + // 何时调用:在onLoad中调用 + // 主要功能: + // 1. 获取通行证激活状态 + // 2. 需要补发时调用补发方法 + // ============================================ passCheckBuyState() { let passCheckActivate = cc.fx.StorageMessage.getStorage("PassCheckActivate"); if (passCheckActivate) { @@ -2428,6 +2871,15 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 补发通行证方法 + // 功能:处理通行证购买后的补发逻辑 + // 何时调用:检测到未完成的购买时调用 + // 主要功能: + // 1. 设置通行证激活状态 + // 2. 缓存购买参数 + // 3. 从服务器获取通行证信息 + // ============================================ reissuePaaCheck() { cc.fx.GameConfig.GM_INFO.passCheckActivate = true; // 本地缓存一个购买通行证参数 如果没有给服务器发送成功,后续进入再发 过期自动清空 @@ -2465,6 +2917,7 @@ export default class JiaZai extends cc.Component { }) } + // 弹出通行证弹窗 popUpPassCheck() { // console.log("弹出通行证", cc.fx.GameConfig.GM_INFO.popPassCheck) if (cc.fx.GameConfig.GM_INFO.popPassCheck) { @@ -2491,7 +2944,12 @@ export default class JiaZai extends cc.Component { } } - + // ============================================ + // 打开通行证弹窗方法 + // 功能:创建并显示通行证预制体 + // 何时调用:点击通行证按钮时调用 + // 预制体检测:确保预制体已加载 + // ============================================ openPassCheck(event?: cc.Event, customEventData?: string) { if (!JiaZai.cachedPassCheckPrefab) { console.error('PassCheck prefab is not loaded yet.') @@ -2594,6 +3052,15 @@ export default class JiaZai extends cc.Component { } + // ============================================ + // 清空通行证数据方法 + // 功能:重置通行证进度和数据 + // 何时调用:需要重置通行证时调用 + // 主要功能: + // 1. 清空服务器通行证数据 + // 2. 重置本地通行证等级 + // 3. 清空缓存的进度 + // ============================================ qinglishuju() { let passCheck = null; Utils.setPassCheckInfo(() => { @@ -2604,6 +3071,15 @@ export default class JiaZai extends cc.Component { }, passCheck) } + // ============================================ + // 设置通行证进度方法 + // 功能:从服务器获取通行证数据并更新本地进度 + // 何时调用:进入主界面或通行证状态变化时调用 + // 主要功能: + // 1. 获取通行证信息 + // 2. 解析通行证数据 + // 3. 更新本地通行证等级 + // ============================================ setPassProgress() { Utils.getPassCheckInfo((res) => { if (res.code === 1) { @@ -2717,6 +3193,12 @@ export default class JiaZai extends cc.Component { // console.log("进度", cc.fx.GameConfig.GM_INFO.getProgressLevel, cc.fx.GameConfig.GM_INFO.getProgress); } + // ============================================ + // 检查通行证等级方法 + // 功能:检测并设置玩家通行证等级 + // 何时调用:进入主界面时调用 + // 触发条件:关卡达到21级时记录通行证等级 + // ============================================ checkAndSetPlayerPassLevel() { const currentLevel = cc.fx.GameConfig.GM_INFO.level; // 判断是否已经记录过playerPassLevel,如果没有并且当前等级大于等于21级,则记录 @@ -2931,6 +3413,11 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 引导锤子动画方法 + // 功能:播放新手引导锤子动画 + // 何时调用:新玩家首次进入游戏时调用 + // ============================================ guideHammerAnimation() { if (this.node == undefined || this.node == null) { return; @@ -2960,6 +3447,11 @@ export default class JiaZai extends cc.Component { this.guideAnimation(hammer, guideSprNode); } + // ============================================ + // 引导通行证动画方法 + // 功能:播放新手引导通行证动画 + // 何时调用:新玩家首次进入游戏时调用 + // ============================================ guidePassCheckAnimation() { // 检查节点是否存在 if (!this.node) { @@ -2994,6 +3486,15 @@ export default class JiaZai extends cc.Component { this.guideAnimation(passBtn, guideSprNode); } + + // ============================================ + // 引导动画方法 + // 功能:播放通用引导动画 + // 何时调用:引导过程中调用 + // 参数说明: + // - endNode:目标节点 + // - guideSprNode:引导精灵节点 + // ============================================ guideAnimation(endNode, guideSprNode) { let timeout = 0; if (this.guideInProgress) { @@ -3035,12 +3536,22 @@ export default class JiaZai extends cc.Component { }, timeout); } + // ============================================ + // 关闭通行证弹窗方法 + // 功能:关闭通行证界面并检查通行证等级 + // 何时调用:点击关闭按钮时调用 + // ============================================ closePassCheck() { // console.log("关闭过时数据", cc.fx.GameConfig.GM_INFO.getItemType) this.checkAndSetPlayerPassLevel(); } - //获取入职排行榜 + // ============================================ + // 获取S级排行榜方法 + // 功能:从服务器获取S级排名数据 + // 何时调用:需要显示排行榜时调用 + // 参数说明:isShow是否显示排行榜 + // ============================================ getSRank(isShow: boolean = true) { // console.log("_________________________重新获取排行"); if (this.RankNode == null && this.RankNode == undefined) { @@ -3155,6 +3666,15 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 添加自己到排行榜方法 + // 功能:将当前玩家添加到排行榜数据中 + // 何时调用:获取排行榜后调用 + // 主要功能: + // 1. 处理头像和昵称 + // 2. 计算排名位置 + // 3. 插入自己到排名列表 + // ============================================ addSelfToRank(rankData) { let rankingData = []; let self = false; @@ -3210,6 +3730,11 @@ export default class JiaZai extends cc.Component { // console.log("修改后", rankData); } + // ============================================ + // 设置排行榜数据方法 + // 功能:处理排行榜数据并添加玩家自己 + // 何时调用:获取排行榜数据后调用 + // ============================================ setRankData() { if (this.careerRank) { if (this.careerRank.rankData) { @@ -3252,7 +3777,7 @@ export default class JiaZai extends cc.Component { // console.log("rankData更新!!!!!!!!", this.careerRank.rankData); } - + // 加载入职排行榜预制体 LoadCareer(callback: () => void, isShow: boolean = true) { cc.assetManager.loadBundle('career', (err: Error, bundle: cc.AssetManager.Bundle) => { if (err) { @@ -3275,6 +3800,11 @@ export default class JiaZai extends cc.Component { }); } + // ============================================ + // 打开位置弹窗方法 + // 功能:显示排行榜中的省份位置信息 + // 何时调用:点击位置按钮时调用 + // ============================================ openPosition() { if (this.RankNode) { if (this.RankNode.getChildByName("ScrollView")) { @@ -3329,7 +3859,15 @@ export default class JiaZai extends cc.Component { } - //授权位置信息 + // ============================================ + // 定位授权方法 + // 功能:获取微信位置授权并获取省份信息 + // 何时调用:需要获取玩家位置时调用 + // 主要功能: + // 1. 获取位置授权 + // 2. 获取经纬度 + // 3. 调用接口获取省份信息 + // ============================================ runAuthorize() { if (this.RankNode) { if (this.RankNode.getChildByName("ScrollView")) { @@ -3392,6 +3930,11 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 回到顶部方法 + // 功能:滚动列表回到顶部位置 + // 何时调用:点击回到顶部按钮时调用 + // ============================================ backTop() { // console.log("给用户移动到列表顶部"); let top = this.node.getChildByName("Load").getChildByName("Top"); @@ -3411,13 +3954,23 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 打开兑换码方法 + // 功能:显示兑换码输入界面 + // 何时调用:点击兑换码按钮时调用 + // ============================================ openRedeemCode() { let reddemCodeNode = cc.instantiate(this.reddemCodeNode); if (this.node && reddemCodeNode) this.node.addChild(reddemCodeNode); } - // 困难关卡显示紫色图标 + // ============================================ + // 特殊关卡显示方法 + // 功能:困难关卡显示紫色图标 + // 何时调用:在start中调用 + // 特殊关卡:关卡100、200、300等整百关卡 + // ============================================ specialLevelShow() { let startBtn = this.node.getChildByName("Load").getChildByName("startBtn") startBtn.getChildByName("difficultySpr").active = false; @@ -3434,6 +3987,12 @@ export default class JiaZai extends cc.Component { } } + // ============================================ + // 无尽关卡显示方法 + // 功能:无尽模式关卡显示相应图标 + // 何时调用:在start中调用 + // 无尽模式:关卡达到最大值后解锁 + // ============================================ endlessLevelShow() { const currentLevel = cc.fx.GameConfig.GM_INFO.level; let levelNode = this.node.getChildByName("Load").getChildByName("levelNode"); @@ -3482,6 +4041,12 @@ export default class JiaZai extends cc.Component { + // ============================================ + // Cocos生命周期 - update方法 + // 功能:每帧执行更新逻辑 + // 何时调用:每帧自动调用 + // 主要功能:检测新手礼包弹窗是否显示,隐藏月卡弹窗 + // ============================================ update(dt) { if (this.newbieGift && this.monthlyCardNode) { if (this.monthlyCardNode.active == true) { diff --git a/assets/Script/Map.ts b/assets/Script/Map.ts index 4a4a01e..e66d77d 100644 --- a/assets/Script/Map.ts +++ b/assets/Script/Map.ts @@ -197,6 +197,19 @@ export default class MapConroler extends cc.Component { questionArray: any[]; blocks2: any[]; + // ============================================ + // Cocos生命周期 - onLoad方法 + // 功能:场景加载时初始化游戏控制器 + // 何时调用:Map场景节点加载到场景时自动调用 + // 主要初始化内容: + // 1. 设置游戏配置(场景值、云关卡、审核状态等) + // 2. 初始化各种数组(方块、墙壁、门、花瓣等) + // 3. 初始化游戏状态(游戏结束、游戏胜利等标志) + // 4. 设置帧率(63帧) + // 5. 播放转场动画 + // 6. 获取场景管理器引用 + // 7. 获取城市排行榜数据 + // ============================================ onLoad() { //以下为检验关卡 // console.log("当前关卡", cc.fx.GameConfig.GM_INFO.level); @@ -309,6 +322,18 @@ export default class MapConroler extends cc.Component { }, cc.fx.GameConfig.GM_INFO.address); } + + + // ============================================ + // Cocos生命周期 - start方法 + // 功能:场景首次激活时预加载资源和初始化地图 + // 何时调用:场景第一次激活时自动调用(在onLoad之后) + // 主要功能: + // 1. 预加载HomeScene场景(1秒后开始) + // 2. 从GameManager获取预制体和精灵图集引用 + // 3. 调用initMap初始化地图 + // 注意事项:广告预加载代码已被注释 + // ============================================ start() { setTimeout(() => { cc.director.preloadScene("HomeScene", (err, asset) => { @@ -337,7 +362,21 @@ export default class MapConroler extends cc.Component { // } // }); } - //道具数量 + // ============================================ + // 设置道具数量显示方法 + // 功能:根据玩家拥有的道具数量更新UI显示 + // 何时调用:在onLoad中调用,初始化道具显示 + // 处理逻辑: + // 1. 冻结道具数量:如果大于0显示数量,否则显示"mul10"图标 + // 2. 锤子道具数量:同上 + // 3. 魔法棒道具数量:同上 + // 4. 道具锁定状态: + // - 1-7关:所有道具锁定 + // - 8-10关:只有锤子解锁 + // - 11-15关:锤子和冻结解锁 + // - 16关之后:所有道具解锁 + // 5. 首次使用标记:如果某个道具首次使用,显示特殊标记 + // ============================================ setPropNum() { //如果道具数量大于0,显示 cc.fx.GameConfig.GM_INFO.freezeAmount,如果为零显示'mul10' @@ -441,6 +480,22 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 开始游戏计时方法 + // 功能:玩家第一次点击方块时触发,开始游戏倒计时 + // 何时调用:玩家第一次点击方块时(blockInit后方块可交互时) + // 主要功能: + // 1. 处理冰冻状态:如果冰冻生效则直接返回 + // 2. 处理回放状态:开始回放时也启动计时 + // 3. 标记游戏已开始(gameStart=true) + // 4. 检查体力状态,扣除体力 + // 5. 更新每日任务进度(使用体力任务) + // 6. 记录游戏开始时间 + // 7. 发送游戏进入事件 + // 8. 处理连胜状态判断(10连胜以上进入狂热模式) + // 9. 处理无限关卡模式 + // 10. 发送游戏开始事件到服务器 + // ============================================ startUpdate() { // 停止冰冻外圈特效 this.onBlockClick(); @@ -503,6 +558,21 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 地图初始化方法 + // 功能:初始化游戏地图,包括获取UI引用、加载关卡数据、初始化墙壁和方块 + // 何时调用:在start方法中调用 + // 主要功能: + // 1. 处理连胜按钮显示(10连胜以下隐藏) + // 2. 获取时间、关卡、金币UI节点引用 + // 3. 设置关卡时间并显示 + // 4. 更新金币显示 + // 5. 设置关卡名称显示 + // 6. 获取关卡配置数据 + // 7. 初始化地图尺寸 + // 8. 调用wallInit初始化墙壁 + // 9. 调用blockInit初始化方块 + // ============================================ initMap() { if (cc.fx.GameConfig.GM_INFO.winStreak < 10 || cc.fx.GameConfig.GM_INFO.otherLevel > 0) { @@ -694,7 +764,21 @@ export default class MapConroler extends cc.Component { } - + // ============================================ + // 方块初始化方法 + // 功能:根据关卡配置创建所有方块 + // 何时调用:在initMap中调用 + // 主要功能: + // 1. 获取方块配置数据 + // 2. 检测是否有可移动地板块 + // 3. 对方块进行排序 + // 4. 使用分帧创建避免卡顿(每帧创建1-10个方块) + // 5. 为每个方块设置初始化参数(类型、颜色、位置等) + // 6. 处理粘合块队伍的初始化 + // 7. 处理可移动地板块队伍的初始化 + // 8. 播放方块创建音效 + // 性能优化:使用分帧创建,避免一次性创建大量方块导致卡顿 + // ============================================ blockInit() { let blockArray = cc.fx.GameConfig.BLOCK_INFO[0]; for (let i = 0; i < blockArray.length; i++) { @@ -835,7 +919,16 @@ export default class MapConroler extends cc.Component { // 开始分帧创建方块 createBlocks(); } - //给创建方块排序,用来降低drawcall 合批 + // ============================================ + // 方块排序方法(降低DrawCall优化) + // 功能:对方块数组进行排序,使相同属性的方块相邻,提高渲染效率 + // 何时调用:在blockInit中调用 + // 参数说明:allBlocks - 包含color、block、type、floor属性的方块数组 + // 排序规则: + // 1. 如果是可移动地板块关卡,按floor分组(相同floor的排在一起) + // 2. 否则按color、block、type排序 + // DrawCall优化说明:相同纹理的方块排在一起可以减少渲染切换 + // ============================================ sortBlock(allBlocks: { color: number; block: number; type: number; floor: number }[]) { return allBlocks.sort((a, b) => { // 最高优先级:如果a或者b有一个有floor,则不打乱有floor的排序 @@ -897,7 +990,13 @@ export default class MapConroler extends cc.Component { }); } - //给变色方块组队 + // ============================================ + // 变色方块组队方法 + // 功能:将颜色互补的变色方块配对,使它们能互相切换颜色 + // 何时调用:在blockInit中方块创建完成后调用 + // 配对规则:如果方块A的颜色序列是[红,绿],方块B的颜色序列是[绿,红],则它们互为互补 + // 配对效果:当其中一个方块被消除时,另一个方块会切换到自己的下一个颜色 + // ============================================ addChangeBlock() { let changeBlock = this.blocks.filter(block => block.getComponent("Block").type == 20 || (block.getComponent("Block").block_Info.colorArray != undefined && block.getComponent("Block").block_Info.colorArray != null)); @@ -922,8 +1021,18 @@ export default class MapConroler extends cc.Component { } } - //创建墙壁 - + // ============================================ + // 墙壁初始化方法 + // 功能:根据关卡配置创建所有墙壁 + // 何时调用:在initMap中调用 + // 主要功能: + // 1. 使用分帧创建避免卡顿(每帧创建1-10个墙壁) + // 2. 获取墙壁方向(根据位置判断是上、下、左、右墙) + // 3. 调用createWall创建墙壁并设置类型 + // 4. 墙壁类型包括:普通墙、旋转门、跳跃门、伸缩门、变色墙等 + // 5. 调用createCornerNodes创建墙角装饰 + // 性能优化:使用分帧创建,与blockInit类似的优化策略 + // ============================================ wallInit() { let index = 0; // 当前要创建的墙壁索引 let WALLS_PER_FRAME = 1; // 初始每帧创建的墙壁数量 @@ -976,6 +1085,17 @@ export default class MapConroler extends cc.Component { // ... 已有代码 ... + // ============================================ + // 获取墙壁方向方法 + // 功能:根据周围格子状态判断墙壁的开口方向 + // 何时调用:在wallInit中为每个墙壁调用 + // 参数说明: + // - type:墙壁类型("wall"或其他) + // - pointA:墙壁的坐标位置 + // 返回值:墙壁方向数组,如["left", "right"]表示左右通透 + // 缺角处理:如果墙壁某侧被标记为opacity=249,表示该侧是缺角,不算作有效连接 + // 墙角处理:如果检测到是墙角位置,返回null跳过创建 + // ============================================ getWllDiraction(type, pointA) { let dir = []; let pointB = cc.v2(pointA.x + 1, pointA.y); @@ -1087,7 +1207,13 @@ export default class MapConroler extends cc.Component { } } - //创建角落填补方块 + // ============================================ + // 创建墙角装饰节点方法 + // 功能:为墙壁拐角处创建装饰性填补方块,使视觉效果更完整 + // 何时调用:在wallInit所有墙壁创建完成后调用 + // 装饰位置:墙壁的拐角处(opacity=250的位置) + // 视觉效果:填补墙壁之间的空隙,使地图看起来更完整 + // ============================================ createCornerNodes() { // 定义拐角位置 for (let i = 0; i < this.wallInfo.length; i++) { @@ -1104,7 +1230,13 @@ export default class MapConroler extends cc.Component { } } - //给墙壁数组排序,方便管理 + // ============================================ + // 墙壁排序方法 + // 功能:按照关卡配置中的编号对墙壁数组进行排序,方便管理和查找 + // 何时调用:在wallInit中创建完所有墙壁后调用 + // 与sortBlock的区别:sortBlock优化DrawCall,这个方法优化墙壁的管理和查找 + // 用途:确保墙壁按照配置顺序排列,便于后续门的管理 + // ============================================ sortWall() { let doorInfo = cc.fx.GameConfig.WALL_INFO[0]; for (let i = 0; i < doorInfo.length; i++) { @@ -1124,7 +1256,27 @@ export default class MapConroler extends cc.Component { } } - //创建普通门和墙壁 + // ============================================ + // 创建墙壁/门方法 + // 功能:根据方向创建墙壁或门,并设置到对应的数组中 + // 何时调用:在wallInit中调用 + // 参数说明: + // - direction:墙壁方向("right", "left", "top", "bottom") + // - node:墙壁节点 + // 创建逻辑: + // 1. 根据方向设置墙壁开口方向 + // 2. 实例化对应的墙壁预制体 + // 3. 根据墙壁类型设置特殊属性(开关门、旋转门、跳跃门等) + // 4. 添加到对应的数组中进行管理 + // 墙壁类型数组: + // - leftDoors/rightDoors/topDoors/bottomDoors:四面门 + // - openWall:开关门 + // - freezeWall:冻结门 + // - lockWall:锁门 + // - revolvingWallArray:旋转门 + // - jumpWallArray:跳跃门 + // - stickWallArray:伸缩门 + // ============================================ createWall(direction, node) { let wall = null; let wall2 = null; @@ -1308,7 +1460,17 @@ export default class MapConroler extends cc.Component { // } } - //设置门的信息 + // ============================================ + // 设置门信息方法 + // 功能:从关卡配置中读取门的信息并设置到墙壁组件上 + // 何时调用:在createWall中调用 + // 参数说明:wall - 墙壁节点 + // 设置内容: + // 1. special:特殊类型(4=开关门, 10=冻结门等) + // 2. team:队伍编号(用于变色门) + // 3. color:颜色(用于变色门) + // 4. 开关门和冻结门的特殊属性 + // ============================================ setDoorInfo(wall) { let doorInfo = cc.fx.GameConfig.WALL_INFO[0]; if (doorInfo) { @@ -1331,7 +1493,16 @@ export default class MapConroler extends cc.Component { } } - //创建拐角墙壁 + // ============================================ + // 创建拐角墙壁方法 + // 功能:为墙壁拐角处创建L形的拐角墙壁节点 + // 何时调用:在createCornerNodes中调用 + // 参数说明: + // - direction:拐角类型("upright", "rightup", "downright", "rightdown"等) + // - node:墙壁节点(用于获取位置) + // - posX, posY:墙壁的网格坐标 + // 拐角类型:L形墙壁有4种旋转方向,表示不同的拐角形状 + // ============================================ createTurn(direction, node, posX, posY) { let wall = null; wall = cc.instantiate(this.wallTurnPrefab); @@ -1394,7 +1565,17 @@ export default class MapConroler extends cc.Component { } - //创建跳跃门设置功能 + // ============================================ + // 创建跳跃门方法 + // 功能:创建跳跃门及其对应的传送目标 + // 何时调用:在wallInit中处理跳跃门类型时调用 + // 跳跃门机制: + // 1. 从关卡配置中读取跳跃门信息 + // 2. 找出每个跳跃门的传送目标(成对的跳跃门) + // 3. 将配对的跳跃门添加到一个小组 + // 4. 每对跳跃门共享传送目标信息 + // special类型说明:special=2表示跳跃门 + // ============================================ createJumpWall() { // 第一步:将数组分为N个小数组,每个小数组以length不为0的元素开头 let wallTemp = []; @@ -1460,6 +1641,13 @@ export default class MapConroler extends cc.Component { // console.log("排序后的WALL_INFO数组:", this.jumpWallArray); } + // ============================================ + // 跳跃门动作方法(已废弃) + // 功能:控制跳跃门的传送动画 + // 何时调用:已废弃,不再使用 + // 废弃原因:代码逻辑已被重构,现在使用新的跳跃门实现方式 + // 注意:这个方法的内容已被注释,不再执行任何操作 + // ============================================ jumpWallAction(startPos, endPos, wall) { // debugger; // let startWall = this.jumpWallArray[startPos][0].getChildByName("revolving"); @@ -1495,7 +1683,16 @@ export default class MapConroler extends cc.Component { } - //创建旋转门设置功能 + // ============================================ + // 创建旋转门方法 + // 功能:创建旋转门及其旋转动画 + // 何时调用:在wallInit中处理旋转门类型时调用 + // 旋转门机制: + // 1. special=1表示旋转门 + // 2. 根据配置决定旋转方向(顺时针/逆时针) + // 3. 旋转门可以改变方向(toggle)来切换通行状态 + // 4. 支持变色旋转门(根据team决定旋转哪一侧的门) + // ============================================ createRevolvingWall() { // 第一步:将数组分为N个小数组,每个小数组以length不为0的元素开头 let wallTemp = []; @@ -1550,6 +1747,20 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 旋转门动作方法 + // 功能:控制旋转门的旋转动画和状态切换 + // 何时调用:当方块触碰到旋转门时调用 + // 参数说明: + // - startPos:起始旋转门组索引 + // - endPos:目标旋转门组索引 + // - wall:墙壁节点 + // 动画逻辑: + // 1. 获取起始和目标旋转门的旋转角度 + // 2. 计算旋转动画的目标角度 + // 3. 使用补间动画实现平滑旋转 + // 4. 旋转完成后切换门的通行状态 + // ============================================ revolvingWallAction(startPos, endPos, wall) { let startWall = this.revolvingWallArray[startPos][0].getChildByName("revolving"); let startLength = this.revolvingWallArray[startPos][0].getChildByName("wall").getComponent("Wall").wall_Info.length; @@ -1588,6 +1799,16 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 旋转门变色动作方法 + // 功能:控制变色旋转门的旋转动画和颜色切换 + // 何时调用:当方块触碰到变色旋转门时调用 + // 与revolvingWallAction区别:这个方法处理的是变色旋转门,会在旋转时切换门的颜色 + // 参数说明: + // - startPos:起始旋转门组索引 + // - endPos:目标旋转门组索引 + // - wall:墙壁节点 + // ============================================ revolvingColorWallAction(startPos, endPos, wall) { let startWall = this.revolvingWallArray[startPos][0].getChildByName("revolving"); let startLength = this.revolvingWallArray[startPos][0].getChildByName("wall").getComponent("Wall").wall_Info.length; @@ -1628,7 +1849,15 @@ export default class MapConroler extends cc.Component { } - //地图底块缺口判断 + // ============================================ + // 地图底块缺口判断方法 + // 功能:判断指定位置是否是地图缺口(不可通行区域) + // 何时调用:在墙壁创建时判断某个位置是否可以放置墙壁 + // 参数说明: + // - point:网格坐标位置 + // - gap:缺口数组,包含所有不可放置墙壁的位置 + // 返回值:true表示不是缺口可以放置墙壁,false表示是缺口不能放置 + // ============================================ mapGap(point, gap) { for (let i = 0; i < gap.length; i++) { if (point.x == gap[i].x && point.y == gap[i].y) { @@ -1638,7 +1867,16 @@ export default class MapConroler extends cc.Component { return true; } - //升降地块判断 + // ============================================ + // 升降地块判断方法 + // 功能:判断指定位置是否是升降地块,并设置对应的显示状态 + // 何时调用:在墙壁创建时调用 + // 参数说明: + // - point:网格坐标位置 + // - risefall:升降地块配置数组 + // - block:墙壁节点 + // 视觉效果:根据配置显示上升或下降的地块图标 + // ============================================ mapRiseFall(point, risefall, block) { for (let i = 0; i < risefall.length; i++) { if (point.x == risefall[i].x && point.y == risefall[i].y) { @@ -1656,7 +1894,15 @@ export default class MapConroler extends cc.Component { } return false; } - //升降地块 + // ============================================ + // 改变升降地块状态方法 + // 功能:根据颜色和方向改变升降地块的显示状态 + // 何时调用:当需要切换升降地块的上升/下降状态时调用 + // 参数说明: + // - color:地块颜色(字符串) + // - down:true表示显示下降状态,false表示显示上升状态 + // 使用场景:通常与门的开关配合使用,门的颜色决定了触发哪个升降地块 + // ============================================ changeRiseFall(color, down) { color = color.toString(); for (let i = 0; i < this.riseFallBlcok.length; i++) { @@ -1673,7 +1919,15 @@ export default class MapConroler extends cc.Component { } } - //存放伸缩门所占用的地块 + // ============================================ + // 存放伸缩门地块方法 + // 功能:将伸缩门所占用的地块位置记录到地图中 + // 何时调用:在创建伸缩门时调用 + // 参数说明: + // - blockPos:伸缩门所占用的位置数组 + // - wall:伸缩门墙壁节点 + // 用途:用于判断伸缩门是否正在被占用,防止方块进入被伸缩门占据的位置 + // ============================================ pushStick_block(blockPos, wall) { for (let i = 0; i < blockPos.length; i++) { if (this.mapBlocksWall[blockPos[i].x][blockPos[i].y]) { @@ -1685,6 +1939,13 @@ export default class MapConroler extends cc.Component { wall.stickWallChange(false); } + // ============================================ + // 判断伸缩杆占用地块方法 + // 功能:判断指定位置是否被伸缩杆占用(不能落点) + // 何时调用:在方块移动前判断该位置是否可以落点 + // 参数说明:point - 网格坐标位置 + // 返回值:true表示可以落点,false表示被伸缩杆占用不能落点 + // ============================================ judgeStick(point) { if (this.stickWallArray.length == 0) return true; if (this.mapBlocksWall[point.x][point.y]) { @@ -1695,7 +1956,13 @@ export default class MapConroler extends cc.Component { return true; } - //查询叠加快id + // ============================================ + // 查询叠加块方法 + // 功能:根据blockId查找对应的方块节点 + // 何时调用:当需要通过blockId获取方块引用时调用 + // 参数说明:id - 方块的唯一标识ID + // 返回值:找到的方块节点,未找到返回null + // ============================================ foundDownBlock(id) { for (let i = 0; i < this.blocks.length; i++) { if (this.blocks[i].getComponent("Block").blockId == id) { @@ -1705,7 +1972,14 @@ export default class MapConroler extends cc.Component { return null; } - //删除块 + // ============================================ + // 删除块方法 + // 功能:根据blockId查找并返回对应的方块节点(用于删除) + // 何时调用:当需要删除某个方块时调用 + // 参数说明:id - 方块的唯一标识ID + // 返回值:找到的方块节点,未找到返回null + // 与foundDownBlock区别:这个方法用于删除操作,可能有副作用 + // ============================================ removeBlock(id) { for (let i = 0; i < this.blocks.length; i++) { if (this.blocks[i].getComponent("Block").blockId == id) { @@ -1715,6 +1989,14 @@ export default class MapConroler extends cc.Component { return null; } + // ============================================ + // 获取方块边界信息方法 + // 功能:计算方块在地图中的移动边界 + // 何时调用:在方块移动前获取其可移动范围 + // 参数说明:block - 方块节点 + // 返回值:包含minX、maxX、minY、maxY的边界对象 + // 边界计算:考虑方块大小、地图尺寸、以及地图边缘限制 + // ============================================ getMinAndMax(block) { let width = Math.floor(block.width / 120); let height = Math.floor(block.height / 120); @@ -1753,7 +2035,20 @@ export default class MapConroler extends cc.Component { return { minX: minX, maxX: maxX, minY: minY, maxY: maxY }; } - //检测落点是否可以消除 + // ============================================ + // 检测落点是否可以消除方法 + // 功能:判断方块移动到某位置后是否满足消除条件 + // 何时调用:在方块移动过程中调用 + // 参数说明: + // - node:当前方块节点 + // - blocks:所有可检测的方块数组 + // 检测内容: + // 1. 获取方块边界信息 + // 2. 获取方块当前坐标 + // 3. 遍历所有可检测方块 + // 4. 检查是否有同颜色方块在可消除范围内 + // 5. 返回可消除的方块数组 + // ============================================ checkPass(node, blocks) { let minAndMax = this.getMinAndMax(node); let minX = minAndMax.minX; @@ -1938,6 +2233,18 @@ export default class MapConroler extends cc.Component { return jg; } + // ============================================ + // 改变状态方法 + // 功能:当方块消除后,改变相关墙壁和方块的状态 + // 何时调用:当有方块被消除时调用 + // 参数说明: + // - type:消除类型 + // - node:被消除的方块节点 + // 状态改变内容: + // 1. 如果type存在,调用changeLockWall改变锁墙状态 + // 2. 调用changeBlockColor改变变色块颜色 + // 3. 调用changeAdhesive改变粘合块状态 + // ============================================ changeState(type, node) { if (type) { this.changeLockWall(); @@ -1948,6 +2255,13 @@ export default class MapConroler extends cc.Component { // console.log("粘合块处理完毕"); } + // ============================================ + // 冻结块状态变化方法 + // 功能:当有方块消除时,触发冻结门释放被冻结的墙壁 + // 何时调用:当有方块被消除时调用 + // 触发条件:freezeWall数组不为空 + // 延迟执行:使用setTimeout延迟执行,等待其他动画完成 + // ============================================ changeFreeze() { setTimeout(() => { if (this) { @@ -1964,6 +2278,13 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 锁块状态变化方法 + // 功能:当有方块消除时,触发锁墙释放被锁定的墙壁 + // 何时调用:当有方块被消除时调用 + // 触发条件:lockWall数组不为空 + // 延迟执行:使用setTimeout延迟执行,等待其他动画完成 + // ============================================ changeLock() { setTimeout(() => { if (this) { @@ -1981,6 +2302,13 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 粘合块状态变化方法 + // 功能:当有方块消除时,减少所有粘合块的粘合计数 + // 何时调用:当有方块被消除时调用 + // 触发条件:adhesiveBlock数组不为空 + // 处理逻辑:遍历所有粘合块,调用reduceAdhesive减少粘合计数 + // ============================================ changeAdhesive() { if (this.adhesiveBlock.length != 0) { for (let i = 0; i < this.adhesiveBlock.length; i++) { @@ -1990,6 +2318,16 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 方块颜色状态变化方法 + // 功能:当有方块消除时,触发变色块改变颜色 + // 何时调用:当有方块被消除时调用 + // 触发条件:change_colorBlock或change_Block为true + // 处理逻辑: + // 1. 查找所有type=10的变色块 + // 2. 如果变色块与消除的方块有绑定关系,触发颜色切换 + // 3. 调用Block组件的colorChange方法 + // ============================================ changeBlockColor(node) { if (this.change_colorBlock == false && this.change_Block == false) return; let colorBlock = this.node.children.filter(child => { @@ -2013,6 +2351,14 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 锁门状态变化方法 + // 功能:当有方块消除时,触发开关门切换状态 + // 何时调用:当有方块被消除时调用 + // 触发条件:openWall数组不为空 + // 音效:播放"lockDoor"音效 + // 延迟执行:使用setTimeout延迟执行,等待其他动画完成 + // ============================================ changeLockWall() { setTimeout(() => { if (this) { @@ -2030,6 +2376,16 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 爆炸块状态变化方法 + // 功能:当有方块消除时,触发炸弹块消除周围方块 + // 何时调用:当有方块被消除时调用 + // 触发条件:bombBlock为true + // 处理逻辑: + // 1. 查找所有type=17的炸弹块 + // 2. 触发炸弹块的爆炸效果 + // 3. 炸弹块会消除周围一定范围内的方块 + // ============================================ changeBoom(node) { if (this.bombBlock == false) return; let boomBlock = this.node.children.filter(child => { @@ -2046,7 +2402,7 @@ export default class MapConroler extends cc.Component { } - + //跳跃门状态变化 changeJumpWall() { //没有跳跃门,直接不处理 if (this.jump_state == null) { @@ -2086,6 +2442,7 @@ export default class MapConroler extends cc.Component { } } + //跳跃门改变后的长度变化 changeLength(wallArray) { setTimeout(() => { for (let i = 0; i < wallArray.length; i++) { @@ -2175,6 +2532,7 @@ export default class MapConroler extends cc.Component { } } + //自带锁方块的状态变化(可不可以消除状态) changeBlockLock() { if (this.blockLock == false) return; if (this.blockLock) { @@ -2193,6 +2551,7 @@ export default class MapConroler extends cc.Component { } } + //检测是否可以消除 checkBlockLock() { if (this.blockLock == false) return false; if (this.blockLock) { @@ -2209,7 +2568,7 @@ export default class MapConroler extends cc.Component { } } - + //长短门状态变化 changeLongAndShortWall() { //长短门状态变化 if (this.longAndShortWall.length != 0) { @@ -2224,6 +2583,7 @@ export default class MapConroler extends cc.Component { } } + //伸缩杆的门态变化 changeStickWall() { if (this.stickWallArray.length != 0) { for (let i = 0; i < this.stickWallArray.length; i++) { @@ -2232,13 +2592,26 @@ export default class MapConroler extends cc.Component { } } + //时间增加 addTime(time) { if (this.gameOver == true || this.timeNumber <= 0) return; this.timeNumber += time; NumberToImage.getTimeMargi3((this.timeNumber), 45, "company_", this.timeLabel) } - //检测是否可以通过门 + // ============================================ + // 检测是否可以通过门方法 + // 功能:判断方块是否可以穿过门 + // 何时调用:当方块移动到门的位置时调用 + // 参数说明: + // - jg:是否是对称门 + // - wallArray:门数组 + // - node:移动的方块节点 + // 通过条件: + // 1. 门是打开状态 + // 2. 门的颜色与方块颜色匹配(如果是变色门) + // 3. 门的长度设置允许通过 + // ============================================ passWall(jg, wallArray, node) { let colorArray = []; for (let i = 0; i < wallArray.length; i++) { @@ -2369,6 +2742,7 @@ export default class MapConroler extends cc.Component { } } + //暂时废弃 changeColorWall() { // for (let i = 0; i < this.wallArray.length; i++) { // if (this.wallArray[i].getComponent("Wall").colorArray.length > 0) { @@ -2377,7 +2751,16 @@ export default class MapConroler extends cc.Component { // } } - //检测方块和门中间有没有夹杂其他块 + // ============================================ + // 检测方块和门之间是否有夹杂方块方法 + // 功能:判断从门到方块之间的路径上是否有其他方块阻挡 + // 何时调用:在门打开时调用,判断方块是否可以穿过门 + // 参数说明: + // - direction:方向("horizontal"或"vertical") + // - posX, posY:目标方块的位置 + // - blocks:需要检测的所有方块数组 + // 返回值:jg=true表示可以通过,jg=false表示有阻挡 + // ============================================ detectingBlock(direction, posX, posY, blocks) { let jg = true; let id = ""; @@ -2400,7 +2783,17 @@ export default class MapConroler extends cc.Component { return jg; } - //检测物体各方向是否有别的物块,防止碰到墙壁了但是是凹凸形状,墙与块之间有阻挡物块 + // ============================================ + // 检测物体各方向阻挡方法 + // 功能:检测物体移动方向上是否有其他物体阻挡 + // 何时调用:在物体移动时判断是否会被阻挡 + // 参数说明: + // - id:当前物体的唯一ID + // - direction:移动方向("left", "right", "up", "down") + // - x, y:当前物体的位置 + // 用途:防止物体穿过凹凸形状的墙壁 + // 返回值:jg=true表示可以通过,jg=false表示有阻挡 + // ============================================ checkAllDirections(id, direction, x, y) { let jg = true; if (direction == "left") { @@ -2496,6 +2889,16 @@ export default class MapConroler extends cc.Component { return jg; } + // ============================================ + // 检测物体各方向是否可通行方法 + // 功能:检测物体四个方向是否可以通行 + // 何时调用:在物体移动前检测各方向的通行性 + // 参数说明: + // - allBlocks:当前物体占据的所有格子位置 + // - maxX, maxY:地图的最大尺寸 + // 返回值:布尔数组[jg[0], jg[1], jg[2], jg[3]],分别表示左、右、上、下是否可通行 + // 与checkAllDirections区别:这个方法检测所有方向,返回可通行性数组 + // ============================================ checkDiraction(allBlocks, maxX, maxY) { let jg = [false, false, false, false]; for (let i = 0; i < allBlocks.length; i++) { @@ -2525,7 +2928,18 @@ export default class MapConroler extends cc.Component { - //特殊处理,方块带道具或者需要消除冰块 + // ============================================ + // 特殊处理方法 + // 功能:处理方块携带的道具或需要消除的冰块 + // 何时调用:当方块被消除时调用 + // 参数说明: + // - node:被消除的方块节点 + // - type:消除类型 + // - prop:道具类型 + // 处理内容: + // 1. 如果有冰块,消除所有冰块 + // 2. 如果有道具,触发对应的道具效果 + // ============================================ special_Treatment(node, type, prop) { let freezeBlock = this.node.children.filter(child => { if (child.getComponent("Block")) { @@ -2646,6 +3060,20 @@ export default class MapConroler extends cc.Component { } } + //判断游戏是否成功 + // ============================================ + // 判断游戏胜利方法 + // 功能:判断是否满足游戏胜利条件 + // 何时调用:当有方块被消除时调用 + // 参数说明: + // - number=1:只判断是否消除所有方块 + // - number=0:判断是否消除所有方块,且检查是否有剩余冰块 + // 胜利条件: + // 1. 方块数量为0或1 + // 2. 游戏尚未胜利 + // 3. 游戏尚未结束 + // 胜利后操作:停止计时、停止爆炸动画、触发胜利流程 + // ============================================ judgeWin(number) { this.blockNum = this.blocks.length; if (number == 1) { @@ -2871,6 +3299,7 @@ export default class MapConroler extends cc.Component { } } + //检查是否是新功能关卡 check_NewMode() { for (let i = 0; i < cc.fx.GameConfig.NEW_LEVEL.length; i++) { if ((cc.fx.GameConfig.GM_INFO.level + 1) == cc.fx.GameConfig.NEW_LEVEL[i].level) { @@ -2885,10 +3314,15 @@ export default class MapConroler extends cc.Component { } } + //关闭最大关卡提示窗 winMaxLevelShowClose() { this.node.parent.parent.getChildByName("Win").getChildByName("specialTips").active = false; } + //下一关 + //判断是否是最大关卡 + //如果是最大关卡,弹窗提示 + //如果不是最大关卡,直接下一关 winLevel2() { let recordInfinity = cc.fx.StorageMessage.getStorage("EndLevelPop"); console.log("已经最大关卡房间 弹窗提示", recordInfinity, cc.fx.GameTool.maxLevel()) @@ -2908,6 +3342,18 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 下一关方法 + // 功能:处理游戏胜利后进入下一关的逻辑 + // 何时调用:当玩家点击"下一关"按钮时调用 + // 前置条件:必须等待按钮可交互才能点击 + // 主要功能: + // 1. 检查按钮是否可点击 + // 2. 上报游戏完成事件 + // 3. 更新游戏数据(关卡、游戏时长、连胜状态等) + // 4. 显示下一关按钮 + // 5. 处理特殊关卡跳转 + // ============================================ winLevel() { // MiniGameSdk.API.showToast(cc.fx.GameConfig.GM_INFO.level); if (this.node.parent.parent.getChildByName("Win").getChildByName("tween"). @@ -3008,6 +3454,7 @@ export default class MapConroler extends cc.Component { } } + //记录通行证关卡 setPassProgress() { Utils.getPassCheckInfo((res) => { if (res.code === 1) { @@ -3117,6 +3564,7 @@ export default class MapConroler extends cc.Component { // console.log("进度", cc.fx.GameConfig.GM_INFO.getProgressLevel, cc.fx.GameConfig.GM_INFO.getProgress); } + //添加移动地板块 addMoveFloor() { this.teamBlocks = []; @@ -3180,6 +3628,7 @@ export default class MapConroler extends cc.Component { } + //移除移动地板块 removeFloor(type) { // console.log("结束__________"); if (type == true) { @@ -3194,6 +3643,18 @@ export default class MapConroler extends cc.Component { } + // ============================================ + // 重新开始游戏方法 + // 功能:重新开始当前关卡 + // 何时调用:当玩家点击"重玩"按钮时调用 + // 主要功能: + // 1. 播放按钮音效 + // 2. 清空粘合块数组 + // 3. 检查体力值,不足时提示并阻止重玩 + // 4. 扣除体力(如果需要) + // 5. 重置游戏状态 + // 6. 重新加载关卡 + // ============================================ againLevel() { cc.fx.AudioManager._instance.playEffect("anniu_Big", null); this.adhesiveBlock = []; @@ -3293,6 +3754,7 @@ export default class MapConroler extends cc.Component { } } + //复活函数 runReviveAndCheck(data, retryCount: number = 0, callback: (success: boolean) => void = null) { // if (callback) callback(true); if (this.predict_End(false)) { @@ -3385,6 +3847,7 @@ export default class MapConroler extends cc.Component { }); } + //执行复活函数具体执行状态改变操作 runChangeState(data) { if (data.type == "lock") { this.changeLockWall(); //改变开关门 @@ -3421,6 +3884,10 @@ export default class MapConroler extends cc.Component { } } + //执行复活函数 + //判断是否是最大关卡 + //如果是最大关卡,弹窗提示 + //如果不是最大关卡,直接下一关 runRewiveCopy() { this.isreview = true; MiniGameSdk.API.showToast("继续游戏"); @@ -3439,6 +3906,7 @@ export default class MapConroler extends cc.Component { this.stopTimeCutDown(); } + //上传数数游戏完成事件 可成功可失败 trackFinishi(name) { let overTime = Date.now(); this.count_Time = overTime - this.count_Time; @@ -3458,7 +3926,17 @@ export default class MapConroler extends cc.Component { cc.fx.GameTool.shushu_Track("finish_stage", data); } - + // ============================================ + // 返回主界面方法 + // 功能:返回游戏主界面 + // 何时调用:当玩家点击"返回"按钮时调用 + // 主要功能: + // 1. 检查体力状态 + // 2. 播放按钮音效 + // 3. 检查按钮是否可点击 + // 4. 处理结算界面显示 + // 5. 返回HomeScene场景 + // ============================================ homeBtn() { this.powerState = cc.fx.GameTool.getUserPowerTime(); // if (this.powerState) { // 之前直接返回homeScene @@ -3517,6 +3995,9 @@ export default class MapConroler extends cc.Component { } } + //打开健康条 + //如果是最大关卡,弹窗提示 + //如果不是最大关卡,直接下一关 openHealth() { if (cc.fx.GameConfig.GM_INFO.otherLevel == 0) { this.revive.getComponent("Revive").offShow(); @@ -3537,12 +4018,13 @@ export default class MapConroler extends cc.Component { this.node.parent.parent.getChildByName("Lose").getChildByName("lose").getChildByName("WinStreak").active = false; } + //关闭连胜界面 closeWinStreak() { this.homeCanTouch = true; this.node.parent.parent.getChildByName("Lose").getChildByName("lose").getChildByName("WinStreak").active = false; } - + //上传数据到云存储 uploadToCloud(level: number) { //@ts-ignore if (typeof wx !== 'undefined') { @@ -3557,6 +4039,7 @@ export default class MapConroler extends cc.Component { } } + //返回主界面 returnHome(event, customEventData) { cc.fx.AudioManager._instance.playEffect("anniu_Big", null); if (MapConroler._instance = null) { @@ -3609,7 +4092,16 @@ export default class MapConroler extends cc.Component { }, 1200); } - //判断游戏失败 + // ============================================ + // 判断游戏失败方法 + // 功能:判断是否满足游戏失败条件 + // 何时调用:当计时器归零或无法继续消除时调用 + // 参数说明:type - 失败类型 + // 失败条件: + // 1. 计时器时间归零 + // 2. 游戏尚未结束 + // 失败后操作:显示失败界面、扣除体力、更新游戏状态 + // ============================================ failLevel(type) { if (this.gameOver == true || this.gameWin == true) { return; @@ -3826,7 +4318,7 @@ export default class MapConroler extends cc.Component { this.node.parent.parent.getChildByName("NewMode").getComponent("NewMode").setMode(type); } - + //正在点击方块颜色,对应颜色门下降 downDoor(color, type) { for (let i = 0; i < this.wallArray.length; i++) { if (this.wallArray[i].getChildByName("wall").getComponent("Wall").color == color) { @@ -3847,6 +4339,7 @@ export default class MapConroler extends cc.Component { } } + //执行旋转函数 runRevolving() { this.revolving_state = 1; this.revolving_state = 2; @@ -3855,6 +4348,7 @@ export default class MapConroler extends cc.Component { } } + //正在点击方块颜色,对应颜色门上升 upDoor() { for (let i = 0; i < this.wallArray.length; i++) { if (this.wallArray[i].getChildByName("wall").opacity == 0) { @@ -3863,7 +4357,18 @@ export default class MapConroler extends cc.Component { } } - //开始倒计时 + // ============================================ + // 开始倒计时方法 + // 功能:启动游戏计时器,进行倒计时 + // 何时调用:在startUpdate中玩家第一次点击方块后调用 + // 主要功能: + // 1. 启动爆炸效果动画 + // 2. 记录玩家上次点击时间 + // 3. 每秒执行一次计时器回调 + // 4. 检测玩家是否长时间未点击方块(超时判定为失败) + // 5. 更新倒计时显示 + // 6. 时间归零时触发游戏失败 + // ============================================ startTimeCutDown() { this.startBoom(); this.lastBlockClickTime = Date.now(); // 初始化上次点击时间 @@ -3907,7 +4412,15 @@ export default class MapConroler extends cc.Component { }.bind(this); this.schedule(this.scheduleCallback, 1); } - // 停止倒计时 + // ============================================ + // 停止倒计时方法 + // 功能:停止游戏计时器 + // 何时调用:游戏胜利或失败时调用 + // 主要功能: + // 1. 取消计时器回调 + // 2. 重置计时器回调为null + // 3. 调用onBlockClick重置未点击时间 + // ============================================ stopTimeCutDown() { if (this.scheduleCallback) { this.unschedule(this.scheduleCallback); @@ -3916,6 +4429,15 @@ export default class MapConroler extends cc.Component { this.onBlockClick(); } + // ============================================ + // 方块点击事件方法 + // 功能:记录玩家最后一次点击方块的时间 + // 何时调用:玩家点击方块时、计时器停止时调用 + // 主要功能: + // 1. 记录当前时间戳 + // 2. 重置未点击持续时间为0 + // 3. 处理涟漪收缩效果 + // ============================================ onBlockClick() { this.lastBlockClickTime = Date.now(); this.noBlockClickDuration = 0; @@ -4067,6 +4589,7 @@ export default class MapConroler extends cc.Component { } } + //购买道具成功处理 handleBuySuccess(data) { this.node.parent.parent.parent.getComponent("SceneManager").resetBtn(); this.updateCoin(); @@ -4168,12 +4691,24 @@ export default class MapConroler extends cc.Component { } + //更新金币显示 updateCoin() { if (this.coin) NumberToImage.numberToImageNodes5(cc.fx.GameConfig.GM_INFO.coin, 31, 20, "Black", this.coin, true); } - //使用锤子道具 + // ============================================ + // 使用锤子道具方法 + // 功能:激活锤子道具模式,允许玩家直接消除一个方块 + // 何时调用:当玩家点击锤子道具按钮时调用 + // 使用条件: + // 1. 道具可用 + // 2. 游戏未结束 + // 3. 距离上次使用超过1秒 + // 4. 魔法棒遮罩未激活 + // 5. 剩余时间大于1秒 + // 效果:进入锤子模式,玩家点击方块会直接消除该方块 + // ============================================ useHammer() { if (this.propCanbeUse) { return; @@ -4221,6 +4756,7 @@ export default class MapConroler extends cc.Component { } + //取消锤子道具 cancleHammer() { console.log("取消锤子"); let hammerBtn = this.node.parent.getChildByName("Bottom").getChildByName("destroyBtn"); @@ -4244,6 +4780,7 @@ export default class MapConroler extends cc.Component { } + //使用锤子道具 costHammer() { if (cc.fx.GameConfig.GM_INFO.otherLevel == 0) { if (cc.fx.GameConfig.GM_INFO.tasks.useProp.value < cc.fx.GameConfig.GM_INFO.tasks.useProp.target) { @@ -4280,7 +4817,7 @@ export default class MapConroler extends cc.Component { cc.fx.GameTool.shushu_Track("resource_cost", data); } - + //购买魔法棒道具 buyMagic() { if (cc.fx.GameConfig.GM_INFO.coin < 900) { MiniGameSdk.API.showToast("金币不足,无法购买道具"); @@ -4293,6 +4830,7 @@ export default class MapConroler extends cc.Component { cc.fx.GameTool.buyProp(2003, this.handleBuySuccess.bind(this, "magicAmount")); } + //购买锤子道具 buyHammer() { if (cc.fx.GameConfig.GM_INFO.coin < 600) { MiniGameSdk.API.showToast("金币不足,无法购买道具"); @@ -4305,6 +4843,7 @@ export default class MapConroler extends cc.Component { cc.fx.GameTool.buyProp(2002, this.handleBuySuccess.bind(this, "hammerAmount")); } + //购买冻结时间道具 buyFreeze() { if (cc.fx.GameConfig.GM_INFO.coin < 600) { MiniGameSdk.API.showToast("金币不足,无法购买道具"); @@ -4317,6 +4856,7 @@ export default class MapConroler extends cc.Component { cc.fx.GameTool.buyProp(2001, this.handleBuySuccess.bind(this, "freezeAmount")); } + //打开商店 openShop() { const winCOIN = cc.find("Canvas"); // 假设 Canvas 节点 if (winCOIN) { @@ -4332,6 +4872,7 @@ export default class MapConroler extends cc.Component { } } + //初始化魔法棒特效 initMagicEffects() { // 初始化两个特效节点,如果还没有创建的话 if (!this.magicEffect1) { @@ -4348,7 +4889,18 @@ export default class MapConroler extends cc.Component { } } - //使用魔法棒随机消除两个方块 + // ============================================ + // 使用魔法棒道具方法 + // 功能:激活魔法棒道具模式,随机消除两个相邻同色方块 + // 何时调用:当玩家点击魔法棒道具按钮时调用 + // 使用条件: + // 1. 道具可用 + // 2. 游戏未结束 + // 3. 距离上次使用超过1.2秒 + // 4. 魔法棒遮罩未激活 + // 5. 剩余时间大于1秒 + // 效果:进入魔法棒模式,自动寻找并消除两个相邻的同色方块 + // ============================================ useMagic() { if (this.propCanbeUse) { return; @@ -4395,6 +4947,7 @@ export default class MapConroler extends cc.Component { } } + //使用魔法棒随机消除两个方块 runMagic() { let magicBtn = this.node.parent.getChildByName("Bottom").getChildByName("magicBtn"); if (cc.fx.GameConfig.GM_INFO.otherLevel == 0) { @@ -4910,7 +5463,17 @@ export default class MapConroler extends cc.Component { } - //按下暂停按钮 + // ============================================ + // 暂停游戏方法 + // 功能:切换游戏的暂停/继续状态 + // 何时调用:当玩家点击暂停按钮时调用 + // 暂停效果: + // 1. 停止计时器 + // 2. 停止爆炸动画 + // 3. 阻止方块交互 + // 继续效果:恢复计时器和动画 + // 特殊:冰冻状态下不能暂停 + // ============================================ usePause() { if (this.pause) { if (this.iceTrue() == false) { @@ -4968,7 +5531,15 @@ export default class MapConroler extends cc.Component { this.node.parent.parent.parent.getChildByName("Pause").scale = gmScale; } - //创建门的粒子特效 + // ============================================ + // 创建粒子特效方法 + // 功能:为门创建粒子特效 + // 何时调用:当需要显示门的特效时调用 + // 参数说明: + // - block:需要特效的方块节点 + // - jg:是否是对称门(影响粒子特效的类型) + // 特效类型:根据门的类型(普通门/对称门)播放不同的粒子效果 + // ============================================ createParticle(block, jg) { let particle = cc.instantiate(MapConroler._instance.Block_Prop[9]); particle.parent = this.node; @@ -5041,6 +5612,7 @@ export default class MapConroler extends cc.Component { }, 1200); } + //移除一个方块 removeOneBlock() { // 移除所有方块 for (let i = 0; i < this.blocks.length; i++) { @@ -5051,6 +5623,7 @@ export default class MapConroler extends cc.Component { } } + //炸弹块开始计时 startBoom() { for (let i = 0; i < this.blocks.length; i++) { if (this.blocks[i].getComponent("Block").type == 6) { @@ -5059,6 +5632,7 @@ export default class MapConroler extends cc.Component { } } + //炸弹块停止计时 stopBoom() { for (let i = 0; i < this.blocks.length; i++) { if (this.blocks[i].getComponent("Block").type == 6) { @@ -5069,6 +5643,7 @@ export default class MapConroler extends cc.Component { this.onBlockClick(); } + //获取平滑路径 getSmoothPath(pts: cc.Vec3[], radius = 10): cc.Vec3[] { if (pts.length < 3) return pts.slice(); const smoothPts: cc.Vec3[] = [pts[0]]; @@ -5090,6 +5665,7 @@ export default class MapConroler extends cc.Component { return smoothPts; } + //播放锤子动画 startHammer(pos: cc.Vec3) { this.hammerAni.active = true; this.hammerAni.scale = 1; @@ -5397,6 +5973,7 @@ export default class MapConroler extends cc.Component { } } + //创建排名界面 createRank() { // console.log("通过关卡数量:", cc.fx.GameConfig.GM_INFO.addLevel); let rank = this.node.parent.parent.getChildByName("Win").getChildByName("Rank"); @@ -5694,6 +6271,7 @@ export default class MapConroler extends cc.Component { .start(); } + //设置帮助他人通关 setOtherLevel() { if (cc.fx.GameConfig.GM_INFO.otherLevel > 0) { console.log("帮助他人通关"); @@ -5712,6 +6290,13 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 判断冰冻状态方法 + // 功能:判断当前是否处于冰冻状态 + // 何时调用:在需要判断是否能进行操作时调用 + // 返回值:true表示冰冻中(不能操作),false表示可以正常操作 + // 冰冻条件:Ice节点active为true或游戏已结束 + // ============================================ iceTrue() { if (this.node.parent.getChildByName("Ice").active == true || this.gameOver || this.gameWin) { return true; @@ -5721,6 +6306,22 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 数字转图片节点方法 + // 功能:将数字转换为精灵图片显示 + // 何时调用:当需要显示数字图片时调用 + // 参数说明: + // - number:要显示的数字 + // - width:数字之间的间距 + // - posX:位置X坐标 + // - name:图片名称前缀 + // - targetNode:目标父节点 + // - right:是否右对齐(默认false左对齐) + // 特殊处理: + // 1. 数字超过99时位置调整 + // 2. 冒号":"会被转换为第10张图片 + // 3. 支持右对齐排列方式 + // ============================================ numberToImageNodes2(number, width, posX, name, targetNode: cc.Node, right: boolean = false) { const numStr = number.toString(); let cha = 0; @@ -5769,7 +6370,18 @@ export default class MapConroler extends cc.Component { } } - //连胜特殊锤子 + // ============================================ + // 使用连胜特殊锤子方法 + // 功能:激活连胜特殊锤子道具(可穿透任意方块) + // 何时调用:当玩家点击连胜特殊锤子按钮时调用 + // 与useHammer区别:这个锤子可以穿透所有方块直接消除目标 + // 使用条件: + // 1. 游戏未结束 + // 2. 距离上次使用超过1秒 + // 3. 魔法棒遮罩未激活 + // 4. 剩余时间大于1秒 + // 效果:进入特殊锤子模式,可直接消除任意方块 + // ============================================ useHammerSpecial() { if (this.gameOver == true || this.gameWin == true) { return; @@ -5799,7 +6411,15 @@ export default class MapConroler extends cc.Component { else MiniGameSdk.API.showToast("道具使用中,请稍后再试"); } - //连击播放声音 + // ============================================ + // 播放碰撞音效方法 + // 功能:播放方块碰撞的连击音效 + // 何时调用:当方块碰撞消除时调用 + // 音效规则: + // 1. 根据连击次数选择不同音效(hit1-hit5) + // 2. 连击数超过5时上限为5 + // 3. 记录播放时间用于冷却 + // ============================================ playHitSound() { this.hitSoundCount++; if (this.hitSoundCount > 5) { @@ -5809,6 +6429,16 @@ export default class MapConroler extends cc.Component { this.hitSoundTime = Date.now(); // 记录当前播放时间 } + // ============================================ + // 打开授权位置界面方法 + // 功能:检查玩家是否已授权位置信息 + // 何时调用:当需要获取玩家位置时调用 + // 检查逻辑: + // 1. 检查本地缓存是否有位置信息 + // 2. 无缓存或无授权:重新授权 + // 3. 有缓存但超过24小时:重新授权 + // 4. 有缓存且有效:使用缓存地址 + // ============================================ openPosition() { this.node.parent.parent.getChildByName("Win").getChildByName("Ruzhi").active = false; let address = cc.fx.StorageMessage.getStorage("address"); @@ -5848,6 +6478,15 @@ export default class MapConroler extends cc.Component { } } + // ============================================ + // 授权位置方法 + // 功能:获取并缓存玩家的位置信息 + // 何时调用:在openPosition中需要授权时调用 + // 获取结果: + // 1. 成功:保存地址到本地缓存,记录授权时间,上报到服务器 + // 2. 失败:保存失败状态到本地缓存 + // 缓存内容:地址、授权时间戳、是否授权成功 + // ============================================ runAuthorize() { console.log("点击授权了"); // 获取CareerList组件实例 @@ -5896,6 +6535,15 @@ export default class MapConroler extends cc.Component { }, true); // 第二个参数设为true启用逆解析 } + // ============================================ + // 设置远程头像图片方法 + // 功能:从URL加载远程图片并设置为Sprite的纹理 + // 何时调用:当需要显示玩家远程头像时调用 + // 参数说明: + // - url:头像图片的远程地址 + // - node:需要设置头像的节点 + // 图片格式:仅支持PNG格式(ext: '.png') + // ============================================ public setPic(url, node) { cc.assetManager.loadRemote(url, { ext: '.png' }, (err, texture: cc.Texture2D) => { if (texture) { @@ -5909,6 +6557,16 @@ export default class MapConroler extends cc.Component { }) } + // ============================================ + // 无尽关卡显示方法 + // 功能:显示无尽模式的关卡信息 + // 何时调用:在initMap中调用 + // 显示内容: + // 1. 显示无尽模式节点 + // 2. 隐藏普通关卡显示 + // 3. 根据关卡数字调整位置(个位数、十位数、百位数、千位数) + // 4. 调用数字转图片方法显示关卡数字 + // ============================================ endlessLevelShow() { // console.log("刷新关卡等级", cc.fx.GameTool.maxLevel(), cc.fx.GameConfig.GM_INFO.endLevelNum); let top = this.node.parent.getChildByName("Top"); @@ -5942,7 +6600,16 @@ export default class MapConroler extends cc.Component { } } - //处理花瓣 + // ============================================ + // 处理花瓣方法 + // 功能:将消除的花瓣数量分配给花瓣收集方块 + // 何时调用:当需要分配花瓣时调用 + // 参数说明:flowerArray - 包含花瓣颜色和数量的数组 + // 处理逻辑: + // 1. 将数组转换为字符串统计每个颜色的数量 + // 2. 遍历所有花瓣收集方块 + // 3. 根据方块的花瓣颜色匹配数量并添加 + // ============================================ moveFlower(flowerArray) { let flowerStr = flowerArray.toString().replace(/,/g, ''); let countMap = {}; @@ -5964,7 +6631,13 @@ export default class MapConroler extends cc.Component { } } - + // ============================================ + // Cocos生命周期 - update方法 + // 功能:每帧更新的逻辑 + // 何时调用:每帧自动调用 + // 主要功能: + // 1. 检测连击音效超时(3秒无碰撞消除则重置连击计数) + // ============================================ update(dt) { // 检测连击超时,如果超过3秒没有播放音效,重置连击计数 if (this.hitSoundCount > 0 && this.hitSoundTime && Date.now() - this.hitSoundTime > 3000) { diff --git a/游戏说明书.md b/游戏说明书.md new file mode 100644 index 0000000..b4ea2b8 --- /dev/null +++ b/游戏说明书.md @@ -0,0 +1,417 @@ +# ColorBlock 消消乐游戏 - 整体说明书 + +## 一、游戏架构概述 + +### 1.1 场景流程 +``` +Main.ts (入口) + ↓ +Load.ts (加载场景初始化) + ↓ +GameManager.ts (游戏管理器 - 预加载资源) + ↓ +JiaZai.ts (主页场景 - 主菜单) + ↓ +Map.ts + Block.ts (游戏场景 - 核心玩法) + ↓ +GameOver.ts (结算场景) +``` + +### 1.2 核心模块划分 + +| 模块 | 说明 | +|------|------| +| **核心游戏** | 游戏主逻辑、场景管理、地图控制、方块控制 | +| **道具系统** | 各种特殊方块(钥匙、炸弹、冻结等) | +| **UI系统** | 界面控制、弹窗管理、设置面板 | +| **工具模块** | 音频管理、网络请求、数据存储 | +| **SDK模块** | 微信小游戏SDK、分享、支付 | + +--- + +## 二、核心类说明 + +### 2.1 入口与初始化 + +| 文件 | 类名 | 功能说明 | +|------|------|----------| +| **Main.ts** | Main | 游戏入口,加载 LoadScene 场景 | +| **Load.ts** | NewClass | 加载场景初始化,配置碰撞系统、微信参数 | +| **GameManager.ts** | GameManager | 游戏总管理器,单例模式,负责游戏初始化、资源预加载、微信配置 | + +### 2.2 主页场景 + +| 文件 | 类名 | 功能说明 | +|------|------|----------| +| **JiaZai.ts** | JiaZai | 主页场景控制器(HomeScene),负责:
- UI管理(关卡、金币、体力显示)
- 商店、月卡、每日任务
- 通行证系统
- 排行榜功能
- 分享奖励
- 新手引导 | + +### 2.3 游戏核心 + +| 文件 | 类名 | 功能说明 | +|------|------|----------| +| **Map.ts** | MapConroler | 地图控制器,核心游戏逻辑:
- 地图生成与渲染
- 方块生成与布局
- 门控制(颜色门、星星门、锁门)
- 特殊效果(冰冻、锤子、魔法棒)
- 胜负判定 | +| **Block.ts** | Block | 方块组件,控制所有方块行为:
- 22种方块类型(普通、钥匙、锁、冻结、炸弹、粘合等)
- 7种颜色
- 移动、消除逻辑
- 碰撞检测 | +| **SceneManager.ts** | SceneManager | 游戏场景管理器(GameScene),负责:
- 道具使用(锤子、魔法棒、冰冻)
- 弹窗管理(商店、奖励、月卡)
- 复活逻辑 | + +### 2.4 道具系统 (prop文件夹) + +| 文件 | 道具名 | 功能说明 | +|------|--------|----------| +| **Key.ts** | 钥匙块 | 用来打开锁块 | +| **Lock.ts** | 锁块 | 被锁锁住,需要钥匙消除 | +| **Boom.ts** | 炸弹块 | 炸毁周围方块 | +| **Freeze.ts** | 冻结块 | 冻住一定步数 | +| **Star.ts** | 星星块 | 打开星星门 | +| **Adhesive.ts** | 粘合块 | 与其他方块粘合移动 | +| **Question.ts** | 问号块 | 随机效果 | +| **AddTime.ts** | 加时间块 | 增加游戏时间 | +| **Floor.ts** | 地板块 | 可移动的地板 | +| **Switchs.ts** | 开关块 | 控制开关逻辑 | + +### 2.5 UI界面 + +| 文件 | 类名 | 功能说明 | +|------|------|----------| +| **GameOver.ts** | NewClass | 游戏结算界面,显示分数、通关率、排行榜 | +| **Pause.ts** | - | 暂停界面(已注释) | +| **Reward.ts** | - | 奖励界面 | +| **Revive.ts** | - | 复活界面 | +| **Barrier.ts** | - | 障碍物界面 | +| **Window.ts** | - | 通用弹窗 | +| **gameOverUi.ts** | - | 游戏结束UI | + +### 2.6 工具模块 (module文件夹) + +#### 配置与数据 + +| 文件 | 功能说明 | +|------|----------| +| **GameConfig.ts** | 游戏配置中心,存储GM_INFO等全局数据 | +| **GameTool.ts** | 工具类,提供登录认证、埋点上传、排行榜、存储等 | + +#### 音频与音乐 + +| 文件 | 功能说明 | +|------|----------| +| **AudioManager.ts** | 音频管理器,单例模式,管理所有游戏音效和背景音乐 | + +#### 存储与网络 + +| 文件 | 功能说明 | +|------|----------| +| **Storage.ts** | 本地存储,封装localStorage操作 | +| **HttpUtil.ts** | 网络请求工具,封装加密HTTP请求 | + +#### 支付与道具 + +| 文件 | 功能说明 | +|------|----------| +| **Utils.ts** | 支付工具,处理月卡、通行证、订单等 | + +#### 其他工具 + +| 文件 | 功能说明 | +|------|----------| +| **Notification.ts** | 事件通知系统 | +| **NodePoolMgr.ts** | 对象池管理器 | +| **GetPosition.ts** | 地理位置获取 | +| **RankManager.ts** | 排行榜管理 | +| **List.ts** | 列表组件 | +| **scrollviewList.ts** | 滚动列表 | + +### 2.7 SDK模块 (Sdk文件夹) + +| 文件 | 功能说明 | +|------|----------| +| **MiniGameSdk.ts** | 微信小游戏SDK封装 | +| **MiniGameManager.ts** | 小游戏管理器 | + +### 2.8 物理与碰撞系统 + +| 文件 | 功能说明 | +|------|----------| +| **lq_collide_system/** | 自定义碰撞检测系统 | +| **CollisionDetection.ts** | 碰撞检测工具 | + +--- + +## 三、游戏核心玩法 + +### 3.1 方块类型 (Block.ts) + +| 类型 | 说明 | +|------|------| +| 普通块 | 最基础的方块,可以移动并消除在对应颜色的门上 | +| 叠加块上/下 | 叠加方块的上下两部分 | +| 钥匙块 | 带有钥匙功能的方块,用来打开对应的锁 | +| 上锁块 | 被锁锁住的方块,需要对应钥匙才能消除 | +| 冻结块 | 带有冰冻效果的方块,会冻住一定步数 | +| 星星块 | 带有星星的方块,用来打开星星门 | +| 炸弹块 | 带有炸弹的方块,可以炸毁周围方块 | +| 水平块 | 只能在水平方向移动的方块 | +| 垂直块 | 只能在垂直方向移动的方块 | +| 粘合块 | 会与其他方块粘合在一起移动的方块 | +| 障碍块 | 障碍物,无法消除 | +| 问号块 | 随机效果的方块 | +| 变色块 | 颜色会变化的方块 | +| 加时间块 | 增加游戏时间的方块 | +| 可移动地板块 | 可以在地图上移动的地板块 | +| 三连粘合块 | 会与三个方向粘合的方块 | + +### 3.2 颜色系统 + +| 颜色 | 说明 | +|------|------| +| 紫色 | 对应紫色门 | +| 黄色 | 对应黄色门 | +| 绿色 | 对应绿色门 | +| 蓝色 | 对应蓝色门 | +| 粉色 | 对应粉色门 | +| 橘黄色 | 对应橘黄色门 | +| 青色 | 对应青色门 | + +### 3.3 门类型 (Map.ts) + +| 门类型 | 消除条件 | +|--------|----------| +| 颜色门 | 对应颜色的方块可以消除 | +| 星星门 | 需要星星块消除 | +| 锁门 | 需要钥匙块消除 | +| 冰冻门 | 冻结块可以冻住 | + +### 3.4 道具系统 + +| 道具 | 功能 | +|------|------| +| 锤子 | 消除单个方块 | +| 魔法棒 | 改变方块颜色 | +| 冰冻 | 暂停方块移动 | + +--- + +## 四、数据结构 + +### 4.1 GM_INFO 主要属性 + +```typescript +{ + level: number, // 当前关卡 + coin: number, // 金币 + hp: number, // 体力值 + hp_Max: number, // 体力上限 + score: number, // 分数 + openid: string, // 微信openid + userId: number, // 用户ID + userPowerTime: number, // 无限体力到期时间 + playerPassLevel: number, // 通行证等级 + passCheckActivate: boolean, // 通行证是否激活 + gameId: number, // 游戏ID + scode: string, // 渠道码 + matchId: string, // 比赛ID + successList: boolean[], // 成功列表 +} +``` + +### 4.2 关卡数据结构 + +```typescript +{ + id: string, // 关卡ID + map: number[], // 地图数据 + risefall: {...}, // 升降台配置 + gap: {...} // 鸿沟配置 +} +``` + +### 4.3 方块数据结构 + +```typescript +{ + type: BlockType, // 方块类型 + color: BlockColor, // 方块颜色 + pos: cc.Vec2, // 位置坐标 + special: number, // 特殊属性 +} +``` + +--- + +## 五、场景说明 + +| 场景名 | 控制器 | 功能 | +|--------|--------|------| +| **LoadScene** | Load.ts | 加载场景,初始化微信参数 | +| **HomeScene** | JiaZai.ts | 主菜单,显示关卡、金币、商店、任务等 | +| **GameScene** | Map.ts + SceneManager.ts | 游戏主场景,核心玩法 | +| **GameOver** | GameOver.ts | 结算场景 | + +--- + +## 六、系统功能说明 + +### 6.1 体力系统 + +- 玩家拥有体力值,每进行一关游戏消耗体力 +- 体力会随时间恢复(每5分钟恢复1点) +- 可以通过月卡获得无限体力 +- 体力不足时显示恢复倒计时 + +### 6.2 月卡系统 + +- 购买月卡后享受每日奖励 +- 月卡期间体力上限提升 +- 月卡到期后自动恢复默认体力上限 + +### 6.3 通行证系统(PassCheck) + +- 通过积累进度提升通行证等级 +- 通行证达到特定等级可获得奖励 +- 需要购买通行证才能获得奖励 + +### 6.4 每日任务 + +- 每日有分享任务 +- 完成分享任务可获得奖励 +- 任务进度每日重置 + +### 6.5 排行榜系统 + +- 显示好友排行榜 +- 按关卡等级排序 +- 支持显示玩家省份信息 + +### 6.6 分享系统 + +- 分享到群聊邀请好友 +- 好友通过分享链接进入游戏 +- 分享成功可获得奖励 + +--- + +## 七、文件目录结构 + +``` +assets/Script/ +├── Sdk/ # SDK模块 +│ ├── MiniGameSdk.ts # 微信小游戏SDK +│ └── MiniGameManager.ts # 小游戏管理器 +├── lq_base/ # 基础模块 +│ ├── data/ # 数据定义 +│ └── util/ # 工具函数 +├── lq_collide_system/ # 碰撞系统 +├── module/ # 功能模块 +│ ├── Config/GameConfig.ts # 游戏配置 +│ ├── Crypto/HttpUtil.ts # 加密网络请求 +│ ├── Music/AudioManager.ts # 音频管理 +│ ├── Pay/Utils.ts # 支付工具 +│ ├── Position/GetPosition.ts # 位置获取 +│ ├── RankList/ # 排行榜 +│ ├── Storage/Storage.ts # 本地存储 +│ └── Tool/GameTool.ts # 游戏工具 +├── prop/ # 道具系统 +│ ├── Key.ts # 钥匙 +│ ├── Lock.ts # 锁 +│ ├── Boom.ts # 炸弹 +│ ├── Freeze.ts # 冻结 +│ ├── Star.ts # 星星 +│ ├── Adhesive.ts # 粘合 +│ └── Question.ts # 问号 +├── Avatar.ts # 头像组件 +├── Barrier.ts # 障碍物 +├── Block.ts # 方块组件 +├── CollisionDetection.ts # 碰撞检测 +├── ControlManager.ts # 控制管理 +├── GameManager.ts # 游戏管理器 +├── GameOver.ts # 游戏结束 +├── ItemGuide.ts # 道具引导 +├── JiaZai.ts # 主页场景 +├── Load.ts # 加载场景 +├── Main.ts # 游戏入口 +├── Map.ts # 地图控制 +├── MapBlock.ts # 地图方块 +├── Message.ts # 消息 +├── MessageContent.ts # 消息内容 +├── NewMode.ts # 新模式 +├── NumberToImage.ts # 数字转图片 +├── Pause.ts # 暂停 +├── RedeemCode.ts # 兑换码 +├── Reduce.ts # 减少 +├── Revive.ts # 复活 +├── Reward.ts # 奖励 +├── RippleShrink.ts # 涟漪收缩 +├── SceneManager.ts # 场景管理 +├── Uid.ts # 用户ID +├── Wall.ts # 墙壁 +├── Window.ts # 窗口 +├── btnControl.ts # 按钮控制 +├── gameOverUi.ts # 游戏结束UI +├── heathnum.ts # 体力数字 +├── monthlyCard.ts # 月卡 +├── peizhi.ts # 配置 +├── position.ts # 位置 +└── ranking.ts # 排行榜 +``` + +--- + +## 八、技术栈 + +| 技术 | 说明 | +|------|------| +| **引擎** | Cocos Creator | +| **语言** | TypeScript | +| **平台** | 微信小游戏、字节跳动小游戏 | +| **网络** | HTTPS + 加密传输 | +| **存储** | localStorage + 微信云存储 | + +--- + +## 九、游戏流程图 + +``` +┌─────────────────────────────────────────────────────┐ +│ Main.ts │ +│ 游戏入口加载 │ +└─────────────────────┬───────────────────────────────┘ + │ +┌─────────────────────▼───────────────────────────────┐ +│ Load.ts │ +│ 加载场景-初始化配置 │ +└─────────────────────┬───────────────────────────────┘ + │ +┌─────────────────────▼───────────────────────────────┐ +│ GameManager.ts │ +│ 游戏管理器-预加载资源、微信配置 │ +└─────────────────────┬───────────────────────────────┘ + │ +┌─────────────────────▼───────────────────────────────┐ +│ JiaZai.ts (HomeScene) │ +│ 主页-关卡选择/商店/任务/排行榜/通行证/分享 │ +└─────────────────────┬───────────────────────────────┘ + │ +┌─────────────────────▼───────────────────────────────┐ +│ Map.ts + Block.ts (GameScene) │ +│ 游戏核心-地图/方块/道具/胜负判定 │ +└─────────────────────┬───────────────────────────────┘ + │ +┌─────────────────────▼───────────────────────────────┐ +│ GameOver.ts │ +│ 结算-分数/排行榜/奖励 │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +## 十、总结 + +这是一款基于 **Cocos Creator** 开发的**微信消消乐小游戏**,核心玩法是通过移动方块来消除对应颜色的门。游戏包含完整的商业化系统: + +- **体力系统**:控制游戏节奏 +- **商店系统**:售卖虚拟商品 +- **月卡系统**:提供订阅价值 +- **通行证系统**:提供成长目标 +- **每日任务**:提高用户粘性 +- **排行榜系统**:促进社交互动 +- **分享系统**:裂变获客 + +游戏设计精巧,代码结构清晰,是一款成熟的三消类小游戏产品。