feat(技能系统): 添加治疗和护盾技能支持
实现治疗和护盾技能的基础功能,包括: 1. 在SACastSystem中添加对治疗和护盾技能类型的支持 2. 新增技能目标选择逻辑,根据技能类型选择敌人或友军 3. 添加buff动画效果和技能提示 4. 更新刘邦的技能配置为护盾技能 5. 移除不再使用的EndAnm相关文件
This commit is contained in:
@@ -29,10 +29,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 10
|
"__id__": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 12
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": {
|
"_prefab": {
|
||||||
"__id__": 12
|
"__id__": 14
|
||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
@@ -259,6 +262,24 @@
|
|||||||
"__type__": "cc.CompPrefabInfo",
|
"__type__": "cc.CompPrefabInfo",
|
||||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "0f3c4JhFbFO2rEFqBJJ7hFv",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 13
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "5dZdUy5cVPjLHtC1SlLIIB"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.PrefabInfo",
|
"__type__": "cc.PrefabInfo",
|
||||||
"root": {
|
"root": {
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
|||||||
buffs:[],neAttrs:[],info:"治疗自己,回复30%最大生命值",
|
buffs:[],neAttrs:[],info:"治疗自己,回复30%最大生命值",
|
||||||
},
|
},
|
||||||
6101:{
|
6101:{
|
||||||
uuid:6101,name:"魔法盾",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Self,SType:SType.buff,act:"buff",DTType:DTType.single,DType:DType.WIND,
|
uuid:6101,name:"魔法盾",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Self,SType:SType.shield,act:"buff",DTType:DTType.single,DType:DType.WIND,
|
||||||
ap:30,map:0,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,dis:80,ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
ap:30,map:0,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,dis:80,ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
|
||||||
buffs:[],neAttrs:[],info:"获得30%最大生命值的护盾",
|
buffs:[],neAttrs:[],info:"获得30%最大生命值的护盾",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export const HeroInfo: Record<number, heroInfo> = {
|
|||||||
|
|
||||||
// 刘邦 - 领导型战士(善于用人,知人善任)
|
// 刘邦 - 领导型战士(善于用人,知人善任)
|
||||||
5001:{uuid:5001,name:"刘邦",path:"hk1", fac:FacSet.HERO, kind:1,as:1.5,
|
5001:{uuid:5001,name:"刘邦",path:"hk1", fac:FacSet.HERO, kind:1,as:1.5,
|
||||||
type:HType.warrior,lv:1,hp:1000,mp:85,map:10,def:9,mdef:0,ap:15,dis:100,speed:120,skills:[6002,6001],
|
type:HType.warrior,lv:1,hp:1000,mp:85,map:10,def:9,mdef:0,ap:15,dis:100,speed:120,skills:[6002,6101],
|
||||||
buff:[],tal:[7101,7201,7301],info:"楚汉争霸领袖,领导统御型战士"},
|
buff:[],tal:[7101,7201,7301],info:"楚汉争霸领袖,领导统御型战士"},
|
||||||
|
|
||||||
// 荆轲 - 刺客(敏捷型,高速度和暴击率)
|
// 荆轲 - 刺客(敏捷型,高速度和暴击率)
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ export class HeroSpine extends Component {
|
|||||||
do_buff(){
|
do_buff(){
|
||||||
this.anm.buff()
|
this.anm.buff()
|
||||||
}
|
}
|
||||||
|
buff(){
|
||||||
|
this.anm.buff()
|
||||||
|
}
|
||||||
move(){
|
move(){
|
||||||
// console.log("change to move",this.status);
|
// console.log("change to move",this.status);
|
||||||
if(this.status=="move") return
|
if(this.status=="move") return
|
||||||
|
|||||||
@@ -438,6 +438,10 @@ export class HeroViewComp extends CCComp {
|
|||||||
case "atk":
|
case "atk":
|
||||||
this.as.atk()
|
this.as.atk()
|
||||||
break
|
break
|
||||||
|
case "buff":
|
||||||
|
this.as.buff()
|
||||||
|
this.tooltip(TooltipTypes.skill, skill.name)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,20 +49,24 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
const readySkills = skills.getReadySkills(heroAttrs.mp);
|
const readySkills = skills.getReadySkills(heroAttrs.mp);
|
||||||
if (readySkills.length === 0) return;
|
if (readySkills.length === 0) return;
|
||||||
|
|
||||||
// 选择第一个可施放的伤害技能
|
// 选择第一个可施放的技能(支持伤害/治疗/护盾)
|
||||||
for (const s_uuid of readySkills) {
|
for (const s_uuid of readySkills) {
|
||||||
const skill = skills.getSkill(s_uuid);
|
const skill = skills.getSkill(s_uuid);
|
||||||
if (!skill) continue;
|
if (!skill) continue;
|
||||||
if (skill.hset === HSSet.max && !skills.max_auto) continue;
|
if (skill.hset === HSSet.max && !skills.max_auto) continue;
|
||||||
|
|
||||||
const config = SkillSet[skill.s_uuid];
|
const config = SkillSet[skill.s_uuid];
|
||||||
if (!config || config.SType !== SType.damage) continue;
|
if (!config) continue;
|
||||||
|
|
||||||
// 检查是否有敌人在技能攻击范围内
|
// 根据技能类型检查目标
|
||||||
if (!this.hasEnemyInSkillRange(heroView, heroAttrs, skill.dis)) continue;
|
if (config.SType === SType.damage) {
|
||||||
|
if (!this.hasEnemyInSkillRange(heroView, heroAttrs, skill.dis)) continue;
|
||||||
|
} else if (config.SType === SType.heal || config.SType === SType.shield) {
|
||||||
|
if (!this.hasAllyInSkillRange(heroView, heroAttrs, skill.dis)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
// ✅ 开始执行施法
|
// ✅ 开始执行施法
|
||||||
this.startCast(e,skill,skill.hset);
|
this.startCast(e, skill, skill.hset);
|
||||||
|
|
||||||
// 一次只施放一个技能
|
// 一次只施放一个技能
|
||||||
break;
|
break;
|
||||||
@@ -151,8 +155,15 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
if (hset === HSSet.max) talComp.updateCur(TriType.MAX);
|
if (hset === HSSet.max) talComp.updateCur(TriType.MAX);
|
||||||
}
|
}
|
||||||
/**********************天赋处理*************************************************************************/
|
/**********************天赋处理*************************************************************************/
|
||||||
// 获取目标位置
|
// 根据技能类型执行不同逻辑
|
||||||
let targets = this.sTargets(heroView, s_uuid);
|
if (config.SType === SType.heal) {
|
||||||
|
return this.executeHealSkill(casterEntity, s_uuid, heroView, hset);
|
||||||
|
} else if (config.SType === SType.shield) {
|
||||||
|
return this.executeShieldSkill(casterEntity, s_uuid, heroView, hset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取目标位置(伤害技能)
|
||||||
|
let targets = this.sTargets(heroView, s_uuid);
|
||||||
if (targets.length === 0) {
|
if (targets.length === 0) {
|
||||||
console.warn("[SACastSystem] 没有找到有效目标");
|
console.warn("[SACastSystem] 没有找到有效目标");
|
||||||
return false;
|
return false;
|
||||||
@@ -349,5 +360,158 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查技能范围内是否有友军
|
||||||
|
*/
|
||||||
|
private hasAllyInSkillRange(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number): boolean {
|
||||||
|
if (!heroView || !heroView.node) return false;
|
||||||
|
|
||||||
|
const currentPos = heroView.node.position;
|
||||||
|
const team = heroAttrs.fac;
|
||||||
|
|
||||||
|
let found = false;
|
||||||
|
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
|
||||||
|
const model = e.get(HeroAttrsComp);
|
||||||
|
const view = e.get(HeroViewComp);
|
||||||
|
if (!view || !view.node) return false;
|
||||||
|
const distance = Math.abs(currentPos.x - view.node.position.x);
|
||||||
|
if (model.fac === team && !model.is_dead) {
|
||||||
|
if (distance <= skillDistance) {
|
||||||
|
found = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行治疗技能
|
||||||
|
*/
|
||||||
|
private executeHealSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean {
|
||||||
|
const heroAttrs = casterEntity.get(HeroAttrsComp);
|
||||||
|
const config = SkillSet[s_uuid];
|
||||||
|
if (!config) return false;
|
||||||
|
|
||||||
|
const targets = this.sHealTargets(heroView, heroAttrs, config);
|
||||||
|
if (targets.length === 0) return false;
|
||||||
|
|
||||||
|
const healAmount = config.ap;
|
||||||
|
const delay = 0.3;
|
||||||
|
|
||||||
|
heroView.scheduleOnce(() => {
|
||||||
|
for (const targetEntity of targets) {
|
||||||
|
const targetAttrs = targetEntity.get(HeroAttrsComp);
|
||||||
|
const targetView = targetEntity.get(HeroViewComp);
|
||||||
|
if (!targetAttrs || !targetView) continue;
|
||||||
|
|
||||||
|
targetAttrs.add_hp(healAmount, false);
|
||||||
|
targetView.health(healAmount);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行护盾技能
|
||||||
|
*/
|
||||||
|
private executeShieldSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean {
|
||||||
|
const heroAttrs = casterEntity.get(HeroAttrsComp);
|
||||||
|
const config = SkillSet[s_uuid];
|
||||||
|
if (!config) return false;
|
||||||
|
|
||||||
|
const targets = this.sShieldTargets(heroView, heroAttrs, config);
|
||||||
|
if (targets.length === 0) return false;
|
||||||
|
|
||||||
|
const shieldAmount = config.ap;
|
||||||
|
const delay = 0.3;
|
||||||
|
|
||||||
|
heroView.scheduleOnce(() => {
|
||||||
|
for (const targetEntity of targets) {
|
||||||
|
const targetAttrs = targetEntity.get(HeroAttrsComp);
|
||||||
|
const targetView = targetEntity.get(HeroViewComp);
|
||||||
|
if (!targetAttrs || !targetView) continue;
|
||||||
|
|
||||||
|
targetAttrs.add_shield(shieldAmount, false);
|
||||||
|
targetView.add_shield(shieldAmount);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择治疗目标
|
||||||
|
*/
|
||||||
|
private sHealTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: any): ecs.Entity[] {
|
||||||
|
const targets: ecs.Entity[] = [];
|
||||||
|
const maxTargets = Math.max(1, Number(config.t_num ?? 1));
|
||||||
|
const range = Number(config.dis ?? 300);
|
||||||
|
|
||||||
|
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
|
||||||
|
const model = e.get(HeroAttrsComp);
|
||||||
|
const view = e.get(HeroViewComp);
|
||||||
|
if (!model || !view || !view.node) return;
|
||||||
|
if (model.fac !== heroAttrs.fac) return;
|
||||||
|
if (model.is_dead) return;
|
||||||
|
|
||||||
|
const distance = Math.abs(caster.node.position.x - view.node.position.x);
|
||||||
|
if (distance <= range) {
|
||||||
|
targets.push(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
targets.sort((a, b) => {
|
||||||
|
const attrsA = a.get(HeroAttrsComp);
|
||||||
|
const attrsB = b.get(HeroAttrsComp);
|
||||||
|
if (!attrsA || !attrsB) return 0;
|
||||||
|
return attrsA.hp - attrsB.hp;
|
||||||
|
});
|
||||||
|
|
||||||
|
return targets.slice(0, maxTargets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择护盾目标
|
||||||
|
*/
|
||||||
|
private sShieldTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: any): ecs.Entity[] {
|
||||||
|
const targets: ecs.Entity[] = [];
|
||||||
|
const maxTargets = Math.max(1, Number(config.t_num ?? 1));
|
||||||
|
const range = Number(config.dis ?? 300);
|
||||||
|
|
||||||
|
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
|
||||||
|
const model = e.get(HeroAttrsComp);
|
||||||
|
const view = e.get(HeroViewComp);
|
||||||
|
if (!model || !view || !view.node) return;
|
||||||
|
if (model.fac !== heroAttrs.fac) return;
|
||||||
|
if (model.is_dead) return;
|
||||||
|
|
||||||
|
const distance = Math.abs(caster.node.position.x - view.node.position.x);
|
||||||
|
if (distance <= range) {
|
||||||
|
targets.push(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return targets.slice(0, maxTargets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据位置查找实体
|
||||||
|
*/
|
||||||
|
private findEntityAtPosition(pos: Vec3): ecs.Entity | null {
|
||||||
|
let foundEntity: ecs.Entity | null = null;
|
||||||
|
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
|
||||||
|
const view = e.get(HeroViewComp);
|
||||||
|
if (!view || !view.node) return false;
|
||||||
|
const distance = Vec3.distance(pos, view.node.position);
|
||||||
|
if (distance < 50) {
|
||||||
|
foundEntity = e;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return foundEntity;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
|
||||||
|
|
||||||
/** EndAnm 模块 */
|
|
||||||
@ecs.register(`EndAnm`)
|
|
||||||
export class EndAnm extends ecs.Entity {
|
|
||||||
/** ---------- 数据层 ---------- */
|
|
||||||
// EndAnmModel!: EndAnmModelComp;
|
|
||||||
|
|
||||||
/** ---------- 业务层 ---------- */
|
|
||||||
// EndAnmBll!: EndAnmBllComp;
|
|
||||||
|
|
||||||
/** ---------- 视图层 ---------- */
|
|
||||||
// EndAnmView!: EndAnmViewComp;
|
|
||||||
|
|
||||||
/** 实始添加的数据层组件 */
|
|
||||||
protected init() {
|
|
||||||
// this.addComponents<ecs.Comp>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 模块资源释放 */
|
|
||||||
destroy() {
|
|
||||||
// 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放
|
|
||||||
super.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** EndAnm 模块业务逻辑系统组件,如无业务逻辑处理可删除此对象 */
|
|
||||||
export class EcsEndAnmSystem extends ecs.System {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// this.add(new ecs.ComblockSystem());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"ver": "4.0.24",
|
|
||||||
"importer": "typescript",
|
|
||||||
"imported": true,
|
|
||||||
"uuid": "1262d5a7-b1a1-49dc-9715-b7e28619304f",
|
|
||||||
"files": [],
|
|
||||||
"subMetas": {},
|
|
||||||
"userData": {}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
|
||||||
import { smc } from "../common/SingletonModuleComp";
|
|
||||||
|
|
||||||
/** 业务层对象 */
|
|
||||||
@ecs.register('EndAnmCom')
|
|
||||||
export class EndAnmComComp extends ecs.Comp {
|
|
||||||
/** 业务层组件移除时,重置所有数据为默认值 */
|
|
||||||
reset() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 业务层业务逻辑处理对象 */
|
|
||||||
export class EndAnmComSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
|
||||||
filter(): ecs.IMatcher {
|
|
||||||
return ecs.allOf(EndAnmComComp);
|
|
||||||
}
|
|
||||||
|
|
||||||
entityEnter(e: ecs.Entity): void {
|
|
||||||
// 注:自定义业务逻辑
|
|
||||||
if(!smc.mission.play || smc.mission.pause) return;
|
|
||||||
e.remove(EndAnmComComp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"ver": "4.0.24",
|
|
||||||
"importer": "typescript",
|
|
||||||
"imported": true,
|
|
||||||
"uuid": "e0728072-f94e-4741-b172-4157e7a3b335",
|
|
||||||
"files": [],
|
|
||||||
"subMetas": {},
|
|
||||||
"userData": {}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user