From bffbb9077e559ea343d5972c2865db16dab4af7d Mon Sep 17 00:00:00 2001 From: walkpan Date: Sat, 1 Feb 2025 00:14:25 +0800 Subject: [PATCH] dd --- assets/resources/game/heros/Hero.prefab | 279 ++++++ assets/resources/game/heros/Hero.prefab.meta | 13 + .../game/heros/heros/k1.meta} | 2 +- assets/resources/game/heros/heros/k1/k1.atlas | 90 ++ .../game/heros/heros/k1/k1.atlas.meta | 1 + assets/resources/game/heros/heros/k1/k1.json | 580 +++++++++++ .../game/heros/heros/k1/k1.json.meta | 11 + assets/resources/game/heros/heros/k1/k1.png | Bin 0 -> 32910 bytes .../resources/game/heros/heros/k1/k1.png.meta | 42 + assets/script/game/GameBootstrap.ts | 11 + ...taViewVM.ts.meta => GameBootstrap.ts.meta} | 2 +- assets/script/game/common/Constants.ts | 20 + .../Constants.ts.meta} | 2 +- .../game/{heros.meta => component.meta} | 2 +- assets/script/game/component/hero.meta | 9 + assets/script/game/component/hero/Combat.ts | 37 + .../hero/Combat.ts.meta} | 2 +- .../game/component/hero/HeroAnimState.ts | 6 + .../hero/HeroAnimState.ts.meta} | 2 +- .../script/game/component/hero/HeroModel.ts | 40 + .../game/component/hero/HeroModel.ts.meta | 9 + .../script/game/component/hero/HeroState.ts | 13 + .../game/component/hero/HeroState.ts.meta | 9 + .../game/component/hero/HeroStateMachine.ts | 19 + .../component/hero/HeroStateMachine.ts.meta | 9 + assets/script/game/component/hero/HeroView.ts | 52 + .../game/component/hero/HeroView.ts.meta | 9 + assets/script/game/component/hero/Movement.ts | 19 + .../game/component/hero/Movement.ts.meta | 9 + .../script/game/component/hero/SpineComp.ts | 41 + .../game/component/hero/SpineComp.ts.meta | 9 + assets/script/game/config.meta | 9 + assets/script/game/config/HeroConfig.ts | 49 + assets/script/game/config/HeroConfig.ts.meta | 9 + assets/script/game/core.meta | 9 + assets/script/game/core/EntityFactory.ts | 18 + assets/script/game/core/EntityFactory.ts.meta | 9 + assets/script/game/core/GameEvents.ts | 18 + assets/script/game/core/GameEvents.ts.meta | 9 + assets/script/game/data/dataModelComp.ts | 46 - assets/script/game/data/dataViewComp.ts | 26 - assets/script/game/data/dataViewVM.ts | 23 - assets/script/game/entity.meta | 9 + assets/script/game/entity/hero.meta | 9 + assets/script/game/entity/hero/Hero.ts | 72 ++ assets/script/game/entity/hero/Hero.ts.meta | 9 + .../{hero/Mon.ts => entity/hero/Monster.ts} | 0 .../script/game/entity/hero/Monster.ts.meta | 9 + .../data.ts => hero/Aheros/Module-001.ts} | 25 +- .../game/hero/Aheros/Module-001.ts.meta | 9 + assets/script/game/hero/Aheros/ModuleBll.ts | 24 + .../script/game/hero/Aheros/ModuleBll.ts.meta | 9 + assets/script/game/hero/Aheros/ModuleModel.ts | 26 + .../game/hero/Aheros/ModuleModel.ts.meta | 9 + assets/script/game/hero/Aheros/ModuleTable.ts | 23 + .../game/hero/Aheros/ModuleTable.ts.meta | 9 + assets/script/game/hero/Aheros/ModuleView.ts | 29 + .../game/hero/Aheros/ModuleView.ts.meta | 9 + assets/script/game/hero/Hero.ts | 112 --- assets/script/game/hero/Hero.ts.meta | 1 - assets/script/game/hero/HeroConst.ts | 13 + assets/script/game/hero/HeroConst.ts.meta | 9 + assets/script/game/hero/HeroController.ts | 23 + .../script/game/hero/HeroController.ts.meta | 9 + assets/script/game/hero/HeroManager.ts | 18 + assets/script/game/hero/HeroManager.ts.meta | 9 + assets/script/game/hero/HeroModelComp.ts | 23 - assets/script/game/hero/HeroModelComp.ts.meta | 1 - assets/script/game/hero/HeroViewComp.ts | 906 ------------------ assets/script/game/hero/HeroViewComp.ts.meta | 1 - assets/script/game/hero/Mon.ts.meta | 1 - assets/script/game/hero/MonModelComp.ts | 29 - assets/script/game/hero/MonModelComp.ts.meta | 9 - assets/script/game/heros/HeroComponent.ts | 50 - .../script/game/heros/HeroComponent.ts.meta | 9 - assets/script/game/heros/HeroSystem.ts | 22 - assets/script/game/heros/HeroTypeSystem.ts | 28 - assets/script/game/heros/Heros.ts | 0 assets/script/game/heros/Heros.ts.meta | 9 - assets/script/game/manager.meta | 9 + assets/script/game/manager/SpineManager.ts | 37 + .../script/game/manager/SpineManager.ts.meta | 9 + assets/script/game/map/MissionComp.ts | 106 +- assets/script/game/skill.meta | 2 +- assets/script/game/skill/DOTSystem.ts.meta | 9 + .../game/skill/SkillCollisionSystem.ts.meta | 9 + .../script/game/skill/SkillComponent.ts.meta | 9 + .../game/skill/SkillEffectSystem.ts.meta | 9 + assets/script/game/system.meta | 9 + assets/script/game/system/CombatSystem.ts | 41 + .../script/game/system/CombatSystem.ts.meta | 9 + 91 files changed, 2067 insertions(+), 1327 deletions(-) create mode 100644 assets/resources/game/heros/Hero.prefab create mode 100644 assets/resources/game/heros/Hero.prefab.meta rename assets/{script/game/data.meta => resources/game/heros/heros/k1.meta} (70%) create mode 100644 assets/resources/game/heros/heros/k1/k1.atlas create mode 100644 assets/resources/game/heros/heros/k1/k1.atlas.meta create mode 100644 assets/resources/game/heros/heros/k1/k1.json create mode 100644 assets/resources/game/heros/heros/k1/k1.json.meta create mode 100644 assets/resources/game/heros/heros/k1/k1.png create mode 100644 assets/resources/game/heros/heros/k1/k1.png.meta create mode 100644 assets/script/game/GameBootstrap.ts rename assets/script/game/{data/dataViewVM.ts.meta => GameBootstrap.ts.meta} (70%) create mode 100644 assets/script/game/common/Constants.ts rename assets/script/game/{data/dataModelComp.ts.meta => common/Constants.ts.meta} (70%) rename assets/script/game/{heros.meta => component.meta} (70%) create mode 100644 assets/script/game/component/hero.meta create mode 100644 assets/script/game/component/hero/Combat.ts rename assets/script/game/{data/data.ts.meta => component/hero/Combat.ts.meta} (70%) create mode 100644 assets/script/game/component/hero/HeroAnimState.ts rename assets/script/game/{data/dataViewComp.ts.meta => component/hero/HeroAnimState.ts.meta} (70%) create mode 100644 assets/script/game/component/hero/HeroModel.ts create mode 100644 assets/script/game/component/hero/HeroModel.ts.meta create mode 100644 assets/script/game/component/hero/HeroState.ts create mode 100644 assets/script/game/component/hero/HeroState.ts.meta create mode 100644 assets/script/game/component/hero/HeroStateMachine.ts create mode 100644 assets/script/game/component/hero/HeroStateMachine.ts.meta create mode 100644 assets/script/game/component/hero/HeroView.ts create mode 100644 assets/script/game/component/hero/HeroView.ts.meta create mode 100644 assets/script/game/component/hero/Movement.ts create mode 100644 assets/script/game/component/hero/Movement.ts.meta create mode 100644 assets/script/game/component/hero/SpineComp.ts create mode 100644 assets/script/game/component/hero/SpineComp.ts.meta create mode 100644 assets/script/game/config.meta create mode 100644 assets/script/game/config/HeroConfig.ts create mode 100644 assets/script/game/config/HeroConfig.ts.meta create mode 100644 assets/script/game/core.meta create mode 100644 assets/script/game/core/EntityFactory.ts create mode 100644 assets/script/game/core/EntityFactory.ts.meta create mode 100644 assets/script/game/core/GameEvents.ts create mode 100644 assets/script/game/core/GameEvents.ts.meta delete mode 100644 assets/script/game/data/dataModelComp.ts delete mode 100644 assets/script/game/data/dataViewComp.ts delete mode 100644 assets/script/game/data/dataViewVM.ts create mode 100644 assets/script/game/entity.meta create mode 100644 assets/script/game/entity/hero.meta create mode 100644 assets/script/game/entity/hero/Hero.ts create mode 100644 assets/script/game/entity/hero/Hero.ts.meta rename assets/script/game/{hero/Mon.ts => entity/hero/Monster.ts} (100%) create mode 100644 assets/script/game/entity/hero/Monster.ts.meta rename assets/script/game/{data/data.ts => hero/Aheros/Module-001.ts} (50%) create mode 100644 assets/script/game/hero/Aheros/Module-001.ts.meta create mode 100644 assets/script/game/hero/Aheros/ModuleBll.ts create mode 100644 assets/script/game/hero/Aheros/ModuleBll.ts.meta create mode 100644 assets/script/game/hero/Aheros/ModuleModel.ts create mode 100644 assets/script/game/hero/Aheros/ModuleModel.ts.meta create mode 100644 assets/script/game/hero/Aheros/ModuleTable.ts create mode 100644 assets/script/game/hero/Aheros/ModuleTable.ts.meta create mode 100644 assets/script/game/hero/Aheros/ModuleView.ts create mode 100644 assets/script/game/hero/Aheros/ModuleView.ts.meta delete mode 100644 assets/script/game/hero/Hero.ts delete mode 100644 assets/script/game/hero/Hero.ts.meta create mode 100644 assets/script/game/hero/HeroConst.ts create mode 100644 assets/script/game/hero/HeroConst.ts.meta create mode 100644 assets/script/game/hero/HeroController.ts create mode 100644 assets/script/game/hero/HeroController.ts.meta create mode 100644 assets/script/game/hero/HeroManager.ts create mode 100644 assets/script/game/hero/HeroManager.ts.meta delete mode 100644 assets/script/game/hero/HeroModelComp.ts delete mode 100644 assets/script/game/hero/HeroModelComp.ts.meta delete mode 100644 assets/script/game/hero/HeroViewComp.ts delete mode 100644 assets/script/game/hero/HeroViewComp.ts.meta delete mode 100644 assets/script/game/hero/Mon.ts.meta delete mode 100644 assets/script/game/hero/MonModelComp.ts delete mode 100644 assets/script/game/hero/MonModelComp.ts.meta delete mode 100644 assets/script/game/heros/HeroComponent.ts delete mode 100644 assets/script/game/heros/HeroComponent.ts.meta delete mode 100644 assets/script/game/heros/HeroSystem.ts delete mode 100644 assets/script/game/heros/HeroTypeSystem.ts delete mode 100644 assets/script/game/heros/Heros.ts delete mode 100644 assets/script/game/heros/Heros.ts.meta create mode 100644 assets/script/game/manager.meta create mode 100644 assets/script/game/manager/SpineManager.ts create mode 100644 assets/script/game/manager/SpineManager.ts.meta create mode 100644 assets/script/game/skill/DOTSystem.ts.meta create mode 100644 assets/script/game/skill/SkillCollisionSystem.ts.meta create mode 100644 assets/script/game/skill/SkillComponent.ts.meta create mode 100644 assets/script/game/skill/SkillEffectSystem.ts.meta create mode 100644 assets/script/game/system.meta create mode 100644 assets/script/game/system/CombatSystem.ts create mode 100644 assets/script/game/system/CombatSystem.ts.meta diff --git a/assets/resources/game/heros/Hero.prefab b/assets/resources/game/heros/Hero.prefab new file mode 100644 index 00000000..dba6510b --- /dev/null +++ b/assets/resources/game/heros/Hero.prefab @@ -0,0 +1,279 @@ +[ + { + "__type__": "cc.Prefab", + "_name": "Hero", + "_objFlags": 0, + "__editorExtras__": {}, + "_native": "", + "data": { + "__id__": 1 + }, + "optimizationPolicy": 0, + "persistent": false + }, + { + "__type__": "cc.Node", + "_name": "Hero", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": null, + "_children": [ + { + "__id__": 2 + } + ], + "_active": true, + "_components": [ + { + "__id__": 8 + }, + { + "__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": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "Spine", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 3 + }, + { + "__id__": 5 + } + ], + "_prefab": { + "__id__": 7 + }, + "_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": 1073741824, + "_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": 100, + "height": 100 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "eavoxMfTVNTZQ5Ncin8/IA" + }, + { + "__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": null, + "defaultSkin": "", + "defaultAnimation": "", + "_premultipliedAlpha": true, + "_timeScale": 1, + "_preCacheMode": -1, + "_cacheMode": 0, + "_sockets": [], + "_useTint": false, + "_debugMesh": false, + "_debugBones": false, + "_debugSlots": false, + "_enableBatch": false, + "loop": true, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "bcFVRht+5DyZogkN152H5x" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "d4UPOWdrxLOq8+0uki2YgO", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.RigidBody2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 9 + }, + "enabledContactListener": true, + "bullet": true, + "awakeOnLoad": true, + "_group": 4, + "_type": 1, + "_allowSleep": false, + "_gravityScale": 1, + "_linearDamping": 0, + "_angularDamping": 0, + "_linearVelocity": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_angularVelocity": 0, + "_fixedRotation": true, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "9em5Qd7IJDLK7bBlRbsBHx" + }, + { + "__type__": "cc.BoxCollider2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 11 + }, + "tag": 0, + "_group": 4, + "_density": 1, + "_sensor": false, + "_friction": 1, + "_restitution": 0, + "_offset": { + "__type__": "cc.Vec2", + "x": -1.8, + "y": 37.7 + }, + "_size": { + "__type__": "cc.Size", + "width": 50.8, + "height": 78.6 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "63wUCNn+RFvo5PEvaO4kQ5" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "c46/YsCPVOJYA4mWEpNYRx", + "instance": null, + "targetOverrides": null + } +] \ No newline at end of file diff --git a/assets/resources/game/heros/Hero.prefab.meta b/assets/resources/game/heros/Hero.prefab.meta new file mode 100644 index 00000000..801a7c5e --- /dev/null +++ b/assets/resources/game/heros/Hero.prefab.meta @@ -0,0 +1,13 @@ +{ + "ver": "1.1.50", + "importer": "prefab", + "imported": true, + "uuid": "6254c3d4-6f68-45c7-934c-7056d25a93d3", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": { + "syncNodeName": "Hero" + } +} diff --git a/assets/script/game/data.meta b/assets/resources/game/heros/heros/k1.meta similarity index 70% rename from assets/script/game/data.meta rename to assets/resources/game/heros/heros/k1.meta index cd323577..ae52fb39 100644 --- a/assets/script/game/data.meta +++ b/assets/resources/game/heros/heros/k1.meta @@ -2,7 +2,7 @@ "ver": "1.2.0", "importer": "directory", "imported": true, - "uuid": "7d9b27df-701e-44ee-8732-b53f9d22cca2", + "uuid": "a280e152-6b3d-45e5-8fe4-b5f2984ad21d", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/resources/game/heros/heros/k1/k1.atlas b/assets/resources/game/heros/heros/k1/k1.atlas new file mode 100644 index 00000000..1a1e9c92 --- /dev/null +++ b/assets/resources/game/heros/heros/k1/k1.atlas @@ -0,0 +1,90 @@ + +k1.png +size: 454,208 +format: RGBA8888 +filter: Linear,Linear +repeat: none +Body + rotate: false + xy: 321, 60 + size: 84, 88 + orig: 128, 128 + offset: 22, 18 + index: -1 +Face 01 + rotate: false + xy: 207, 20 + size: 112, 52 + orig: 200, 128 + offset: 51, 28 + index: -1 +Face 02 + rotate: false + xy: 207, 2 + size: 104, 16 + orig: 200, 128 + offset: 56, 34 + index: -1 +Face 03 + rotate: false + xy: 207, 74 + size: 112, 74 + orig: 200, 128 + offset: 50, 13 + index: -1 +Head + rotate: false + xy: 2, 3 + size: 203, 203 + orig: 280, 280 + offset: 37, 28 + index: -1 +Left Arm + rotate: false + xy: 375, 13 + size: 41, 45 + orig: 64, 64 + offset: 11, 9 + index: -1 +Left Hand + rotate: false + xy: 383, 161 + size: 48, 45 + orig: 64, 64 + offset: 8, 7 + index: -1 +Left Leg + rotate: true + xy: 321, 18 + size: 40, 52 + orig: 64, 64 + offset: 12, 6 + index: -1 +Right Leg + rotate: true + xy: 321, 18 + size: 40, 52 + orig: 64, 64 + offset: 12, 6 + index: -1 +Right Arm + rotate: false + xy: 407, 64 + size: 41, 45 + orig: 64, 64 + offset: 11, 9 + index: -1 +Right Hand + rotate: true + xy: 407, 111 + size: 48, 45 + orig: 64, 64 + offset: 8, 10 + index: -1 +Weapon + rotate: false + xy: 207, 150 + size: 174, 56 + orig: 180, 64 + offset: 3, 5 + index: -1 diff --git a/assets/resources/game/heros/heros/k1/k1.atlas.meta b/assets/resources/game/heros/heros/k1/k1.atlas.meta new file mode 100644 index 00000000..c90846da --- /dev/null +++ b/assets/resources/game/heros/heros/k1/k1.atlas.meta @@ -0,0 +1 @@ +{"ver":"1.0.1","importer":"*","imported":true,"uuid":"1c73817e-2607-44cd-838a-01ae45bbd135","files":[".atlas",".json"],"subMetas":{},"userData":{}} diff --git a/assets/resources/game/heros/heros/k1/k1.json b/assets/resources/game/heros/heros/k1/k1.json new file mode 100644 index 00000000..c5f6e702 --- /dev/null +++ b/assets/resources/game/heros/heros/k1/k1.json @@ -0,0 +1,580 @@ +{ +"skeleton": { + "hash": "gb+/032H6y/yhUHAxZJyKUrXWfw=", + "spine": "3.8.75", + "x": -151.92, + "y": -10.85, + "width": 294.8, + "height": 336.35, + "fps": 10, + "images": "./items/Knight Gray/Vector Parts/", + "audio": "D:/Game/games/spine/items/Knight Gray/Vector Parts" +}, +"bones": [ + { "name": "root" }, + { "name": "root-bone_006", "parent": "root", "length": 56.22, "rotation": 89.4, "x": 0.14, "y": 33.73 }, + { "name": "root-bone_005", "parent": "root", "length": 35.46, "rotation": 261.59, "x": -17.93, "y": 37.64 }, + { "name": "root-bone_004", "parent": "root", "length": 34.35, "rotation": 275.19, "x": 19.35, "y": 36.24 }, + { "name": "root-bone_006-ext_Body", "parent": "root-bone_006", "rotation": 270.6, "x": 25.27, "y": -0.21 }, + { "name": "root-bone_004-ext_Left Leg", "parent": "root-bone_004", "rotation": 91.37, "x": 11.74, "y": 0.49 }, + { "name": "root-bone_006-bone_000", "parent": "root-bone_006", "length": 29.84, "rotation": 259.65, "x": 43.93, "y": -17.8 }, + { "name": "root-bone_006-bone_002", "parent": "root-bone_006", "length": 31.19, "rotation": 148.48, "x": 41.59, "y": 27.83 }, + { "name": "root-bone_006-bone_007", "parent": "root-bone_006", "length": 151.15, "rotation": 357.24, "x": 56.22 }, + { "name": "root-bone_005-ext_Right Leg", "parent": "root-bone_005", "rotation": 91.78, "x": 12.69, "y": 0.71 }, + { "name": "root-bone_006-bone_000-ext_Left Arm", "parent": "root-bone_006-bone_000", "rotation": 100.44, "x": 9.61, "y": -1.42 }, + { "name": "root-bone_006-bone_007-ext_Head", "parent": "root-bone_006-bone_007", "rotation": 273.37, "x": 94.64, "y": 18.24 }, + { "name": "root-bone_006-bone_002-bone_003", "parent": "root-bone_006-bone_002", "length": 18.89, "rotation": 358.5, "x": 31.19 }, + { "name": "root-bone_006-bone_007-ext_Face 01", "parent": "root-bone_006-bone_007", "rotation": 273.37, "x": 50.67, "y": -8.19 }, + { "name": "root-bone_006-bone_002-ext_Right Arm", "parent": "root-bone_006-bone_002", "rotation": 100.91, "x": 9.76, "y": -1.83 }, + { "name": "root-bone_006-bone_000-bone_001", "parent": "root-bone_006-bone_000", "length": 23.33, "rotation": 358.01, "x": 29.84 }, + { "name": "root-bone_006-bone_002-bone_003-bone_008", "parent": "root-bone_006-bone_002-bone_003", "length": 27.4, "rotation": 213.62, "x": 2.91, "y": -4.01 }, + { "name": "root-bone_006-bone_000-bone_001-ext_Weapon", "parent": "root-bone_006-bone_000-bone_001", "rotation": 83.05, "x": 21.41, "y": 60.75 }, + { "name": "root-bone_006-bone_000-bone_001-ext_Left Hand", "parent": "root-bone_006-bone_000-bone_001", "rotation": 102.43, "x": 9.48, "y": 0.28 }, + { "name": "root-bone_006-bone_002-bone_003-ext_Right Hand", "parent": "root-bone_006-bone_002-bone_003", "rotation": 102.41, "x": 7.46, "y": 1.31 } +], +"slots": [ + { "name": "root-bone_006-bone_000-ext_Left Arm", "bone": "root-bone_006-bone_000-ext_Left Arm", "attachment": "Left Arm" }, + { "name": "root-bone_006-bone_000-bone_001-ext_Weapon", "bone": "root-bone_006-bone_000-bone_001-ext_Weapon", "attachment": "Weapon" }, + { "name": "root-bone_006-bone_000-bone_001-ext_Left Hand", "bone": "root-bone_006-bone_000-bone_001-ext_Left Hand", "attachment": "Left Hand" }, + { "name": "root-bone_004-ext_Left Leg", "bone": "root-bone_004-ext_Left Leg", "attachment": "Left Leg" }, + { "name": "root-bone_005-ext_Right Leg", "bone": "root-bone_005-ext_Right Leg", "attachment": "Right Leg" }, + { "name": "root-bone_006-ext_Body", "bone": "root-bone_006-ext_Body", "attachment": "Body" }, + { "name": "root-bone_006-bone_007-ext_Head", "bone": "root-bone_006-bone_007-ext_Head", "attachment": "Head" }, + { "name": "root-bone_006-bone_007-ext_Face 01", "bone": "root-bone_006-bone_007-ext_Face 01", "attachment": "Face 01" }, + { "name": "root-bone_006-bone_002-bone_003-ext_Right Hand", "bone": "root-bone_006-bone_002-bone_003-ext_Right Hand", "attachment": "Right Hand" }, + { "name": "root-bone_006-bone_002-ext_Right Arm", "bone": "root-bone_006-bone_002-ext_Right Arm", "attachment": "Right Arm" } +], +"skins": [ + { + "name": "default", + "attachments": { + "root-bone_006-bone_000-bone_001-ext_Left Hand": { + "Left Hand": { "width": 64, "height": 64 } + }, + "root-bone_006-ext_Body": { + "Body": { "width": 128, "height": 128 } + }, + "root-bone_006-bone_007-ext_Head": { + "Head": { "width": 280, "height": 280 } + }, + "root-bone_006-bone_002-ext_Right Arm": { + "Right Arm": { "width": 64, "height": 64 } + }, + "root-bone_006-bone_002-bone_003-ext_Right Hand": { + "Right Hand": { "width": 64, "height": 64 } + }, + "root-bone_006-bone_000-bone_001-ext_Weapon": { + "Weapon": { "width": 180, "height": 64 } + }, + "root-bone_005-ext_Right Leg": { + "Right Leg": { "width": 64, "height": 64 } + }, + "root-bone_006-bone_000-ext_Left Arm": { + "Left Arm": { "width": 64, "height": 64 } + }, + "root-bone_006-bone_007-ext_Face 01": { + "Face 01": { "width": 200, "height": 128 }, + "Face 02": { "width": 200, "height": 128 }, + "Face 03": { "width": 200, "height": 128 } + }, + "root-bone_004-ext_Left Leg": { + "Left Leg": { "width": 64, "height": 64 } + } + } + } +], +"animations": { + "Attacking": { + "bones": { + "root-bone_006": { + "rotate": [ + {}, + { "time": 0.1, "angle": 4.2 }, + { "time": 0.2, "angle": 4.48 }, + { "time": 0.275, "angle": -13.49 }, + { "time": 0.3, "angle": -14.54 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.1, "x": -1.12, "y": 3.35 }, + { "time": 0.2, "x": -1.6, "y": 4.31 }, + { "time": 0.275, "x": 0.8, "y": -2.1 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000": { + "rotate": [ + {}, + { "time": 0.1, "angle": 47.01 }, + { "time": 0.2, "angle": 48.51 }, + { "time": 0.275, "angle": -28.36 }, + { "time": 0.3, "angle": -25.38 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000-bone_001": { + "rotate": [ + {}, + { "time": 0.1, "angle": 16.78, "curve": "stepped" }, + { "time": 0.2, "angle": 16.78 }, + { "time": 0.275, "angle": -27.03 }, + { "time": 0.3, "angle": -23.87 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002": { + "rotate": [ + {}, + { "time": 0.1, "angle": -7.81 }, + { "time": 0.2, "angle": -10.58 }, + { "time": 0.275, "angle": -26.88 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002-bone_003-bone_008": { + "rotate": [ + {}, + { "time": 0.1, "angle": 3.62 }, + { "time": 0.2, "angle": 6.1 }, + { "time": 0.275, "angle": 40.37 }, + { "time": 0.3, "angle": 41.41 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_007": { + "rotate": [ + {}, + { "time": 0.1, "angle": 5.61 }, + { "time": 0.2, "angle": 6.48 }, + { "time": 0.275, "angle": 0.87 }, + { "time": 0.4 } + ], + "translate": [ + { "time": 0.1 }, + { "time": 0.2, "x": 1.94, "y": 1.11 }, + { "time": 0.275, "x": 0.97, "y": 0.56 }, + { "time": 0.4 } + ] + } + } + }, + "Hurt": { + "slots": { + "root-bone_006-bone_007-ext_Face 01": { + "attachment": [ + { "name": "Face 03" } + ] + } + }, + "bones": { + "root-bone_004": { + "rotate": [ + {}, + { "time": 0.1, "angle": 27.58 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.1, "x": -2.95, "y": 7.87 }, + { "time": 0.4 } + ] + }, + "root-bone_006": { + "rotate": [ + {}, + { "time": 0.1, "angle": 11.65 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.1, "x": -0.86, "y": 6.16 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000": { + "rotate": [ + {}, + { "time": 0.1, "angle": 15.45 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000-bone_001": { + "rotate": [ + {}, + { "time": 0.1, "angle": -5.6 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002": { + "rotate": [ + {}, + { "time": 0.05, "angle": 8.94 }, + { "time": 0.1, "angle": -4.58 }, + { "time": 0.15, "angle": -18.09 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002-bone_003-bone_008": { + "rotate": [ + {}, + { "time": 0.05, "angle": -8.94 }, + { "time": 0.1, "angle": 4.58 }, + { "time": 0.15, "angle": 18.09 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_007": { + "rotate": [ + {}, + { "time": 0.05, "angle": -9.85 }, + { "time": 0.1, "angle": 1.01 }, + { "time": 0.15, "angle": 11.87 }, + { "time": 0.4 } + ] + } + } + }, + "Idle": { + "bones": { + "root-bone_006": { + "rotate": [ + {}, + { "time": 0.2, "angle": 2.13 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.2, "x": -0.4, "y": 2.83 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000": { + "rotate": [ + {}, + { "time": 0.2, "angle": 3.4 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000-bone_001": { + "rotate": [ + {}, + { "time": 0.2, "angle": 6.25 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002": { + "rotate": [ + {}, + { "time": 0.2, "angle": -11.19 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002-bone_003-bone_008": { + "rotate": [ + {}, + { "time": 0.2, "angle": 9.06 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_007": { + "rotate": [ + {}, + { "time": 0.05, "angle": -2.83 }, + { "time": 0.2, "angle": 3.15 }, + { "time": 0.25, "angle": 5.15 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.05, "x": -2.31, "y": -1.39 }, + { "time": 0.2, "x": 2.68, "y": -0.61 }, + { "time": 0.25, "x": 4.35, "y": -0.35 }, + { "time": 0.4 } + ] + } + } + }, + "Idle Blink": { + "slots": { + "root-bone_006-bone_007-ext_Face 01": { + "attachment": [ + { "time": 0.3, "name": "Face 02" } + ] + } + }, + "bones": { + "root-bone_006": { + "rotate": [ + {}, + { "time": 0.2, "angle": 2.13 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.2, "x": -0.4, "y": 2.83 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000": { + "rotate": [ + {}, + { "time": 0.2, "angle": 3.4 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_000-bone_001": { + "rotate": [ + {}, + { "time": 0.2, "angle": 6.25 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002": { + "rotate": [ + {}, + { "time": 0.2, "angle": -11.19 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_002-bone_003-bone_008": { + "rotate": [ + {}, + { "time": 0.2, "angle": 9.06 }, + { "time": 0.4 } + ] + }, + "root-bone_006-bone_007": { + "rotate": [ + {}, + { "time": 0.05, "angle": -2.83 }, + { "time": 0.25, "angle": 5.15 }, + { "time": 0.4 } + ], + "translate": [ + {}, + { "time": 0.05, "x": -2.31, "y": -1.39 }, + { "time": 0.25, "x": 4.35, "y": -0.35 }, + { "time": 0.4 } + ] + } + } + }, + "Taunt": { + "bones": { + "root-bone_004": { + "rotate": [ + {}, + { "time": 0.1, "angle": -12.01 }, + { "time": 0.3, "angle": -9.61 }, + { "time": 0.5, "angle": -12.01 }, + { "time": 0.6 } + ], + "translate": [ + {}, + { "time": 0.1, "x": 5.7, "y": 0.39 }, + { "time": 0.3, "x": 4.56, "y": 0.31 }, + { "time": 0.5, "x": 5.7, "y": 0.39 }, + { "time": 0.6 } + ] + }, + "root-bone_005": { + "rotate": [ + {}, + { "time": 0.1, "angle": -17.76 }, + { "time": 0.3, "angle": -14.21 }, + { "time": 0.5, "angle": -17.76 }, + { "time": 0.6 } + ], + "translate": [ + {}, + { "time": 0.1, "x": 6.07, "y": 0.58 }, + { "time": 0.3, "x": 4.86, "y": 0.47 }, + { "time": 0.5, "x": 6.07, "y": 0.58 }, + { "time": 0.6 } + ] + }, + "root-bone_006": { + "rotate": [ + {}, + { "time": 0.1, "angle": 3.8 }, + { "time": 0.3, "angle": 3.04 }, + { "time": 0.5, "angle": 3.8 }, + { "time": 0.6 } + ], + "translate": [ + {}, + { "time": 0.1, "x": 6.46, "y": 7.45 }, + { "time": 0.3, "x": 5.17, "y": 5.96 }, + { "time": 0.5, "x": 6.46, "y": 7.45 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_000": { + "rotate": [ + {}, + { "time": 0.1, "angle": 17.07 }, + { "time": 0.3, "angle": 13.66 }, + { "time": 0.5, "angle": 17.07 }, + { "time": 0.6 } + ], + "translate": [ + {}, + { "time": 0.1, "y": -6.99 }, + { "time": 0.3, "y": -5.59 }, + { "time": 0.5, "y": -6.99 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_000-bone_001": { + "rotate": [ + {}, + { "time": 0.1, "angle": -19.79 }, + { "time": 0.3, "angle": -15.83 }, + { "time": 0.5, "angle": -19.79 }, + { "time": 0.6 } + ], + "translate": [ + {}, + { "time": 0.1, "x": 3.53, "y": 1.56 }, + { "time": 0.3, "x": 2.83, "y": 1.25 }, + { "time": 0.5, "x": 3.53, "y": 1.56 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_002": { + "rotate": [ + {}, + { "time": 0.1, "angle": -30.01 }, + { "time": 0.3, "angle": -24.01 }, + { "time": 0.5, "angle": -30.01 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_002-bone_003-bone_008": { + "rotate": [ + {}, + { "time": 0.1, "angle": 44.75 }, + { "time": 0.3, "angle": 35.8 }, + { "time": 0.5, "angle": 44.75 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_007": { + "rotate": [ + {}, + { "time": 0.1, "angle": 7.67 }, + { "time": 0.3, "angle": 6.13 }, + { "time": 0.5, "angle": 7.67 }, + { "time": 0.6 } + ], + "translate": [ + {}, + { "time": 0.1, "x": 3.4, "y": 1.56 }, + { "time": 0.3, "x": 2.72, "y": 1.24 }, + { "time": 0.5, "x": 3.4, "y": 1.56 }, + { "time": 0.6 } + ] + } + } + }, + "Walking": { + "bones": { + "root-bone_004": { + "rotate": [ + { "angle": -34.88 }, + { "time": 0.15, "angle": -6.9 }, + { "time": 0.3, "angle": 15.46 }, + { "time": 0.45, "angle": -6.9 }, + { "time": 0.6, "angle": -34.88 } + ] + }, + "root-bone_005": { + "rotate": [ + { "angle": 40.24 }, + { "time": 0.15, "angle": 6.17 }, + { "time": 0.3, "angle": -13.58 }, + { "time": 0.45, "angle": 6.17 }, + { "time": 0.6, "angle": 40.24 } + ] + }, + "root-bone_006": { + "rotate": [ + { "angle": -4.72 }, + { "time": 0.15, "angle": 1.64 }, + { "time": 0.3, "angle": -4.72 }, + { "time": 0.45, "angle": 1.64 }, + { "time": 0.6, "angle": -4.72 } + ], + "translate": [ + {}, + { "time": 0.15, "y": 4.41 }, + { "time": 0.3 }, + { "time": 0.45, "y": 4.41 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_000": { + "rotate": [ + { "angle": -26.08 }, + { "time": 0.15, "angle": -48.44 }, + { "time": 0.3, "angle": -70.79 }, + { "time": 0.45, "angle": -48.44 }, + { "time": 0.6, "angle": -26.08 } + ] + }, + "root-bone_006-bone_000-bone_001": { + "rotate": [ + { "angle": 10.29 }, + { "time": 0.15, "angle": 16.39 }, + { "time": 0.3, "angle": 22.49 }, + { "time": 0.45, "angle": 16.39 }, + { "time": 0.6, "angle": 10.29 } + ] + }, + "root-bone_006-bone_002": { + "rotate": [ + {}, + { "time": 0.15, "angle": 39.98 }, + { "time": 0.3, "angle": 79.95 }, + { "time": 0.45, "angle": 39.98 }, + { "time": 0.6 } + ] + }, + "root-bone_006-bone_002-bone_003-bone_008": { + "rotate": [ + { "angle": 4.72 }, + { "time": 0.15, "angle": -35.26 }, + { "time": 0.3, "angle": -75.24 }, + { "time": 0.45, "angle": -35.26 }, + { "time": 0.6, "angle": 4.72 } + ] + }, + "root-bone_006-bone_007": { + "rotate": [ + { "angle": -1.29 }, + { "time": 0.05, "angle": -6.45 }, + { "time": 0.15, "angle": -0.47 }, + { "time": 0.2, "angle": 2.53 }, + { "time": 0.3, "angle": -2.13 }, + { "time": 0.35, "angle": -4.45 }, + { "time": 0.45, "angle": 1 }, + { "time": 0.5, "angle": 3.72 }, + { "time": 0.6, "angle": -1.29 } + ], + "translate": [ + {}, + { "time": 0.05, "x": -2.12, "y": -0.12 }, + { "time": 0.15, "x": 0.7, "y": 0.34 }, + { "time": 0.2, "x": 2.12, "y": 0.57 }, + { "time": 0.3, "x": -1.06, "y": 0.09 }, + { "time": 0.35, "x": -2.66, "y": -0.15 }, + { "time": 0.45, "x": 0.53, "y": -0.02 }, + { "time": 0.5, "x": 2.13, "y": 0.04 }, + { "time": 0.6 } + ] + } + } + } +} +} \ No newline at end of file diff --git a/assets/resources/game/heros/heros/k1/k1.json.meta b/assets/resources/game/heros/heros/k1/k1.json.meta new file mode 100644 index 00000000..d9c5b67b --- /dev/null +++ b/assets/resources/game/heros/heros/k1/k1.json.meta @@ -0,0 +1,11 @@ +{ + "ver": "1.2.6", + "importer": "spine-data", + "imported": true, + "uuid": "1fd0e272-fdc4-42ee-8576-eef38128235a", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/assets/resources/game/heros/heros/k1/k1.png b/assets/resources/game/heros/heros/k1/k1.png new file mode 100644 index 0000000000000000000000000000000000000000..804901c0dfb2008849cc62072b51cb904f57e0f5 GIT binary patch literal 32910 zcmZ5{Ral!%*EQ}E++9k8LveR^f@{$hhXN@DiiF?}Ew06#;!bdf0>veGftFwe3Z-A3 z_xg|i9NbrOa_^bR-ZN{jwI)_ySB(&l77qmlg-}CX*$@QJghDT1FVc3D#eytMUW7Fk`D^%(l^hX#>yqzm$TK}$(cqjO) z+e8$e2bV$ZNgzi&6zd-ZYD4!UXSX~~SKa9c1tP9;x>?M!R?Z*$u;l2wC5AifXB zs$@?d_ks^cmWmd>#SvnvZ0@wUa$in!6YO=9iN|B*Uun|rW?#)Ea^7zs9Ij^CAwoDL zrv#nyBX}9U2#1>)G2!@I=^TdUZh=2ERec;i#k;bMJ;VCm(of>Zzk6~wU%A>P;YA4x zeNzV`z+uPeh8IpK0RmTiK;jglN=6=5r)|1y8HUNz_LLcsB{JigTFQtAa^%=S;mKb^{6G zlHlP()569aw0>)Auub6icD5KvoSLh@+2ORB;6(Z*Q^n1PPGn6~D^v=sMh67@q_x1L zrsQKTX)XcVFu`53n?@^f0fGIHz7>)XzYm_&J7eJc=aD)E^3MCpZ=D`m8xfUXJ!V*k zLVu!!tMzhdYCn~u^u6~8niA{g-4DLz%~R;<$)QUQ7%PJaR+N~P8Di?pcZ{zoe0MM& zv8@{t+X>#M{3E|l-sdGYqwz%%>gsQ$N$m%W3+WF0674DH2oR^(bz-%oK%2U|5C!}% z^V`q8g23Xh$bV(7ltupSw)WfyrIC*n`t>;LDlZW7lSEXe#hy~)eEoBs(w9wxWfWp# zpchVzjm7)7_fH-RLdmE}5FB=&3+4?=9XReLF&qnwz1Yz5ed=irwmp`VO@tQ#$ikQ3T`_Aw_2KEZEtly8pIyg`uE{g?M!-5*0Am z>clwgGfiSj6;Eg>%8mfIGxfPX;+Myt*3el3#-x>NFI{ieq^7qnS!}(k8N%K^DNaB4 z=m->F;P)s`t6hbR(tgYz%kyZW4HoBuBc#$R&3PDI&+P&YoTav3@5qL@E|iS4gpBbe z+ABpHsFuY+@1oF+(4NeiTi1BEqoa?N$@PA1)kfJqgzjVZo6FC(fJsz{l!a2IHNe!x zYuSJDxa%99rMhj>Gwlmwnd2m@aV4sEW;hdR7pgX9=lAvc9e2-_s9IJYL`_yHt{|_v zJ+_(S0HS;W%|#Se(owo~VJ~JHvc1+;jIj&M0LddOT?qK&~3f?p_!S-qHFc4bttS zEA)`omG7C9yZi`RFrq}O3i7m}?D~*+-U&lL-hl4!7MEhNyh3L&>8qoNC2wlgfa)j)%6@Dr~kHAFYl8)nuUqG*vKT@Tqm$zWvVPj%l8h*Qy{a}s7J%>ntDX!&zzU#1`%_0 zVHB(=n)CQmyjoO6AdXT3eww$D^!o$x5UsOTIWy&3gpie(S2z=nMO5YdZg|~9BpiL# zRkEjnio;4J_5wntIv}@$7iv>neuaRpEAs^jRkH6Q_NOSzX%(X?#-emFyIG9EK~_)V zL5his(~Efon*O_>qv2+9klr|1K>u z%4#(kHS=--pqeQls#s!m<0!u%xAU3e>7I0Z_a!1+kRI@=g4=QR4OS9>i%NkHDj_0$ zD)Pr7Q^LN$uxzQwaOA2WwuA-&j3zj76HoF6!$qotmTc?~MJB&%vucbc&cCcM|5}bE zh&+d+x9z;3S`0Fn}mcqBi0mvd9wy(?u{*_Rb zGd49hlEBBXLG#-I^DYLY2p@lSSaO7AgI^jq=K11>s#@8ng;O)KSz|I!+NCNDDKVb1 zzn15pT~IP*D?`@BCP|fdq!Mfa{sVcAB_C3oaXDycC}i-9J+1rWO!%#fn!MD?;r{t_ z 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 JPDHLkV1m8d%ccMT literal 0 HcmV?d00001 diff --git a/assets/resources/game/heros/heros/k1/k1.png.meta b/assets/resources/game/heros/heros/k1/k1.png.meta new file mode 100644 index 00000000..aca51eae --- /dev/null +++ b/assets/resources/game/heros/heros/k1/k1.png.meta @@ -0,0 +1,42 @@ +{ + "ver": "1.0.26", + "importer": "image", + "imported": true, + "uuid": "696b70ef-b479-40f7-9375-6ad93c67aaf5", + "files": [ + ".json", + ".png" + ], + "subMetas": { + "6c48a": { + "importer": "texture", + "uuid": "696b70ef-b479-40f7-9375-6ad93c67aaf5@6c48a", + "displayName": "k1", + "id": "6c48a", + "name": "texture", + "userData": { + "wrapModeS": "repeat", + "wrapModeT": "repeat", + "minfilter": "linear", + "magfilter": "linear", + "mipfilter": "none", + "anisotropy": 0, + "isUuid": true, + "imageUuidOrDatabaseUri": "696b70ef-b479-40f7-9375-6ad93c67aaf5", + "visible": false + }, + "ver": "1.0.22", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + } + }, + "userData": { + "hasAlpha": true, + "type": "texture", + "fixAlphaTransparencyArtifacts": false, + "redirect": "696b70ef-b479-40f7-9375-6ad93c67aaf5@6c48a" + } +} diff --git a/assets/script/game/GameBootstrap.ts b/assets/script/game/GameBootstrap.ts new file mode 100644 index 00000000..4d364492 --- /dev/null +++ b/assets/script/game/GameBootstrap.ts @@ -0,0 +1,11 @@ +import { ecs } from "../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; + +export class GameBootstrap { + init() { + // 初始化ECS引擎 + ecs.init(); + + // 自动注册所有带@ecs.register装饰器的组件 + ecs.scan(/* 可以指定扫描路径 */); + } +} \ No newline at end of file diff --git a/assets/script/game/data/dataViewVM.ts.meta b/assets/script/game/GameBootstrap.ts.meta similarity index 70% rename from assets/script/game/data/dataViewVM.ts.meta rename to assets/script/game/GameBootstrap.ts.meta index bb04b7c1..f946e105 100644 --- a/assets/script/game/data/dataViewVM.ts.meta +++ b/assets/script/game/GameBootstrap.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.23", "importer": "typescript", "imported": true, - "uuid": "4209bcee-3867-4c0b-83c9-a4eeee989328", + "uuid": "6cc513d1-e193-45db-b277-1346505847d2", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/script/game/common/Constants.ts b/assets/script/game/common/Constants.ts new file mode 100644 index 00000000..1dca82be --- /dev/null +++ b/assets/script/game/common/Constants.ts @@ -0,0 +1,20 @@ +/** 游戏通用常量配置 */ +export const GameConstants = { + /** Spine资源路径 */ + SPINE: { + HERO: "game/heros/heros", // 英雄资源根目录 + // MONSTER: "game/heros/monster" // 怪物资源根目录 + }, + /** 英雄预制体路径 */ + HERO_PREFAB_PATH: "game/hero/prefabs/", + /** 默认英雄缩放 */ + DEFAULT_SCALE: 1, + /** 游戏层定义 */ + LAYERS: { + HERO: 10, + MONSTER: 20 + } +} as const; + +export const MONSTER_PREFAB_PATH = "game/monster/prefab/"; +export const SKILL_EFFECT_PATH = "game/effect/"; \ No newline at end of file diff --git a/assets/script/game/data/dataModelComp.ts.meta b/assets/script/game/common/Constants.ts.meta similarity index 70% rename from assets/script/game/data/dataModelComp.ts.meta rename to assets/script/game/common/Constants.ts.meta index b958d579..3dd13482 100644 --- a/assets/script/game/data/dataModelComp.ts.meta +++ b/assets/script/game/common/Constants.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.23", "importer": "typescript", "imported": true, - "uuid": "0aefc30a-9392-4ada-b3d0-8c15625e8cfc", + "uuid": "da1b1900-d741-411c-b677-c1eb7770897e", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/script/game/heros.meta b/assets/script/game/component.meta similarity index 70% rename from assets/script/game/heros.meta rename to assets/script/game/component.meta index 87ac5875..4c952c5e 100644 --- a/assets/script/game/heros.meta +++ b/assets/script/game/component.meta @@ -2,7 +2,7 @@ "ver": "1.2.0", "importer": "directory", "imported": true, - "uuid": "7419c29e-7ead-48a1-bef4-06c52b520491", + "uuid": "c4fb6bf5-feb8-447f-a0ea-c8c246f96362", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/script/game/component/hero.meta b/assets/script/game/component/hero.meta new file mode 100644 index 00000000..5ad34111 --- /dev/null +++ b/assets/script/game/component/hero.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "c10720f1-7ee0-426a-aaa8-15344c003fb1", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/component/hero/Combat.ts b/assets/script/game/component/hero/Combat.ts new file mode 100644 index 00000000..300a7e74 --- /dev/null +++ b/assets/script/game/component/hero/Combat.ts @@ -0,0 +1,37 @@ +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; + +/** 战斗组件 */ +@ecs.register('Combat') +export class Combat extends ecs.Comp { + /** 攻击力 */ + attackPower: number = 10; + /** 攻击范围(像素) */ + attackRange: number = 100; + /** 攻击间隔(秒) */ + attackInterval: number = 1; + /** 当前攻击计时 */ + attackTimer: number = 0; + /** 攻击目标 */ + target: ecs.Entity | null = null; + + init(attack: number, range: number) { + this.attackPower = attack; + this.attackRange = range; + } + + /** 攻击结束回调 */ + onAttackEnd() { + // 重置攻击目标 + this.target = null; + // 触发攻击结束事件 + oops.message.dispatch('AttackEnd', this.ent); + } + + reset() { + this.attackPower = 10; + this.attackRange = 100; + this.attackInterval = 1; + this.attackTimer = 0; + this.target = null; + } +} \ No newline at end of file diff --git a/assets/script/game/data/data.ts.meta b/assets/script/game/component/hero/Combat.ts.meta similarity index 70% rename from assets/script/game/data/data.ts.meta rename to assets/script/game/component/hero/Combat.ts.meta index 7b361e0a..27e61294 100644 --- a/assets/script/game/data/data.ts.meta +++ b/assets/script/game/component/hero/Combat.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.23", "importer": "typescript", "imported": true, - "uuid": "cb9afa42-2112-471e-b86c-79407ba6abd4", + "uuid": "4470e6fb-5c92-486b-851e-1842bc8f2ff5", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/script/game/component/hero/HeroAnimState.ts b/assets/script/game/component/hero/HeroAnimState.ts new file mode 100644 index 00000000..d1f0431f --- /dev/null +++ b/assets/script/game/component/hero/HeroAnimState.ts @@ -0,0 +1,6 @@ +export enum HeroAnimState { + IDLE = "Idle", + WALKING = "Walking", + ATTACKING = "Attacking", + TAUNT = "Taunt" +} \ No newline at end of file diff --git a/assets/script/game/data/dataViewComp.ts.meta b/assets/script/game/component/hero/HeroAnimState.ts.meta similarity index 70% rename from assets/script/game/data/dataViewComp.ts.meta rename to assets/script/game/component/hero/HeroAnimState.ts.meta index edad6608..085c2b06 100644 --- a/assets/script/game/data/dataViewComp.ts.meta +++ b/assets/script/game/component/hero/HeroAnimState.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.23", "importer": "typescript", "imported": true, - "uuid": "8ae6d033-ff0f-44d5-9ff7-c57751bd4ea1", + "uuid": "426117c2-67a7-4c89-b6b1-4f1074448b29", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/script/game/component/hero/HeroModel.ts b/assets/script/game/component/hero/HeroModel.ts new file mode 100644 index 00000000..b38a96d0 --- /dev/null +++ b/assets/script/game/component/hero/HeroModel.ts @@ -0,0 +1,40 @@ +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { HeroConfig } from "../../config/HeroConfig"; + +@ecs.register('HeroModel') +export class HeroModel extends ecs.Comp { + /** 角色配置ID */ + configId: number = 0; + /** 当前生命值 */ + hp: number = 0; + /** 最大生命值 */ + maxHp: number = 0; + /** 基础攻击力 */ + attack: number = 0; + /** 防御力 */ + defense: number = 0; + /** 暴击率 0-100 */ + critRate: number = 5; + /** 闪避率 0-100 */ + dodgeRate: number = 5; + + init(config: HeroConfig) { + this.configId = config.id; + this.maxHp = config.hp; + this.hp = config.hp; + this.attack = config.attack; + this.defense = config.defense; + this.critRate = config.critRate || 5; + this.dodgeRate = config.dodgeRate || 5; + } + + reset() { + this.configId = 0; + this.hp = 0; + this.maxHp = 0; + this.attack = 0; + this.defense = 0; + this.critRate = 5; + this.dodgeRate = 5; + } +} \ No newline at end of file diff --git a/assets/script/game/component/hero/HeroModel.ts.meta b/assets/script/game/component/hero/HeroModel.ts.meta new file mode 100644 index 00000000..cf90c1f0 --- /dev/null +++ b/assets/script/game/component/hero/HeroModel.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "1d8dd962-7f0e-4601-82d1-f371f816bd21", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/component/hero/HeroState.ts b/assets/script/game/component/hero/HeroState.ts new file mode 100644 index 00000000..195aa957 --- /dev/null +++ b/assets/script/game/component/hero/HeroState.ts @@ -0,0 +1,13 @@ +import { HeroAnimState } from "./HeroAnimState"; +import { HeroViewComp } from "./HeroView"; + +export class HeroStateMachine { + private _currentState: HeroAnimState = HeroAnimState.IDLE; + + changeState(newState: HeroAnimState, view: HeroViewComp) { + if (this._currentState !== newState) { + view.playAnimation(newState); + this._currentState = newState; + } + } +} \ No newline at end of file diff --git a/assets/script/game/component/hero/HeroState.ts.meta b/assets/script/game/component/hero/HeroState.ts.meta new file mode 100644 index 00000000..c475f177 --- /dev/null +++ b/assets/script/game/component/hero/HeroState.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "8af7a4d9-a1d8-4fca-bb8f-4c0198e3f837", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/component/hero/HeroStateMachine.ts b/assets/script/game/component/hero/HeroStateMachine.ts new file mode 100644 index 00000000..e99dabdd --- /dev/null +++ b/assets/script/game/component/hero/HeroStateMachine.ts @@ -0,0 +1,19 @@ +import { HeroView } from "./HeroView"; +import { HeroAnimState } from "./HeroState"; + +/** 英雄动画状态机 */ +export class HeroStateMachine { + private _currentState: HeroAnimState = HeroAnimState.IDLE; + + /** + * 切换状态 + * @param newState 新状态 + * @param view 视图组件 + */ + changeState(newState: HeroAnimState, view: HeroView) { + if (this._currentState !== newState) { + view.playAnimation(newState); + this._currentState = newState; + } + } +} \ No newline at end of file diff --git a/assets/script/game/component/hero/HeroStateMachine.ts.meta b/assets/script/game/component/hero/HeroStateMachine.ts.meta new file mode 100644 index 00000000..c72988a6 --- /dev/null +++ b/assets/script/game/component/hero/HeroStateMachine.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "940cfabd-66b2-44dc-aa05-8247bfafc907", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/component/hero/HeroView.ts b/assets/script/game/component/hero/HeroView.ts new file mode 100644 index 00000000..8dc45bc0 --- /dev/null +++ b/assets/script/game/component/hero/HeroView.ts @@ -0,0 +1,52 @@ +import { _decorator, Component, Node, Prefab, instantiate, Vec3, resources, sp } from "cc"; +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { CCComp } from "../../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; +import { SpineComp } from "./SpineComp"; + +const { ccclass, property } = _decorator; + +/** 英雄视图组件 */ +@ccclass('HeroViewComp') +@ecs.register('HeroView', false) +export class HeroViewComp extends CCComp { + private _node: Node = null!; + private _spineComp: SpineComp = null!; + + /** 加载角色模型 */ + async load(spinePath: string) { + // 加载Spine预制体 + const prefab = await this.loadSpinePrefab(spinePath); + + // 实例化节点 + this._node = instantiate(prefab); + this.node.addChild(this._node); + + // 添加Spine组件 + const spine = this._node.getComponent(sp.Skeleton)!; + this._spineComp = this.ent.add(SpineComp).init(spine); + } + + private loadSpinePrefab(path: string): Promise { + return new Promise((resolve, reject) => { + resources.load(path, Prefab, (err, prefab) => { + err ? reject(err) : resolve(prefab!); + }); + }); + } + + /** 更新位置 */ + setPosition(pos: Vec3) { + this.node.position = pos; + } + + /** 播放动画 */ + playAnimation(name: string) { + this._spineComp.play(name); + } + + /** 重置组件 */ + reset() { + this._node.destroy(); + this.ent.remove(SpineComp); + } +} \ No newline at end of file diff --git a/assets/script/game/component/hero/HeroView.ts.meta b/assets/script/game/component/hero/HeroView.ts.meta new file mode 100644 index 00000000..ebeb343f --- /dev/null +++ b/assets/script/game/component/hero/HeroView.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "fe44963c-f45c-42cf-9564-220332438687", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/component/hero/Movement.ts b/assets/script/game/component/hero/Movement.ts new file mode 100644 index 00000000..934282fc --- /dev/null +++ b/assets/script/game/component/hero/Movement.ts @@ -0,0 +1,19 @@ +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { Vec3 } from "cc"; + +/** 移动组件 */ +@ecs.register('Movement') +export class Movement extends ecs.Comp { + /** 移动速度(像素/秒) */ + speed: number = 200; + /** 目标位置 */ + target: Vec3 = new Vec3(); + /** 当前移动方向 */ + direction: Vec3 = new Vec3(); + + reset() { + this.speed = 200; + this.target.set(); + this.direction.set(); + } +} \ No newline at end of file diff --git a/assets/script/game/component/hero/Movement.ts.meta b/assets/script/game/component/hero/Movement.ts.meta new file mode 100644 index 00000000..1f795ceb --- /dev/null +++ b/assets/script/game/component/hero/Movement.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "05f87dbf-e598-448c-953a-30cc66ff24f8", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/component/hero/SpineComp.ts b/assets/script/game/component/hero/SpineComp.ts new file mode 100644 index 00000000..de0937b4 --- /dev/null +++ b/assets/script/game/component/hero/SpineComp.ts @@ -0,0 +1,41 @@ +import { _decorator, Component, sp } from 'cc'; +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { HeroAnimState } from "./HeroAnimState"; + +@ecs.register('SpineComp') +export class SpineComp extends ecs.Comp { + private _skeleton: sp.Skeleton = null!; + + /** 设置动画过渡混合时间 */ + setMix(from: string, to: string, duration: number) { + this._skeleton.setMix(from, to, duration); + } + + /** 初始化Spine组件 */ + init(node: sp.Skeleton): this { + this._skeleton = node; + // 根据实际动画配置过渡 + this.setMix("Walking", "Attacking", 0.2); + this.setMix("Attacking", "Walking", 0.3); + this.setMix("Attacking", "Idle", 0.1); + return this; + } + + /** + * 播放动画 + * @param animationName 动画名称 + * @param loop 是否循环 + */ + play(animationName: string, loop: boolean = true) { + this._skeleton.setAnimation(0, animationName, loop); + } + + /** 设置皮肤 */ + setSkin(skinName: string) { + this._skeleton.setSkin(skinName); + } + + reset() { + this._skeleton = null!; + } +} \ No newline at end of file diff --git a/assets/script/game/component/hero/SpineComp.ts.meta b/assets/script/game/component/hero/SpineComp.ts.meta new file mode 100644 index 00000000..0375f2fd --- /dev/null +++ b/assets/script/game/component/hero/SpineComp.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "0c91a304-611d-4cd1-9245-0410812a0a64", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/config.meta b/assets/script/game/config.meta new file mode 100644 index 00000000..5b2eaa99 --- /dev/null +++ b/assets/script/game/config.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "b3270123-095d-4f33-906b-471e87a48c70", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/config/HeroConfig.ts b/assets/script/game/config/HeroConfig.ts new file mode 100644 index 00000000..44b0ae43 --- /dev/null +++ b/assets/script/game/config/HeroConfig.ts @@ -0,0 +1,49 @@ +export interface HeroConfig { + id: number; + name: string; + prefabPath: string; + hp: number; + attack: number; + defense: number; + speed: number; + skills: number[]; + critRate?: number; + dodgeRate?: number; + moveSpeed: number; + attackRange: number; + assetPath: string; + baseAttack: number; +} + +export const HeroConfigs: Record = { + 1001: { + id: 1001, + name: 'K1英雄', + prefabPath: 'hero/warrior', + hp: 150, + attack: 15, + defense: 8, + speed: 120, + skills: [2001, 2002], + critRate: 10, + dodgeRate: 5, + moveSpeed: 120, + attackRange: 150, + assetPath: "k1", + baseAttack: 15 + }, + 1002: { + id: 1002, + name: '法师', + prefabPath: 'hero/mage', + hp: 100, + attack: 25, + defense: 5, + speed: 100, + skills: [2003], + assetPath: "mage", + moveSpeed: 100, + attackRange: 200, + baseAttack: 25 + } +}; \ No newline at end of file diff --git a/assets/script/game/config/HeroConfig.ts.meta b/assets/script/game/config/HeroConfig.ts.meta new file mode 100644 index 00000000..e7032a4b --- /dev/null +++ b/assets/script/game/config/HeroConfig.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "3916b0eb-f3ed-4af6-8e01-63ebddf11fa3", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/core.meta b/assets/script/game/core.meta new file mode 100644 index 00000000..602745af --- /dev/null +++ b/assets/script/game/core.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "9973d027-ed06-45a3-9900-0b47f3100f49", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/core/EntityFactory.ts b/assets/script/game/core/EntityFactory.ts new file mode 100644 index 00000000..26efacbb --- /dev/null +++ b/assets/script/game/core/EntityFactory.ts @@ -0,0 +1,18 @@ +export class EntityFactory { + static createHero(config: HeroConfig): ecs.Entity { + const hero = ecs.Entity.create(); + + // 基础组件 + hero.add(HeroModel).init(config); + hero.add(HeroView).loadModel(config.prefabPath); + hero.add(Movement).init(config.speed); + hero.add(Combat).init(config.baseAttack, config.attackRange); + + // 技能系统 + config.skills.forEach(skill => { + hero.add(Skill).registerSkill(skill); + }); + + return hero; + } +} \ No newline at end of file diff --git a/assets/script/game/core/EntityFactory.ts.meta b/assets/script/game/core/EntityFactory.ts.meta new file mode 100644 index 00000000..ae674c98 --- /dev/null +++ b/assets/script/game/core/EntityFactory.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "d29e9c6d-1fbc-439e-b674-0a5fdf1d929a", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/core/GameEvents.ts b/assets/script/game/core/GameEvents.ts new file mode 100644 index 00000000..648efdc4 --- /dev/null +++ b/assets/script/game/core/GameEvents.ts @@ -0,0 +1,18 @@ +export class CombatEvent { + static readonly type = 'CombatEvent'; + constructor( + public readonly attacker: ecs.Entity, + public readonly target: ecs.Entity, + public readonly damage: number + ) {} +} + +// 事件监听示例 +oops.message.on(CombatEvent.type, (event: CombatEvent) => { + const targetModel = event.target.get(HeroModel); + targetModel.hp = Math.max(targetModel.hp - event.damage, 0); + + if (targetModel.hp <= 0) { + event.target.add(Status).setDead(); + } +}); \ No newline at end of file diff --git a/assets/script/game/core/GameEvents.ts.meta b/assets/script/game/core/GameEvents.ts.meta new file mode 100644 index 00000000..38ec76cc --- /dev/null +++ b/assets/script/game/core/GameEvents.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "45c6bedf-311f-4ad5-9e0e-92542a7655c4", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/data/dataModelComp.ts b/assets/script/game/data/dataModelComp.ts deleted file mode 100644 index cd32dbd3..00000000 --- a/assets/script/game/data/dataModelComp.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { VM } from "../../../../extensions/oops-plugin-framework/assets/libs/model-view/ViewModel"; -import { CCVMParentComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCVMParentComp"; - - -/** 数据层对象 */ -@ecs.register('dataModel') -export class dataModelComp extends CCVMParentComp { - /** 提供 MVVM 组件使用的数据 */ - /** VM 组件绑定数据 */ - vm: any = { - name : "数据测试", - /** 当前等级 */ - porwer: 0, - /** 当前经验 */ - def : 0, - /** 下级经验 */ - speed : 0, - hp: { - min:50, - max:100 - } - }; - - /** 显示数据添加到 MVVM 框架中监视 */ - vmAdd() { - console.log("dataModelComp vmAdd"); - VM.add(this.vm, "data"); - } - changeHp(min: number, max: number) { - this.vm.hp.min =this.vm.hp.min +min - this.vm.hp.max =this.vm.hp.max +max - } - /** 显示数据从 MVVM 框架中移除 */ - vmRemove() { - VM.remove("data"); - } - - /** 数据层组件移除时,重置所有数据为默认值 */ - reset() { - for (var key in this.vm) { - delete this.vm[key]; - } - } -} - diff --git a/assets/script/game/data/dataViewComp.ts b/assets/script/game/data/dataViewComp.ts deleted file mode 100644 index 9e49af71..00000000 --- a/assets/script/game/data/dataViewComp.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { _decorator } from "cc"; -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; - -const { ccclass, property } = _decorator; - -/** 视图层对象 */ -@ccclass('dataViewComp') -@ecs.register('dataView', true) -export class dataViewComp extends CCComp { - /** 视图层逻辑代码分离演示 */ - start() { - var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 - // this.on(ModuleEvent.Cmd, this.onHandler, this); - } - - /** 全局消息逻辑处理 */ - private onHandler(event: string, args: any) { - console.log(event, args); - } - - /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ - reset() { - this.node.destroy(); - } -} \ No newline at end of file diff --git a/assets/script/game/data/dataViewVM.ts b/assets/script/game/data/dataViewVM.ts deleted file mode 100644 index d2bf2537..00000000 --- a/assets/script/game/data/dataViewVM.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { _decorator } from "cc"; -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { CCVMParentComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCVMParentComp"; - -const { ccclass, property } = _decorator; - -/** 视图层对象 - 支持 MVVM 框架的数据绑定 */ -@ccclass('dataViewVMComp') -@ecs.register('dataViewVM', false) -export class dataViewVMComp extends CCVMParentComp { - /** 脚本控制的界面 MVVM 框架绑定数据 */ - data: any = {}; - - /** 视图层逻辑代码分离演示 */ - start() { - // var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 - } - - /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ - reset() { - this.node.destroy(); - } -} \ No newline at end of file diff --git a/assets/script/game/entity.meta b/assets/script/game/entity.meta new file mode 100644 index 00000000..ccbf6c75 --- /dev/null +++ b/assets/script/game/entity.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "58262c23-5fe8-433c-9fa4-a7346d757792", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/entity/hero.meta b/assets/script/game/entity/hero.meta new file mode 100644 index 00000000..4bb3e3da --- /dev/null +++ b/assets/script/game/entity/hero.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "1ae91b78-eb18-4fbf-a48b-6cc4f7477a38", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/entity/hero/Hero.ts b/assets/script/game/entity/hero/Hero.ts new file mode 100644 index 00000000..c2c06992 --- /dev/null +++ b/assets/script/game/entity/hero/Hero.ts @@ -0,0 +1,72 @@ +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { HeroModel } from "../../component/hero/HeroModel"; +import { HeroViewComp } from "../../component/hero/HeroView"; +import { Movement } from "../../component/hero/Movement"; +import { Combat } from "../../component/hero/Combat"; +import type { HeroConfig } from "../../config/HeroConfig"; +import { HeroConfigs } from "../../config/HeroConfig"; +import { GameConstants } from "../../common/Constants"; +import { HeroStateMachine } from "../../component/hero/HeroStateMachine"; +import { HeroAnimState } from "../../component/hero/HeroAnimState"; +const HERO_PREFAB_PATH = GameConstants.HERO_PREFAB_PATH; + +/** + * 英雄实体 + * 实现功能: + * 1. 角色数据管理 + * 2. 视图加载与更新 + * 3. 移动控制 + * 4. 战斗行为 + */ +@ecs.register('Hero') +export class Hero extends ecs.Entity { + HeroModel!: HeroModel; + HeroView!: HeroViewComp; + Movement!: Movement; + Combat!: Combat; + + private _stateMachine = new HeroStateMachine(); + + protected init() { + // 数据层初始化 + this.addComponents( + HeroModel, + HeroViewComp, + Movement, + Combat + ); + } + + /** 初始化英雄实体 */ + initHero(config: HeroConfig) { + // 数据层初始化 + this.HeroModel.init(config); + + // 视图层初始化 + const spinePath = `${GameConstants.SPINE.HERO}/${config.assetPath}`; + this.HeroView.load(spinePath); + + // 设置初始动画 + this._stateMachine.changeState(HeroAnimState.IDLE, this.HeroView); + + // 移动组件初始化 + this.Movement.speed = config.moveSpeed; + + // 战斗组件初始化 + this.Combat.init(config.baseAttack, config.attackRange); + } + + /** 销毁实体 */ + destroyHero() { + this.remove(HeroViewComp); + this.remove(Movement); + this.remove(Combat); + this.destroy(); + } + + update() { + if (this.Movement.speed > 0) { + this._stateMachine.changeState(HeroAnimState.WALKING, this.HeroView); + } + } +} \ No newline at end of file diff --git a/assets/script/game/entity/hero/Hero.ts.meta b/assets/script/game/entity/hero/Hero.ts.meta new file mode 100644 index 00000000..53176769 --- /dev/null +++ b/assets/script/game/entity/hero/Hero.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "10003378-5396-44df-b3c4-870d4ef4aa35", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/entity/hero/Monster.ts similarity index 100% rename from assets/script/game/hero/Mon.ts rename to assets/script/game/entity/hero/Monster.ts diff --git a/assets/script/game/entity/hero/Monster.ts.meta b/assets/script/game/entity/hero/Monster.ts.meta new file mode 100644 index 00000000..6e19e67f --- /dev/null +++ b/assets/script/game/entity/hero/Monster.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "9abdffa5-b818-4b94-8502-d1eb6f03d31d", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/data/data.ts b/assets/script/game/hero/Aheros/Module-001.ts similarity index 50% rename from assets/script/game/data/data.ts rename to assets/script/game/hero/Aheros/Module-001.ts index c0e9c8cc..bcf563d2 100644 --- a/assets/script/game/data/data.ts +++ b/assets/script/game/hero/Aheros/Module-001.ts @@ -1,25 +1,22 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { dataModelComp } from "./dataModelComp"; -import { dataViewComp } from "./dataViewComp"; -/** data 模块 */ -@ecs.register(`data`) -export class data extends ecs.Entity { + +/** Module_001 模块 */ +@ecs.register(`Module_001`) +export class Module_001 extends ecs.Entity { /** ---------- 数据层 ---------- */ - dataModel!: dataModelComp; + // Module_001Model!: Module_001ModelComp; /** ---------- 业务层 ---------- */ - // dataBll!: dataBllComp; + // Module_001Bll!: Module_001BllComp; /** ---------- 视图层 ---------- */ - dataView!: dataViewComp; + // Module_001View!: Module_001ViewComp; /** 实始添加的数据层组件 */ protected init() { - this.addComponents(dataViewComp,dataModelComp); - } - changeHp(min: number, max: number){ - var data = this.dataModel; + // this.addComponents(); } + /** 模块资源释放 */ destroy() { // 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放 @@ -27,8 +24,8 @@ export class data extends ecs.Entity { } } -/** data 模块业务逻辑系统组件,如无业务逻辑处理可删除此对象 */ -export class EcsdataSystem extends ecs.System { +/** Module_001 模块业务逻辑系统组件,如无业务逻辑处理可删除此对象 */ +export class EcsModule_001System extends ecs.System { constructor() { super(); diff --git a/assets/script/game/hero/Aheros/Module-001.ts.meta b/assets/script/game/hero/Aheros/Module-001.ts.meta new file mode 100644 index 00000000..a910e128 --- /dev/null +++ b/assets/script/game/hero/Aheros/Module-001.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "f3b2b36f-bb80-4a29-9ff9-99b0d95dfd64", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Aheros/ModuleBll.ts b/assets/script/game/hero/Aheros/ModuleBll.ts new file mode 100644 index 00000000..a88b0daa --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleBll.ts @@ -0,0 +1,24 @@ +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; + +/** 业务层对象 */ +@ecs.register('ModuleBll') +export class ModuleBllComp extends ecs.Comp { + /** 业务层组件移除时,重置所有数据为默认值 */ + reset() { + + } +} + +/** 业务层业务逻辑处理对象 */ +export class ModuleBllSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem { + filter(): ecs.IMatcher { + return ecs.allOf(ModuleBllComp); + } + + entityEnter(e: ecs.Entity): void { + // 注:自定义业务逻辑 + + + e.remove(ModuleBllComp); + } +} \ No newline at end of file diff --git a/assets/script/game/hero/Aheros/ModuleBll.ts.meta b/assets/script/game/hero/Aheros/ModuleBll.ts.meta new file mode 100644 index 00000000..0ef52c22 --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleBll.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "14d41483-d32e-4fd4-8942-ef879316a4bc", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Aheros/ModuleModel.ts b/assets/script/game/hero/Aheros/ModuleModel.ts new file mode 100644 index 00000000..8990279f --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleModel.ts @@ -0,0 +1,26 @@ +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { VM } from "../../../../../extensions/oops-plugin-framework/assets/libs/model-view/ViewModel"; + +/** 数据层对象 */ +@ecs.register('ModuleModel') +export class ModuleModelComp extends ecs.Comp { + /** 提供 MVVM 组件使用的数据 */ + private vm: any = {}; + + /** 显示数据添加到 MVVM 框架中监视 */ + vmAdd() { + VM.add(this.vm, "ModuleModel"); + } + + /** 显示数据从 MVVM 框架中移除 */ + vmRemove() { + VM.remove("ModuleModel"); + } + + /** 数据层组件移除时,重置所有数据为默认值 */ + reset() { + for (var key in this.vm) { + delete this.vm[key]; + } + } +} \ No newline at end of file diff --git a/assets/script/game/hero/Aheros/ModuleModel.ts.meta b/assets/script/game/hero/Aheros/ModuleModel.ts.meta new file mode 100644 index 00000000..d3c323eb --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleModel.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "f90b89ec-548a-42cd-87c0-a65863491af3", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Aheros/ModuleTable.ts b/assets/script/game/hero/Aheros/ModuleTable.ts new file mode 100644 index 00000000..8d903759 --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleTable.ts @@ -0,0 +1,23 @@ +import { JsonUtil } from "../../../../../extensions/oops-plugin-framework/assets/core/utils/JsonUtil"; + +/** 策划 Excel 导出的 Json 静态数据 */ +export class ModuleTable { + static TableName: string = "配置表文件名"; + + /** 静态表中一条数据 */ + private data: any; + + init(id: number) { + var table = JsonUtil.get(ModuleTable.TableName); + this.data = table[id]; + this.id = id; + } + + /** 数据唯一编号 */ + id: number = 0; + + /** 数据 */ + // get test(): number { + // return this.data.test; + // } +} \ No newline at end of file diff --git a/assets/script/game/hero/Aheros/ModuleTable.ts.meta b/assets/script/game/hero/Aheros/ModuleTable.ts.meta new file mode 100644 index 00000000..f0a0fa7a --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleTable.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "60c52974-9781-4174-80c1-ee4aff34a504", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Aheros/ModuleView.ts b/assets/script/game/hero/Aheros/ModuleView.ts new file mode 100644 index 00000000..874c9b31 --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleView.ts @@ -0,0 +1,29 @@ +import { _decorator } from "cc"; +import { ecs } from "../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; +import { CCComp } from "../../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; + +const { ccclass, property } = _decorator; + +/** 视图层对象 */ +@ccclass('ModuleViewComp') +@ecs.register('ModuleView', false) +export class ModuleViewComp extends CCComp { + /** 视图层逻辑代码分离演示 */ + start() { + // var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 + // this.on(ModuleEvent.Cmd, this.onHandler, this); + } + + /** 全局消息逻辑处理 */ + // private onHandler(event: string, args: any) { + // switch (event) { + // case ModuleEvent.Cmd: + // break; + // } + // } + + /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ + reset() { + this.node.destroy(); + } +} \ No newline at end of file diff --git a/assets/script/game/hero/Aheros/ModuleView.ts.meta b/assets/script/game/hero/Aheros/ModuleView.ts.meta new file mode 100644 index 00000000..d3e24ac4 --- /dev/null +++ b/assets/script/game/hero/Aheros/ModuleView.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "3d3a257d-5259-434a-bfa3-6af80203fad2", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts deleted file mode 100644 index 4ac65328..00000000 --- a/assets/script/game/hero/Hero.ts +++ /dev/null @@ -1,112 +0,0 @@ - -import { instantiate, Node, Prefab, Vec3 ,v3,resources,SpriteFrame,Sprite,SpriteAtlas} from "cc"; -import { UICallbacks } from "../../../../extensions/oops-plugin-framework/assets/core/gui/layer/Defines"; -import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { UIID } from "../common/config/GameUIConfig"; -import { smc } from "../common/SingletonModuleComp"; -import { HeroModelComp } from "./HeroModelComp"; -import { HeroSpine } from "./HeroSpine"; -import { HeroViewComp } from "./HeroViewComp"; -import { BoxSet } from "../common/config/BoxSet"; -import { RandomManager } from "../../../../extensions/oops-plugin-framework/assets/core/common/random/RandomManager"; -import { HeroInfo } from "../common/config/heroSet"; -import { MoveToComp } from "../common/ecs/position/MoveTo"; -import { Talents } from "../common/config/TalentSet"; -import { MonModelComp } from "./MonModelComp"; -/** 角色实体 */ -@ecs.register(`Hero`) -export class Hero extends ecs.Entity { - // 数据层 - HeroModel!: HeroModelComp; - // 视图层 - HeroView!: HeroViewComp; - protected init() { - - } - destroy(): void { - this.remove(HeroViewComp); - this.remove(MoveToComp); - super.destroy(); - } - /** 加载角色 */ - load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001,is_call:boolean=false,lv:number=1) { - scale = 1 - let box_group=BoxSet.HERO - this.addComponents( HeroModelComp); - var path = "game/heros/"+HeroInfo[uuid].path; - var prefab: Prefab = oops.res.get(path, Prefab)!; - var node = instantiate(prefab); - - var scene = smc.map.MapView.scene; - node.parent = scene.entityLayer!.node! - - node.setPosition(pos) - this.hero_init(uuid,node,scale,box_group,is_call,lv) - oops.message.dispatchEvent("hero_load",this) - } - hero_init(uuid:number=1001,node:Node,scale:number=1,box_group=BoxSet.HERO,is_call:boolean=false,lv:number=1){ - var hv = node.getComponent(HeroViewComp)!; - // console.log("hero_init",buff) - let hero= HeroInfo[uuid] // 共用英雄数据 - let role =smc.heros[uuid] - if(is_call){ - role={slv:0,lv:lv} - } - let talents=Talents; - hv.scale = scale; - hv.box_group = box_group; - hv.hero_uuid= uuid; - hv.hero_name= hero.name; - hv.speed =hv.ospeed = hero.speed; - hv.dis = hero.dis; - hv.pw = hero.pw; - hv.pwm= hero.pwm; - hv.pws= hero.pws - hv.apw=hero.apw; - hv.uapw=hero.uapw; - hv.cpw=hero.cpw; - hv.dpw=hero.dpw; - hv.dopw=hero.dopw; - - hv.lv = role.lv; - hv.type = hero.type; - let slv= Math.floor(( hv.lv) / 5); - let sklv=slv - if(sklv >= 5) sklv=5; - - hv.sk1 = hero.sk1[sklv] - hv.sk2 = hero.sk2[sklv] - hv.sk3 = hero.sk3[sklv] - hv.akc = hero.akc[sklv] - hv.uac = hero.uac[sklv] - hv.crc = hero.crc[sklv] - hv.dgc = hero.dgc[sklv] - hv.akr = hero.akr[sklv] - hv.uar = hero.uar[sklv] - hv.crr = hero.crr[sklv] - hv.dgr = hero.dgr[sklv] - hv.rhp_max=hv.hp= hv.hp_max =(hero.hp+hero.hp_up*hv.lv)*(1+hero.shp_up/100*slv) - hv.ap = (hero.ap+hero.ap_up*hv.lv) *(1+hero.sap_up/100*slv); - hv.def= (hero.def+hero.def_up*hv.lv)*(1+hero.sdef_up/100*slv); - hv.cd = hero.a_cd - hv.crit = hero.crit //暴击率 - hv.crit_add = hero.crit_add;//暴击伤害加成 - hv.dodge = hero.dodge //闪避率 - hv.aexp=hero.aexp - hv.uaexp=hero.uaexp - hv.cexp=hero.cexp - hv.doexp=hero.doexp - hv.dexp=hero.dexp - this.add(hv); - } - -} - -/** Module 模块业务逻辑系统组件,如无业务逻辑处理可删除此对象 */ -export class EcsModuleSystem extends ecs.System { - constructor() { - super(); - // this.add(new ecs.ComblockSystem()); - } -} \ No newline at end of file diff --git a/assets/script/game/hero/Hero.ts.meta b/assets/script/game/hero/Hero.ts.meta deleted file mode 100644 index 386b79a5..00000000 --- a/assets/script/game/hero/Hero.ts.meta +++ /dev/null @@ -1 +0,0 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"31289da2-91ea-4ffe-85f3-879a3ac7641d","files":[],"subMetas":{},"userData":{}} diff --git a/assets/script/game/hero/HeroConst.ts b/assets/script/game/hero/HeroConst.ts new file mode 100644 index 00000000..e8eb33e5 --- /dev/null +++ b/assets/script/game/hero/HeroConst.ts @@ -0,0 +1,13 @@ +import { Vec3 } from 'cc'; + +export enum HeroDefault { + DEFAULT_UUID = 1001, + BASE_SCALE = 1, + INIT_LEVEL = 1 +} + +// 将位置常量作为普通常量导出 +export const HERO_POSITION = Vec3.ZERO; + +// 路径作为独立常量 +export const HERO_PREFAB_PATH = "game/heros/"; \ No newline at end of file diff --git a/assets/script/game/hero/HeroConst.ts.meta b/assets/script/game/hero/HeroConst.ts.meta new file mode 100644 index 00000000..fd67dd25 --- /dev/null +++ b/assets/script/game/hero/HeroConst.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "39ff7cef-ab22-47d4-aa35-f307385ffa99", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroController.ts b/assets/script/game/hero/HeroController.ts new file mode 100644 index 00000000..1ac2d62a --- /dev/null +++ b/assets/script/game/hero/HeroController.ts @@ -0,0 +1,23 @@ +import { _decorator, Component, Node, sp, tween, v3, Vec3 } from 'cc'; + +const { ccclass, property } = _decorator; + +@ccclass('HeroController') +export class HeroController extends Component { + @property(sp.Skeleton) + spine: sp.Skeleton = null!; // 绑定spine组件 + + @property + moveSpeed: number = 200; // 可配置移动速度 + + // 初始化动画 + init(spineData: sp.SkeletonData) { + this.spine.skeletonData = spineData; + this.spine.setAnimation(0, 'Idle', true); + } + + // 播放动画方法 + playAnimation(name: string, loop: boolean = true) { + this.spine.setAnimation(0, name, loop); + } +} \ No newline at end of file diff --git a/assets/script/game/hero/HeroController.ts.meta b/assets/script/game/hero/HeroController.ts.meta new file mode 100644 index 00000000..9e3c1f17 --- /dev/null +++ b/assets/script/game/hero/HeroController.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "f85a719e-f1e0-48ac-920b-121036144be5", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroManager.ts b/assets/script/game/hero/HeroManager.ts new file mode 100644 index 00000000..9001ef3d --- /dev/null +++ b/assets/script/game/hero/HeroManager.ts @@ -0,0 +1,18 @@ +import { _decorator, Component, Node, instantiate, Prefab, resources } from 'cc'; + +export class HeroManager { + static async createHero(parent: Node) { + const prefab = await this.loadPrefab('prefabs/Hero'); + const hero = instantiate(prefab); + parent.addChild(hero); + return hero; + } + + private static loadPrefab(path: string): Promise { + return new Promise((resolve, reject) => { + resources.load(path, Prefab, (err, prefab) => { + err ? reject(err) : resolve(prefab!); + }); + }); + } +} \ No newline at end of file diff --git a/assets/script/game/hero/HeroManager.ts.meta b/assets/script/game/hero/HeroManager.ts.meta new file mode 100644 index 00000000..171c0a1b --- /dev/null +++ b/assets/script/game/hero/HeroManager.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "7cf87b0a-58f4-4643-8fe0-a19a74737ab9", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroModelComp.ts b/assets/script/game/hero/HeroModelComp.ts deleted file mode 100644 index bb11fa51..00000000 --- a/assets/script/game/hero/HeroModelComp.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; - -/** - * 角色属性数据 - */ -@ecs.register('HeroModel') -export class HeroModelComp extends ecs.Comp { - /** 角色编号 */ - id: number = -1; - - /** 角色名 */ - name: string = "mon"; - /** speed */ - // speed: number = 0; - /** 动画名资源 */ - anim: string = "mon"; - - reset() { - this.id = -1; - // this.speed = 0; - this.name = ""; - } -} diff --git a/assets/script/game/hero/HeroModelComp.ts.meta b/assets/script/game/hero/HeroModelComp.ts.meta deleted file mode 100644 index 07a09bcc..00000000 --- a/assets/script/game/hero/HeroModelComp.ts.meta +++ /dev/null @@ -1 +0,0 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"c9121e83-b457-492d-aa56-2119d79a3360","files":[],"subMetas":{},"userData":{}} diff --git a/assets/script/game/hero/HeroViewComp.ts b/assets/script/game/hero/HeroViewComp.ts deleted file mode 100644 index ba5dcaa1..00000000 --- a/assets/script/game/hero/HeroViewComp.ts +++ /dev/null @@ -1,906 +0,0 @@ -/* - * @Author: dgflash - * @Date: 2021-11-18 17:42:59 - * @LastEditors: dgflash - * @LastEditTime: 2022-08-17 12:36:18 - */ - -import { Vec3, _decorator , v3,Collider2D,Contact2DType,Label,RigidBody2D ,Node,Prefab,instantiate,ProgressBar, Component, Material, Sprite, math, clamp, Game, tween} from "cc"; -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; -import { HeroSpine } from "./HeroSpine"; -import { HeroModelComp } from "./HeroModelComp"; -import { BoxSet, GameSet } from "../common/config/BoxSet"; -import { smc } from "../common/SingletonModuleComp"; -import { Skill } from "../skills/Skill"; -import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer"; -import { SkillCom } from "../skills/SkillCom"; -import { SkillSet, SkTG, SkType } from "../common/config/SkillSet"; -import { RandomManager } from "../../../../extensions/oops-plugin-framework/assets/core/common/random/RandomManager"; -import { HeroSet } from "../common/config/heroSet"; -import { BuffComp } from "./BuffComp"; -import { MonModelComp } from "./MonModelComp"; -import { getMonsterDrops, MonsterType } from "../common/config/RewardSet"; -const { ccclass, property } = _decorator; - -/** 角色显示组件 */ -@ccclass('HeroViewComp') // 定义为 Cocos Creator 组件 -@ecs.register('HeroView', false) // 定义为 ECS 组件 -export class HeroViewComp extends CCComp { - BUFFCOMP:BuffComp=null! - enemy_pos:Vec3=null! - // enemy:any=null!; - - as: HeroSpine = null! - anm_timer:Timer = new Timer(0.3); - anm_name="idle" - status:String = "idle" - - hero_uuid:number = 1001; - hero_name : string = "hero"; - lv:number =1; - slv:number =1; - scale: number = 1; /** 角色阵营 1:hero -1 :mon */ - type: number = 0; /**角色类型 0近战 1 远程 2 辅助 */ - - box_group:number = BoxSet.HERO; - atk_range:number = 150; - - - is_dead:boolean = false; //是否摧毁 - is_stop:boolean = false; - is_atking:boolean = false; - is_boss:boolean = false; - is_big_boss:boolean = false; - - hp: number = 100; /** 血量 */ - hp_max: number = 100; /** 最大血量 */ - rhp_max: number = 100; - hp_speed: number = 0; //每秒回复量 - - pw: number = 0; /**能量**/ - pwm: number = 15; /** 能量最大值 */ - pws: number = 1; //能量回复速度每0.1秒回复量 - apw:number=0; - uapw:number=0; - cpw:number=0; - dopw:number=0; - dpw:number=0; - pwt:Timer = new Timer(1); //计时器 - - sk1:number = 9001; - sk2:number = 1001; - sk3:number = 1001; - akr:number=0; //攻击触发机率 - uar:number=0; //受伤触发机率 - dgr:number=0; //闪避触发机率 - crr:number=0; //暴击触发机率 - akc:number=0; //攻击次数触发 - uac:number=0; //受伤次数触发 - dgc:number=0; //闪避次数触发 - crc:number=0; //暴击次数触发 - - aexp:number=0; //攻击经验 - uaexp:number=0; //受伤经验 - cexp:number=0; //暴击经验 */ - doexp:number=0; //闪避经验 */ - dexp:number=0; //死亡经验 */ - - ap: number = 10; /**攻击力 */ - ap_max: number = 0; - ap_buff: number = 0; - ap_buffs:any = []; - // atk_speed: number = 1; - cd: number = 1.3; /**攻击速度 攻击间隔 */ - dis: number = 80; - at: number = 0; /** 冷却时间 */ - - def: number = 0; //防御 - def_max: number = 0; - vun: number = 0; //易伤 - - crit: number = 0; //暴击率 - crit_max: number = 0; - crit_add: number = 0;//暴击伤害加成 - dodge: number = 10; //闪避率 - dodge_max: number = 10; //闪避率 - - - shield:number = 0; //护盾,免伤1次减1 - speed: number = 100; /** 角色移动速度 */ - ospeed: number = 100; /** 角色初始速度 */ - - atk_count: number = 0; - atked_count: number = 0; - dodge_count: number = 0; - crit_count: number = 0; - - - stop_cd: number = 0; /*停止倒计时*/ - yun_cd: number = 0; //眩晕倒计时 - ice_cd: number = 0; //冰冻倒计时 - dir_y:number = 0; - speek_time:number = 0; - - onLoad() { - this.as = this.getComponent(HeroSpine); - - } /** 视图层逻辑代码分离演示 */ - - start () { - - this.as.idle() - this.BUFFCOMP=this.node.getComponent(BuffComp); - /** 方向 */ - this.node.setScale(this.scale,1); - this.node.getChildByName("top").setScale(this.scale,1); - if(this.is_boss){ - this.node.setScale(this.node.scale.x*1.5,this.node.scale.y*1.5); - this.node.getChildByName("top").getChildByName("sboss").active = true; - } - /** 显示角色血量 */ - this.node.getChildByName("top").getChildByName("hp").active = true; - - // this.node.getChildByName("shielded").active = false; - // this.node.getChildByName("top").setScale(this.scale,1); - // this.node.getChildByName("atk").setScale(this.scale,1); - // this.node.getChildByName("atk").getComponent(Label).string = this.ap.toString(); - // this.node.getChildByName("hp_max").setScale(this.scale,1); - // this.node.getChildByName("hp_max").getComponent(Label).string=this.hp_max.toString(); - - // 注册单个碰撞体的回调函数 - - let collider = this.getComponent(Collider2D); - collider.group = this.box_group; - // console.log("hero collider ",this.scale,collider); - if (collider) { - collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); - // collider.on(Contact2DType.END_CONTACT, this.onEndContact, this); - collider.on(Contact2DType.PRE_SOLVE, this.onPreSolve, this); - // collider.on(Contact2DType.POST_SOLVE, this.onPostSolve, this); - } - - - } - onBeginContact (seCol: Collider2D, oCol: Collider2D) { - - if(oCol.tag==BoxSet.SKILL_TAG&&seCol.group != oCol.group){ - let skill = oCol.node.getComponent(SkillCom)!; - // console.log(Date.now()+this.hero_name+":"+this.uuid+' onBeginContact: '+skill.s_name+skill.uuid); - if(this.hp <= 0 ) return - if(skill.tg< 3) return - this.check_uatk(skill); - } - - } - - onEndContact (seCol: Collider2D, oCol: Collider2D) { - - } - onPreSolve (seCol: Collider2D, oCol: Collider2D) { - let se_x = seCol.node.position.x; - let ot_x = oCol.node.position.x; - let oCom= oCol.node.getComponent(HeroViewComp) - if(seCol.group == oCol.group&&seCol.tag==oCol.tag){ - - if(seCol.group==BoxSet.HERO){ - if(oCom.type == this.type&&oCom.yun_cd<=0&&oCom.ice_cd<=0 && se_x < ot_x && Math.abs(ot_x-se_x) < 40 ){ - // this.node.setSiblingIndex(oCol.node.getSiblingIndex()-10) - this.stop_cd = 0.1; - } - } - if(seCol.group==BoxSet.MONSTER){ - if(oCom.type == this.type&&oCom.yun_cd<=0&&oCom.ice_cd<=0 && se_x > ot_x && Math.abs(ot_x-se_x) < 40 ){ - // this.node.setSiblingIndex(oCol.node.getSiblingIndex()-10) - this.stop_cd = 0.1; - } - } - - } - if(seCol.group != oCol.group&&oCol.tag == 0){ - this.stop_cd = 0.1; - this.is_atking=true - } - } - - onPostSolve (seCol: Collider2D, oCol: Collider2D) { - } - update(dt: number){ - if(!smc.mission.play||smc.mission.pause) return - if(this.is_dead) { - if(!this.in_grave()) this.to_grave() - return - } - - if (this.pwt.update(dt)) { - this.pw+=this.pws - } - - this.check_power() - this.check_atk_counts() - this.check_enemy_alive() - this.check_mission_buff() - this.hp_show() - if(this.ice_cd > 0){ - this.ice_cd -=dt; - return - } - if(this.yun_cd > 0){ - this.yun_cd -=dt; - return - } - this.at += dt; - this.in_stop(dt); - this.in_atk(dt); - this.move(dt); - } - hp_show(){ - let hp_progress= this.hp/this.rhp_max; - this.node.getChildByName("top").getChildByName("hp").getComponent(ProgressBar)!.progress = hp_progress; - if(this.is_boss) return - if(this.hp == this.rhp_max){ - this.node.getChildByName("top").getChildByName("hp").active = false; - } else{ - this.node.getChildByName("top").getChildByName("hp").active = true; - } - } - //移动 - move(dt: number){ - if(this.stop_cd > 0||smc.mission.is_victory||smc.mission.is_defeat){ - this.status_change("idle") - return - } - if (this.node.position.x >= 300 && this.scale==1) { - return; - } - if(this.scale===-1&&this.node.position.x <= -300){ - return; - } - this.status_change("move") - - - // if(this.enemy){ - // return - // } - this.node.setPosition(this.node.position.x+dt*this.speed*this.scale, this.node.position.y+dt*this.dir_y, this.node.position.z); - } - check_mission_buff(){ - this.ap_max=(100+smc.vmdata.mission.ap)/100*this.ap - this.crit_max=(100+smc.vmdata.mission.crit)/100*this.crit - this.def_max=(100+smc.vmdata.mission.def)/100*this.def - this.dodge_max=(100+smc.vmdata.mission.dodge)/100*this.dodge - this.rhp_max=(100+smc.vmdata.mission.hp)/100*this.hp_max - if(this.box_group == BoxSet.MONSTER){ - this.ap_max=(100+smc.vmdata.mission.map)/100*this.ap - this.crit_max=(100+smc.vmdata.mission.mcrit)/100*this.crit - this.def_max=(100+smc.vmdata.mission.mdef)/100*this.def - this.dodge_max=(100+smc.vmdata.mission.mdodge)/100*this.dodge - this.rhp_max=(100+smc.vmdata.mission.mhp)/100*this.hp_max - } - } - check_enemy_alive(){ - // let dir = 720 - // let enemys=smc.enemy_pos - // this.enemy = v3(720,this.node.position.y) - // if(this.box_group == BoxSet.MONSTER){ - // enemys=smc.hero_pos - // // console.log("MONSTER enemys",enemys); - // this.enemy=v3(-720,this.node.position.y) - // } - // for (let i = 0; i < enemys.length; i++) { - // let ho:any = enemys[i]; - // let x=Math.abs(ho.x-this.node.position.x) - // if(x < dir){ - // dir = x - // this.enemy = ho - // } - // } - let dir = Math.abs(smc.mon_front_x-this.node.position.x) - if(this.box_group == BoxSet.MONSTER){ - dir = Math.abs(smc.hero_front_x-this.node.position.x) - } - if(dir < this.dis){ - this.is_atking=true - if(this.dis-dir > 80 &&this.type > 0 ) this.stop_cd = 0.1 - if(dir < 65 &&this.type == 0 ) this.stop_cd = 0.1 - }else{ - this.is_atking=false - } - } - //状态切换 - status_change(type:string){ - this.status=type - if(type == "idle"){ - this.as.idle() - // this.as.change_default("idle") - } - if(type == "move"){ - this.as.move() - // this.as.change_default("move") - } - } - - //受伤判断 - check_uatk(skill:any){ - - if(this.check_dodge()) return - this.in_atked(); - let l_hp=this.check_less(skill.ap,skill.is_crit,skill.crit_add) - this.check_debuff(skill,l_hp) - if(this.shield > 0){ - this.shield -=1 - if(this.shield == 0) this.BUFFCOMP.show_shield(false) - l_hp = 0 - } - this.hp_less(l_hp,skill.is_crit); - } - check_less(ap:number,is_crit:boolean,crit_add:number=0){ - let d=this.def_max/ap - if(d > 1) d = 1 - let l_hp=ap*(1-d*GameSet.DEF_RATE) //防御最高减免伤害比率计算 - if(is_crit){ - l_hp = l_hp * (150+crit_add)/100 - } - let luck = RandomManager.instance.getRandomInt(-10,10) - l_hp=l_hp*(100+luck)/100 - return Math.ceil(l_hp) - } - /** - * 检查并处理英雄受到的减益效果(debuff)。 - * 根据技能的不同减益类型,执行相应的逻辑,如冰冻、燃烧等。 - * - * @param skill - 包含减益效果信息的技能对象 - * @param l_hp - 可选参数,表示英雄的当前生命值,默认为0 - */ - check_debuff(skill:any,l_hp:number=0){ - // console.log(this.hero_name+this.uuid+": skillname: "+skill.s_name+" :check_debuff "+skill.debuff); - if(skill.debuff == 0) return - let num=RandomManager.instance.getRandomInt(0,100) - switch (skill.debuff){ - case 1: - // console.log(this.hero_name+":"+this.uuid+"冰冻触判断: i="+num+":rate="+skill.rate); - if(num > skill.depb) return - // console.log(this.hero_name+":"+this.uuid+"冰冻触成功: i="+num+":debtime="+skill.debtime); - this.ice_cd = skill.debtime - this.BUFFCOMP.in_iced(skill.debtime) - break; - case 2: - if(num > skill.depb) return - // console.log(this.hero_name+":"+this.uuid+"debuff触发成功: i="+num+":debtime="+skill.debtime+":l_hp="+l_hp); - this.BUFFCOMP.in_fired(skill.debtime,l_hp*skill.derate/100) - break; - case 3: - if(num > skill.depb) return - this.yun_cd = skill.debtime - this.BUFFCOMP.in_yun(skill.debtime) - break; - case 4: - if(num > skill.depb) return - this.BUFFCOMP.buff_get("deap") - this.ap = this.ap-Math.floor(l_hp*skill.derate/100) - break; - case 5: - if(num > skill.depb) return - break; - case 6: - if(num > skill.depb) return - break; - case 7: - if(num > skill.depb) return - break; - case 8: - if(num > skill.depb) return - if(this.node.position.x > 300||this.node.position.x < -300) return - tween(this.node).to( 0.1, - { position: new Vec3(this.node.position.x-this.scale*50,this.node.position.y) }, - { } - ).start(); - break; - } - } - - - - //暴击判断 - /** - * 检查是否触发暴击,并执行相应的暴击效果。 - * @returns {boolean} 如果触发暴击则返回 true,否则返回 false。 - * 该方法首先通过 RandomManager 获取一个随机数,如果该随机数小于当前暴击最大值(crit_max), - * 则触发暴击效果,包括显示暴击提示、增加暴击计数、增加暴击经验以及增加暴击威力。 - * 如果未触发暴击,则直接返回 false。 - */ - check_crit():boolean - { - let i = RandomManager.instance.getRandomInt(0,100,3) - if(i < this.crit_max){ - // this.BUFFCOMP.tooltip(5,"*会心一击*"); - this.crit_count += 1 - this.exp_add(this.cexp) // 暴击经验 - this.power_add(this.cpw) - return true - }else{ - return false - } - } - //闪避判断 - /** - * 检查并处理角色的闪避逻辑。 - * 生成一个随机数,如果小于角色的最大闪避值,则触发闪避效果,增加经验、能量,并更新闪避计数。 - * @returns {boolean} 如果触发闪避则返回true,否则返回false。 - */ - check_dodge():boolean - { - let i = RandomManager.instance.getRandomInt(0,100,3) - if(this.dodge_max > GameSet.DODGE_MAX) this.dodge_max = GameSet.DODGE_MAX - if(i < this.dodge_max){ - // console.log("闪避触发: i="+i+":dodge="+dodge); - this.BUFFCOMP.tooltip(5,"闪避"); - this.exp_add(this.doexp) // 闪避经验 - this.power_add(this.dopw) - this.dodge_count += 1 - return true - }else{ - return false - } - } - /** - * 检查并处理角色的攻击、闪避、暴击和受伤计数。 - * 当计数达到一定值时,会触发相应的技能效果,并重置计数。 - * 触发效果包括激活名为"max"的节点,并在0.8秒后关闭。 - * 使用do_skill方法处理触发的技能。 - */ - check_atk_counts() { - if (this.atk_count >= this.akc) { - this.atk_count = 0 - // console.log("atk_count 清零:"+this.atk_count); - let i = RandomManager.instance.getRandomInt(0,100,3) - // console.log("攻击判断: i="+i+":akr="+this.akr); - if(i < this.akr){ - // console.log("攻击触发: i="+i+":akr="+this.akr); - // this.BUFFCOMP.max_show() - this.do_skill(this.sk3) - } - } - if(this.dodge_count >= this.dgc){ - this.dodge_count = 0 - // console.log("dodge_count 清零:"+this.dodge_count); - let i = RandomManager.instance.getRandomInt(0,100,3) - // console.log("闪避判断: i="+i+":dgr="+this.dgr); - if(i < this.dgr){ - // console.log("闪避触发: i="+i+":dgr="+this.dgr); - // this.BUFFCOMP.max_show() - this.do_skill(this.sk3) - } - } - if(this.crit_count >= this.crc){ - this.crit_count = 0 - // console.log("crit_count 清零:"+this.crit_count); - let i = RandomManager.instance.getRandomInt(0,100,3) - // console.log("暴击判断: i="+i+":crr="+this.crr); - if(i < this.crr){ - // console.log("暴击触发: i="+i+":crr="+this.crr); - - // this.BUFFCOMP.max_show() - this.do_skill(this.sk3) - } - } - if(this.atked_count >= this.uac){ - this.atked_count = 0 - let i = RandomManager.instance.getRandomInt(0,100,3) - // console.log("受伤判断:i="+i+":akr="+this.uar); - if(i < this.uar){ - // console.log("受伤触发: i="+i+":uar="+this.uar); - // this.BUFFCOMP.max_show() - this.do_skill(this.sk3) - } - } - } - in_atk(dt: number) { - if(this.at >= this.cd){ - if(this.is_atking){ - this.at = 0; - this.atk_count++ - this.exp_add(this.aexp) //攻击经验 - this.power_add(this.apw) - // console.log("cd:"+this.cd); - this.as.atk(); - this.scheduleOnce(()=>{ - this.shoot_enemy(this.sk1) - },0.3) - } - } - } - //能量判断 - check_power(){ - if(this.pw >= this.pwm){ - this.pw = 0 - this.BUFFCOMP.max_show() - this.do_skill(this.sk2) - return true - }else{ - return false - } - } - //使用max_skill - do_skill(skill:number){ - // this.at = 0; //共享普攻攻击cd - this.BUFFCOMP.tooltip(3,SkillSet[skill].name,skill); - if(SkillSet[skill].flash){ - this.as.max() - this.scheduleOnce(()=>{ - this.BUFFCOMP.show_do_buff(SkillSet[skill].fname) - },0.1) - } - switch (SkillSet[skill].tg) { - case SkTG.self: //自己 - this.do_add_buff(this.node.getComponent(HeroViewComp),skill) - break; - case SkTG.friend: //伙伴 - if(this.box_group == BoxSet.HERO) this.check_other_hero_buff(skill) - if(this.box_group == BoxSet.MONSTER) this.check_other_mon_buff(skill) - break; - case SkTG.team: //自己和伙伴 - this.do_all_buff(skill) - break; - case SkTG.enemy: //敌人 - this.shoot_enemy(skill) - break; - case SkTG.all: //敌人和自己 - this.do_add_buff(this.node.getComponent(HeroViewComp),skill) - this.shoot_enemy(skill) - break; - } - } - shoot_enemy(sk:number,y:number=0,x:number=0){ - // console.log("mon shoot_enemy"); - let skill = ecs.getEntity(Skill); - let t_pos=v3(smc.mon_front_x,BoxSet.GAME_LINE) //最前排目标 - if(this.box_group==BoxSet.MONSTER){ - t_pos=v3(smc.hero_front_x,BoxSet.GAME_LINE) - } - switch(SkillSet[sk].type){ - case SkType.leastHealth: //血量最少单体 - t_pos=this.check_heros().l_hero.node.position - if(this.box_group==BoxSet.MONSTER) t_pos=this.check_mons().l_hero.node.position - break; - case SkType.highestHealth: //血量最多单体 - t_pos=this.check_heros().m_hero.node.position - if(this.box_group==BoxSet.MONSTER) t_pos=this.check_mons().m_hero.node.position - break; - case SkType.backRow: //最后排 - t_pos=v3(smc.mon_back_x,BoxSet.GAME_LINE) - if(this.box_group==BoxSet.MONSTER){ - t_pos=v3(smc.hero_back_x,BoxSet.GAME_LINE) - } - break; - } - let pos =this.node.position - let is_crit=this.check_crit() - this.to_console(this.scale+this.hero_name+"使用技能:"+sk+SkillSet[sk].name+" pos:"+pos+" t_pos:"+t_pos+" box:"+this.box_group,); - skill.load(pos,this.box_group,this.node,sk,this.ap_max,t_pos,is_crit,this.crit_add,this.rhp_max); - - } - check_heros(){ - let heros:any = ecs.query(ecs.allOf(HeroModelComp)); - let l_hp:number=0 - let h_hp:number=9999999999 - let right_x:number=360 - let left_x:number=-360 - let f_hero:any= null - let b_hero:any= null - let l_hero:any= null - let m_hero:any= null - let r_hero:any= null - let i = RandomManager.instance.getRandomInt(0,heros.length-1,3) - while(!heros[i].HeroView){ - i = RandomManager.instance.getRandomInt(0,heros.length-1,3) - if(!heros[i].HeroView.in_grave){ - r_hero= heros[i].HeroView - break - } - } - for (let i = 0; i < heros.length; i++) { - let hero:any = heros[i].HeroView; - if (hero.in_grave) continue - if((hero.rhp_max-hero.hp) > l_hp){ - l_hp = (hero.rhp_max-hero.hp) - l_hero = hero - } - if((hero.rhp_max-hero.hp) < h_hp){ - h_hp = (hero.rhp_max-hero.hp) - m_hero = hero - } - if(hero.node.position.x > left_x){ - left_x = hero.node.position.x - f_hero = hero - } - if(hero.node.position.x < right_x){ - right_x = hero.node.position.x - b_hero = hero - } - } - return {l_hero,m_hero,f_hero,b_hero,r_hero} - } - check_mons(){ - let heros:any=ecs.query(ecs.allOf(MonModelComp)) - let l_hp:number=0 - let h_hp:number=9999999999 - let right_x:number=360 - let left_x:number=-360 - let f_hero:any= null - let b_hero:any= null - let l_hero:any= null - let m_hero:any= null - let r_hero:any= null - let i = RandomManager.instance.getRandomInt(0,heros.length-1,3) - while(!heros[i].HeroView){ - i = RandomManager.instance.getRandomInt(0,heros.length-1,3) - if(!heros[i].HeroView.in_grave){ - r_hero= heros[i].HeroView - break - } - } - for (let i = 0; i < heros.length; i++) { - let hero:any = heros[i].HeroView; - if (hero.in_grave) continue - if((hero.rhp_max-hero.hp) > l_hp){ - l_hp = (hero.rhp_max-hero.hp) - l_hero = hero - } - if((hero.rhp_max-hero.hp) < h_hp){ - h_hp = (hero.rhp_max-hero.hp) - m_hero = hero - } - if(hero.node.position.x < right_x){ - right_x = hero.node.position.x - f_hero = hero - } - if(hero.node.position.x > left_x){ - left_x = hero.node.position.x - b_hero = hero - } - } - return {l_hero,m_hero,f_hero,b_hero,r_hero} - } - check_other_hero_buff(skill:number){ - switch(SkillSet[skill].type){ - case SkType.random: - this.do_add_buff(this.check_heros().r_hero,skill) - break; - case SkType.leastHealth: //血量最少单体 - this.do_add_buff(this.check_heros().l_hero,skill) - break; - case SkType.highestHealth: //血量最多单体 - this.do_add_buff(this.check_heros().m_hero,skill) - break; - case SkType.frontRow: //最前排 - this.do_add_buff(this.check_heros().f_hero,skill) - break; - case SkType.backRow: //最后排 - this.do_add_buff(this.check_heros().b_hero,skill) - break; - } - } - check_other_mon_buff(skill:number){ - switch(SkillSet[skill].type){ - case SkType.random: - this.do_add_buff(this.check_mons().r_hero,skill) - break; - case SkType.leastHealth: //血量最少单体 - this.do_add_buff(this.check_mons().l_hero,skill) - break; - case SkType.highestHealth: //血量最多单体 - this.do_add_buff(this.check_mons().m_hero,skill) - break; - case SkType.frontRow: //最前排 - this.do_add_buff(this.check_mons().f_hero,skill) - break; - case SkType.backRow: //最后排 - this.do_add_buff(this.check_mons().b_hero,skill) - break; - } - } - do_all_buff(sk:number){ - let skill = ecs.getEntity(Skill); - let pos=v3(0,0) - let t_pos = pos - // this.to_console("to_all_buff:"+sk) - let is_crit=this.check_crit() - skill.load(pos,this.box_group,this.node,sk,this.ap_max,t_pos,is_crit,this.crit_add,this.rhp_max); - // this.to_console("使用buff:"+sk+" t_pos:"+t_pos+" box:"+this.box_group); - } - - do_add_buff(hero:any,sk:number){ - let skill = ecs.getEntity(Skill); - let t_pos=hero.node.position - let pos = this.node.position - // this.to_console("do_add_buff:"+hero.hero_name+" "+sk); - let is_crit=this.check_crit() - skill.load(pos,this.box_group,this.node,sk,this.ap_max,t_pos,is_crit,this.crit_add,this.rhp_max); - // this.to_console(this.scale+this.hero_name+"使用buff:"+sk+SkillSet[sk].name+" t_pos:"+t_pos+" box:"+this.box_group,); - } - - exp_add(exp:number=0){ - if(this.box_group==BoxSet.HERO){ - smc.vmdata.mission.exp +=exp - } - if(this.box_group==BoxSet.MONSTER){ - smc.vmdata.mission.mexp +=exp - } - } - power_add(p:number){ - this.pw+= p - } - add_shield(shield:number){ - this.shield =shield - if(this.shield>0) this.BUFFCOMP.show_shield(true) - } - // add_cd(cd: number){ - // this.cd += this.cd*((100-cd)/100); - // this.BUFFCOMP.buff_get("cd") - // } - - /** - * 增加英雄的攻击(AP)。 - * @param ap 要增加的攻击。 - */ - add_ap(ap: number){ - this.ap += Math.floor(ap); - this.BUFFCOMP.buff_get("ap") - } - de_ap(ap: number){ - this.ap -= Math.floor(ap); - this.BUFFCOMP.buff_get("deap") - } - add_def(def: number){ - this.def += Math.floor(def); - this.BUFFCOMP.buff_get("def") - } - de_def(def: number){ - this.def -= Math.floor(def); - this.BUFFCOMP.buff_get("dedef") - } - /** - * 增加英雄的暴击率。 - * @param crit 要增加的暴击率。 - */ - - add_crit(critRate: number) { - this.crit += Math.floor(critRate); - this.BUFFCOMP.buff_get("crit"); - } - de_crit(critRate: number) { - this.crit += Math.floor(critRate); - this.BUFFCOMP.buff_get("decrit"); - } - /** - * 增加英雄的闪避率。 - * @param dodge 要增加的闪避率。 - */ - add_dodge(dodgeRate: number) { - this.dodge += Math.floor(dodgeRate); - this.BUFFCOMP.buff_get("dodge"); - } - de_dodge(dodgeRate: number) { - this.dodge += Math.floor(dodgeRate); - this.BUFFCOMP.buff_get("dedodge"); - } - add_hp_max(hprate: number=0){ - this.BUFFCOMP.buff_get("hp") - this.hp_max += Math.floor(hprate/100*this.rhp_max) ; - this.add_hp2(hprate) - } - de_hp_max(hprate: number=0){ - this.BUFFCOMP.buff_get("dehp") - this.hp_max -= Math.floor(hprate/100*this.rhp_max) ; - } - add_hp(hp: number = 0) { - this.BUFFCOMP.heathed(); - this.hp+=Math.floor(hp); - if(this.hp > this.rhp_max){ - this.hp = this.rhp_max; - } - this.BUFFCOMP.tooltip(2,hp.toFixed(0)); - } - add_hp2(hprate: number=0){ - this.hp += Math.floor(hprate/100*this.hp_max) ; - } - - hp_less(hp: number,is_crit:boolean=false){ - if(this.is_dead) return - hp=Math.floor(hp) - this.hp -= hp - if(is_crit){ - this.BUFFCOMP.tooltip(4,hp.toFixed(0),250); - }else{ - this.BUFFCOMP.tooltip(1,hp.toFixed(0),250); - } - if(this.hp > this.rhp_max){ - this.hp = this.rhp_max; - } - if(this.hp <= 0){ - this.dead(); - this.to_grave() - this.is_dead = true; - } - } - /** 静止时间 */ - in_stop (dt: number) { - if(this.stop_cd > 0){ - this.stop_cd -= dt; - if(this.stop_cd <= 0){ - this.stop_cd = 0; - this.is_atking = false; - } - } - } - - in_atked() { - this.BUFFCOMP.in_atked() - // this.as.atked(); - this.atked_count++; - this.exp_add(this.uaexp) - this.power_add(this.uapw) - } - dead(){ - this.BUFFCOMP.dead() - this.exp_add(this.dexp) - this.power_add(this.dpw) - this.to_drop() - } - //掉落物品 - to_drop(){ - let Drops = getMonsterDrops(1, MonsterType.Normal, 1.2); - if(this.is_boss) Drops =getMonsterDrops(1, MonsterType.Elite, 1.2); - if(this.is_big_boss) Drops =getMonsterDrops(1, MonsterType.Boss, 1.2); - // console.log("掉落物品:",Drops); - //根据掉落类型和uuid 写入用户数据文件SingletonModuleComp =smc,英雄碎片对应smc.heros[uuid].num,smc.heros[uuid].x1 记录本局掉落的数量,也需要添加对应值 - //金币uuid=9001 对应smc.vmdata.gold.num,宝箱uuid1003,对应smc.vmdata.box.num ,smc.itmes[9001].x1,smc.itmes[1003].x1 记录本局 - for (let i = 0; i < Drops.length; i++) { - const drop = Drops[i]; - if(drop.type == 1 ){ //英雄碎片 - smc.heros[drop.uuid].num += drop.num - smc.heros[drop.uuid].x1 += drop.num - } - if(drop.type==2){ - if(drop.uuid == 9001){ - smc.vmdata.gold.num+=drop.num - smc.items[9001].x1+=drop.num - } - if(drop.uuid == 1003){ - smc.vmdata.box.num+=drop.num - smc.items[1003].x1+=drop.num - } - } - } - - } - //进入墓地 - to_grave(){ - let pos =v3(-999,this.node.position.y) - if(this.box_group == BoxSet.MONSTER){ - pos =v3(999,this.node.position.y) - smc.vmdata.mission.mdead +=1 - }else{ - smc.vmdata.mission.dead +=1 - } - this.node.setPosition(pos) - } - //是否在墓地 - in_grave(){ - return this.node.position.x < -900 || this.node.position.x > 900; - } - to_alive(){ - let pos =v3(HeroSet.StartPos[this.type],this.node.position.y,this.node.position.z) - this.node.setPosition(pos) - } - - to_console(value:any,value2:any=null,value3:any=null){ - console.log("["+this.scale+this.hero_name+']'+value,value2,value3) - } - reset() { - this.is_dead = false; - this.node.destroy(); - } - -} \ No newline at end of file diff --git a/assets/script/game/hero/HeroViewComp.ts.meta b/assets/script/game/hero/HeroViewComp.ts.meta deleted file mode 100644 index edc01acd..00000000 --- a/assets/script/game/hero/HeroViewComp.ts.meta +++ /dev/null @@ -1 +0,0 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"873f877e-4a89-4c12-8f03-8934f1651878","files":[],"subMetas":{},"userData":{}} diff --git a/assets/script/game/hero/Mon.ts.meta b/assets/script/game/hero/Mon.ts.meta deleted file mode 100644 index 5b29d269..00000000 --- a/assets/script/game/hero/Mon.ts.meta +++ /dev/null @@ -1 +0,0 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"c1d7128f-5af5-4f7c-b4a1-6bb6fd4f12e0","files":[],"subMetas":{},"userData":{}} diff --git a/assets/script/game/hero/MonModelComp.ts b/assets/script/game/hero/MonModelComp.ts deleted file mode 100644 index 087154f6..00000000 --- a/assets/script/game/hero/MonModelComp.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * @Author: dgflash - * @Date: 2021-11-18 15:56:01 - * @LastEditors: dgflash - * @LastEditTime: 2022-08-17 13:43:25 - */ -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; - -/** - * 角色属性数据 - */ -@ecs.register('MonModel') -export class MonModelComp extends ecs.Comp { - /** 角色编号 */ - id: number = -1; - - /** 角色名 */ - name: string = "mon"; - /** speed */ - // speed: number = 0; - /** 动画名资源 */ - anim: string = "mon"; - - reset() { - this.id = -1; - // this.speed = 0; - this.name = ""; - } -} diff --git a/assets/script/game/hero/MonModelComp.ts.meta b/assets/script/game/hero/MonModelComp.ts.meta deleted file mode 100644 index b9430677..00000000 --- a/assets/script/game/hero/MonModelComp.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.23", - "importer": "typescript", - "imported": true, - "uuid": "118ca580-773a-458b-8544-ab6c3cb2b376", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/assets/script/game/heros/HeroComponent.ts b/assets/script/game/heros/HeroComponent.ts deleted file mode 100644 index b0ee83a2..00000000 --- a/assets/script/game/heros/HeroComponent.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; - -import { _decorator, Node } from 'cc'; -const { ccclass } = _decorator; - -// 继承框架的ECComponent - -// 基础属性组件 -@ecs.register('HeroBase') -export class HeroBase extends ecs.Comp { - // 定义需要序列化的字段 - static serializeFields = ['hp', 'attack', 'node']; - - hp: number = 100; - attack: number = 10; - node: Node = null; - - reset() { - this.hp = 100; - this.attack = 10; - this.node = null; - } -} - -// 技能组件 -@ecs.register('HeroSkill') -export class HeroSkill extends ecs.Comp { - static serializeFields = ['skillId']; - - skillId: string = ""; - cooldown: number = 0; - - reset() { - this.skillId = ""; - this.cooldown = 0; - } -} - -// 状态组件 -@ecs.register('HeroState') -export class HeroState extends ecs.Comp { - current: 'idle' | 'attack' | 'die' = 'idle'; - previous: 'idle' | 'attack' | 'die' = 'idle'; - - reset() { - this.current = 'idle'; - this.previous = 'idle'; - } -} - diff --git a/assets/script/game/heros/HeroComponent.ts.meta b/assets/script/game/heros/HeroComponent.ts.meta deleted file mode 100644 index ac622877..00000000 --- a/assets/script/game/heros/HeroComponent.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.23", - "importer": "typescript", - "imported": true, - "uuid": "dbeb1c15-5c41-49bd-b633-728335443a38", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/assets/script/game/heros/HeroSystem.ts b/assets/script/game/heros/HeroSystem.ts deleted file mode 100644 index 20166527..00000000 --- a/assets/script/game/heros/HeroSystem.ts +++ /dev/null @@ -1,22 +0,0 @@ -@ecs.registerSystem() -export class HeroMoveSystem extends ecs.System { - filter(): ecs.IMatcher { - return ecs.allOf(HeroModelComp, HeroViewComp, MoveToComp); - } - - update(entities: Hero[]) { - const deltaTime = oops.timer.delta; - entities.forEach(hero => { - // 每个英雄独立计算移动 - const move = hero.get(MoveToComp); - const view = hero.get(HeroViewComp); - - // 计算移动向量(单个英雄逻辑) - const dir = move.target.subtract(view.node.position).normalize(); - const speed = view.speed * deltaTime; - - // 更新位置(独立操作) - view.node.position = view.node.position.add(dir.multiplyScalar(speed)); - }); - } -} \ No newline at end of file diff --git a/assets/script/game/heros/HeroTypeSystem.ts b/assets/script/game/heros/HeroTypeSystem.ts deleted file mode 100644 index 174a9c1e..00000000 --- a/assets/script/game/heros/HeroTypeSystem.ts +++ /dev/null @@ -1,28 +0,0 @@ -@ecs.registerSystem() -export class HeroTypeSystem extends ecs.System { - filter() { - return ecs.allOf(HeroTypeComp); - } - - update(entities: Hero[]) { - entities.forEach(hero => { - const type = hero.get(HeroTypeComp).type; - switch(type) { - case HeroType.MELEE: - this.processMelee(hero); - break; - case HeroType.RANGED: - this.processRanged(hero); - break; - } - }); - } - - private processMelee(hero: Hero) { - // 近战英雄特有逻辑 - } - - private processRanged(hero: Hero) { - // 远程英雄特有逻辑 - } -} \ No newline at end of file diff --git a/assets/script/game/heros/Heros.ts b/assets/script/game/heros/Heros.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/assets/script/game/heros/Heros.ts.meta b/assets/script/game/heros/Heros.ts.meta deleted file mode 100644 index c5fe37de..00000000 --- a/assets/script/game/heros/Heros.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.23", - "importer": "typescript", - "imported": true, - "uuid": "3d62e7a3-a90b-47f3-bf88-85745af0b8b4", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/assets/script/game/manager.meta b/assets/script/game/manager.meta new file mode 100644 index 00000000..f92248c6 --- /dev/null +++ b/assets/script/game/manager.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "6d0a9f29-e325-40e7-8a9e-f7b9cc09e76b", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/manager/SpineManager.ts b/assets/script/game/manager/SpineManager.ts new file mode 100644 index 00000000..f052cab1 --- /dev/null +++ b/assets/script/game/manager/SpineManager.ts @@ -0,0 +1,37 @@ +import { Prefab, resources } from 'cc'; +import { GameConstants } from '../common/Constants'; + +export class SpineManager { + private _cache: Map = new Map(); + + async load(spinePath: string): Promise { + if (this._cache.has(spinePath)) { + return this._cache.get(spinePath)!; + } + + const prefab = await this._load(spinePath); + this._cache.set(spinePath, prefab); + return prefab; + } + + private _load(path: string): Promise { + return new Promise((resolve, reject) => { + resources.load(path, Prefab, (err, prefab) => { + err ? reject(err) : resolve(prefab); + }); + }); + } + + release(spinePath: string) { + if (this._cache.has(spinePath)) { + resources.release(spinePath); + this._cache.delete(spinePath); + } + } + + // 加载英雄资源 + async loadHero(name: string): Promise { + const path = `${GameConstants.SPINE.HERO}/${name}`; + return this.load(path); + } +} \ No newline at end of file diff --git a/assets/script/game/manager/SpineManager.ts.meta b/assets/script/game/manager/SpineManager.ts.meta new file mode 100644 index 00000000..2f492e12 --- /dev/null +++ b/assets/script/game/manager/SpineManager.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "10e51fd3-8d01-4030-80a3-f98466d8c017", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/map/MissionComp.ts b/assets/script/game/map/MissionComp.ts index a116b588..1fd5b66b 100644 --- a/assets/script/game/map/MissionComp.ts +++ b/assets/script/game/map/MissionComp.ts @@ -21,6 +21,11 @@ import { UIID } from "../common/config/GameUIConfig"; import { CardControllerComp } from "./CardController"; import { MissionHomeComp } from "./MissionHomeComp"; import { GameEvent } from "../common/config/GameEvent"; +import { HeroViewComp } from "../hero/HeroViewComp"; +import { MoveToComp } from "../hero/MoveToComp"; +import { HeroSkillComp } from "../hero/HeroSkillComp"; +import { HeroStateComp } from "../hero/HeroStateComp"; +import { instantiate } from "cc"; const { ccclass, property } = _decorator; /** 视图层对象 */ @@ -323,17 +328,66 @@ export class MissionComp extends CCComp { this.fight_start= true } /** 添加玩家 */ - private addHero(uuid:number=1001,i:number=0) { - let hero = ecs.getEntity(Hero); - let scale = 1 - let pos:Vec3 = v3(HeroSet.StartPos[1]-i*10,BoxSet.GAME_LINE); - hero.load(pos,scale,uuid); + private createEntity( + entityClass: ecs.TypedConstructor, + components: ecs.Comp[] + ): T { + const entity = ecs.Entity.create(entityClass); + components.forEach(comp => entity.add(comp)); + return entity; } - private addMonster(uuid:number=1001,i:number=0,is_boss:boolean=false) { - let mon = ecs.getEntity(Monster); - let scale = -1 - let pos:Vec3 = v3(-1*HeroSet.StartPos[1]+i*10,BoxSet.GAME_LINE); - mon.load(pos,scale,uuid,is_boss); + + private addHero(uuid: number = 1001, index: number = 0) { + // 组件初始化 + const components = [ + this.createHeroModel(uuid), + this.createHeroView(index), + new MoveToComp() + ]; + + // 创建实体 + const hero = this.createEntity(Hero, components); + + // 初始化技能系统 + hero.get(HeroSkillComp)?.initSkills(); + } + + private createHeroModel(uuid: number): HeroModelComp { + const model = new HeroModelComp(); + model.uuid = uuid; + model.level = 1; + return model; + } + + private createHeroView(index: number): HeroViewComp { + const view = new HeroViewComp(); + const pos = v3(HeroSet.StartPos[1] - index * 10, BoxSet.GAME_LINE); + view.initPosition(pos, 1); + return view; + } + + private addMonster(uuid: number = 2001, index: number = 0, isBoss: boolean = false) { + const components = [ + this.createMonsterModel(uuid, isBoss), + this.createMonsterView(index), + new MoveToComp() + ]; + + this.createEntity(Monster, components); + } + + private createMonsterModel(uuid: number, isBoss: boolean): MonModelComp { + const model = new MonModelComp(); + model.uuid = uuid; + model.isBoss = isBoss; + return model; + } + + private createMonsterView(index: number): HeroViewComp { + const view = new HeroViewComp(); + const pos = v3(-HeroSet.StartPos[1] + index * 10, BoxSet.GAME_LINE); + view.initPosition(pos, -1); + return view; } @@ -343,4 +397,36 @@ export class MissionComp extends CCComp { reset() { this.node.destroy(); } + + private clearEntities() { + // 使用类型安全的方式销毁实体 + this.destroyEntities(ecs.allOf(HeroModelComp)); + this.destroyEntities(ecs.allOf(MonModelComp)); + } + + private destroyEntities(matcher: ecs.IMatcher) { + ecs.query(matcher).forEach(entity => { + const view = entity.get(HeroViewComp); + view?.destroyNode(); + entity.destroy(); + }); + } + + // 添加实体类型守卫 + private isHero(entity: ecs.Entity): entity is Hero { + return entity.has(HeroModelComp); + } + + private isMonster(entity: ecs.Entity): entity is Monster { + return entity.has(MonModelComp); + } + + // 统一实体处理 + private updateEntities() { + ecs.query(ecs.allOf(HeroModelComp)).forEach(entity => { + if (this.isHero(entity)) { + entity.HeroModel.updateState(); + } + }); + } } \ No newline at end of file diff --git a/assets/script/game/skill.meta b/assets/script/game/skill.meta index 6afe16f3..391061ab 100644 --- a/assets/script/game/skill.meta +++ b/assets/script/game/skill.meta @@ -1,5 +1,5 @@ { - "ver": "1.1.0", + "ver": "1.2.0", "importer": "directory", "imported": true, "uuid": "a80a879f-d214-454c-a574-18f080ae0d91", diff --git a/assets/script/game/skill/DOTSystem.ts.meta b/assets/script/game/skill/DOTSystem.ts.meta new file mode 100644 index 00000000..dd7bb567 --- /dev/null +++ b/assets/script/game/skill/DOTSystem.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "d6c0bfaa-8380-4bb8-a8bc-ce53498aa6fc", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/skill/SkillCollisionSystem.ts.meta b/assets/script/game/skill/SkillCollisionSystem.ts.meta new file mode 100644 index 00000000..391be566 --- /dev/null +++ b/assets/script/game/skill/SkillCollisionSystem.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "6f163fe3-2052-4028-9cdc-b36c66cae518", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/skill/SkillComponent.ts.meta b/assets/script/game/skill/SkillComponent.ts.meta new file mode 100644 index 00000000..9a1433b3 --- /dev/null +++ b/assets/script/game/skill/SkillComponent.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "dc2271f5-75c7-4376-9508-9112769e1479", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/skill/SkillEffectSystem.ts.meta b/assets/script/game/skill/SkillEffectSystem.ts.meta new file mode 100644 index 00000000..76042612 --- /dev/null +++ b/assets/script/game/skill/SkillEffectSystem.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "5704a6a4-e232-4fe9-99b7-9cb14be0bd1a", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/system.meta b/assets/script/game/system.meta new file mode 100644 index 00000000..2003c16a --- /dev/null +++ b/assets/script/game/system.meta @@ -0,0 +1,9 @@ +{ + "ver": "1.2.0", + "importer": "directory", + "imported": true, + "uuid": "f7ed668b-2d29-4149-b1e7-9c30a35f7a78", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/system/CombatSystem.ts b/assets/script/game/system/CombatSystem.ts new file mode 100644 index 00000000..1b781a76 --- /dev/null +++ b/assets/script/game/system/CombatSystem.ts @@ -0,0 +1,41 @@ +@ecs.registerSystem() +export class CombatSystem extends ecs.System { + filter(): ecs.IMatcher { + return ecs.allOf(Combat, HeroModel); + } + + update(entities: ecs.Entity[]) { + entities.forEach(attacker => { + if (attacker.has(HeroModel)) { + this.processHeroAttack(attacker); + } + }); + } + + private processHeroAttack(attacker: ecs.Entity) { + const combat = attacker.get(Combat); + const model = attacker.get(HeroModel); + + if (combat.target && model.hp > 0) { + // 攻击逻辑 + combat.attackTimer += this.dt; + if (combat.attackTimer >= combat.attackInterval) { + this.executeAttack(attacker, combat.target); + combat.attackTimer = 0; + } + } + } + + private executeAttack(attacker: ecs.Entity, target: ecs.Entity) { + // 伤害计算逻辑 + const attack = attacker.get(HeroModel).attack; + const defense = target.get(HeroModel).defense; + const damage = Math.max(attack - defense, 1); + + oops.message.dispatch('CombatEvent', { + attacker, + target, + damage + }); + } +} \ No newline at end of file diff --git a/assets/script/game/system/CombatSystem.ts.meta b/assets/script/game/system/CombatSystem.ts.meta new file mode 100644 index 00000000..562f3dab --- /dev/null +++ b/assets/script/game/system/CombatSystem.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "477f2c7f-0408-46db-8101-08d5a7717bac", + "files": [], + "subMetas": {}, + "userData": {} +}