Compare commits
4 Commits
50a8958cb7
...
9a24f0a9a5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a24f0a9a5 | ||
|
|
965b04094d | ||
|
|
e18bcf2133 | ||
|
|
75ef3af42b |
@@ -250,7 +250,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -85.933,
|
||||
"y": -40.433,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -290,8 +290,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 384,
|
||||
"height": 384
|
||||
"width": 191.9,
|
||||
"height": 192
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1094,7 +1094,7 @@
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"width": 80,
|
||||
"height": 100
|
||||
},
|
||||
"_id": ""
|
||||
|
||||
@@ -981,8 +981,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1090,12 +1090,12 @@
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 50
|
||||
"y": 75
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -84.866,
|
||||
"y": -84.432,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -978,8 +978,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1087,12 +1087,12 @@
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 50
|
||||
"y": 75
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -84.192,
|
||||
"y": -57.035,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -290,8 +290,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 384,
|
||||
"height": 384
|
||||
"width": 256,
|
||||
"height": 256
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -981,8 +981,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1090,12 +1090,12 @@
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 50
|
||||
"y": 75
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.041,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
@@ -250,7 +250,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -87.202,
|
||||
"y": -57.266,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -290,8 +290,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 384,
|
||||
"height": 384
|
||||
"width": 256,
|
||||
"height": 256
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -978,8 +978,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1087,12 +1087,12 @@
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 50
|
||||
"y": 75
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 100
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -81.733,
|
||||
"y": -53.96,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -290,8 +290,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 384,
|
||||
"height": 384
|
||||
"width": 256,
|
||||
"height": 256
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -978,8 +978,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 200,
|
||||
"height": 220
|
||||
"width": 150,
|
||||
"height": 150
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1087,12 +1087,12 @@
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 110
|
||||
"y": 75
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 150,
|
||||
"height": 220
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -27,6 +27,11 @@ export enum FightSet {
|
||||
HERO_ROW_FRONT_X = -200, // 前排(最靠右迎敌):坦克 / 战士
|
||||
HERO_ROW_MID_X = -260, // 中排:刺客 / 射手
|
||||
HERO_ROW_BACK_X = -320, // 后排(最靠左):法师 / 辅助
|
||||
|
||||
/** 怪物三排出生/编队基准 x(y 均为 BoxSet.GAME_LINE):前排迎敌、中排、后排靠右 */
|
||||
MON_ROW_FRONT_X = 200, // 前排(最靠左迎敌):近战 / 重型 / 近战Boss
|
||||
MON_ROW_MID_X = 260, // 中排:远程 / 刺客 / 远程Boss
|
||||
MON_ROW_BACK_X = 320, // 后排(最靠右):辅助 / 召唤师
|
||||
WAVE_COIN_BASE = 7, // 回合金币基础奖励
|
||||
WAVE_COIN_GROW = 2, // 回合金币递增值
|
||||
WAVE_COIN_MAX = 17, // 回合金币最大基础奖励
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { v3 } from "cc"
|
||||
import { v3 } from "cc"
|
||||
import { BoxSet, FacSet, FightSet } from "./GameSet"
|
||||
import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams } from "./SkillSet"
|
||||
import { BuffList, BuffConfig, ModOp } from "./BuffSet"
|
||||
@@ -145,12 +145,12 @@ export const HRoleName: Record<HRole, string> = {
|
||||
* Why: 局外升级机制将在加载时(Hero.ts / Mon.ts)统一重算属性,配置表只承担"基准+增量"的静态表达。
|
||||
*/
|
||||
export const HERO_ROLE_BASE: Record<HRole, { hp: number; ap: number; def: number }> = {
|
||||
[HRole.Tank]: { hp: 300, ap: 20, def: 50 }, // 坦克:高防高血,前排承伤
|
||||
[HRole.Warrior]: { hp: 280, ap: 22, def: 30 }, // 战士:均衡
|
||||
[HRole.Assassin]: { hp: 280, ap: 22, def: 10 }, // 刺客:低防,近战爆发
|
||||
[HRole.Archer]: { hp: 140, ap: 32, def: 10 }, // 射手:低防,远程物理主C
|
||||
[HRole.Mage]: { hp: 140, ap: 32, def: 10 }, // 法师:低防,远程增益
|
||||
[HRole.Support]: { hp: 140, ap: 32, def: 15 }, // 辅助:低防,光环/治疗
|
||||
[HRole.Tank]: { hp: 600, ap: 20, def: 50 }, // 坦克:高防高血,前排承伤
|
||||
[HRole.Warrior]: { hp: 560, ap: 22, def: 30 }, // 战士:均衡
|
||||
[HRole.Assassin]: { hp: 560, ap: 22, def: 10 }, // 刺客:低防,近战爆发
|
||||
[HRole.Archer]: { hp: 280, ap: 32, def: 10 }, // 射手:低防,远程物理主C
|
||||
[HRole.Mage]: { hp: 280, ap: 32, def: 10 }, // 法师:低防,远程增益
|
||||
[HRole.Support]: { hp: 280, ap: 32, def: 15 }, // 辅助:低防,光环/治疗
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -782,6 +782,8 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
* 性能基准:1 级怪物与 1 级英雄单体性能持平 ——
|
||||
* 近战怪基准 hp300/ap22/cd1.20,远程怪基准 hp160/ap28/cd1.20,
|
||||
* 重型/Boss 以更高 hp 换取更低 DPS,承担"墙"与"压场"定位。
|
||||
* 怪物普攻统一使用 SkillSet 基础单体攻击(6001~6014 段),
|
||||
* 并通过 overrides.ap=100 显式声明伤害为攻击力的 100%。
|
||||
* 运行时最终属性 = 本表基础值 × RogueConfig.MON_HP_MUL / MON_AP_MUL
|
||||
* (Boss 额外 × BOSS_HP_BONUS_MUL),校准目标:整场战斗双方对砍 ≈ 30s。
|
||||
*/
|
||||
@@ -791,7 +793,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
// 前排怪物 — 近战镜像 1 级英雄基准(hp300/ap22/cd1.20),变体微分定位
|
||||
6001: {
|
||||
uuid: 6001, name: "兽人战士", path: "m1", fac: FacSet.MON, lv: 1, type: HType.Melee, monType: MonType.Melee, hp: 300, ap: 22, def: 20, speed: 70,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "基础前排怪, 与1级近战英雄持平"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "基础前排怪, 与1级近战英雄持平"
|
||||
},
|
||||
6002: {
|
||||
uuid: 6002, name: "兽人精锐战士", path: "m2", fac: FacSet.MON, lv: 1, type: HType.Melee, monType: MonType.Melee, hp: 340, ap: 26, def: 25, speed: 110,
|
||||
@@ -799,56 +801,56 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
},
|
||||
6003: {
|
||||
uuid: 6003, name: "兽人重装兵", path: "m3", fac: FacSet.MON, lv: 1, type: HType.Melee, monType: MonType.Heavy, hp: 800, ap: 14, def: 60, speed: 50,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0 } }, info: "重型坦克怪, 高HP低攻承伤位"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "重型坦克怪, 高HP低攻承伤位"
|
||||
},
|
||||
// 后排怪物 — 远程镜像 1 级法师基准(hp160/ap28/cd1.20),变体微分定位
|
||||
6004: {
|
||||
uuid: 6004, name: "兽人射手", path: "m4", fac: FacSet.MON, lv: 1, type: HType.Long, monType: MonType.Long, hp: 160, ap: 28, def: 8, speed: 70,
|
||||
skills: { 6006: { uuid: 6006, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "后排输出怪, 与1级远程英雄持平"
|
||||
skills: { 6006: { uuid: 6006, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "后排输出怪, 与1级远程英雄持平"
|
||||
},
|
||||
6005: {
|
||||
uuid: 6005, name: "兽人刺客", path: "m5", fac: FacSet.MON, lv: 1, type: HType.Long, monType: MonType.Assassin, hp: 130, ap: 26, def: 5, speed: 130,
|
||||
skills: { 6102: { uuid: 6102, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0 } }, info: "高攻速低HP刺客"
|
||||
skills: { 6002: { uuid: 6002, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "高攻速低HP刺客"
|
||||
},
|
||||
// 特殊位怪物
|
||||
6006: {
|
||||
uuid: 6006, name: "骷髅领主", path: "m6", fac: FacSet.MON, lv: 1, type: HType.Melee, monType: MonType.MeleeBoss, hp: 900, ap: 20, def: 40, speed: 60,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0 } }, info: "前排MiniBoss级坦克"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排MiniBoss级坦克"
|
||||
},
|
||||
6007: {
|
||||
uuid: 6007, name: "兽人术士", path: "m7", fac: FacSet.MON, lv: 1, type: HType.Long, monType: MonType.Support, hp: 240, ap: 18, def: 10, speed: 70,
|
||||
skills: { 6102: { uuid: 6102, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "后排辅助法师怪"
|
||||
skills: { 6009: { uuid: 6009, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "后排辅助法师怪"
|
||||
},
|
||||
6008: {
|
||||
uuid: 6008, name: "兽人火法", path: "m8", fac: FacSet.MON, lv: 1, type: HType.Long, monType: MonType.Summoner, hp: 220, ap: 24, def: 10, speed: 70,
|
||||
skills: { 6014: { uuid: 6014, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "后排召唤系法师怪"
|
||||
skills: { 6010: { uuid: 6010, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "后排召唤系法师怪"
|
||||
},
|
||||
|
||||
// BOSS怪物 — 本表 hp/ap 仅作外观/技能档位参考,运行时面板由 RogueConfig 的
|
||||
// BOSS_BASE_HP / BOSS_BASE_AP(初始英雄 2 倍强度)统一决定,不读取本表数值
|
||||
6101: {
|
||||
uuid: 6101, name: "兽人首领-双刀战士", path: "mb1", fac: FacSet.MON, lv: 6, type: HType.Melee, monType: MonType.MeleeBoss, hp: 1200, ap: 24, def: 45, speed: 120,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "前排Boss, 攻速型"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排Boss, 攻速型"
|
||||
},
|
||||
6102: {
|
||||
uuid: 6102, name: "兽人首领-斧头战士", path: "mb2", fac: FacSet.MON, lv: 6, type: HType.Melee, monType: MonType.MeleeBoss, hp: 1500, ap: 18, def: 55, speed: 60,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0 } }, info: "前排Boss, 超高HP"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排Boss, 超高HP"
|
||||
},
|
||||
6103: {
|
||||
uuid: 6103, name: "兽人首领-魔法师", path: "mb3", fac: FacSet.MON, lv: 6, type: HType.Long, monType: MonType.LongBoss, hp: 1000, ap: 28, def: 25, speed: 110,
|
||||
skills: { 6102: { uuid: 6102, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "后排法系Boss"
|
||||
skills: { 6009: { uuid: 6009, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2 } } }, info: "后排法系Boss"
|
||||
},
|
||||
6104: {
|
||||
uuid: 6104, name: "兽人首领-射手", path: "mb4", fac: FacSet.MON, lv: 6, type: HType.Long, monType: MonType.LongBoss, hp: 1100, ap: 24, def: 25, speed: 70,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0 } }, info: "后排位Boss, 均衡型"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "后排位Boss, 均衡型"
|
||||
},
|
||||
6105: {
|
||||
uuid: 6105, name: "亡灵首领-法师", path: "mb5", fac: FacSet.MON, lv: 6, type: HType.Long, monType: MonType.LongBoss, hp: 1000, ap: 30, def: 20, speed: 110,
|
||||
skills: { 6014: { uuid: 6014, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 80, timed_buff_id: 7002 } } }, info: "后排高AP Boss"
|
||||
skills: { 6011: { uuid: 6011, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: { ap: 100, hit_count: 2, timed_buff_id: 7002 } } }, info: "后排高AP Boss"
|
||||
},
|
||||
6106: {
|
||||
uuid: 6106, name: "亡灵首领-骑马战士", path: "mb6", fac: FacSet.MON, lv: 6, type: HType.Melee, monType: MonType.MeleeBoss, hp: 1800, ap: 20, def: 60, speed: 130,
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0 } }, info: "前排终极Boss, 最高HP+高速"
|
||||
skills: { 6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VerySlow].cd, ccd: 0, overrides: { ap: 100 } } }, info: "前排终极Boss, 最高HP+高速"
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@ import { FlashSprite } from "./hit-flash-white/scripts/FlashSprite";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('HeroAnmComp')
|
||||
export default class HeroAnmComp extends Component{
|
||||
fsSprite:FlashSprite = null!;
|
||||
private anmcon:any=null
|
||||
export default class HeroAnmComp extends Component {
|
||||
fsSprite: FlashSprite = null!;
|
||||
private anmcon: any = null
|
||||
private _hasStop = true;
|
||||
private _atkIndex = 0;
|
||||
private default_anim:string='idle'
|
||||
anms:any[]=["idle","move","atk0","max0","max1"]
|
||||
onLoad () {
|
||||
this.anmcon=this.node.getComponent(Animation)
|
||||
private default_anim: string = 'idle'
|
||||
anms: any[] = ["idle", "move", "atk0", "max0", "max1"]
|
||||
onLoad() {
|
||||
this.anmcon = this.node.getComponent(Animation)
|
||||
this.fsSprite = this.node.getComponent(FlashSprite);
|
||||
this.anmcon.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
||||
}
|
||||
@@ -24,46 +24,61 @@ export default class HeroAnmComp extends Component{
|
||||
}
|
||||
}
|
||||
|
||||
stop () {
|
||||
/** 大招是否播放中(最高优先级,期间禁止一切动画切换) */
|
||||
private get maxPlaying(): boolean {
|
||||
return !!(this.anmcon.getState("max0")?.isPlaying || this.anmcon.getState("max1")?.isPlaying);
|
||||
}
|
||||
/** 普攻是否播放中(次优先级,仅可被大招打断) */
|
||||
private get atkPlaying(): boolean {
|
||||
return !!this.anmcon.getState("atk0")?.isPlaying;
|
||||
}
|
||||
/** buff 是否播放中(可被大招/普攻打断,但拦截 idle/move) */
|
||||
private get buffPlaying(): boolean {
|
||||
return !!this.anmcon.getState("buff")?.isPlaying;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._hasStop = true;
|
||||
}
|
||||
onAnimationFinished(type:Animation.EventType, state:AnimationState){
|
||||
if(state.name!="idle"&&state.name!="move"){
|
||||
onAnimationFinished(type: Animation.EventType, state: AnimationState) {
|
||||
if (state.name != "idle" && state.name != "move") {
|
||||
this.anmcon.play(this.default_anim)
|
||||
}
|
||||
}
|
||||
atked(){
|
||||
atked() {
|
||||
this.fsSprite.clickFlash();
|
||||
}
|
||||
move () {
|
||||
if(this.anmcon.getState("move").isPlaying) return
|
||||
this.anmcon.play("move")
|
||||
this.default_anim='move'
|
||||
move() {
|
||||
if (this.maxPlaying || this.atkPlaying || this.buffPlaying) return
|
||||
if (this.anmcon.getState("move").isPlaying) return
|
||||
this.anmcon.play("move")
|
||||
this.default_anim = 'move'
|
||||
}
|
||||
atk () {
|
||||
if(this.anmcon.getState("max0").isPlaying||this.anmcon.getState("max1").isPlaying) return
|
||||
atk() {
|
||||
if (this.maxPlaying) return
|
||||
this.anmcon.play(`atk0`)
|
||||
}
|
||||
max () {
|
||||
if(this.anmcon.getState("max0").isPlaying||this.anmcon.getState("max1").isPlaying) return
|
||||
this.anmcon.play("max0")
|
||||
max() {
|
||||
if (this.maxPlaying) return
|
||||
this.anmcon.play("max0")
|
||||
}
|
||||
play(anm:string=""){
|
||||
if(anm==="") return
|
||||
if(this.anmcon.getState("max0").isPlaying||this.anmcon.getState("max1").isPlaying) return
|
||||
play(anm: string = "") {
|
||||
if (anm === "") return
|
||||
if (this.maxPlaying) return
|
||||
this.anmcon.play(anm)
|
||||
}
|
||||
|
||||
idle () {
|
||||
if(this.anmcon.getState("idle").isPlaying) return
|
||||
idle() {
|
||||
if (this.maxPlaying || this.atkPlaying || this.buffPlaying) return
|
||||
if (this.anmcon.getState("idle").isPlaying) return
|
||||
this.anmcon.play("idle")
|
||||
this.default_anim='idle'
|
||||
this.default_anim = 'idle'
|
||||
}
|
||||
buff(){
|
||||
if(this.anmcon.getState("max0").isPlaying||this.anmcon.getState("max1").isPlaying) return
|
||||
buff() {
|
||||
if (this.maxPlaying) return
|
||||
this.anmcon.play("buff")
|
||||
}
|
||||
dead(){
|
||||
|
||||
dead() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* 2. 战斗开始:PhasePrepareEnd 时恢复怪物行动(in_fight 前怪物仅原地待命,不会推进/索敌)。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 5 只怪在 X∈[100,320] 内按登场序号均匀铺开,Boss/小怪同时登场,玩家看清阵容后三选一。
|
||||
* - 怪物按类型落排(近战/Boss→前排、远程/刺客→中排、辅助/召唤→后排),与英雄三排镜像对应。
|
||||
* - 实际推进由统一 MoveComp 在战斗中向敌人移动自然形成,不再使用固定网格点。
|
||||
* - 槽位索引仅用于 monGrid 寻路与 SCastSystem 索敌定位。
|
||||
*/
|
||||
@@ -19,8 +19,9 @@ import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/O
|
||||
import { Monster } from "../hero/Mon";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { BoxSet } from "../common/config/GameSet";
|
||||
import { spawningEngine, GeneratedMonster, TestModeConfig, BOSS_COUNT, MINION_COUNT } from "./RogueConfig";
|
||||
import { BoxSet, FightSet } from "../common/config/GameSet";
|
||||
import { MonType } from "../common/config/heroSet";
|
||||
import { spawningEngine, GeneratedMonster, TestModeConfig } from "./RogueConfig";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { MoveComp } from "../hero/MoveComp";
|
||||
|
||||
@@ -33,10 +34,23 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
/** 怪物出生掉落高度 */
|
||||
private static readonly MON_DROP_HEIGHT = 0;
|
||||
/** 怪物登场 X 范围下限(靠近英雄侧) */
|
||||
private static readonly SPAWN_X_MIN = 100;
|
||||
/** 怪物登场 X 范围上限(靠近右侧) */
|
||||
private static readonly SPAWN_X_MAX = 320;
|
||||
|
||||
/**
|
||||
* 怪物类型 → 编队优先级(与英雄 HRole 枚举值升序一致):
|
||||
* 近战/重型/近战Boss → 0(最优先,占前排),
|
||||
* 远程/刺客/远程Boss → 1(占中排),
|
||||
* 辅助/召唤师 → 2(占后排)。
|
||||
*/
|
||||
private static readonly MON_TYPE_PRIORITY: Record<number, number> = {
|
||||
[MonType.Melee]: 0,
|
||||
[MonType.Heavy]: 0,
|
||||
[MonType.MeleeBoss]: 0,
|
||||
[MonType.Long]: 1,
|
||||
[MonType.Assassin]: 1,
|
||||
[MonType.LongBoss]: 1,
|
||||
[MonType.Support]: 2,
|
||||
[MonType.Summoner]: 2,
|
||||
};
|
||||
|
||||
/** 槽位基准 Y(3行×4列结构仅供 monGrid 寻路与 SCastSystem 索敌定位) */
|
||||
public static readonly MON_POSITIONS: Vec3[] = [
|
||||
@@ -104,11 +118,16 @@ export class MissionMonCompComp extends CCComp {
|
||||
smc.vmdata.mission_data.pending_mon_num = this.waveTargetCount;
|
||||
|
||||
// 怪物先行登场:玩家侦查 Boss 组合后再做英雄三选一(in_fight 前怪物原地待命,不推进不索敌)
|
||||
const squad = this.spawnQueue;
|
||||
// 按编队优先级排序后依次登场:近战/Boss(0) → 远程/刺客(1) → 辅助/召唤(2)
|
||||
const squad = [...this.spawnQueue].sort((a, b) => {
|
||||
const pa = MissionMonCompComp.MON_TYPE_PRIORITY[a.type] ?? 1;
|
||||
const pb = MissionMonCompComp.MON_TYPE_PRIORITY[b.type] ?? 1;
|
||||
return pa - pb;
|
||||
});
|
||||
this.spawnQueue = [];
|
||||
smc.vmdata.mission_data.pending_mon_num = 0;
|
||||
for (const monData of squad) {
|
||||
this.addMonsterAtGrid(this.waveSpawnedCount, monData, this.currentWave);
|
||||
for (let i = 0; i < squad.length; i++) {
|
||||
this.addMonsterAtGrid(i, squad[i], this.currentWave);
|
||||
this.waveSpawnedCount++;
|
||||
}
|
||||
|
||||
@@ -126,9 +145,24 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
// ======================== 怪物生成 ========================
|
||||
|
||||
/**
|
||||
* 解析怪物出生 X:按编队优先级名次映射三排锚点(与英雄编队排队逻辑一致)。
|
||||
* 名次映射:rank0→前排(MON_ROW_FRONT_X)、rank1→中排(MON_ROW_MID_X)、rank≥2→后排(MON_ROW_BACK_X)。
|
||||
* 效果:高优先级类型永远占据更靠前的排;当更高优先级类型插入时,低优先级类型自动向后让位。
|
||||
*
|
||||
* @param index 当前怪物在排序后列表中的索引(名次)
|
||||
* @returns 出生 X 坐标
|
||||
*/
|
||||
private resolveSpawnX(index: number): number {
|
||||
if (index === 0) return FightSet.MON_ROW_FRONT_X;
|
||||
if (index === 1) return FightSet.MON_ROW_MID_X;
|
||||
return FightSet.MON_ROW_BACK_X;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定位置索引处生成一个怪物
|
||||
* 5 只怪在 X∈[100,320] 内按登场序号均匀铺开,Boss/小怪同时登场直接开打
|
||||
* 怪物按编队优先级名次落排(rank0→前排、rank1→中排、rank≥2→后排),
|
||||
* 与英雄编队排队逻辑一致:高优先级类型永远占更靠前的排,低优先级自动让位。
|
||||
*/
|
||||
private addMonsterAtGrid(
|
||||
posIndex: number,
|
||||
@@ -139,9 +173,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
let scale = -1;
|
||||
|
||||
const basePos = MissionMonCompComp.MON_POSITIONS[posIndex % MissionMonCompComp.MON_POSITIONS.length];
|
||||
const spawnX = MissionMonCompComp.SPAWN_X_MIN
|
||||
+ (MissionMonCompComp.SPAWN_X_MAX - MissionMonCompComp.SPAWN_X_MIN)
|
||||
* (posIndex / Math.max(1, BOSS_COUNT + MINION_COUNT - 1));
|
||||
const spawnX = this.resolveSpawnX(posIndex);
|
||||
const landingY = basePos.y;
|
||||
const spawnPos: Vec3 = v3(spawnX, landingY + MissionMonCompComp.MON_DROP_HEIGHT, 0);
|
||||
this.globalSpawnOrder = (this.globalSpawnOrder + 1) % 999;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* 游戏机制:
|
||||
* - 整局只有一场战斗:开局英雄三次三选一后自动开战。
|
||||
* - 怪物从 BossComboLibrary 按权重随机抽一组(1 Boss + 4 小怪),
|
||||
* - 怪物从 BossComboLibrary 按权重随机抽一组(固定 3 只怪:0~2 Boss + 剩余小怪),
|
||||
* 战斗开始瞬间一次全量登场(X∈[100,320] 均匀铺开),双方立即互相攻击。
|
||||
* - 怪物全灭 → 胜利结算;英雄全灭 → 失败结算;无回合递进、无分批刷怪。
|
||||
*
|
||||
@@ -18,7 +18,7 @@
|
||||
* Boss 基础面板固定为初始英雄 2 倍强度(BOSS_BASE_HP/BOSS_BASE_AP),与小怪共用同一套系数,
|
||||
* 场上 Boss 恰好为小怪 2 倍强度(如需额外压场可调 BOSS_HP_BONUS_MUL)。
|
||||
* 小怪基础面板与 1 级英雄持平(近战镜像 hp300/ap22/cd1.8),默认系数校准为
|
||||
* 整场战斗(3 英雄 vs 4 小怪 + 1 Boss)双方对砍 ≈ WAVE_DURATION(30s)。
|
||||
* 整场战斗(3 英雄 vs 3 只怪)双方对砍 ≈ WAVE_DURATION(30s)。
|
||||
* 手感微调只改 MON_HP_MUL / MON_AP_MUL / BOSS_HP_BONUS_MUL 三个系数即可。
|
||||
*/
|
||||
|
||||
@@ -31,9 +31,10 @@ import { FacSet } from "../common/config/GameSet";
|
||||
/** 单场战斗时长基准(秒):供清屏速度评价(BattleBannerComp 清屏奖励)等使用 */
|
||||
export const WAVE_DURATION = 30;
|
||||
|
||||
/** 怪物登场固定构成:1 个 Boss + 4 个小怪(一次全量登场,打完即整局结束) */
|
||||
export const BOSS_COUNT = 1;
|
||||
export const MINION_COUNT = 4;
|
||||
/** 怪物登场固定构成:单场战斗固定 3 只怪,Boss 数量由组合配置决定(0~2 个),
|
||||
* 剩余位置由小怪填充。例如:3 小怪、1 Boss + 2 小怪、2 Boss + 1 小怪(最大难度) */
|
||||
export const BOSS_COUNT = 2;
|
||||
export const MINION_COUNT = 3;
|
||||
|
||||
/** 怪物血量可调系数:最终 hp = HeroInfo 基础hp × MON_HP_MUL。
|
||||
* 2.6 = 校准后怪物总血量 / 3 英雄 30s 输出(≈30 DPS),双方对砍 ≈ 30s 分胜负 */
|
||||
@@ -104,11 +105,13 @@ export interface BossComboMinionSlot {
|
||||
count: number;
|
||||
}
|
||||
|
||||
/** Boss 组合配置:一场战斗随机抽一组登场(1 Boss + minions 小怪) */
|
||||
/** Boss 组合配置:一场战斗随机抽一组登场(固定 3 只怪,Boss 数量由 bossCount 决定) */
|
||||
export interface BossComboConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
/** 小怪构成(合计数量建议等于 MINION_COUNT,超出截断、不足自动补近战) */
|
||||
/** 本场 Boss 数量(0~2),剩余位置由小怪填充 */
|
||||
bossCount: number;
|
||||
/** 小怪构成(合计数量建议等于 MINION_COUNT - bossCount,超出截断、不足自动补近战) */
|
||||
minions: BossComboMinionSlot[];
|
||||
/** Boss 技能池 id(引用 BossSkillPool,可选) */
|
||||
boss_skill_pool?: string[];
|
||||
@@ -118,37 +121,46 @@ export interface BossComboConfig {
|
||||
weight: number;
|
||||
}
|
||||
|
||||
/** Boss 组合库(硬编码):每场战斗按权重随机抽一组 */
|
||||
/** Boss 组合库(硬编码):每场战斗按权重随机抽一组,固定 3 只怪。
|
||||
* 组合类型:
|
||||
* - 3 小怪(0 Boss):均衡难度
|
||||
* - 1 Boss + 2 小怪:标准难度
|
||||
* - 2 Boss + 1 小怪:最大难度 */
|
||||
export const BossComboLibrary: Record<string, BossComboConfig> = {
|
||||
/** 3 小怪:均衡组合 */
|
||||
rage_charge: {
|
||||
id: "rage_charge", name: "狂暴冲锋组", weight: 10,
|
||||
minions: [{ type: MonType.Melee, count: 3 }, { type: MonType.Heavy, count: 1 }],
|
||||
boss_skill_pool: ["boss_rage"],
|
||||
id: "rage_charge", name: "狂暴冲锋组", weight: 10, bossCount: 0,
|
||||
minions: [{ type: MonType.Melee, count: 2 }, { type: MonType.Heavy, count: 1 }],
|
||||
},
|
||||
iron_wall: {
|
||||
id: "iron_wall", name: "铁壁推进组", weight: 8,
|
||||
minions: [{ type: MonType.Heavy, count: 2 }, { type: MonType.Support, count: 1 }, { type: MonType.Long, count: 1 }],
|
||||
boss_skill_pool: ["boss_iron"],
|
||||
id: "iron_wall", name: "铁壁推进组", weight: 8, bossCount: 0,
|
||||
minions: [{ type: MonType.Heavy, count: 2 }, { type: MonType.Support, count: 1 }],
|
||||
skill_pool: ["tough"],
|
||||
},
|
||||
doom_ritual: {
|
||||
id: "doom_ritual", name: "毁灭仪式组", weight: 6,
|
||||
minions: [{ type: MonType.Summoner, count: 1 }, { type: MonType.Long, count: 2 }, { type: MonType.Support, count: 1 }],
|
||||
boss_skill_pool: ["boss_doom"],
|
||||
id: "doom_ritual", name: "毁灭仪式组", weight: 6, bossCount: 0,
|
||||
minions: [{ type: MonType.Summoner, count: 1 }, { type: MonType.Long, count: 1 }, { type: MonType.Support, count: 1 }],
|
||||
skill_pool: ["warcry"],
|
||||
},
|
||||
/** 1 Boss + 2 小怪:标准难度 */
|
||||
assassin_raid: {
|
||||
id: "assassin_raid", name: "刺客突袭组", weight: 7,
|
||||
minions: [{ type: MonType.Assassin, count: 2 }, { type: MonType.Melee, count: 2 }],
|
||||
id: "assassin_raid", name: "刺客突袭组", weight: 7, bossCount: 1,
|
||||
minions: [{ type: MonType.Assassin, count: 1 }, { type: MonType.Melee, count: 1 }],
|
||||
boss_skill_pool: ["boss_rage", "boss_doom"],
|
||||
skill_pool: ["berserk"],
|
||||
},
|
||||
blood_legion: {
|
||||
id: "blood_legion", name: "吸血军团组", weight: 5,
|
||||
minions: [{ type: MonType.Melee, count: 2 }, { type: MonType.Long, count: 1 }, { type: MonType.Summoner, count: 1 }],
|
||||
id: "blood_legion", name: "吸血军团组", weight: 5, bossCount: 1,
|
||||
minions: [{ type: MonType.Melee, count: 1 }, { type: MonType.Long, count: 1 }],
|
||||
boss_skill_pool: ["boss_iron", "boss_doom"],
|
||||
skill_pool: ["leech"],
|
||||
},
|
||||
/** 2 Boss + 1 小怪:最大难度 */
|
||||
twin_boss: {
|
||||
id: "twin_boss", name: "双王降临", weight: 3, bossCount: 2,
|
||||
minions: [{ type: MonType.Support, count: 1 }],
|
||||
boss_skill_pool: ["boss_rage", "boss_iron", "boss_doom"],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -277,7 +289,7 @@ export const BossSkillPool: Record<string, MonSkillSet> = {
|
||||
export function validateRogueConfig(): string[] {
|
||||
const errors: string[] = [];
|
||||
|
||||
// 1. 校验组合引用与数量
|
||||
// 1. 校验组合引用与数量(固定 3 只怪:bossCount + minionTotal 必须等于 MINION_COUNT)
|
||||
for (const id in BossComboLibrary) {
|
||||
const combo = BossComboLibrary[id];
|
||||
let minionTotal = 0;
|
||||
@@ -287,8 +299,12 @@ export function validateRogueConfig(): string[] {
|
||||
errors.push(`组合 ${id} 引用的怪物类型 ${slot.type}(${MonTypeName[slot.type] || "?"}) 在 MonList 中无可用 uuid`);
|
||||
}
|
||||
}
|
||||
if (minionTotal !== MINION_COUNT) {
|
||||
errors.push(`组合 ${id} 小怪数量=${minionTotal} 与 MINION_COUNT=${MINION_COUNT} 不一致`);
|
||||
const totalMon = combo.bossCount + minionTotal;
|
||||
if (totalMon !== MINION_COUNT) {
|
||||
errors.push(`组合 ${id} 总怪数=${totalMon}(bossCount=${combo.bossCount} + minions=${minionTotal})与 MINION_COUNT=${MINION_COUNT} 不一致`);
|
||||
}
|
||||
if (combo.bossCount < 0 || combo.bossCount > BOSS_COUNT) {
|
||||
errors.push(`组合 ${id} bossCount=${combo.bossCount} 超出允许范围 [0, ${BOSS_COUNT}]`);
|
||||
}
|
||||
if (combo.skill_pool) {
|
||||
for (const skillId of combo.skill_pool) {
|
||||
@@ -371,7 +387,7 @@ export const TestModeConfig = {
|
||||
export class RogueSpawningEngine {
|
||||
|
||||
/**
|
||||
* 生成一场战斗的怪物列表:随机一组 Boss 组合(1 Boss + 4 小怪,属性走基础×系数)。
|
||||
* 生成一场战斗的怪物列表:随机一组 Boss 组合(固定 3 只怪,Boss 数量由 combo.bossCount 决定)。
|
||||
* Boss 压队尾(登场时由 MissionMonComp 统一布位)。
|
||||
* @returns 怪物列表(小怪在前、Boss 在尾)
|
||||
*/
|
||||
@@ -383,6 +399,7 @@ export class RogueSpawningEngine {
|
||||
|
||||
const combo = pickBossCombo();
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
const bossCount = combo ? Math.max(0, Math.min(combo.bossCount, BOSS_COUNT)) : 0;
|
||||
|
||||
if (combo) {
|
||||
for (const slot of combo.minions) {
|
||||
@@ -391,13 +408,14 @@ export class RogueSpawningEngine {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 组合库为空或数量不足兜底:补近战小怪至 MINION_COUNT
|
||||
while (monsters.length < MINION_COUNT) {
|
||||
// 组合库为空或数量不足兜底:补近战小怪至 MINION_COUNT - bossCount
|
||||
const minionTarget = MINION_COUNT - bossCount;
|
||||
while (monsters.length < minionTarget) {
|
||||
monsters.push(this.makeMonster(MonType.Melee, monsters.length));
|
||||
}
|
||||
|
||||
// Boss 压队尾
|
||||
for (let i = 0; i < BOSS_COUNT; i++) {
|
||||
for (let i = 0; i < bossCount; i++) {
|
||||
monsters.push(this.makeBoss());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user