extends AnimationPlayer class_name Skill @onready var character: Character = (get_owner() as Character) @onready var view: View = (%View as View) @onready var status: Status = (%Status as Status) @onready var effect: Effect = (%Effect as Effect) @onready var buff: Buff = (%Buff as Buff) var skill_dict: Dictionary = {} #name -> skill var skill_map: Dictionary = {} #input -> skillCfg[] func init(): cancel_skill() func add_skill(action: String, skillCfg: SkillCfg): if not action in skill_map: skill_map[action] = [] skill_map[action].append(skillCfg) skill_dict[skillCfg.get_res_name()] = skillCfg func remove_skill(action: String, skillCfg: SkillCfg) -> void: if not action in skill_map: return skill_map[action].filter(func(cfg): return cfg != skillCfg) skill_dict.erase(skillCfg.get_res_name()) func _process(delta): if status.is_skill_running and status.is_pause == is_playing(): if status.is_pause: pause(); else: play(); func _on_animation_finished(_anim_name): cancel_skill() func cast_skill_by_name(name: String, cast_dir: Vector2): var cfg: SkillCfg = skill_dict.get(name) if cfg: cast_skill(cfg, cast_dir) func cast_skill(cfg: SkillCfg, cast_dir: Vector2, action_key: String = "") -> bool: if cast_dir.length() == 0: cast_dir = Vector2.RIGHT if status.is_right else Vector2.LEFT if !cfg.free_lock and status.target: var target: Character = Global.character_mgr.get_character(status.target) if target: cast_dir = character.pos2D().direction_to(target.pos2D()).normalized() var animation_name: String = "animation_library/%s" % cfg.get_res_name() if not has_animation(animation_name): print("技能animation不存在", animation_name) return false if status.mp < cfg.mp_cost: #todo mp不足 return false break_skill() character.cost_mp(cfg.mp_cost) status.speed_up_rate = -1 status.is_free_control = false status.is_free_turn = false status.is_skill_running = true status.skill_cfg = cfg status.skill_dir = cast_dir status.break_level = Enum.EBreakLevel.None status.stance = cfg.stance_to status.is_charging = cfg.is_charging status.skill_action_key = action_key character.set_body_scale(cfg.get_owner()) if cfg.is_charging: buff.add_buff("charging", -1) if cast_dir.x != 0: status.is_right = cast_dir.x > 0 play(animation_name, -1, Setting.animation_speed_scale) return true func break_skill(): stop() status.speed_up_rate = 0 status.skill_move_speed = 0 status.skill_float_speed = 0 status.is_free_control = true status.is_free_turn = true status.is_skill_running = false status.skill_cfg = null status.break_level = Enum.EBreakLevel.Walk status.speed_down_push_rate = 0 status.skill_move_stop = false status.is_speed_y_freeze = false status.is_charging = false status.charging_level = 0 status.skill_action_key = "" buff.remove_buff("charging") if status.throw_target != 0: var character_to: Character = Global.character_mgr.get_character(status.throw_target) character_to.set_status("is_be_throw", false) status.throw_target = 0 effect.release_effect() func cancel_skill(): break_skill() character.set_body_scale(status.cfg) view.reset() func on_attack_miss(): # 攻击未命中时跳帧 _frame_forward() func on_hold() -> void: _frame_back(0) func on_check_ground(frame_offset: int) -> void: if status.is_on_floor: # 落地检测成功时跳帧 _frame_forward() else: _frame_back(frame_offset) func on_check_charging(charging_level: int) -> void: if status.charging_level >= charging_level: _frame_forward() return if status.mp >= charging_level: status.charging_level += 1 _frame_forward() return _frame_back(1) func _frame_forward() -> void: advance(Setting.animation_frame_rate) func _frame_back(frame_offset: int) -> void: var frame: int = int(current_animation_position / Setting.animation_frame_rate) - frame_offset frame = frame if frame >= 0 else 0 var frame_pos: float = frame * Setting.animation_frame_rate seek(frame_pos- Setting.animation_frame_rate / 2, true, true) func on_cast_sub_character() -> void: var cfg: SkillCfg = status.skill_cfg if not cfg or not cfg.sub_character: return var pos: Vector3 = character.pos() var dir: Vector2 = status.skill_dir Global.character_mgr.create_character(cfg.sub_character, status.team, pos, dir, status.id)