extends CharacterBody3D class_name Character @onready var collision: CollisionShape3D = (%Collision) @onready var pushbox: Hitbox = (%Pushbox as Hitbox) @onready var status: Status = (%Status as Status) @onready var view: View = (%View as View) @onready var buff: Buff = (%Buff as Buff) @onready var skill: Skill = (%Skill as Skill) @onready var battle: Battle = (%Battle as Battle) @onready var effect: Effect = (%Effect as Effect) @onready var move: Move = (%Move as Move) func init(id: int, cfg: CharacterCfg, team: Enum.ETeam, owner_id: int): status.id = id status.owner_id = owner_id status.team = team status.cfg = cfg view.init(cfg.sprite_frames) skill.init() effect.init(cfg.type) effect.cast_self_particle() set_body_scale(cfg) func init_after(): var cfg: CharacterCfg = status.cfg as CharacterCfg set_status("hp_max", cfg.hp_max) set_status("shield_max", cfg.shield.shield_max) set_status("stun_max", cfg.stun.stun_max) set_status("mp_max", cfg.mp.mp_max) set_status("mp_sub_max", cfg.mp.mp_sub_max) set_status("hp", cfg.hp_max) set_shield(cfg.shield.shield_max) add_mp_sub(0, true) func set_body_scale(cfg: CharacterCfg) -> void: if not cfg: cfg = status.cfg if not cfg: return var height: float = Setting.pixel_size * cfg.sprite_height var width: float = Setting.pixel_size * cfg.sprite_width var body_scale: Vector3 = Vector3(width, height, width) var half_height: float = height / 2 var center_height: float = Setting.pixel_size * 26 collision.position = Vector3(0, half_height, 0) collision.scale = body_scale pushbox.position = Vector3(0, half_height, 0) pushbox.scale = body_scale status.basic_offset = Vector3(0, center_height, randf()*0.001) status.ui_offset = Vector3(0, height*1.25, 0) status.ui_center_offset = Vector3(0, center_height, 0) status.radius = width status.height = height effect.set_body_scale(body_scale) func set_material(material: ShaderMaterial, material_sub: ShaderMaterial): view.material_override = material view.material_override.next_pass = material_sub func is_on_stair()->bool: if velocity.x > 0: if raycast_stair(Vector3.RIGHT): return true elif velocity.x < 0: if raycast_stair(Vector3.LEFT): return true if velocity.z > 0: if raycast_stair(Vector3.BACK): return true elif velocity.z < 0: if raycast_stair(Vector3.FORWARD): return true return false func raycast_stair(dir: Vector3)->bool: var width: float = Setting.pixel_size * status.cfg.sprite_width var from: Vector3 = position + (Vector3.UP * Setting.pixel_size * 6) + (dir * width * 0.4) var to: Vector3 = from + dir * width * 0.2 var up: Vector3 = to + Vector3.UP * Setting.pixel_size * 4 return Util.raycast_wall(from, to) and Util.raycast_wall(up, to) #==getter== func id()->int: return status.id func cfg()->CharacterCfg: return status.cfg func team()->Enum.ETeam: return status.team func pos2D()->Vector2: return Vector2(position.x, position.z) func pos()->Vector3: return position func radius()->float: return status.radius func height()->float: return status.height func view_pos()->Vector3: return position + view.position func ui_pos()->Vector3: return position + status.ui_offset func ui_pos_center()->Vector3: return position + status.ui_center_offset func target()->int: return status.target func is_right()->bool: return status.is_right #==interface== func get_status(status_name: String) -> Variant: return status.get_status(status_name) func set_status(status_name: String, value): status.set_status(status_name, value) func set_shield(value: float): status.set_shield(value) func set_pos(pos: Vector3): position = pos SignalManager.character_pos_changed.emit(id(), pos()) func move_to(dir: Vector2): set_status("move_dir", dir.normalized()) func move_stop(): set_status("move_dir", Vector2.ZERO) move.stop() func add_buff(buff_name: String, duration: float, ignore_pause: bool = false): buff.add_buff(buff_name, duration, ignore_pause) func remove_buff(buff_name: String): buff.remove_buff(buff_name) func has_buff(buff_name: String)->bool: return buff.has_buff(buff_name) func set_hit_move(hit_back_dir: Vector2, hit_back_speed: float, hit_up_speed: float): status.hit_back_dir = hit_back_dir status.hit_back_speed = hit_back_speed status.hit_up_speed = hit_up_speed func set_pause_time(pause_time: float): status.pause_time=pause_time add_buff("pause", pause_time) func cancel_skill(): skill.cancel_skill() func set_view_trigger(trigger_name: String): status.set("trigger_%s" % trigger_name, true) func show_hit_text(value: String): SignalManager.character_hit_text.emit(id(), value) func show_hit_damage(value: float): SignalManager.character_hit_damage.emit(id(), value) func add_mp_sub(value: float, from_battle: bool): battle.add_mp_sub(value, from_battle) func cost_mp(value: int): battle.cost_mp(value) func set_target(target: int): set_status("target", target) func set_is_lock(value: bool): set_status("is_lock", value) func cast_particle(resource: Resource, is_attach: bool, offset: Vector3 = Vector3.ZERO, scale: Vector3 = Vector3.ONE): effect.cast_particle(resource, is_attach, offset, scale) func get_character_owner() -> Character: var owner: Character = Global.character_mgr.get_character(status.owner_id) as Character if owner: return owner return self func attack1() -> bool: return battle.character_attack1() func attack2() -> bool: return battle.character_attack2()