diff --git a/assets/bundles/battleHero/prefab/skill/隔山打牛.prefab b/assets/bundles/battleHero/prefab/skill/隔山打牛.prefab new file mode 100644 index 0000000..8c10f70 --- /dev/null +++ b/assets/bundles/battleHero/prefab/skill/隔山打牛.prefab @@ -0,0 +1,262 @@ +[ + { + "__type__": "cc.Prefab", + "_name": "隔山打牛", + "_objFlags": 0, + "__editorExtras__": {}, + "_native": "", + "data": { + "__id__": 1 + }, + "optimizationPolicy": 0, + "persistent": false + }, + { + "__type__": "cc.Node", + "_name": "隔山打牛", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": null, + "_children": [ + { + "__id__": 2 + } + ], + "_active": true, + "_components": [ + { + "__id__": 10 + } + ], + "_prefab": { + "__id__": 12 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 33554432, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "隔山打牛", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 3 + }, + { + "__id__": 5 + }, + { + "__id__": 7 + } + ], + "_prefab": { + "__id__": 9 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 33554432, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 2 + }, + "_enabled": true, + "__prefab": { + "__id__": 4 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 438, + "height": 192 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5271917891828981, + "y": 0.1018749972184499 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "76ZZbT4/ZIqbtvk3NBMY6I" + }, + { + "__type__": "sp.Skeleton", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 2 + }, + "_enabled": true, + "__prefab": { + "__id__": 6 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_skeletonData": { + "__uuid__": "4316bb66-bc50-49dc-82fc-b44973b80528", + "__expectedType__": "sp.SkeletonData" + }, + "defaultSkin": "default", + "defaultAnimation": "animation", + "_premultipliedAlpha": true, + "_timeScale": 1, + "_preCacheMode": 0, + "_cacheMode": 0, + "_sockets": [], + "_useTint": false, + "_debugMesh": false, + "_debugBones": false, + "_debugSlots": false, + "_enableBatch": false, + "loop": true, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "87oQz6Hv1CFZDfHuDFAGS7" + }, + { + "__type__": "cc.Sorting2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 2 + }, + "_enabled": true, + "__prefab": { + "__id__": 8 + }, + "_sortingLayer": 4, + "_sortingOrder": 0, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "357LOOZDhGz6N8HJgzem9G" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "0dSiqHBHBO9ovVVKPIEJiD", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 11 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 100, + "height": 100 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "6a7/yPPNVIo6oyr7ThcJE1" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "4fxj20EUZCpoGh4SVCREIU", + "instance": null, + "targetOverrides": null + } +] \ No newline at end of file diff --git a/assets/bundles/battleHero/prefab/skill/隔山打牛.prefab.meta b/assets/bundles/battleHero/prefab/skill/隔山打牛.prefab.meta new file mode 100644 index 0000000..52be66f --- /dev/null +++ b/assets/bundles/battleHero/prefab/skill/隔山打牛.prefab.meta @@ -0,0 +1,13 @@ +{ + "ver": "1.1.50", + "importer": "prefab", + "imported": true, + "uuid": "61c1005c-b736-4626-8d07-d80895dda794", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": { + "syncNodeName": "隔山打牛" + } +} diff --git a/assets/mx/module/battle/core/BattleSession.ts b/assets/mx/module/battle/core/BattleSession.ts index 419e578..bd22a3b 100644 --- a/assets/mx/module/battle/core/BattleSession.ts +++ b/assets/mx/module/battle/core/BattleSession.ts @@ -295,6 +295,16 @@ export class BattleSession implements BattleServices { /** 备战结束 / 连续模式开波 */ startCombat(): void { if (this.ended) return; + // 备战中被 pauseBattle 弹窗(如三选一)暂停:仍登记开波,resume 后进 COMBAT + if (this._phase === BattlePhase.PAUSE) { + if (!this.isContinuousFlow && this._phaseBeforePause !== BattlePhase.PREP) return; + if (!this.spawner.hasMoreWaves()) return; + if (this.spawner.isWaveCombatActive()) return; + if (this._waveAdvancePending) return; + this._phaseBeforePause = BattlePhase.COMBAT; + this._tryStartWaveWithPrepDelay(this.spawner.waveIndex + 1); + return; + } if (!this.isContinuousFlow && this._phase !== BattlePhase.PREP) return; if (!this.spawner.hasMoreWaves()) return; if (this.spawner.isWaveCombatActive()) return; diff --git a/assets/res/spine/隔山打牛JSON.meta b/assets/res/spine/隔山打牛JSON.meta new file mode 100644 index 0000000..fffc77f --- /dev/null +++ b/assets/res/spine/隔山打牛JSON.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "4ed941b7-020f-4e00-97fe-3eebc70ee182", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/res/spine/隔山打牛JSON/.WeDrive b/assets/res/spine/隔山打牛JSON/.WeDrive new file mode 100644 index 0000000..de15d51 --- /dev/null +++ b/assets/res/spine/隔山打牛JSON/.WeDrive @@ -0,0 +1 @@ +D:\WXWork\1688855084654441\WeDrive\中昱智云\抖音游戏\战斗类\【新】2048数字守卫战\动效\隔山打牛\隔山打牛JSON \ No newline at end of file diff --git a/assets/res/spine/隔山打牛JSON/隔山打牛.atlas b/assets/res/spine/隔山打牛JSON/隔山打牛.atlas new file mode 100644 index 0000000..b75d1cc --- /dev/null +++ b/assets/res/spine/隔山打牛JSON/隔山打牛.atlas @@ -0,0 +1,104 @@ + +隔山打牛.png +size: 872,872 +format: RGBA8888 +filter: Linear,Linear +repeat: none +1 + rotate: false + xy: 425, 244 + size: 243, 267 + orig: 246, 269 + offset: 1, 1 + index: -1 +2 + rotate: true + xy: 298, 20 + size: 215, 295 + orig: 217, 297 + offset: 1, 1 + index: -1 +3 + rotate: true + xy: 0, 10 + size: 225, 296 + orig: 227, 298 + offset: 1, 1 + index: -1 +4 + rotate: false + xy: 670, 200 + size: 200, 311 + orig: 202, 313 + offset: 1, 1 + index: -1 +5 + rotate: true + xy: 0, 237 + size: 209, 312 + orig: 211, 314 + offset: 1, 1 + index: -1 +6 + rotate: true + xy: 0, 448 + size: 230, 317 + orig: 232, 319 + offset: 1, 1 + index: -1 +7 + rotate: false + xy: 793, 650 + size: 74, 67 + orig: 76, 69 + offset: 1, 1 + index: -1 +a0 + rotate: true + xy: 863, 808 + size: 62, 5 + orig: 64, 7 + offset: 1, 1 + index: -1 +a1 + rotate: true + xy: 793, 553 + size: 95, 25 + orig: 97, 27 + offset: 1, 1 + index: -1 +a2 + rotate: true + xy: 595, 21 + size: 177, 101 + orig: 182, 103 + offset: 3, 1 + index: -1 +a3 + rotate: true + xy: 319, 406 + size: 272, 104 + orig: 280, 106 + offset: 5, 1 + index: -1 +a4 + rotate: false + xy: 435, 513 + size: 356, 204 + orig: 363, 206 + offset: 3, 1 + index: -1 +a5 + rotate: false + xy: 435, 719 + size: 426, 151 + orig: 439, 153 + offset: 6, 1 + index: -1 +a6 + rotate: false + xy: 0, 680 + size: 433, 190 + orig: 438, 192 + offset: 4, 1 + index: -1 diff --git a/assets/res/spine/隔山打牛JSON/隔山打牛.atlas.meta b/assets/res/spine/隔山打牛JSON/隔山打牛.atlas.meta new file mode 100644 index 0000000..7b016c0 --- /dev/null +++ b/assets/res/spine/隔山打牛JSON/隔山打牛.atlas.meta @@ -0,0 +1,12 @@ +{ + "ver": "1.0.0", + "importer": "*", + "imported": true, + "uuid": "d68878c7-e4ba-4692-a744-ee4cc6aaec63", + "files": [ + ".atlas", + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/assets/res/spine/隔山打牛JSON/隔山打牛.json b/assets/res/spine/隔山打牛JSON/隔山打牛.json new file mode 100644 index 0000000..5d9a192 --- /dev/null +++ b/assets/res/spine/隔山打牛JSON/隔山打牛.json @@ -0,0 +1 @@ +{"skeleton":{"hash":"pERjccZ3ExdzzTEfOZP4MZdU2Gw","spine":"3.8.75","x":-230.91,"y":-19.56,"width":438,"height":192},"bones":[{"name":"root"},{"name":"隔山打牛效果","parent":"root","length":45.73,"rotation":89.6,"x":0.27,"y":-1.19},{"name":"冲击效果","parent":"root","length":67.07,"rotation":90.4,"x":9.41,"y":-75.94},{"name":"冲击效果2","parent":"root","length":67.07,"rotation":90.4,"x":9.41,"y":-75.94}],"slots":[{"name":"冲击效果3","bone":"冲击效果2","attachment":"a6"},{"name":"隔山打牛效果","bone":"隔山打牛效果","attachment":"7"},{"name":"冲击效果","bone":"冲击效果","attachment":"a6"},{"name":"冲击效果2","bone":"冲击效果","attachment":"a6","blend":"additive"}],"skins":[{"name":"default","attachments":{"隔山打牛效果":{"0":{"x":141.75,"y":-8.74,"rotation":-89.6,"width":443,"height":383},"1":{"x":124.7,"y":-0.86,"rotation":-89.6,"width":246,"height":269},"2":{"x":138.69,"y":-0.26,"rotation":-89.6,"width":217,"height":297},"3":{"x":139.17,"y":2.75,"rotation":-89.6,"width":227,"height":298},"4":{"x":146.73,"y":-5.7,"rotation":-89.6,"width":202,"height":313},"5":{"x":148.24,"y":-7.19,"rotation":-89.6,"width":211,"height":314},"6":{"x":154.79,"y":-13.64,"rotation":-89.6,"width":232,"height":319},"7":{"x":41.78,"y":-13.44,"rotation":-89.6,"width":76,"height":69}},"冲击效果":{"a0":{"x":4.86,"y":-2.72,"rotation":-90.4,"width":64,"height":7},"a1":{"x":14.88,"y":-0.29,"rotation":-90.4,"width":97,"height":27},"a2":{"x":52.92,"y":4.94,"rotation":-90.4,"width":182,"height":103},"a3":{"x":59.52,"y":19.9,"rotation":-90.4,"width":280,"height":106},"a4":{"x":122.47,"y":12.96,"rotation":-90.4,"width":363,"height":206},"a5":{"x":114.06,"y":25.02,"rotation":-90.4,"width":439,"height":153},"a6":{"x":152.53,"y":20.25,"rotation":-90.4,"width":438,"height":192}},"冲击效果2":{"a0":{"x":4.86,"y":-2.72,"rotation":-90.4,"width":64,"height":7},"a1":{"x":14.88,"y":-0.29,"rotation":-90.4,"width":97,"height":27},"a2":{"x":52.92,"y":4.94,"rotation":-90.4,"width":182,"height":103},"a3":{"x":59.52,"y":19.9,"rotation":-90.4,"width":280,"height":106},"a4":{"x":122.47,"y":12.96,"rotation":-90.4,"width":363,"height":206},"a5":{"x":114.06,"y":25.02,"rotation":-90.4,"width":439,"height":153},"a6":{"x":152.53,"y":20.25,"rotation":-90.4,"width":438,"height":192}},"冲击效果3":{"a0":{"x":4.86,"y":-2.72,"rotation":-90.4,"width":64,"height":7},"a1":{"x":14.88,"y":-0.29,"rotation":-90.4,"width":97,"height":27},"a2":{"x":52.92,"y":4.94,"rotation":-90.4,"width":182,"height":103},"a3":{"x":59.52,"y":19.9,"rotation":-90.4,"width":280,"height":106},"a4":{"x":122.47,"y":12.96,"rotation":-90.4,"width":363,"height":206},"a5":{"x":114.06,"y":25.02,"rotation":-90.4,"width":439,"height":153},"a6":{"x":152.53,"y":20.25,"rotation":-90.4,"width":438,"height":192}}}}],"animations":{"animation":{"slots":{"隔山打牛效果":{"attachment":[{"time":0.0667,"name":"0"},{"time":0.1333,"name":"1"},{"time":0.2,"name":"2"},{"time":0.2667,"name":"3"},{"time":0.3333,"name":"4"},{"time":0.4,"name":"5"},{"time":0.4667,"name":null}]},"冲击效果3":{"attachment":[{"name":null},{"time":0.0667,"name":"a1"},{"time":0.1333,"name":"a2"},{"time":0.2,"name":"a3"},{"time":0.2667,"name":"a4"},{"time":0.3333,"name":"a5"},{"time":0.4,"name":"a6"},{"time":0.4667,"name":null},{"time":1,"name":null}]},"冲击效果2":{"attachment":[{"name":null},{"time":0.0667,"name":"a1"},{"time":0.1333,"name":"a2"},{"time":0.2,"name":"a3"},{"time":0.2667,"name":"a4"},{"time":0.3333,"name":"a5"},{"time":0.4,"name":"a6"},{"time":0.4667,"name":null}]},"冲击效果":{"attachment":[{"name":null},{"time":0.0667,"name":"a1"},{"time":0.1333,"name":"a2"},{"time":0.2,"name":"a3"},{"time":0.2667,"name":"a4"},{"time":0.3333,"name":"a5"},{"time":0.4,"name":"a6"},{"time":0.4667,"name":null}]}},"bones":{"冲击效果":{"translate":[{"time":0.0667,"x":-6.82,"y":71.92}],"scale":[{"time":0.0667,"x":1.082,"y":0.766}],"shear":[{"time":0.0667,"x":-6.61,"y":-2.69}]},"冲击效果2":{"translate":[{"time":0.0667,"x":-6.82,"y":71.92}],"scale":[{"time":0.0667,"x":1.407,"y":0.766}],"shear":[{"time":0.0667},{"time":0.4333,"x":-6.61,"y":-2.69}]}}}}} \ No newline at end of file diff --git a/assets/res/spine/隔山打牛JSON/隔山打牛.json.meta b/assets/res/spine/隔山打牛JSON/隔山打牛.json.meta new file mode 100644 index 0000000..24606a1 --- /dev/null +++ b/assets/res/spine/隔山打牛JSON/隔山打牛.json.meta @@ -0,0 +1,13 @@ +{ + "ver": "1.2.7", + "importer": "spine-data", + "imported": true, + "uuid": "4316bb66-bc50-49dc-82fc-b44973b80528", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": { + "atlasUuid": "d68878c7-e4ba-4692-a744-ee4cc6aaec63" + } +} diff --git a/assets/res/spine/隔山打牛JSON/隔山打牛.png b/assets/res/spine/隔山打牛JSON/隔山打牛.png new file mode 100644 index 0000000..47e64f4 Binary files /dev/null and b/assets/res/spine/隔山打牛JSON/隔山打牛.png differ diff --git a/assets/res/spine/隔山打牛JSON/隔山打牛.png.meta b/assets/res/spine/隔山打牛JSON/隔山打牛.png.meta new file mode 100644 index 0000000..b7c9705 --- /dev/null +++ b/assets/res/spine/隔山打牛JSON/隔山打牛.png.meta @@ -0,0 +1,134 @@ +{ + "ver": "1.0.27", + "importer": "image", + "imported": true, + "uuid": "54329a0d-1282-4c4e-ae07-05654b38f815", + "files": [ + ".json", + ".png" + ], + "subMetas": { + "6c48a": { + "importer": "texture", + "uuid": "54329a0d-1282-4c4e-ae07-05654b38f815@6c48a", + "displayName": "隔山打牛", + "id": "6c48a", + "name": "texture", + "userData": { + "wrapModeS": "clamp-to-edge", + "wrapModeT": "clamp-to-edge", + "imageUuidOrDatabaseUri": "54329a0d-1282-4c4e-ae07-05654b38f815", + "isUuid": true, + "visible": false, + "minfilter": "linear", + "magfilter": "linear", + "mipfilter": "none", + "anisotropy": 0 + }, + "ver": "1.0.22", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + }, + "f9941": { + "importer": "sprite-frame", + "uuid": "54329a0d-1282-4c4e-ae07-05654b38f815@f9941", + "displayName": "隔山打牛", + "id": "f9941", + "name": "spriteFrame", + "userData": { + "trimThreshold": 1, + "rotated": false, + "offsetX": -1, + "offsetY": -4, + "trimX": 0, + "trimY": 10, + "width": 870, + "height": 860, + "rawWidth": 872, + "rawHeight": 872, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "packable": true, + "pixelsToUnit": 100, + "pivotX": 0.5, + "pivotY": 0.5, + "meshType": 0, + "vertices": { + "rawPosition": [ + -435, + -430, + 0, + 435, + -430, + 0, + -435, + 430, + 0, + 435, + 430, + 0 + ], + "indexes": [ + 0, + 1, + 2, + 2, + 1, + 3 + ], + "uv": [ + 0, + 862, + 870, + 862, + 0, + 2, + 870, + 2 + ], + "nuv": [ + 0, + 0.0022935779816513763, + 0.9977064220183486, + 0.0022935779816513763, + 0, + 0.9885321100917431, + 0.9977064220183486, + 0.9885321100917431 + ], + "minPos": [ + -435, + -430, + 0 + ], + "maxPos": [ + 435, + 430, + 0 + ] + }, + "isUuid": true, + "imageUuidOrDatabaseUri": "54329a0d-1282-4c4e-ae07-05654b38f815@6c48a", + "atlasUuid": "", + "trimType": "auto" + }, + "ver": "1.0.12", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + } + }, + "userData": { + "type": "sprite-frame", + "fixAlphaTransparencyArtifacts": false, + "hasAlpha": true, + "redirect": "54329a0d-1282-4c4e-ae07-05654b38f815@6c48a" + } +} diff --git a/assets/script/battle/combat/PassiveSkillRuntime.ts b/assets/script/battle/combat/PassiveSkillRuntime.ts index 70382f1..dcef77b 100644 --- a/assets/script/battle/combat/PassiveSkillRuntime.ts +++ b/assets/script/battle/combat/PassiveSkillRuntime.ts @@ -167,6 +167,8 @@ export const ICE_CONE_SPLIT_EVENT = 'IceConeSplitApplied'; export const POISON_APPLIED_EVENT = 'PoisonApplied'; /** 中毒清除表现事件名(目标上已无毒 DoT) */ export const POISON_REMOVED_EVENT = 'PoisonRemoved'; +/** 隔山打牛(身后扇形)表现事件名 */ +export const BEHIND_FAN_EVENT = 'BehindFanApplied'; /** 直线火龙预制体宽 100,命中半长(再加半格占地) */ const LINE_DRAGON_HALF_LEN = 50; /** 直线火龙预制体高 30,命中半宽(再加半格占地) */ @@ -210,6 +212,12 @@ export interface PoisonCue { duration: number; } +/** 隔山打牛表现 cue(落在命中目标坐标) */ +export interface BehindFanCue { + /** 命中目标 */ + target: EntityId; +} + /** 爆炸火球一枚(径向直线) */ export interface HomingDragonMissile { /** 方向单位 X */ @@ -2668,6 +2676,10 @@ export class PassiveSkillHost { const radiusCells = radius / Math.max(1, session.grid.cellSize); const ids = session.spatial.queryRadius(cell, radiusCells + 1); const r2 = radius * radius; + if (target > 0) { + const cue: BehindFanCue = { target }; + session.events.emit(BattleEventFactory.custom(BEHIND_FAN_EVENT, cue)); + } this._beginResultGate(); try { for (let i = 0; i < ids.length; i++) { diff --git a/assets/script/battle/view/CocosBattleCombatPresenter.ts b/assets/script/battle/view/CocosBattleCombatPresenter.ts index 11092a6..a1e887b 100644 --- a/assets/script/battle/view/CocosBattleCombatPresenter.ts +++ b/assets/script/battle/view/CocosBattleCombatPresenter.ts @@ -18,6 +18,7 @@ import { GBundle } from '../../game/ConfigRes'; import { BattleSpinePlayback } from '../presentation/BattleSpinePlayback'; import { SkillTransformDriver, computeAimAngleDeg } from '../skill/SkillTransformDriver'; import { + BEHIND_FAN_EVENT, HOMING_DRAGON_EVENT, ICE_CONE_SPLIT_EVENT, LINE_DRAGON_EVENT, @@ -26,6 +27,7 @@ import { LIGHTNING_CHAIN_EVENT, POISON_APPLIED_EVENT, POISON_REMOVED_EVENT, + type BehindFanCue, type HomingDragonCue, type IceConeSplitCue, type LineDragonCue, @@ -100,6 +102,10 @@ const LIGHTNING_HIT_PREFAB = '电母-大招受击'; const LIGHTNING_BOLT_ANIM = '普通雷电'; /** 主链受击动画 */ const LIGHTNING_HIT_ANIM = '普通受击'; +/** 隔山打牛命中特效 */ +const BEHIND_FAN_PREFAB = '隔山打牛'; +/** 隔山打牛 Spine 动画 */ +const BEHIND_FAN_ANIM = 'animation'; /** 电弧根节点宽(锚点 x=0,scaleX=距离/此值) */ const LIGHTNING_BOLT_WIDTH = 150; /** 相对资源原速 */ @@ -123,6 +129,8 @@ export class CocosBattleCombatPresenter { private readonly _swordWaveFx: Node[] = []; private readonly _lightningFx: Node[] = []; private readonly _iceConeFx: Node[] = []; + /** 隔山打牛命中特效(播完回收) */ + private readonly _behindFanFx: { node: Node; endAt: number }[] = []; private readonly _dragonFrom = new Vec3(); private readonly _dragonTo = new Vec3(); private readonly _iceConeFrom = new Vec3(); @@ -146,6 +154,7 @@ export class CocosBattleCombatPresenter { this._recycleAllSwordWaves(); this._recycleAllLightning(); this._recycleAllIceCones(); + this._recycleAllBehindFan(); if (this._battle && this._listener) { this._battle.off(BATTLE_EVENT_ALL, this._listener); } @@ -264,6 +273,8 @@ export class CocosBattleCombatPresenter { this._playLightningChain(event.payload as LightningChainCue | undefined); } else if (event.name === ICE_CONE_SPLIT_EVENT) { this._playIceConeSplit(event.payload as IceConeSplitCue | undefined); + } else if (event.name === BEHIND_FAN_EVENT) { + this._playBehindFan(event.payload as BehindFanCue | undefined); } else if (event.name === POISON_APPLIED_EVENT) { this._onPoisonApplied(event.payload as PoisonCue | undefined); } else if (event.name === POISON_REMOVED_EVENT) { @@ -1012,6 +1023,97 @@ export class CocosBattleCombatPresenter { if (node) this._recycleIceCone(node); }; + /** + * 隔山打牛:在命中怪坐标播一次特效后回收。 + * @param cue 逻辑层 cue + */ + private _playBehindFan(cue: BehindFanCue | undefined): void { + const parent = this._displayRoot; + const battle = this._battle; + if (!cue || !parent?.isValid || !battle) return; + const monster = SkillPresentationEnv.getMonsterNode(cue.target); + const wp = monster?.isValid + ? monster.worldPosition + : SkillPresentationEnv.getTargetGridWorldCenter(cue.target); + if (!wp) { + console.log('[CombatPresenter] 隔山打牛无落点', cue.target); + return; + } + let node: Node | null = null; + try { + node = gg.res.getNode(SWORD_ARRAY_PREFAB_PATH, BEHIND_FAN_PREFAB, GBundle.BattleHero); + } catch (err) { + console.log('[CombatPresenter] 隔山打牛 getNode 失败', String(err)); + return; + } + if (!node?.isValid) { + console.log('[CombatPresenter] 隔山打牛预制体未加载', BEHIND_FAN_PREFAB); + return; + } + node.active = true; + node.layer = parent.layer; + node.angle = 0; + node.setScale(1, 1, 1); + node.setParent(parent); + node.setWorldPosition(wp); + node.setSiblingIndex(parent.children.length - 1); + const sk = node.getComponent(sp.Skeleton) ?? node.getComponentInChildren(sp.Skeleton); + if (!sk?.isValid) { + console.log('[CombatPresenter] 隔山打牛缺 Skeleton'); + gg.res.putNode(node); + return; + } + if (sk.skeletonData) ensureSpineSkeletonDataRuntime(sk.skeletonData); + const delay = BattleSpinePlayback.resolveLogicalCompleteDelay(sk, BEHIND_FAN_ANIM, 1); + if (!(delay != null && delay > 0)) { + console.warn('[CombatPresenter] 隔山打牛无动画时长', BEHIND_FAN_ANIM); + gg.res.putNode(node); + return; + } + BattleSpinePlayback.play(sk, BEHIND_FAN_ANIM, { loop: false }); + const endAt = battle.session.clock.time + delay; + this._behindFanFx.push({ node, endAt }); + battle.session.clock.schedule(delay, this._onBehindFanExpire); + } + + /** 时钟到期后回收已播完的隔山打牛 */ + private readonly _onBehindFanExpire = (): void => { + this._recycleExpiredBehindFan(); + }; + + /** 回收到期隔山打牛节点 */ + private _recycleExpiredBehindFan(): void { + const now = this._battle?.session.clock.time ?? Number.POSITIVE_INFINITY; + for (let i = this._behindFanFx.length - 1; i >= 0; i--) { + if (this._behindFanFx[i].endAt <= now + 0.001) { + this._recycleBehindFanNode(this._behindFanFx[i].node); + this._behindFanFx.splice(i, 1); + } + } + } + + /** 回收全部隔山打牛特效 */ + private _recycleAllBehindFan(): void { + for (let i = 0; i < this._behindFanFx.length; i++) { + this._recycleBehindFanNode(this._behindFanFx[i].node); + } + this._behindFanFx.length = 0; + } + + /** + * 停动画并回池。 + * @param node 特效节点 + */ + private _recycleBehindFanNode(node: Node): void { + if (!node?.isValid) return; + const sk = node.getComponent(sp.Skeleton) ?? node.getComponentInChildren(sp.Skeleton); + BattleSpinePlayback.clearPendingComplete(sk); + BattleSpinePlayback.resetTracks(sk); + node.angle = 0; + node.setScale(1, 1, 1); + gg.res.putNode(node); + } + /** 回收全部分裂冰锥表现 */ private _recycleAllIceCones(): void { for (let i = this._iceConeFx.length - 1; i >= 0; i--) { diff --git a/docs/方案-Battlebuff扩展105-112.md b/docs/方案-Battlebuff扩展105-112.md index 7081d70..7b1e814 100644 --- a/docs/方案-Battlebuff扩展105-112.md +++ b/docs/方案-Battlebuff扩展105-112.md @@ -29,7 +29,7 @@ | 16 | 秒杀 | `tryInstantKillSession` | | 17 | 上毒 | 复用 result 8 DoT | | 18 | 寒潭减速 | `PassiveSkillHost` 地面区 | -| 19 | 目标身后扇形 | 向量扇形圈伤 | +| 19 | 目标身后扇形 | 向量扇形圈伤;命中点播 `隔山打牛` 特效一次 | | 20 | 击杀叠伤 | `dmg_mul` 叠层 | | 21 | 该次伤害必暴+暴击转爆伤 | 伤害预调(配合 condition 7/8) |