extends Camera3D class_name CameraManager @export var global_effect_curve: Curve var target: int var target_character_pos: Vector2 = Vector2.ZERO var target_pos: Vector2 = Vector2.ZERO var target_pos_y: float var target_pos_now: Vector2 = Vector2.ZERO var level_size: Vector2 = Vector2(12.8, 7.68) var level_pos: Vector2 = Vector2.ZERO var offset: float = 10 var shake_offset_x: float var camera_limit: Vector3 = Vector3(6.4, 1.7, 3.58) #x,z-up,z-down var camera_size: float = 7.2 var basic_size: Vector2 = Vector2(640, 360) var scale_y: float = cos(deg_to_rad(45.0)) * 2.0 #1.414 var sample_rate: float = 3.0 var stage_size: Vector2 = basic_size * sample_rate var stage_scale: Vector2 = Vector2(1, scale_y) / sample_rate var stage_offset_y: float = (scale_y - 1.0) * 0.5 / sample_rate * stage_size.y var screen_pos_scale: Vector2 = Vector2(sample_rate, sample_rate/scale_y) var screen_pos_offset: Vector2 = Vector2(0, -stage_offset_y) var global_effect_list: Array[Variant] = [] class GlobalEffect: var effect_type: Enum.EGlobalEffect var life_time: float var life_time_now: float var value: float func _ready(): Global.camera_mgr = self SignalManager.character_create.connect(on_character_create) SignalManager.character_pos_changed.connect(on_character_pos_changed) SignalManager.character_destroy.connect(on_character_destroy) SignalManager.level_size_change.connect(on_level_size_change) SignalManager.level_pos_change.connect(on_level_pos_change) SignalManager.level_loading_end.connect(on_level_loading_end) func _process(delta): update_global_effect(delta) update_camera_pos(delta) func update_global_effect(delta): var remove_list: Array[Variant] = [] for global_effect: GlobalEffect in global_effect_list: global_effect.life_time_now += delta global_effect.life_time_now = min(global_effect.life_time_now, global_effect.life_time) if global_effect.life_time_now == global_effect.life_time: remove_list.append(global_effect) var rate: float = global_effect.life_time_now/global_effect.life_time var value: float = global_effect_curve.sample(rate)*global_effect.value match global_effect.effect_type: Enum.EGlobalEffect.CameraSize: size = camera_size * (1 - value) refresh_target_pos() Enum.EGlobalEffect.CameraShake: shake_offset_x = (sin(rate * PI * 10) - 0.5)*0.04*value Enum.EGlobalEffect.ColorShift: Global.view_mgr.set_post_processing("shift_strength", value) Enum.EGlobalEffect.Blur: Global.view_mgr.set_post_processing("blur_strength", value) Enum.EGlobalEffect.SpeedLine: Global.view_mgr.set_post_processing("speed_line_strength", value) _: pass for global_effect: GlobalEffect in remove_list: global_effect_list.erase(global_effect) func update_camera_pos(delta): target_pos_lerp(0, delta, 10) target_pos_lerp(1, delta, 10) position.x = target_pos_now.x + shake_offset_x position.z = target_pos_now.y + target_pos_y + offset position.y = target_pos_y + offset func target_pos_lerp(index: int, delta: float, delta_scale: float): var target_pos_real: Vector2 = target_pos var diff = abs(target_pos_now[index] - target_pos_real[index]) if diff < Setting.pixel_size: target_pos_now[index] = Util.snap_float(target_pos_real[index]) else: var weight_min = Setting.pixel_size / 2 / diff var weight = max(delta * delta_scale, weight_min) target_pos_now[index] = lerp(target_pos_now[index], target_pos_real[index], weight) func on_character_create(id: int, type: int, pos: Vector3): if type == Enum.ECharacterType.Player: target = id on_character_pos_changed(id, pos) on_level_loading_end() func on_character_pos_changed(id: int, pos: Vector3): if id == target: target_character_pos.x = pos.x target_character_pos.y = pos.z target_pos_y = pos.y refresh_target_pos() func on_character_destroy(id: int): target = 0 func refresh_target_pos(): var pos: Vector2 = target_character_pos var camera_size_diff: float = (camera_size - size)/2.0 var x_min: float = level_pos.x + camera_limit.x - camera_size_diff var x_max: float = level_pos.x + level_size.x - camera_limit.x + camera_size_diff var y_min: float = level_pos.y + camera_limit.y - target_pos_y - camera_size_diff var y_max: float = level_pos.y + level_size.y - camera_limit.z - target_pos_y + camera_size_diff target_pos.x = clamp(pos.x, x_min, x_max) target_pos.y = clamp(pos.y-target_pos_y, y_min, y_max) func on_level_size_change(size: Vector2): level_size = size func on_level_pos_change(pos: Vector2): level_pos = pos func on_level_loading_end(): target_pos_now.x = target_pos.x target_pos_now.y = target_pos.y func get_screen_pos(pos: Vector3) -> Vector2: var ret: Vector2 = unproject_position(pos) ret.x /= screen_pos_scale.x ret.y /= screen_pos_scale.y ret.x += screen_pos_offset.x ret.y += screen_pos_offset.y return ret func add_global_effect(effect_type: Enum.EGlobalEffect, life_time: float, value: float) -> void: for global_effect: GlobalEffect in global_effect_list: if global_effect.effect_type == effect_type: global_effect.life_time = life_time global_effect.life_time_now = 0 global_effect.value = value return var global_effect = GlobalEffect.new() global_effect.effect_type = effect_type global_effect.life_time = life_time global_effect.life_time_now = 0 global_effect.value = value global_effect_list.append(global_effect) return func effect(pause_time) -> void: if not pause_time: return var basic_pause_time: float = 0.3 var effect_time = pause_time * 2 var rate = pause_time/basic_pause_time add_global_effect(Enum.EGlobalEffect.CameraShake, effect_time, 0.8 * rate) add_global_effect(Enum.EGlobalEffect.CameraSize, effect_time, 0.1 * rate) add_global_effect(Enum.EGlobalEffect.ColorShift, effect_time, 0.8 * rate) add_global_effect(Enum.EGlobalEffect.Blur, effect_time, 0.8 * rate) #add_global_effect(Enum.EGlobalEffect.SpeedLine,effect_time,0.2* rate) return