diff --git a/assets/pause/texture.meta b/assets/GameplayIntro.meta similarity index 63% rename from assets/pause/texture.meta rename to assets/GameplayIntro.meta index 6208662..0fc1bae 100644 --- a/assets/pause/texture.meta +++ b/assets/GameplayIntro.meta @@ -1,9 +1,9 @@ { "ver": "1.1.3", - "uuid": "b9306325-5a69-49d8-8065-461b7b0e87a8", + "uuid": "b2ad39e9-35c9-4657-ba4b-621b6b6fb499", "importer": "folder", - "isBundle": false, - "bundleName": "", + "isBundle": true, + "bundleName": "gameplay_intro", "priority": 1, "compressionType": {}, "optimizeHotUpdate": {}, diff --git a/assets/GameplayIntro/README.md b/assets/GameplayIntro/README.md new file mode 100644 index 0000000..47d56d8 --- /dev/null +++ b/assets/GameplayIntro/README.md @@ -0,0 +1,37 @@ +# 玩法介绍正式功能包 + +Asset Bundle 名称:`gameplay_intro`。 + +- `prefab/GameplayIntro.prefab`:本关介绍面板固定布局,可在 Creator 中编辑背景、标题、滑动区域和分页器位置。 +- `assets/Script/module/Tool/LevelGameplay.ts`:主脚本目录中的筛选工具,从实际关卡的方块、门、地块及生成队列识别玩法,并按类型去重。主场景仅以类型引用 GameplayIntro,在分包加载完成后用组件名获取实例,避免启动时依赖尚未加载的分包脚本。 +- `script/GameplayIntro.ts`:绑定预制体节点,关闭按钮或外部点击关闭,相邻三页图片加载与释放。 +- `script/GuideCarousel.ts`:鼠标/触摸翻页、缓动回弹、最多三点分页及白点替换动画;单页隐藏分页且不绑定拖动,双页显示两点。 +- `Texture/`:面板背景、玩法指南标题、问号、关闭按钮及分页圆点等 UI 素材;原有中文玩法图片已清理,玩法图片统一加载公共目录。 +- `assets/resources/Window_Prop/`:34 组公共玩法图片,按 `titleN`、`iconN`、`IntroductionN` 加载。daoju26 使用素材 27,daoju27 使用素材 26。 + +游戏入口由 `assets/Script/SceneManager.ts` 控制:进入场景时按实际加载的关卡生成介绍列表,没有特殊道具就隐藏问号。首次点击 `openGameplayIntro` 加载本包的 `prefab/GameplayIntro`,实例挂到 Inspector 绑定的 `tipPanel` 节点;关闭后保留固定布局,释放所有玩法页图片,再次打开复用实例,按解锁关卡倒序排列后定位最左端的最新玩法;三个分页点时高亮左边第 1 点。 + +`GameplayIntro.open(entries)` 接收已经筛选的介绍列表。`NEW_LEVEL.json` 仅提供介绍编号和排列顺序,不再用解锁关卡或玩家进度筛选。开局方块和 `spawnGates[].spawnQueue[].members` 都纳入本关范围,消除后仍可查看;同类型只展示一页。木箱/快递盒/彩色木箱、普通/定次连接等按实际变体匹配,花盆借用的不可见盖板不增加快递盒介绍。 + +场景接线:在 GameScene 的 Top/tip 下放置问号 Sprite + Button,图片使用本包 `wenhao`;Button 点击事件绑定 Canvas 上的 SceneManager.openGameplayIntro。SceneManager 的 Tip Panel 属性绑定场景现有的 tipPanel。tipPanel 应作为位于游戏内容之上的居中容器,不需要添加覆盖整个屏幕的输入拦截组件。 + +预制体直接引用背景、标题、关闭按钮和两种分页圆点;34 种公共玩法图片由脚本按当前页及相邻页动态加载,不能把所有玩法图片拖到预制体中,以免一次加载全部图片。 + +测试包及预览专用接口已移除,启动场景已恢复为主线正式场景。 + +## 可编辑的固定玩法页结构 + +直接打开 `prefab/GameplayIntro.prefab`: + +``` +IntroViewport +└─ Pages + ├─ Page1 + │ ├─ TitleImage + │ ├─ IconImage + │ └─ DescriptionImage + ├─ Page2(相同结构) + └─ Page3(相同结构) +``` + +所有图片节点已经放在面板预制体内,SpriteFrame 留空。最下方 DescriptionImage 的大小由 Sprite 的 Size Mode、Trim 及节点尺寸/缩放控制,代码不覆盖;TitleImage 和 IconImage 仍以预制体 Width/Height 为展示区域等比适配;三页需要保持相同布局。代码仅复用三个页面、改变分页位置并动态加载图片。说明图不做代码缩放,标题和道具图保留等比适配;没有单图比例修正。翻远或关闭面板时清空图片并归还资源引用,不销毁这三个页面;面板整体销毁时由引擎销毁子节点。 diff --git a/assets/GameplayIntro/README.md.meta b/assets/GameplayIntro/README.md.meta new file mode 100644 index 0000000..a1d7667 --- /dev/null +++ b/assets/GameplayIntro/README.md.meta @@ -0,0 +1,6 @@ +{ + "ver": "2.0.2", + "uuid": "7a8b8085-ff6e-436f-8671-a99801b33134", + "importer": "asset", + "subMetas": {} +} \ No newline at end of file diff --git a/assets/gacha_bundle/img/cat.meta b/assets/GameplayIntro/Texture.meta similarity index 81% rename from assets/gacha_bundle/img/cat.meta rename to assets/GameplayIntro/Texture.meta index 95837c3..4f8e596 100644 --- a/assets/gacha_bundle/img/cat.meta +++ b/assets/GameplayIntro/Texture.meta @@ -1,6 +1,6 @@ { "ver": "1.1.3", - "uuid": "aef15769-3ab2-4a0e-8b96-022a6d62696d", + "uuid": "260eaaff-84cb-4758-95c7-be73182532c5", "importer": "folder", "isBundle": false, "bundleName": "", diff --git a/assets/GameplayIntro/Texture/close.png b/assets/GameplayIntro/Texture/close.png new file mode 100644 index 0000000..34b6a6f Binary files /dev/null and b/assets/GameplayIntro/Texture/close.png differ diff --git a/assets/GameplayIntro/Texture/close.png.meta b/assets/GameplayIntro/Texture/close.png.meta new file mode 100644 index 0000000..09f2f23 --- /dev/null +++ b/assets/GameplayIntro/Texture/close.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "7c6fbbbe-7e71-4e67-bff0-78ed794c6edd", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": false, + "width": 103, + "height": 112, + "platformSettings": {}, + "subMetas": { + "close": { + "ver": "1.0.6", + "uuid": "b920b9e1-7d5d-4218-bc40-797cb0d9319d", + "importer": "sprite-frame", + "rawTextureUuid": "7c6fbbbe-7e71-4e67-bff0-78ed794c6edd", + "trimType": "custom", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 103, + "height": 112, + "rawWidth": 103, + "rawHeight": 112, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/GameplayIntro/Texture/mianba.png b/assets/GameplayIntro/Texture/mianba.png new file mode 100644 index 0000000..1644c85 Binary files /dev/null and b/assets/GameplayIntro/Texture/mianba.png differ diff --git a/assets/GameplayIntro/Texture/mianba.png.meta b/assets/GameplayIntro/Texture/mianba.png.meta new file mode 100644 index 0000000..90161a1 --- /dev/null +++ b/assets/GameplayIntro/Texture/mianba.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "c9aec8f7-4af8-42c2-9761-5d2b3180da1e", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": true, + "width": 902, + "height": 534, + "platformSettings": {}, + "subMetas": { + "mianba": { + "ver": "1.0.6", + "uuid": "506252be-e576-479a-8475-649113ffa72f", + "importer": "sprite-frame", + "rawTextureUuid": "c9aec8f7-4af8-42c2-9761-5d2b3180da1e", + "trimType": "auto", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 902, + "height": 534, + "rawWidth": 902, + "rawHeight": 534, + "borderTop": 200, + "borderBottom": 255, + "borderLeft": 60, + "borderRight": 60, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/GameplayIntro/Texture/wenhao.png b/assets/GameplayIntro/Texture/wenhao.png new file mode 100644 index 0000000..672beaa Binary files /dev/null and b/assets/GameplayIntro/Texture/wenhao.png differ diff --git a/assets/GameplayIntro/Texture/wenhao.png.meta b/assets/GameplayIntro/Texture/wenhao.png.meta new file mode 100644 index 0000000..1507e0f --- /dev/null +++ b/assets/GameplayIntro/Texture/wenhao.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "2dbc727b-eb2b-48f4-9e1a-c76fbe480b78", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": false, + "width": 86, + "height": 90, + "platformSettings": {}, + "subMetas": { + "wenhao": { + "ver": "1.0.6", + "uuid": "d9333256-302a-403b-93bf-e25c42829476", + "importer": "sprite-frame", + "rawTextureUuid": "2dbc727b-eb2b-48f4-9e1a-c76fbe480b78", + "trimType": "custom", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 86, + "height": 90, + "rawWidth": 86, + "rawHeight": 90, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/GameplayIntro/Texture/yuandian.png b/assets/GameplayIntro/Texture/yuandian.png new file mode 100644 index 0000000..b1e8762 Binary files /dev/null and b/assets/GameplayIntro/Texture/yuandian.png differ diff --git a/assets/GameplayIntro/Texture/yuandian.png.meta b/assets/GameplayIntro/Texture/yuandian.png.meta new file mode 100644 index 0000000..6e28239 --- /dev/null +++ b/assets/GameplayIntro/Texture/yuandian.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "b2388707-a337-4107-85c8-3938cbd8d4c5", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": false, + "width": 20, + "height": 20, + "platformSettings": {}, + "subMetas": { + "yuandian": { + "ver": "1.0.6", + "uuid": "93a7437b-9792-42c0-b0f5-73724314cbd8", + "importer": "sprite-frame", + "rawTextureUuid": "b2388707-a337-4107-85c8-3938cbd8d4c5", + "trimType": "custom", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 20, + "height": 20, + "rawWidth": 20, + "rawHeight": 20, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/GameplayIntro/Texture/yuandian00.png b/assets/GameplayIntro/Texture/yuandian00.png new file mode 100644 index 0000000..84dd259 Binary files /dev/null and b/assets/GameplayIntro/Texture/yuandian00.png differ diff --git a/assets/GameplayIntro/Texture/yuandian00.png.meta b/assets/GameplayIntro/Texture/yuandian00.png.meta new file mode 100644 index 0000000..855ed1b --- /dev/null +++ b/assets/GameplayIntro/Texture/yuandian00.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "94a173e9-d339-4583-8962-0a18e0df52d5", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": false, + "width": 38, + "height": 38, + "platformSettings": {}, + "subMetas": { + "yuandian00": { + "ver": "1.0.6", + "uuid": "af06b902-6722-4e79-871c-706dfd075327", + "importer": "sprite-frame", + "rawTextureUuid": "94a173e9-d339-4583-8962-0a18e0df52d5", + "trimType": "custom", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 38, + "height": 38, + "rawWidth": 38, + "rawHeight": 38, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/GameplayIntro/Texture/玩法指南字.png b/assets/GameplayIntro/Texture/玩法指南字.png new file mode 100644 index 0000000..3d037cd Binary files /dev/null and b/assets/GameplayIntro/Texture/玩法指南字.png differ diff --git a/assets/GameplayIntro/Texture/玩法指南字.png.meta b/assets/GameplayIntro/Texture/玩法指南字.png.meta new file mode 100644 index 0000000..eff9d80 --- /dev/null +++ b/assets/GameplayIntro/Texture/玩法指南字.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "e0f7e25d-ab0d-4c0b-ba3b-0a7560ded387", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": false, + "width": 310, + "height": 85, + "platformSettings": {}, + "subMetas": { + "玩法指南字": { + "ver": "1.0.6", + "uuid": "1b908cf0-2bab-4a0e-a4a8-6b1bc8692909", + "importer": "sprite-frame", + "rawTextureUuid": "e0f7e25d-ab0d-4c0b-ba3b-0a7560ded387", + "trimType": "custom", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 310, + "height": 85, + "rawWidth": 310, + "rawHeight": 85, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/libs/dn-sdk-minigame.meta b/assets/GameplayIntro/prefab.meta similarity index 81% rename from assets/libs/dn-sdk-minigame.meta rename to assets/GameplayIntro/prefab.meta index 2fe8053..e605f08 100644 --- a/assets/libs/dn-sdk-minigame.meta +++ b/assets/GameplayIntro/prefab.meta @@ -1,6 +1,6 @@ { "ver": "1.1.3", - "uuid": "97538b78-7842-4668-9318-e04946661548", + "uuid": "768035be-c53f-4e17-b438-a862006a56db", "importer": "folder", "isBundle": false, "bundleName": "", diff --git a/assets/GameplayIntro/prefab/GameplayIntro.prefab b/assets/GameplayIntro/prefab/GameplayIntro.prefab new file mode 100644 index 0000000..32ced8b --- /dev/null +++ b/assets/GameplayIntro/prefab/GameplayIntro.prefab @@ -0,0 +1,2362 @@ +[ + { + "__type__": "cc.Prefab", + "_name": "", + "_objFlags": 0, + "_native": "", + "data": { + "__id__": 1 + }, + "optimizationPolicy": 0, + "asyncLoadAssets": false, + "readonly": false + }, + { + "__type__": "cc.Node", + "_name": "GameplayIntro", + "_objFlags": 0, + "_parent": null, + "_children": [ + { + "__id__": 2 + }, + { + "__id__": 7 + } + ], + "_active": true, + "_components": [ + { + "__id__": 64 + } + ], + "_prefab": { + "__id__": 65 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 1080, + "height": 1920 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "Backdrop", + "_objFlags": 0, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 3 + }, + { + "__id__": 4 + }, + { + "__id__": 5 + } + ], + "_prefab": { + "__id__": 6 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 4000, + "height": 4000 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Graphics", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 2 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57" + } + ], + "_lineWidth": 2, + "_strokeColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_lineJoin": 2, + "_lineCap": 0, + "_fillColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_miterLimit": 10, + "_id": "" + }, + { + "__type__": "cc.BlockInputEvents", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 2 + }, + "_enabled": true, + "_id": "" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 2 + }, + "_enabled": true, + "_normalMaterial": null, + "_grayMaterial": null, + "duration": 0.1, + "zoomScale": 1.1, + "clickEvents": [], + "_N$interactable": true, + "_N$enableAutoGrayEffect": false, + "_N$transition": 0, + "transition": 0, + "_N$normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_N$pressedColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "pressedColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_N$hoverColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "hoverColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_N$disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_N$normalSprite": null, + "_N$pressedSprite": null, + "pressedSprite": null, + "_N$hoverSprite": null, + "hoverSprite": null, + "_N$disabledSprite": null, + "_N$target": { + "__id__": 2 + }, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "RLuNcFtmjzPsfxQx+giP6w", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "IntroPanel", + "_objFlags": 0, + "_parent": { + "__id__": 1 + }, + "_children": [ + { + "__id__": 8 + }, + { + "__id__": 11 + }, + { + "__id__": 14 + }, + { + "__id__": 17 + }, + { + "__id__": 56 + }, + { + "__id__": 58 + } + ], + "_active": true, + "_components": [ + { + "__id__": 62 + } + ], + "_prefab": { + "__id__": 63 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 920, + "height": 1480 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "BackgroundImage", + "_objFlags": 0, + "_parent": { + "__id__": 7 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 9 + } + ], + "_prefab": { + "__id__": 10 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 920, + "height": 1480 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 8 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": { + "__uuid__": "506252be-e576-479a-8475-649113ffa72f" + }, + "_type": 1, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "4JqtbQPABf5EV2rXTzvvqA", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "Title", + "_objFlags": 0, + "_parent": { + "__id__": 7 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 12 + } + ], + "_prefab": { + "__id__": 13 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 310, + "height": 85 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 600, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 11 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": { + "__uuid__": "1b908cf0-2bab-4a0e-a4a8-6b1bc8692909" + }, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "i2/0JpaqcuctRPU1ClWYVw", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "Status", + "_objFlags": 0, + "_parent": { + "__id__": 7 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 15 + } + ], + "_prefab": { + "__id__": 16 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 151, + "g": 111, + "b": 62, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 760, + "height": 100 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 14 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_string": "加载介绍中…", + "_N$string": "加载介绍中…", + "_fontSize": 32, + "_lineHeight": 40, + "_enableWrapText": true, + "_N$file": null, + "_isSystemFontUsed": true, + "_spacingX": 0, + "_batchAsBitmap": false, + "_styleFlags": 0, + "_underlineHeight": 0, + "_N$horizontalAlign": 1, + "_N$verticalAlign": 1, + "_N$fontFamily": "Arial", + "_N$overflow": 2, + "_N$cacheMode": 0, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "d8lgNfQ+Vvz+0A8epBzunQ", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "IntroViewport", + "_objFlags": 0, + "_parent": { + "__id__": 7 + }, + "_children": [ + { + "__id__": 18 + } + ], + "_active": true, + "_components": [ + { + "__id__": 53 + }, + { + "__id__": 54 + } + ], + "_prefab": { + "__id__": 55 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 850, + "height": 1020 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "Pages", + "_objFlags": 0, + "_parent": { + "__id__": 17 + }, + "_children": [ + { + "__id__": 19 + }, + { + "__id__": 30 + }, + { + "__id__": 41 + } + ], + "_active": true, + "_components": [], + "_prefab": { + "__id__": 52 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 850, + "height": 1020 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "Page1", + "_objFlags": 0, + "_parent": { + "__id__": 18 + }, + "_children": [ + { + "__id__": 20 + }, + { + "__id__": 23 + }, + { + "__id__": 26 + } + ], + "_active": true, + "_components": [], + "_prefab": { + "__id__": 29 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 850, + "height": 1020 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "TitleImage", + "_objFlags": 0, + "_parent": { + "__id__": 19 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 21 + } + ], + "_prefab": { + "__id__": 22 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 730, + "height": 125 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 425, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 20 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "fbf81871-1c4d-463d-b388-2287474d2a33", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "IconImage", + "_objFlags": 0, + "_parent": { + "__id__": 19 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 24 + } + ], + "_prefab": { + "__id__": 25 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 660, + "height": 425 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 75, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 23 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "6a13c691-afab-4e00-b2f9-d60c0d707bfe", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "DescriptionImage", + "_objFlags": 0, + "_parent": { + "__id__": 19 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 27 + } + ], + "_prefab": { + "__id__": 28 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 735, + "height": 205 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + -325, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 26 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 1, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "7153a826-10e3-4bfb-8ab8-98e002e6b025", + "sync": false + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "736c29a2-96dc-4509-b40c-07d74d7f81ce", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "Page2", + "_objFlags": 0, + "_parent": { + "__id__": 18 + }, + "_children": [ + { + "__id__": 31 + }, + { + "__id__": 34 + }, + { + "__id__": 37 + } + ], + "_active": true, + "_components": [], + "_prefab": { + "__id__": 40 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 850, + "height": 1020 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 850, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "TitleImage", + "_objFlags": 0, + "_parent": { + "__id__": 30 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 32 + } + ], + "_prefab": { + "__id__": 33 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 730, + "height": 125 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 425, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 31 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "9be1c97e-e0cb-4957-aee2-4ded08c94222", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "IconImage", + "_objFlags": 0, + "_parent": { + "__id__": 30 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 35 + } + ], + "_prefab": { + "__id__": 36 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 660, + "height": 425 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 75, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 34 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "19bad985-5823-4879-9cbf-7dd8f4dc4212", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "DescriptionImage", + "_objFlags": 0, + "_parent": { + "__id__": 30 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 38 + } + ], + "_prefab": { + "__id__": 39 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 735, + "height": 205 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + -325, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 37 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 1, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "b293a531-49fc-4357-9edd-4e7b89d7364d", + "sync": false + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "db760f39-54a3-42b7-84a3-a8945e408a1b", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "Page3", + "_objFlags": 0, + "_parent": { + "__id__": 18 + }, + "_children": [ + { + "__id__": 42 + }, + { + "__id__": 45 + }, + { + "__id__": 48 + } + ], + "_active": true, + "_components": [], + "_prefab": { + "__id__": 51 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 850, + "height": 1020 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 1700, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "TitleImage", + "_objFlags": 0, + "_parent": { + "__id__": 41 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 43 + } + ], + "_prefab": { + "__id__": 44 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 730, + "height": 125 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 425, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 42 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "864c0f29-e875-40d6-9583-d5869845a462", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "IconImage", + "_objFlags": 0, + "_parent": { + "__id__": 41 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 46 + } + ], + "_prefab": { + "__id__": 47 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 660, + "height": 425 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 75, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 45 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "40a3f9ed-8676-4eed-ab77-5070d6a1e4f9", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "DescriptionImage", + "_objFlags": 0, + "_parent": { + "__id__": 41 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 49 + } + ], + "_prefab": { + "__id__": 50 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 735, + "height": 205 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + -325, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 48 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": null, + "_type": 0, + "_sizeMode": 1, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "38f4fe50-3b53-460e-993f-e7213162b477", + "sync": false + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "249c882f-5b3c-4d05-8170-44174198eab4", + "sync": false + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "066a0ec9-5460-4a1a-af70-a9593ced2b37", + "sync": false + }, + { + "__type__": "cc.Mask", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 17 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_spriteFrame": null, + "_type": 0, + "_segments": 64, + "_N$alphaThreshold": 0.1, + "_N$inverted": false, + "_id": "" + }, + { + "__type__": "8168bhI+uRMW5/TmxovW2EE", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 17 + }, + "_enabled": true, + "dotFrame": { + "__uuid__": "93a7437b-9792-42c0-b0f5-73724314cbd8" + }, + "selectedDotFrame": { + "__uuid__": "af06b902-6722-4e79-871c-706dfd075327" + }, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "yraV/Owl8H/VN6T1NEj1Cw", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "Pagination", + "_objFlags": 0, + "_parent": { + "__id__": 7 + }, + "_children": [], + "_active": true, + "_components": [], + "_prefab": { + "__id__": 57 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 160, + "height": 40 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + -615, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "/mpSXwHdYoE0dZohjCJEFQ", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "CloseButton", + "_objFlags": 0, + "_parent": { + "__id__": 7 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 59 + }, + { + "__id__": 60 + } + ], + "_prefab": { + "__id__": 61 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 103, + "height": 110 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 365, + 615, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 58 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": { + "__uuid__": "b920b9e1-7d5d-4218-bc40-797cb0d9319d" + }, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 58 + }, + "_enabled": true, + "_normalMaterial": null, + "_grayMaterial": null, + "duration": 0.1, + "zoomScale": 1.1, + "clickEvents": [], + "_N$interactable": true, + "_N$enableAutoGrayEffect": false, + "_N$transition": 0, + "transition": 0, + "_N$normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_N$pressedColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "pressedColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_N$hoverColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "hoverColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_N$disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_N$normalSprite": null, + "_N$pressedSprite": null, + "pressedSprite": null, + "_N$hoverSprite": null, + "hoverSprite": null, + "_N$disabledSprite": null, + "_N$target": { + "__id__": 58 + }, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "d335EWZtVCrYv8+999km8J", + "sync": false + }, + { + "__type__": "cc.BlockInputEvents", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 7 + }, + "_enabled": true, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "SjhtNLAlHLqHHyNMZb8DSA", + "sync": false + }, + { + "__type__": "b6043noSMtByaaImD9068l0", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 1 + }, + "_enabled": true, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "", + "sync": false + } +] \ No newline at end of file diff --git a/assets/GameplayIntro/prefab/GameplayIntro.prefab.meta b/assets/GameplayIntro/prefab/GameplayIntro.prefab.meta new file mode 100644 index 0000000..2cf8f01 --- /dev/null +++ b/assets/GameplayIntro/prefab/GameplayIntro.prefab.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.3.2", + "uuid": "23d68b2f-0074-44dd-bbb2-5b064ee575a6", + "importer": "prefab", + "optimizationPolicy": "AUTO", + "asyncLoadAssets": false, + "readonly": false, + "subMetas": {} +} \ No newline at end of file diff --git a/assets/passCheck/script.meta b/assets/GameplayIntro/script.meta similarity index 81% rename from assets/passCheck/script.meta rename to assets/GameplayIntro/script.meta index 8227b45..3115793 100644 --- a/assets/passCheck/script.meta +++ b/assets/GameplayIntro/script.meta @@ -1,6 +1,6 @@ { "ver": "1.1.3", - "uuid": "da60b47d-5d32-4804-8b5f-3411aff909a3", + "uuid": "281f1ce9-089b-4ef5-983d-42deec7d4e25", "importer": "folder", "isBundle": false, "bundleName": "", diff --git a/assets/GameplayIntro/script/GameplayIntro.ts b/assets/GameplayIntro/script/GameplayIntro.ts new file mode 100644 index 0000000..01c042d --- /dev/null +++ b/assets/GameplayIntro/script/GameplayIntro.ts @@ -0,0 +1,222 @@ +import GuideCarousel from "./GuideCarousel"; +// 一页图片的资源记录:node 是图片容器,frames 是本页持有引用的资源,sprites 是显示图片的组件。 +// live=false 表示本页已移出保留范围;晚到的加载结果必须丢弃,不能再显示。 +type IntroPage = { node: cc.Node; frames: cc.SpriteFrame[]; sprites: cc.Sprite[]; live: boolean }; +const { ccclass } = cc._decorator; + +// daoju26 是变色跳跃门、daoju27 是障碍杆;公共素材的这两个编号相反。 +const PROP_ART_IDS = Array.from({ length: 34 }, (_, index) => index === 26 ? 27 : index === 27 ? 26 : index); + +/** + * 本关玩法面板控制器,挂在 GameplayIntro 预制体根节点。 + * 阅读顺序:open 接收本关列表 → syncPages 确定需要的三页 → picture 排队加载图片。 + * 关闭时 releasePages 释放玩法图;背景、标题等固定布局留在预制体中供下次复用。 + */ +@ccclass +export default class GameplayIntro extends cc.Component { + private imageLayouts = new Map(); + + // 调用方已按本关配置筛选并去重;按解锁关卡倒序排列,每次打开最左端的最新玩法。 + private introductions: any[] = []; + private carousel: GuideCarousel = null; + private board: cc.Node = null; + private status: cc.Label = null; + // 每次打开/关闭递增的请求编号,用来识别已过期的异步加载回调。 + private request = 0; + private panelTween: cc.Tween = null; + private closing = false; + // 只记录当前页及相邻页的图片,不为所有历史页面常驻图片资源。 + private loadedPages: { [index: number]: IntroPage } = {}; + // 图片逐张加载:队列存“加载任务”,imageLoading 防止同时启动多个任务。 + private imageQueue: Array<() => void> = []; + private imageLoading = false; + + /** entries 是本关实际用到的玩法介绍,空列表直接关闭。 */ + open(entries: any[]) { + this.stopPanelAnimation(); + this.releasePages(); + this.introductions = entries.slice().sort((a, b) => b.level - a.level); + if (!this.introductions.length) { + if (this.carousel) this.carousel.clear(); + this.finishClose(); + return; + } + this.node.active = true; + // 固定节点只查找和绑定一次,避免重复打开时叠加关闭/翻页监听。 + if (!this.board) { + this.board = this.node.getChildByName("IntroPanel"); + this.status = this.board.getChildByName("Status").getComponent(cc.Label); + // Backdrop 是面板外的遮罩,点击它关闭;面板自身通过 BlockInputEvents 阻止穿透。 + const backdrop = this.node.getChildByName("Backdrop"); + const graphics = backdrop.getComponent(cc.Graphics); + graphics.fillColor = new cc.Color(0, 0, 0, 170); + graphics.rect(-backdrop.width / 2, -backdrop.height / 2, backdrop.width, backdrop.height); + graphics.fill(); + backdrop.on("click", this.close, this); + this.board.getChildByName("CloseButton").on("click", this.close, this); + const viewport = this.board.getChildByName("IntroViewport"); + this.carousel = viewport.getComponent(GuideCarousel); + viewport.on("page-changed", () => { + // GuideCarousel 通知目标页已变化,此时及时加载新邻页、释放远处页。 + this.syncPages(); + }, this); + } + // 重置分页状态和滑动监听,保留预制体中的三个固定页面。 + this.carousel.clear(); + this.status.node.targetOff(this); + this.status.node.active = true; + this.status.string = "加载介绍中…"; + this.status.node.active = false; + this.carousel.initialize(this.introductions.length, 0, this.board.getChildByName("Pagination")); + this.board.scale = 0.3; + this.panelTween = cc.tween(this.board) + .to(0.2, { scale: 1.05 }, { easing: "backOut" }) + .to(0.15, { scale: 1 }, { easing: "sineOut" }); + this.panelTween.start(); + } + + /** 性能优化入口:翻页后只保留 current-1、current、current+1 这三页的图片。 */ + private syncPages() { + const current = this.carousel.index; + Object.keys(this.loadedPages).forEach(key => { + const index = Number(key); + // 例如当前为第 5 项,只保留索引 4、5、6;其它已加载页立即释放。 + if (Math.abs(index - current) > 1) this.releasePage(index); + }); + // 优先加载当前页,再加载前一页和后一页;越界或已加载的页面直接跳过。 + // 在真实列表的两端,通常只需保留两页。 + [current, current - 1, current + 1].forEach(index => { + if (index < 0 || index >= this.introductions.length || this.loadedPages[index]) return; + const node = this.carousel.pages[index]; + node.active = true; + const page: IntroPage = { node, frames: [], sprites: [], live: true }; + this.loadedPages[index] = page; + const entry = this.introductions[index]; + const art = PROP_ART_IDS[Number(entry.name.replace("daoju", ""))]; + // 公共玩法图:上方标题、中间道具大图、下方说明。 + if (art !== undefined) { + this.picture(page, "TitleImage", "title" + art); + this.picture(page, "IconImage", "icon" + art); + this.picture(page, "DescriptionImage", "Introduction" + art); + } else this.showMessage(entry.tips); + }); + } + + /** 替换预制体中的图片;说明图由组件控制大小;标题和道具图按预制体展示区域等比适配。 */ + private picture(page: IntroPage, nodeName: string, path: string) { + const node = page.node.getChildByName(nodeName); + const fitImage = nodeName !== "DescriptionImage"; + if (fitImage && !this.imageLayouts.has(node)) { + this.imageLayouts.set(node, { width: node.width, height: node.height, scale: node.scale }); + } + const sprite = node.getComponent(cc.Sprite); + page.sprites.push(sprite); + this.imageQueue.push(() => { + // 排队期间用户可能已翻走或关闭面板,失效任务无需再发起资源加载。 + if (!page.live) { this.nextImage(); return; } + this.imageLoading = true; + cc.resources.load("Window_Prop/" + path, cc.SpriteFrame, (error, frame: cc.SpriteFrame) => { + // addRef 表示本页持有这份资源;释放页时配对 decRef。 + // decRef 减少引用,资源没有其它引用时由引擎回收。 + if (!error && frame) frame.addRef(); + // 已经发出的请求不能靠清空队列取消;因此结果回来时还要再检查页面是否有效。 + if (!page.live || !cc.isValid(node, true)) { + if (!error && frame) frame.decRef(); + } else if (error) { + this.showMessage("图片加载失败"); + cc.error("Gameplay intro image", path, error); + } else { + page.frames.push(frame); + // 禁止加入动态合图,避免图片被复制到长期存在的图集中,影响关闭后的回收。 + frame.getTexture().packable = false; + sprite.spriteFrame = frame; + if (fitImage) { + const layout = this.imageLayouts.get(node); + const size = frame.getOriginalSize(); + node.setContentSize(size.width, size.height); + node.scale = Math.min(layout.width / size.width, layout.height / size.height) * layout.scale; + } + + } + this.imageLoading = false; + this.nextImage(); + }); + }); + this.nextImage(); + } + + /** 一次只启动一张图,当前加载回调结束后才取下一项,减少集中加载造成的卡顿。 */ + private nextImage() { + if (this.imageLoading || !this.imageQueue.length) return; + this.imageQueue.shift()(); + } + + /** 先断开显示引用,再归还资源引用,最后隐藏固定页面,供后续复用。 */ + private releasePage(index: number) { + const page = this.loadedPages[index]; + page.live = false; + page.sprites.forEach(sprite => { + if (cc.isValid(sprite, true)) sprite.spriteFrame = null; + }); + page.frames.forEach(frame => frame.decRef()); + if (cc.isValid(page.node, true)) { + page.node.active = false; + // 固定页面节点保留,下一次仅替换图片。 + } + delete this.loadedPages[index]; + } + + /** 清空待加载任务和已加载图片;在途请求返回后由 picture 中的 live 检查处理。 */ + private releasePages() { + this.imageQueue = []; + Object.keys(this.loadedPages).forEach(key => this.releasePage(Number(key))); + } + + // 即使外部直接隐藏面板而没有调用 close,也要释放图片并让旧请求失效。 + onDisable() { + this.stopPanelAnimation(); + ++this.request; + this.releasePages(); + } + + // 场景退出或节点被销毁时的兜底清理。 + onDestroy() { + this.stopPanelAnimation(); + this.releasePages(); + } + + /** 隐藏面板并通知打开它的场景;是否恢复游戏由 SceneManager 判断。 */ + close() { + if (this.closing || !this.node.active) return; + if (!this.board) { this.finishClose(); return; } + if (this.panelTween) this.panelTween.stop(); + this.closing = true; + this.panelTween = cc.tween(this.board) + .to(0.15, { scale: 0.3 }, { easing: "sineIn" }) + .call(() => this.finishClose()); + this.panelTween.start(); + } + + // 退场完成后再释放图片和通知场景恢复游戏,避免动画期间内容消失。 + private finishClose() { + this.stopPanelAnimation(); + ++this.request; + this.releasePages(); + this.node.active = false; + this.node.emit("intro-closed"); + } + + private stopPanelAnimation() { + if (this.panelTween) this.panelTween.stop(); + this.panelTween = null; + this.closing = false; + // 销毁回调中子节点可能已释放;这里只停止动画,不再写入节点属性。 + // 每次打开都会重新设置起始缩放。 + } + + // 提示也复用主预制体的 Status 节点,避免向固定玩法页追加节点。 + private showMessage(value: string) { + this.status.string = value; + this.status.node.active = true; + } +} diff --git a/assets/GameplayIntro/script/GameplayIntro.ts.meta b/assets/GameplayIntro/script/GameplayIntro.ts.meta new file mode 100644 index 0000000..0aee8f6 --- /dev/null +++ b/assets/GameplayIntro/script/GameplayIntro.ts.meta @@ -0,0 +1,10 @@ +{ + "ver": "1.1.0", + "uuid": "b60439e8-48cb-41c9-a688-983f74ebc974", + "importer": "typescript", + "isPlugin": false, + "loadPluginInWeb": true, + "loadPluginInNative": true, + "loadPluginInEditor": false, + "subMetas": {} +} \ No newline at end of file diff --git a/assets/GameplayIntro/script/GuideCarousel.ts b/assets/GameplayIntro/script/GuideCarousel.ts new file mode 100644 index 0000000..9e14978 --- /dev/null +++ b/assets/GameplayIntro/script/GuideCarousel.ts @@ -0,0 +1,275 @@ +const { ccclass, property } = cc._decorator; + +/** + * 通用横向滑动组件,挂在预制体的 IntroViewport 上。 + * 只负责位移、手势和白点动画,不负责解锁配置及图片加载。 + * 手势流程:begin 按下 → move 跟手 → end 松开选页 → update 每帧完成缓动。 + * 实际页码 index 与白点位置 activeDot 是两套状态,介绍页数可以超过 3。 + */ +@ccclass +export default class GuideCarousel extends cc.Component { + @property(cc.SpriteFrame) + dotFrame: cc.SpriteFrame = null; + @property(cc.SpriteFrame) + selectedDotFrame: cc.SpriteFrame = null; + // 当前目标页索引,从 0 开始;pages 包含所有介绍页的占位节点。 + index = 0; + pages: cc.Node[] = []; + private pageSlots: cc.Node[] = []; + // 所有页面都挂到 track 下;移动这个父节点即可让整排页面一起移动。 + private track: cc.Node = null; + private dots: cc.Node[] = []; + // 最多三个白点;打开时根据默认页定位。 + private activeDot = 0; + // 仅替换动画期间显示的辅助白点,平时隐藏,不表示额外页面。 + private incomingDot: cc.Node = null; + // 替换动画的移动方向:1 向右移动,-1 向左移动,0 不播放。 + private dotDirection = 0; + private dotElapsed = 0; + // width 是一页宽度;offset 是整排页面的横向位移;origin 是按下时的位移基准。 + private width = 880; + private offset = 0; + private origin = 0; + // 拖动起点、最近位置和最近时间,用于计算拖动距离及甩动速度。 + private startX = 0; + private lastX = 0; + private lastTime = 0; + private speed = 0; + // 记录本次拖动属于鼠标还是哪根手指,避免多个输入同时控制页面。 + private pointer: string = null; + // 松手缓动的起点、终点、已过时间;settling=true 时 update 会继续移动。 + private from = 0; + private destination = 0; + private elapsed = 0; + private settling = false; + + /** 传入所有页面、默认页索引和分页器容器;重复初始化会先清理旧内容。 */ + initialize(count: number, selected: number, indicator: cc.Node) { + this.clear(); + this.width = this.node.width; + this.track = this.node.getChildByName("Pages"); + this.pageSlots = this.track.children.slice(); + // 逻辑页共用预制体内的三个固定槽位,相邻三页对应不同槽位。 + const pages = this.pages = Array.from({ length: count }, (_, index) => this.pageSlots[index % 3]); + const dotCount = pages.length > 1 ? Math.min(3, pages.length) : 0; + indicator.active = dotCount > 0; + for (let i = 0; i < dotCount; i++) { + const dot = this.createDot(indicator, "Dot" + i); + dot.x = (i - (dotCount - 1) / 2) * 40; + this.dots.push(dot); + } + if (pages.length > 3) { + this.incomingDot = this.createDot(indicator, "IncomingDot"); + this.incomingDot.active = false; + } + this.index = Math.max(0, Math.min(pages.length - 1, selected)); + this.activeDot = Math.min(Math.max(0, dotCount - 1), this.index); + this.goTo(this.index, false); + if (pages.length < 2) return; + const type = cc.Node.EventType; + this.node.on(type.TOUCH_START, this.touchStart, this); + this.node.on(type.TOUCH_MOVE, this.touchMove, this); + this.node.on(type.TOUCH_END, this.touchEnd, this); + this.node.on(type.TOUCH_CANCEL, this.touchCancel, this); + // 同时监听鼠标与触摸,兼容桌面预览中没有被转换成触摸事件的鼠标拖动。 + this.node.on(type.MOUSE_DOWN, this.mouseDown, this); + this.node.on(type.MOUSE_MOVE, this.mouseMove, this); + this.node.on(type.MOUSE_UP, this.mouseUp, this); + this.node.on(type.MOUSE_LEAVE, this.mouseLeave, this); + } + + /** 清理本组件的监听、页面轨道和白点,防止重复打开后节点/事件越来越多。 */ + clear() { + this.node.targetOff(this); + this.pointer = null; + this.settling = false; + this.dotDirection = 0; + this.pageSlots.forEach(page => { if (cc.isValid(page, true)) page.active = false; }); + this.dots.concat(this.incomingDot ? [this.incomingDot] : []).forEach(dot => { + dot.removeFromParent(); + dot.destroy(); + }); + this.track = null; + this.incomingDot = null; + this.dots = []; + this.pages = []; + this.offset = 0; + } + + /** 切换目标页;animated=false 用于首次打开时直接定位,默认则平滑过渡。 */ + goTo(index: number, animated = true) { + if (!this.track || !this.pages.length) return; + this.pointer = null; + const previous = this.index; + const previousDot = this.activeDot; + this.resetDotAnimation(); + // 限制在真实页码范围内,所以边界拖动不会进入不存在的页面。 + this.index = Math.max(0, Math.min(this.pages.length - 1, index)); + // 查看更早页:左点 → 中点 → 右点 → 一直保持右点;查看更新页则反向移动。 + // 这里只根据实际页码变化量移动白点,并不要求已经到达介绍列表的两端。 + // 如果只是边界回弹,页码未变,白点也不会改变。 + this.activeDot = Math.max(0, Math.min(this.dots.length - 1, this.activeDot + this.index - previous)); + this.from = this.offset; + // 第 n 页原本在 n*width 处,让整排左移 n*width,就能把该页放到视口中心。 + this.destination = -this.index * this.width; + this.elapsed = 0; + this.settling = animated; + if (!animated) this.offset = this.destination; + this.dots.forEach((dot, i) => this.styleDot(dot, i === this.activeDot)); + const delta = this.index - previous; + // 页码确实改变,但高亮点已经停在最左/最右时,播放白点从旁边补进的替换动画。 + // 真正到达列表边界且页码未改变时不播放。 + if (this.incomingDot && animated && delta !== 0 && previousDot === this.activeDot && + ((delta < 0 && this.activeDot === 0) || (delta > 0 && this.activeDot === 2))) { + this.dotDirection = delta < 0 ? 1 : -1; + this.dotElapsed = 0; + this.incomingDot.active = true; + this.animateDots(0); + } + this.render(); + this.node.emit("page-changed", this.index); + } + + // 分页图片由预制体直接持有,重复打开无需异步加载。 + private createDot(parent: cc.Node, name: string): cc.Node { + const dot = new cc.Node(name); + dot.parent = parent; + dot.addComponent(cc.Sprite); + this.styleDot(dot, false); + return dot; + } + + private styleDot(dot: cc.Node, selected: boolean) { + dot.getComponent(cc.Sprite).spriteFrame = selected ? this.selectedDotFrame : this.dotFrame; + dot.scale = 1; + } + + // 动画结束或被打断时恢复三个固定位置,隐藏辅助点,选中点使用白色圆点图片。 + private resetDotAnimation() { + this.dotDirection = 0; + if (this.incomingDot) this.incomingDot.active = false; + this.dots.forEach((dot, i) => { + dot.x = (i - (this.dots.length - 1) / 2) * 40; + dot.opacity = 255; + this.styleDot(dot, i === this.activeDot); + }); + } + + /** dt 是这一帧经过的秒数;旧点移出并淡出,辅助点从另一边进入并放大。 */ + private animateDots(dt: number) { + if (!this.dotDirection) return; + this.dotElapsed += dt; + // 替换动画持续 0.28 秒,三次方缓动使运动先快后慢。 + const t = Math.min(1, this.dotElapsed / 0.28); + const eased = 1 - Math.pow(1 - t, 3); + const direction = this.dotDirection; + this.dots.forEach((dot, i) => { + const destination = i + direction; + this.styleDot(dot, (eased < 0.5 ? i : destination) === this.activeDot); + dot.x = (i - 1) * 40 + direction * 40 * eased; + dot.opacity = destination < 0 || destination > 2 ? Math.round(255 * (1 - eased)) : 255; + }); + this.incomingDot.x = -direction * (80 - 40 * eased); + this.incomingDot.opacity = Math.round(255 * eased); + this.styleDot(this.incomingDot, true); + this.incomingDot.scale = 0.5 + 0.5 * eased; + if (t === 1) this.resetDotAnimation(); + } + + // 把屏幕坐标转成视口局部坐标,面板有缩放时仍能正确计算拖动距离。 + private x(event: cc.Event.EventTouch | cc.Event.EventMouse) { + return this.node.convertToNodeSpaceAR(event.getLocation()).x; + } + + /** 按下时接管当前位置,允许用户在回弹中途再次抓住页面。 */ + private begin(pointer: string, x: number) { + if (this.pointer !== null || this.pages.length < 2) return; + this.pointer = pointer; + this.settling = false; + this.startX = this.lastX = x; + this.lastTime = Date.now(); + this.speed = 0; + this.origin = this.offset; + const min = -(this.pages.length - 1) * this.width; + // 边界位移已经经过阻尼压缩;这里反算原始拖动量。 + // 否则在回弹途中重新按下,第一次 move 会再次压缩位移,导致内容突然跳动。 + if (this.offset > 0) this.origin = 240 * this.offset / (120 - this.offset); + else if (this.offset < min) { + const extra = min - this.offset; + this.origin = min - 240 * extra / (120 - extra); + } + } + + /** 拖动中直接更新位移,实现跟手效果。 */ + private move(pointer: string, x: number) { + if (this.pointer !== pointer) return; + const now = Date.now(); + this.speed = (x - this.lastX) / Math.max(1, now - this.lastTime); + this.lastX = x; + this.lastTime = now; + const raw = this.origin + x - this.startX; + const min = -(this.pages.length - 1) * this.width; + // 合法位移范围是 [min, 0]。超过任一端后使用阻尼:越拉越费劲,位移趋近 120。 + // 240 控制阻力曲线;范围内则直接使用 raw,不额外减慢跟手移动。 + this.offset = raw > 0 ? 120 * raw / (240 + raw) : raw < min ? min - 120 * (min - raw) / (240 + min - raw) : raw; + this.render(); + } + + /** 松手时根据距离/速度决定目标页,再交给 goTo 做吸附或回弹。 */ + private end(pointer: string, cancel = false) { + if (this.pointer !== pointer) return; + const distance = this.lastX - this.startX; + // 停住超过 100 毫秒再松手,就不再把之前的移动速度当作快速甩动。 + const speed = Date.now() - this.lastTime < 100 ? this.speed : 0; + let next = Math.round(-this.offset / this.width); + // 拖过页宽的 18%,或速度超过每毫秒 0.45 个局部坐标单位,即按方向翻一页。 + // 触摸被系统取消时,使用当前位置最近的页面,不额外按甩动方向翻页。 + if (!cancel && (Math.abs(distance) > this.width * 0.18 || Math.abs(speed) > 0.45)) { + next = this.index + ((Math.abs(speed) > 0.45 ? speed : distance) < 0 ? 1 : -1); + } + this.goTo(next); + } + + // 触摸事件带手指 ID;鼠标只响应左键。离开视口也结束拖动,避免内容一直粘着鼠标。 + private touchStart(event: cc.Event.EventTouch) { this.begin("touch" + event.getID(), this.x(event)); event.stopPropagation(); } + private touchMove(event: cc.Event.EventTouch) { this.move("touch" + event.getID(), this.x(event)); event.stopPropagation(); } + private touchEnd(event: cc.Event.EventTouch) { this.end("touch" + event.getID()); event.stopPropagation(); } + private touchCancel(event: cc.Event.EventTouch) { this.end("touch" + event.getID(), true); event.stopPropagation(); } + private mouseDown(event: cc.Event.EventMouse) { if (event.getButton() === 0) this.begin("mouse", this.x(event)); } + private mouseMove(event: cc.Event.EventMouse) { this.move("mouse", this.x(event)); } + private mouseUp(event: cc.Event.EventMouse) { if (event.getButton() === 0) this.end("mouse"); } + private mouseLeave() { this.end("mouse"); } + + /** 应用当前位移;离视口中心越远的页面稍微缩小、变淡,让过渡更自然。 */ + private render() { + this.track.x = this.offset; + this.pageSlots.forEach(page => page.active = false); + for (let i = Math.max(0, this.index - 1); i <= Math.min(this.pages.length - 1, this.index + 1); i++) { + const page = this.pages[i]; + page.active = true; + page.x = i * this.width; + const distance = Math.min(1, Math.abs(i * this.width + this.offset) / this.width); + page.scale = 1 - distance * 0.025; + page.opacity = Math.round(255 - distance * 45); + } + } + + /** Cocos 每帧调用:推进白点动画,以及松手后的 0.32 秒页面缓动。 */ + update(dt: number) { + this.animateDots(dt); + if (!this.settling) return; + this.elapsed += dt; + const t = Math.min(1, this.elapsed / 0.32); + this.offset = this.from + (this.destination - this.from) * (1 - Math.pow(1 - t, 3)); + this.render(); + if (t === 1) this.settling = false; + } + + // 面板隐藏时结束未完成的手势和动画,避免再次显示时残留半途状态。 + onDisable() { + this.resetDotAnimation(); + this.pointer = null; + this.settling = false; + if (this.track && cc.isValid(this.track, true) && this.pageSlots.every(page => cc.isValid(page, true))) { this.offset = -this.index * this.width; this.render(); } + } +} diff --git a/assets/GameplayIntro/script/GuideCarousel.ts.meta b/assets/GameplayIntro/script/GuideCarousel.ts.meta new file mode 100644 index 0000000..fcc0453 --- /dev/null +++ b/assets/GameplayIntro/script/GuideCarousel.ts.meta @@ -0,0 +1,10 @@ +{ + "ver": "1.1.0", + "uuid": "8168b848-fae4-4c5b-9fd3-9b1a2f5b6104", + "importer": "typescript", + "isPlugin": false, + "loadPluginInWeb": true, + "loadPluginInNative": true, + "loadPluginInEditor": false, + "subMetas": {} +} \ No newline at end of file diff --git a/assets/Scene/GameScene.fire b/assets/Scene/GameScene.fire index 776385b..f9f688d 100644 --- a/assets/Scene/GameScene.fire +++ b/assets/Scene/GameScene.fire @@ -17,7 +17,7 @@ "__id__": 2 }, { - "__id__": 297 + "__id__": 296 } ], "_active": false, @@ -84,14 +84,20 @@ "__id__": 258 }, { - "__id__": 262 + "__id__": 261 }, { - "__id__": 287 + "__id__": 286 + }, + { + "__id__": 303 } ], "_active": true, "_components": [ + { + "__id__": 292 + }, { "__id__": 293 }, @@ -100,9 +106,6 @@ }, { "__id__": 295 - }, - { - "__id__": 296 } ], "_prefab": null, @@ -801,6 +804,9 @@ }, { "__id__": 62 + }, + { + "__id__": 298 } ], "_active": true, @@ -12376,7 +12382,7 @@ "__id__": 260 }, { - "__id__": 261 + "__id__": 304 } ], "_prefab": null, @@ -12474,16 +12480,6 @@ "_originalHeight": 0, "_id": "394oVlZVVDDp4PRHaKfK2n" }, - { - "__type__": "cc.BlockInputEvents", - "_name": "", - "_objFlags": 0, - "node": { - "__id__": 258 - }, - "_enabled": true, - "_id": "d9e8Y//+dGO5Tm2vNoQbwO" - }, { "__type__": "cc.Node", "_name": "Loading", @@ -12493,31 +12489,31 @@ }, "_children": [ { - "__id__": 263 + "__id__": 262 }, { - "__id__": 266 + "__id__": 265 }, { - "__id__": 268 + "__id__": 267 }, { - "__id__": 272 + "__id__": 271 }, { - "__id__": 276 + "__id__": 275 }, { - "__id__": 280 + "__id__": 279 }, { - "__id__": 284 + "__id__": 283 } ], "_active": false, "_components": [ { - "__id__": 286 + "__id__": 285 } ], "_prefab": null, @@ -12573,16 +12569,16 @@ "_name": "New Sprite(Splash)", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [], "_active": true, "_components": [ { - "__id__": 264 + "__id__": 263 }, { - "__id__": 265 + "__id__": 264 } ], "_prefab": null, @@ -12638,7 +12634,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 263 + "__id__": 262 }, "_enabled": true, "_materials": [ @@ -12670,7 +12666,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 263 + "__id__": 262 }, "_enabled": true, "_id": "0fS5t0zP5AdI0CPkmzwBv/" @@ -12680,13 +12676,13 @@ "_name": "New Label", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [], "_active": true, "_components": [ { - "__id__": 267 + "__id__": 266 } ], "_prefab": null, @@ -12742,7 +12738,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 266 + "__id__": 265 }, "_enabled": true, "_materials": [ @@ -12775,17 +12771,17 @@ "_name": "block1", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [ { - "__id__": 269 + "__id__": 268 } ], "_active": true, "_components": [ { - "__id__": 271 + "__id__": 270 } ], "_prefab": null, @@ -12841,13 +12837,13 @@ "_name": "light", "_objFlags": 0, "_parent": { - "__id__": 268 + "__id__": 267 }, "_children": [], "_active": true, "_components": [ { - "__id__": 270 + "__id__": 269 } ], "_prefab": null, @@ -12903,7 +12899,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 269 + "__id__": 268 }, "_enabled": true, "_materials": [ @@ -12935,7 +12931,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 268 + "__id__": 267 }, "_enabled": true, "_materials": [ @@ -12967,17 +12963,17 @@ "_name": "block2", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [ { - "__id__": 273 + "__id__": 272 } ], "_active": true, "_components": [ { - "__id__": 275 + "__id__": 274 } ], "_prefab": null, @@ -13033,13 +13029,13 @@ "_name": "light", "_objFlags": 0, "_parent": { - "__id__": 272 + "__id__": 271 }, "_children": [], "_active": true, "_components": [ { - "__id__": 274 + "__id__": 273 } ], "_prefab": null, @@ -13095,7 +13091,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 273 + "__id__": 272 }, "_enabled": true, "_materials": [ @@ -13127,7 +13123,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 272 + "__id__": 271 }, "_enabled": true, "_materials": [ @@ -13159,17 +13155,17 @@ "_name": "block3", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [ { - "__id__": 277 + "__id__": 276 } ], "_active": true, "_components": [ { - "__id__": 279 + "__id__": 278 } ], "_prefab": null, @@ -13225,13 +13221,13 @@ "_name": "light", "_objFlags": 0, "_parent": { - "__id__": 276 + "__id__": 275 }, "_children": [], "_active": true, "_components": [ { - "__id__": 278 + "__id__": 277 } ], "_prefab": null, @@ -13287,7 +13283,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 277 + "__id__": 276 }, "_enabled": true, "_materials": [ @@ -13319,7 +13315,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 276 + "__id__": 275 }, "_enabled": true, "_materials": [ @@ -13351,17 +13347,17 @@ "_name": "block4", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [ { - "__id__": 281 + "__id__": 280 } ], "_active": true, "_components": [ { - "__id__": 283 + "__id__": 282 } ], "_prefab": null, @@ -13417,13 +13413,13 @@ "_name": "light", "_objFlags": 0, "_parent": { - "__id__": 280 + "__id__": 279 }, "_children": [], "_active": true, "_components": [ { - "__id__": 282 + "__id__": 281 } ], "_prefab": null, @@ -13479,7 +13475,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 281 + "__id__": 280 }, "_enabled": true, "_materials": [ @@ -13511,7 +13507,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 280 + "__id__": 279 }, "_enabled": true, "_materials": [ @@ -13543,13 +13539,13 @@ "_name": "cat", "_objFlags": 0, "_parent": { - "__id__": 262 + "__id__": 261 }, "_children": [], "_active": true, "_components": [ { - "__id__": 285 + "__id__": 284 } ], "_prefab": null, @@ -13605,7 +13601,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 284 + "__id__": 283 }, "_enabled": true, "_materials": [ @@ -13637,7 +13633,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 262 + "__id__": 261 }, "_enabled": true, "alignMode": 1, @@ -13668,16 +13664,16 @@ }, "_children": [ { - "__id__": 288 + "__id__": 287 } ], "_active": false, "_components": [ { - "__id__": 291 + "__id__": 290 }, { - "__id__": 292 + "__id__": 291 } ], "_prefab": null, @@ -13733,16 +13729,16 @@ "_name": "New Sprite(Splash)", "_objFlags": 0, "_parent": { - "__id__": 287 + "__id__": 286 }, "_children": [], "_active": true, "_components": [ { - "__id__": 289 + "__id__": 288 }, { - "__id__": 290 + "__id__": 289 } ], "_prefab": null, @@ -13798,7 +13794,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 288 + "__id__": 287 }, "_enabled": true, "_materials": [ @@ -13830,7 +13826,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 288 + "__id__": 287 }, "_enabled": true, "_id": "4fwjz1lnFLD45L1lqUY038" @@ -13840,7 +13836,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 287 + "__id__": 286 }, "_enabled": true, "_materials": [ @@ -13882,7 +13878,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 287 + "__id__": 286 }, "_enabled": false, "_id": "00qpMLeBFNhYRX9r3QZvyP" @@ -13972,7 +13968,10 @@ "__uuid__": "fd85df88-648f-4407-bab2-da4f15478fb9" }, "messageNode": null, - "_id": "4cjBjPtcBO05zIQupw5luh" + "_id": "4cjBjPtcBO05zIQupw5luh", + "tipPanel": { + "__id__": 303 + } }, { "__type__": "f1883pXzMVIp5/ARDAWfZ7j", @@ -13995,7 +13994,7 @@ "_active": true, "_components": [ { - "__id__": 298 + "__id__": 297 } ], "_prefab": null, @@ -14051,7 +14050,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 297 + "__id__": 296 }, "_enabled": true, "_materials": [ @@ -14075,5 +14074,316 @@ "_isTrimmedMode": true, "_atlas": null, "_id": "95joh5iDZB1IGmJkAeXXrL" + }, + { + "__type__": "cc.Node", + "_name": "tip", + "_objFlags": 0, + "_parent": { + "__id__": 15 + }, + "_children": [ + { + "__id__": 299 + } + ], + "_active": true, + "_components": [], + "_prefab": null, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 0, + "height": 0 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "e4LIw406xPc6DLoPDZ9wmy" + }, + { + "__type__": "cc.Node", + "_name": "GameplayInfoButton", + "_objFlags": 0, + "_parent": { + "__id__": 298 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 300 + }, + { + "__id__": 301 + } + ], + "_prefab": null, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 82.66666666666667, + "height": 88 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 282, + -60.562, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "Vg/+kIt8y9qkYZSB/Xx8wA" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 299 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": { + "__uuid__": "d9333256-302a-403b-93bf-e25c42829476" + }, + "_type": 0, + "_sizeMode": 0, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "7urvt+4r1Eol9iPd9AAi5Q" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 299 + }, + "_enabled": true, + "_normalMaterial": null, + "_grayMaterial": null, + "duration": 0.1, + "zoomScale": 1.2, + "clickEvents": [ + { + "__id__": 302 + } + ], + "_N$interactable": true, + "_N$enableAutoGrayEffect": false, + "_N$transition": 0, + "transition": 0, + "_N$normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_N$pressedColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "pressedColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_N$hoverColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "hoverColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_N$disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_N$normalSprite": null, + "_N$pressedSprite": null, + "pressedSprite": null, + "_N$hoverSprite": null, + "hoverSprite": null, + "_N$disabledSprite": null, + "_N$target": { + "__id__": 299 + }, + "_id": "4y6hgv/WvY4E/88bmCerjg" + }, + { + "__type__": "cc.ClickEvent", + "target": { + "__id__": 2 + }, + "component": "", + "_componentId": "80998T1AYNNRZdRxsVvXR65", + "handler": "openGameplayIntro", + "customEventData": "" + }, + { + "__type__": "cc.Node", + "_name": "tipPanel", + "_objFlags": 0, + "_parent": { + "__id__": 2 + }, + "_children": [], + "_active": false, + "_components": [], + "_prefab": null, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 0, + "height": 0 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "ffogY+noNEpL/dzRMkLQ4G" + }, + { + "__type__": "cc.BlockInputEvents", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 258 + }, + "_enabled": true, + "_id": "d9e8Y//+dGO5Tm2vNoQbwO" } ] \ No newline at end of file diff --git a/assets/Script/SceneManager.ts b/assets/Script/SceneManager.ts index b3144cc..234d747 100644 --- a/assets/Script/SceneManager.ts +++ b/assets/Script/SceneManager.ts @@ -1,3 +1,5 @@ +import type GameplayIntro from "../GameplayIntro/script/GameplayIntro"; +import { getLevelGameplay } from "./module/Tool/LevelGameplay"; // Learn TypeScript: // - https://docs.cocos.com/creator/manual/en/scripting/typescript.html // Learn Attribute: @@ -698,7 +700,18 @@ export default class SceneManager extends cc.Component { return true; } + // 在 Creator 的 Inspector 中绑定场景现有 tipPanel;打开后的预制体挂到这里。 + @property(cc.Node) + tipPanel: cc.Node = null; + + // 保存已创建的面板控制器,重复打开复用实例;玩法图片仍由面板按需加载/释放。 + private gameplayIntro: GameplayIntro = null; + private levelGameplay: any[] = []; + isPauseOpen(): boolean { + // 加载期间及面板显示期间都视为暂停,避免重复打开或其它流程提前恢复游戏。 + if (this.dynamicPopupLoads && this.dynamicPopupLoads.gameplayIntro) return true; + if (this.gameplayIntro && cc.isValid(this.gameplayIntro.node) && this.gameplayIntro.node.active) return true; const pauseRoot = this.getDynamicPopup("pause"); return !!(this.dynamicPopupLoads && this.dynamicPopupLoads.pause) || (!!pauseRoot && pauseRoot.active); @@ -792,6 +805,7 @@ export default class SceneManager extends cc.Component { this.dynamicPopupRetries = {}; this.dynamicPopupStates = {}; this.popupBundleWarmupStarted = false; + this.refreshGameplayInfo(); this.ensureLoadingOnTop(); const intercept = this.ensureDynamicPopupIntercept(); if (intercept) intercept.active = false; @@ -1158,8 +1172,75 @@ export default class SceneManager extends cc.Component { }); } - start() { + /** 关卡数据在进入场景前已加载;按完整关卡保存列表,消除道具后仍可查阅。 */ + private refreshGameplayInfo() { + const button = cc.find("Game/GameNode/Top/tip/GameplayInfoButton", this.node); + const apply = (config: any[]) => { + this.levelGameplay = getLevelGameplay(config, cc.fx.GameConfig); + if (button && cc.isValid(button)) button.active = this.levelGameplay.length > 0; + }; + if (cc.fx.GameConfig.NEW_LEVEL) { + apply(cc.fx.GameConfig.NEW_LEVEL); + } else { + // 全局介绍配置是异步读取的,首次进场景时可能仍在加载。 + if (button) button.active = false; + cc.resources.load("Json/NEW_LEVEL", cc.JsonAsset, (error, asset: cc.JsonAsset) => { + if (!this.isPopupRuntimeAlive()) return; + if (error) { cc.error("Gameplay introductions failed to load", error); return; } + apply(asset.json.NEW_LEVEL); + }); + } + } + /** + * 问号 Button 的点击入口。场景按钮需绑定这个方法,Tip Panel 属性需绑定容器节点。 + * 顺序:检查能否打开 → 暂停游戏 → 加载/复用预制体 → 交给 GameplayIntro 显示内容。 + */ + openGameplayIntro() { + if (!this.isPopupRuntimeAlive() || this.isPauseOpen()) return; + if (!this.levelGameplay.length) return; + const map = MapConroler._instance; + if (!map || map.gameOver || map.shopPause) return; + if (!this.tipPanel || !cc.isValid(this.tipPanel)) { + cc.error("GameplayIntro: SceneManager.tipPanel is not assigned"); + return; + } + // 关闭或加载失败时尝试恢复;仍有冰冻、其它暂停面板、商城或已结束时不能强行恢复。 + const resume = () => { + if (!this.isPopupRuntimeAlive()) return; + if (!map.iceTrue() && !this.isPauseOpen() && !map.shopPause && !map.gameOver) { + map.pause = false; + if (map.gameStart) map.startBoom(); + } + }; + // 暂停游戏,并停止场上炸弹计时,避免阅读玩法期间仍消耗倒计时。 + map.pause = true; + map.stopBoom(); + this.tipPanel.active = true; + this.tipPanel.zIndex = cc.macro.MAX_ZINDEX - 2; + // 参数依次为:弹窗缓存名、资源包名、包内预制体路径、挂载父节点、完成回调。 + // 通用加载器首次会 instantiate 并挂载到 tipPanel,以后返回已经创建的根节点。 + this.loadDynamicPopup("gameplayIntro", "gameplay_intro", "prefab/GameplayIntro", this.tipPanel, (error, root) => { + // 无论成功失败都结束加载状态,防止暂停检测一直误认为还在加载。 + this.finishDynamicPopupLoad("gameplayIntro"); + if (error || !root) { + cc.error("GameplayIntro prefab failed to load", error); + resume(); + return; + } + const panel = root.getComponent("GameplayIntro") as GameplayIntro; + if (!panel) { + cc.error("GameplayIntro prefab is missing its controller"); + resume(); + return; + } + // 同一实例只绑定一次关闭回调,避免重开多次后一次关闭触发多次恢复。 + if (this.gameplayIntro !== panel) { + this.gameplayIntro = panel; + root.on("intro-closed", resume); + } + panel.open(this.levelGameplay); + }); } startGame() { diff --git a/assets/Script/module/Tool/LevelGameplay.ts b/assets/Script/module/Tool/LevelGameplay.ts new file mode 100644 index 0000000..46cd9d2 --- /dev/null +++ b/assets/Script/module/Tool/LevelGameplay.ts @@ -0,0 +1,74 @@ +/** 从实际加载的关卡筛选介绍,不使用玩家进度或首次解锁关卡。 */ +export function getLevelGameplay(config: any[], data: any): any[] { + const level = data.LEVEL_INFO && data.LEVEL_INFO[0] || {}; + const blocks = (data.BLOCK_INFO && data.BLOCK_INFO[0] || []).slice(); + const walls = data.WALL_INFO && data.WALL_INFO[0] || []; + const names = new Set(); + const add = (id: number) => names.add("daoju" + id); + + // 生成区域里尚未出场的方块也属于本关;不扫描会随消除而变化的场景节点。 + const gates = level.spawnGates || []; + if (gates.length) add(33); + gates.forEach(gate => (gate.spawnQueue || []).forEach(item => { + blocks.push(...(item.members || [])); + })); + + blocks.forEach(block => { + if (!block || block.block == null || Number(block.block) === 23) return; + const type = Number(block.type); + switch (type) { + case 1: case 10: add(block.colorChange != null ? 21 : 1); break; + case 2: case 3: case 12: case 13: add(4); break; + case 4: add(2); break; + case 5: add(3); break; + case 6: add(7); break; + case 7: case 8: add(Number(block.lockTime) > 0 ? 31 : 0); break; + case 9: case 19: add(Number(block.lockTime) > 0 ? 17 : 5); break; + case 11: add(11); break; + case 14: add(14); break; + case 16: add(16); break; + case 17: add(18); break; + case 20: add(25); break; + case 21: add(22); break; + case 22: add(28); break; + } + if (block.vertical || block.horizontal) add(0); + if (Number(block.color) === 11 || ((type === 1 || type === 10) && Number(block.stacking) === 11)) add(11); + if (block.colorArray != null) add(25); + if (block.lock != null) add(19); // 铁皮的开/合两种状态都需要介绍。 + if (block.flowerSend || block.flowerReceive) add(24); + // 花盆接收块借用 floor 实现碰撞,它的盖板不可见,不额外展示快递盒。 + if (block.floor && block.floorTime && !block.flowerReceive) { + add(block.floorMove === true ? 20 : block.floorMove === false && block.floorColor != null ? 29 : 12); + } + }); + + walls.forEach(wall => { + switch (Number(wall.special)) { + case 1: add(3); break; + case 2: add(6); break; + case 3: add(9); break; + case 4: case 5: add(10); break; // 果酱沿门移动。 + case 6: add(14); break; + case 7: add(23); break; // 箭头挡板。 + case 9: add(27); break; // 伸缩障碍杆。 + case 10: case 11: add(26); break; // 带色挡板移动时覆盖其它门。 + } + if (wall.colorArray) add(13); + if (wall.longAndShort) add(15); + if (wall.toggle) add(30); + }); + (level.risefall || []).forEach(tile => { + if (Object.prototype.hasOwnProperty.call(tile, "vine")) { + if (Number(tile.vine) > 0) add(32); + } else add(tile.unLockFall ? 30 : 8); + }); + + // 沿用介绍的配置顺序,每种玩法只留一页,不因解锁关卡而漏掉实际出现的道具。 + const seen = new Set(); + return (config || []).filter(entry => { + if (!names.has(entry.name) || seen.has(entry.name)) return false; + seen.add(entry.name); + return true; + }); +} diff --git a/assets/Script/module/Tool/LevelGameplay.ts.meta b/assets/Script/module/Tool/LevelGameplay.ts.meta new file mode 100644 index 0000000..40a9525 --- /dev/null +++ b/assets/Script/module/Tool/LevelGameplay.ts.meta @@ -0,0 +1,10 @@ +{ + "ver": "1.1.0", + "uuid": "e1c45ec8-4986-46b4-a622-609cb5e6d1d8", + "importer": "typescript", + "isPlugin": false, + "loadPluginInWeb": true, + "loadPluginInNative": true, + "loadPluginInEditor": false, + "subMetas": {} +} \ No newline at end of file diff --git a/build-templates/wechatgame/project.config.json b/build-templates/wechatgame/project.config.json index 1a2bdec..52ec70c 100644 --- a/build-templates/wechatgame/project.config.json +++ b/build-templates/wechatgame/project.config.json @@ -34,7 +34,12 @@ }, "isGameTourist": false, "packOptions": { - "ignore": [], + "ignore": [ + { + "type": "folder", + "value": "cocos" + } + ], "include": [] }, "editorSetting": { @@ -42,4 +47,4 @@ "tabSize": 2 }, "simulatorPluginLibVersion": {} -} \ No newline at end of file +} diff --git a/settings/project.json b/settings/project.json index 1778c9f..3c518e7 100644 --- a/settings/project.json +++ b/settings/project.json @@ -1,5 +1,5 @@ { - "last-module-event-record-time": 1788866731401, + "last-module-event-record-time": 1789116749030, "group-list": [ "default", "Map"