From ec9c45b42de7012cedf2f04bb253914f50e426b7 Mon Sep 17 00:00:00 2001 From: superhighlevel Date: Mon, 22 Sep 2025 21:10:26 +0700 Subject: [PATCH] Fix bug from MvM Jam --- .../GodotProjectileEngine.gd | 31 ++- .../pattern_composer/component/PCCSingle2D.gd | 4 +- .../pattern_composer/component/PCCSpread2D.gd | 22 +- .../core/pattern_composer/pattern_composer.gd | 5 +- .../projectile_spawner/projectile_spawner.gd | 53 +++-- .../behaviors/projectile_destroy_collision.gd | 16 +- .../projectile_rotation_follow_direction.gd | 1 - .../projectile_updater_2d.gd | 7 +- .../projectile_updater_advanced_2d.gd | 107 ++++----- .../projectile_updater_custom_2d.gd | 5 +- .../projectile_2d/projectile_2d.gd | 206 +++++++++++------- .../projectile_laser_2d.gd | 71 ++++-- .../projectile_node_manager.gd | 6 +- .../projectile_updater_simple_2d.gd | 14 +- .../projectile_wrapper_2d.gd | 21 +- .../base/timing_scheduler_component.gd | 9 +- .../timing_scheduler/cooldown/tsc_cooldown.gd | 7 +- .../core/timing_scheduler/timing_scheduler.gd | 73 ++++--- 18 files changed, 422 insertions(+), 236 deletions(-) diff --git a/addons/godot_projectile_engine/GodotProjectileEngine.gd b/addons/godot_projectile_engine/GodotProjectileEngine.gd index 267f2e90..f92121b4 100644 --- a/addons/godot_projectile_engine/GodotProjectileEngine.gd +++ b/addons/godot_projectile_engine/GodotProjectileEngine.gd @@ -123,7 +123,7 @@ var projectile_wrapper_2d_nodes : Dictionary[String, Array] var projectile_composer_nodes : Dictionary[String, PatternComposer2D] var projectile_updater_2d_nodes : Dictionary[RID, ProjectileUpdater2D] -var projectile_node_manager_2d_nodes : Dictionary[StringName, ProjectileNodeManager2D] +var projectile_node_manager_2d_nodes : Dictionary[ProjectileTemplate2D, ProjectileNodeManager2D] var _projectile_count_temp : int @@ -374,10 +374,35 @@ func get_valid_target_group_nodes(_group_name: String) -> Array[Node2D]: return _valid_nodes -#endregion - +func get_collider_collision_layer(_collider: Node) -> int: + if !_collider: return 0 + if _collider is CollisionObject2D: + return _collider.collision_layer + elif _collider is TileMapLayer: + if !_collider.tile_set: + return 0 + var _tile_set : TileSet = _collider.tile_set + if _tile_set.get_physics_layers_count() <= 0 : + return 0 + for i in range(_tile_set.get_physics_layers_count()): + return _tile_set.get_physics_layer_collision_layer(i) + return 0 + +func get_collider_collision_mask(_collider: Node) -> int: + if _collider is CollisionObject2D: + return _collider.collision_mask + elif _collider is TileMapLayer: + if !_collider.tile_set: + return 0 + var _tile_set : TileSet = _collider.tile_set + if _tile_set.get_physics_layers_count() <= 0 : + return 0 + for i in range(_tile_set.get_physics_layers_count()): + return _tile_set.get_physics_layer_collision_mask(i) + return 0 +#endregion #endregion diff --git a/addons/godot_projectile_engine/core/pattern_composer/component/PCCSingle2D.gd b/addons/godot_projectile_engine/core/pattern_composer/component/PCCSingle2D.gd index 61e2b725..3577fdaf 100644 --- a/addons/godot_projectile_engine/core/pattern_composer/component/PCCSingle2D.gd +++ b/addons/godot_projectile_engine/core/pattern_composer/component/PCCSingle2D.gd @@ -67,7 +67,7 @@ func process_pattern( _pattern_composer_context: PatternComposerContext ) -> Array: - _new_pattern_composer_pack.clear() + _new_pattern_composer_pack = [] for _pattern_composer_data: PatternComposerData in _pattern_composer_pack: _new_pattern_composer_data = _pattern_composer_data.duplicate() _final_rotation = _pattern_composer_data.direction_rotation @@ -106,7 +106,7 @@ func process_pattern( continue DirectionType.MOUSE: - _pattern_composer_data.direction = _pattern_composer_data.position.direction_to(get_mouse_position()) + _new_pattern_composer_data.direction = _new_pattern_composer_data.position.direction_to(get_mouse_position()) _new_pattern_composer_pack.append(_new_pattern_composer_data) continue diff --git a/addons/godot_projectile_engine/core/pattern_composer/component/PCCSpread2D.gd b/addons/godot_projectile_engine/core/pattern_composer/component/PCCSpread2D.gd index 9e77a0ff..37e41ad8 100644 --- a/addons/godot_projectile_engine/core/pattern_composer/component/PCCSpread2D.gd +++ b/addons/godot_projectile_engine/core/pattern_composer/component/PCCSpread2D.gd @@ -35,7 +35,7 @@ func process_pattern( if spread_angle_random != Vector3.ZERO: spread_angle = ProjectileEngine.get_random_float_value(spread_angle_random) - _new_pattern_composer_pack.clear() + _new_pattern_composer_pack = [] match spread_type: SpreadType.STRAIGHT: for _pattern_composer_data: PatternComposerData in _pattern_composer_pack: @@ -58,41 +58,35 @@ var _point_position: Vector2 var _point_direction: Vector2 func _add_projectile_straight_spread(_pattern_composer_data: PatternComposerData) -> Array[PatternComposerData]: - _new_sub_pattern_composer_data.clear() + _new_sub_pattern_composer_data = [] _half_total_width = (spread_amount - 1) * spread_distance / 2.0 for i in range(spread_amount): _new_pattern_composer_data = _pattern_composer_data.duplicate() _offset_distance = (i * spread_distance) - _half_total_width - _new_pattern_composer_data.position += ( - _pattern_composer_data.direction.rotated(deg_to_rad(90) + _pattern_composer_data.direction_rotation) - * _offset_distance - ) + _new_pattern_composer_data.position += (_new_pattern_composer_data.direction * _offset_distance) _new_sub_pattern_composer_data.append(_new_pattern_composer_data) return _new_sub_pattern_composer_data func _add_projectile_angle_spread(_pattern_composer_data: PatternComposerData) -> Array[PatternComposerData]: - _new_sub_pattern_composer_data.clear() + _new_sub_pattern_composer_data = [] _half_total_deg = (spread_amount - 1) * spread_angle / 2.0 for i in range(spread_amount): _new_pattern_composer_data = _pattern_composer_data.duplicate() _offset_angle = (i * spread_angle) - _half_total_deg - _new_pattern_composer_data.direction_rotation += _pattern_composer_data.direction.angle() - deg_to_rad(_offset_angle) + _new_pattern_composer_data.direction = _pattern_composer_data.direction.rotated(deg_to_rad(_offset_angle)).normalized() _new_sub_pattern_composer_data.append(_new_pattern_composer_data) return _new_sub_pattern_composer_data func _add_projectile_hybrid_spread(_pattern_composer_data: PatternComposerData) -> Array[PatternComposerData]: - _new_sub_pattern_composer_data.clear() + _new_sub_pattern_composer_data = [] _half_total_width = (spread_amount - 1) * spread_distance / 2.0 _half_total_deg = (spread_amount - 1) * spread_angle / 2.0 for i in range(spread_amount): _new_pattern_composer_data = _pattern_composer_data.duplicate() _offset_distance = (i * spread_distance) - _half_total_width _offset_angle = (i * spread_angle) - _half_total_deg - _new_pattern_composer_data.position += ( - _pattern_composer_data.direction.rotated(deg_to_rad(90) + _pattern_composer_data.direction_rotation) - * _offset_distance - ) - _new_pattern_composer_data.direction_rotation += _pattern_composer_data.direction.angle() - deg_to_rad(_offset_angle) + _new_pattern_composer_data.direction = _pattern_composer_data.direction.rotated(deg_to_rad(_offset_angle)).normalized() + _new_pattern_composer_data.position += (_new_pattern_composer_data.direction * _offset_distance) _new_sub_pattern_composer_data.append(_new_pattern_composer_data) return _new_sub_pattern_composer_data diff --git a/addons/godot_projectile_engine/core/pattern_composer/pattern_composer.gd b/addons/godot_projectile_engine/core/pattern_composer/pattern_composer.gd index 084367cd..a010aa1c 100644 --- a/addons/godot_projectile_engine/core/pattern_composer/pattern_composer.gd +++ b/addons/godot_projectile_engine/core/pattern_composer/pattern_composer.gd @@ -51,9 +51,6 @@ func _physics_process(delta: float) -> void: ## Take a request pattern to process thorugh Pattern Composer Component to ## return a new Array[PatternComposerData] func request_pattern(_pattern_composer_context : PatternComposerContext) -> Array: - ## Init pattern composer pack - # _init_pattern_composer_data = PatternComposerData.new() - ## Check if can using ProjectileSpawnMarker2Ds _use_projectile_spawn_marker = false if _pattern_composer_context.use_spawn_markers and _pattern_composer_context.projectile_spawn_markers.size() > 0: for _projectile_spawn_marker in _pattern_composer_context.projectile_spawn_markers: @@ -77,6 +74,7 @@ func request_pattern(_pattern_composer_context : PatternComposerContext) -> Arra continue _new_composer_data = PatternComposerData.new() _new_composer_data.projectile_spawn_marker = _projectile_spawn_marker + _new_composer_data.direction = _projectile_spawn_marker.init_direction if _projectile_spawn_marker.use_global_position: _new_composer_data.position = _projectile_spawn_marker.global_position else: @@ -84,6 +82,7 @@ func request_pattern(_pattern_composer_context : PatternComposerContext) -> Arra _pattern_composer_spawner.append(_new_composer_data) else: for _composer_data in _pattern_composer_spawner: + _composer_data.direction = _composer_data.projectile_spawn_marker.init_direction if _composer_data.projectile_spawn_marker.use_global_position: _composer_data.position = _composer_data.projectile_spawn_marker.global_position else: diff --git a/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd b/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd index 78a6c563..689b443d 100644 --- a/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd +++ b/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd @@ -4,6 +4,7 @@ class_name ProjectileSpawner2D signal spawn_timed signal scheduler_completed +signal projectile_spawned(_projectile_template: ProjectileTemplate2D) @export var active : bool = true: set(value): @@ -18,6 +19,8 @@ signal scheduler_completed @export var timing_scheduler : TimingScheduler @export var use_spawn_markers : bool = false @export var audio_stream: AudioStreamPlayer +@export var audio_stream_2d: AudioStreamPlayer2D + var projectile_area : RID @@ -36,6 +39,7 @@ var _pattern_composer_pack : Array func _ready() -> void: + setup_spawn_marker() if active: activate_projectile_spawner() pass @@ -93,12 +97,12 @@ func setup_projectile_spawner() -> void: ProjectileTemplateNode2D: if !is_instance_valid( ProjectileEngine.projectile_node_manager_2d_nodes.get( - projectile_template_2d.projectile_2d_path + projectile_template_2d ) ): create_projectile_node_manager_2d() projectile_node_manager_2d = ProjectileEngine.projectile_node_manager_2d_nodes.get( - projectile_template_2d.projectile_2d_path + projectile_template_2d ) _: return @@ -119,26 +123,34 @@ func spawn_pattern() -> void: pattern_composer_context.position = global_position pattern_composer_context.projectile_template_2d = projectile_template_2d if use_spawn_markers: - setup_spawn_marker() pattern_composer_context.projectile_spawn_markers = projectile_spawn_markers else: pattern_composer_context.projectile_spawn_markers.clear() if typeof(projectile_template_2d) != TYPE_OBJECT: return + if !projectile_composer: + setup_projectile_spawner() + play_audio() match projectile_template_2d.get_script(): ProjectileTemplateNode2D: _pattern_composer_pack = projectile_composer.request_pattern(pattern_composer_context) projectile_node_manager_2d.spawn_projectile_pattern(_pattern_composer_pack) + projectile_spawned.emit(projectile_template_2d) ProjectileTemplateAdvanced2D: _pattern_composer_pack = projectile_composer.request_pattern(pattern_composer_context) projectile_updater_2d.spawn_projectile_pattern(_pattern_composer_pack) + projectile_spawned.emit(projectile_template_2d) + _: _pattern_composer_pack = projectile_composer.request_pattern(pattern_composer_context) projectile_updater_2d.spawn_projectile_pattern(_pattern_composer_pack) + projectile_spawned.emit(projectile_template_2d) + ## built-in classes don't have a script null: return + pass @@ -220,7 +232,7 @@ func create_projectile_node_manager_2d() -> void: ProjectileEngine.projectile_environment.add_child(_projectile_node_manager, true) _projectile_node_manager.owner = ProjectileEngine.projectile_environment ProjectileEngine.projectile_node_manager_2d_nodes.get_or_add( - projectile_template_2d.projectile_2d_path, _projectile_node_manager + projectile_template_2d, _projectile_node_manager ) _projectile_node_manager.setup_projectile_manager() pass @@ -254,36 +266,49 @@ func _spawn_projectile_template_node_2d() -> void: func connect_timing_scheduler() -> void: if !timing_scheduler: return + timing_scheduler.active = true if !timing_scheduler.scheduler_timed.is_connected(spawn_pattern): timing_scheduler.scheduler_timed.connect(spawn_pattern) - timing_scheduler.start_scheduler() pass func disconnect_timing_scheduler() -> void: if !timing_scheduler: return + timing_scheduler.active = false if timing_scheduler.scheduler_timed.is_connected(spawn_pattern): timing_scheduler.scheduler_timed.disconnect(spawn_pattern) - timing_scheduler.stop_scheduler() + # timing_scheduler.stop_scheduler() pass func play_audio() -> void: - if !audio_stream: return - audio_stream.playing = true + # audio_stream.playing = true + if audio_stream_2d: + print("play aduio") + audio_stream_2d.playing = true pass func connect_audio() -> void: - if !audio_stream: return - if !timing_scheduler.scheduler_timed.is_connected(play_audio): - timing_scheduler.scheduler_timed.connect(play_audio) + # if audio_stream_2d: + # projectile_spawned.connect(play_audio) + # if !timing_scheduler.scheduler_timed.is_connected(play_audio): + + # if !audio_stream: return + # if !timing_scheduler.scheduler_timed.is_connected(play_audio): + # timing_scheduler.scheduler_timed.connect(play_audio) + # if !audio_stream_2d: return + # if !timing_scheduler.scheduler_timed.is_connected(play_audio): + # timing_scheduler.scheduler_timed.connect(play_audio) pass func disconnect_audio() -> void: - if !audio_stream: return - if timing_scheduler.scheduler_timed.is_connected(play_audio): - timing_scheduler.scheduler_timed.disconnect(play_audio) + # if !audio_stream: return + # if timing_scheduler.scheduler_timed.is_connected(play_audio): + # timing_scheduler.scheduler_timed.disconnect(play_audio) + # if !audio_stream_2d: return + # if !timing_scheduler.scheduler_timed.is_connected(play_audio): + # timing_scheduler.scheduler_timed.disconnect(play_audio) pass diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/destroy/behaviors/projectile_destroy_collision.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/destroy/behaviors/projectile_destroy_collision.gd index 9329b9c7..089dbe83 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/destroy/behaviors/projectile_destroy_collision.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/destroy/behaviors/projectile_destroy_collision.gd @@ -88,7 +88,8 @@ func process_behavior(_value, _context: Dictionary) -> bool: if destroy_on_body_collide: if _behavior_owner.has_overlapping_bodies(): for _overlap_body in _behavior_owner.get_overlapping_bodies(): - if not _overlap_body.collision_layer & _behavior_owner.collision_mask: + var _overlap_body_collision_layer : int = ProjectileEngine.get_collider_collision_layer(_overlap_body) + if not _overlap_body_collision_layer & _behavior_owner.collision_mask: continue if wait_projectile_piercing: @@ -128,8 +129,16 @@ func process_behavior(_value, _context: Dictionary) -> bool: var _projectile_updater : ProjectileUpdater2D = _behavior_owner.projectile_updater if destroy_on_area_collide: if _projectile_updater.has_overlapping_areas(_behavior_owner.area_index): + # print("ProjectileEngine ProjectileEngine: ", ProjectileEngine) for _overlap_area in _projectile_updater.get_overlapping_areas(_behavior_owner.area_index): - if not _overlap_area.collision_layer & _projectile_updater.projectile_collision_mask: + if !_overlap_area: + _projectile_updater.get_overlapping_areas(_behavior_owner.area_index).erase(_overlap_area) + return true + # print("ProjectileEngine ProjectileEngine: ", ProjectileEngine) + + var _overlap_area_collision_layer : int = ProjectileEngine.get_collider_collision_layer(_overlap_area) + + if not _overlap_area_collision_layer & _projectile_updater.projectile_collision_mask: continue if wait_projectile_piercing: @@ -168,7 +177,8 @@ func process_behavior(_value, _context: Dictionary) -> bool: if destroy_on_body_collide: if _projectile_updater.has_overlapping_bodies(_behavior_owner.area_index): for _overlap_body in _projectile_updater.get_overlapping_bodies(_behavior_owner.area_index): - if not _overlap_body.collision_layer & _projectile_updater.projectile_collision_mask: + var _overlap_body_collision_layer : int = ProjectileEngine.get_collider_collision_layer(_overlap_body) + if not _overlap_body_collision_layer & _projectile_updater.projectile_collision_mask: continue if wait_projectile_piercing: diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/rotation/behaviors/projectile_rotation_follow_direction.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/rotation/behaviors/projectile_rotation_follow_direction.gd index 2fc74b18..b9cb1903 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/rotation/behaviors/projectile_rotation_follow_direction.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/rotation/behaviors/projectile_rotation_follow_direction.gd @@ -19,5 +19,4 @@ func process_behavior(_value: float, _context: Dictionary) -> Dictionary: var _direction := _context.get(ProjectileEngine.BehaviorContext.DIRECTION) var _direction_rotation := _context.get(ProjectileEngine.BehaviorContext.DIRECTION_ROTATION) var _rotation_final : float = _direction.rotated(_direction_rotation).angle() - return {ProjectileEngine.RotationModify.ROTATION_OVERWRITE : _rotation_final} diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_updater/projectile_updater_2d.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_updater/projectile_updater_2d.gd index 5747ed18..0466d01e 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_updater/projectile_updater_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_updater/projectile_updater_2d.gd @@ -118,7 +118,6 @@ func _area_monitor_callback(status: int, area_rid : RID, instance_id: int, area_ return match status: PS.AREA_BODY_ADDED: - ProjectileEngine.projectile_instance_area_shape_entered.emit( projectile_instance_array[self_shape_idx], area_rid, _instance_node, area_shape_idx, @@ -153,7 +152,7 @@ func _area_monitor_callback(status: int, area_rid : RID, instance_id: int, area_ pass func _body_monitor_callback(status: int, body_rid : RID, instance_id: int, body_shape_idx: int, self_shape_idx: int) -> void: - var _instance_node : PhysicsBody2D = instance_from_id(instance_id) + var _instance_node : Node = instance_from_id(instance_id) if !is_instance_valid(_instance_node): return match status: @@ -224,7 +223,6 @@ func draw_projectile_texture() -> void: projectile_texture = projectile_template_2d.texture projectile_texture_modulate = projectile_template_2d.texture_modulate projectile_texture_draw_offset = Vector2.ZERO - projectile_template_2d.texture.get_size() * 0.5 - for index : int in projectile_active_index: draw_set_transform_matrix(projectile_instance_array[index].transform) draw_texture(projectile_texture, projectile_texture_draw_offset, projectile_texture_modulate) @@ -246,7 +244,8 @@ func get_active_projectile_count() -> int: ## Clear all ProjectileInstances in this ProjectileUpdater func clear_projectiles() -> void: for _index in range(projectile_max_pooling): - projectile_active_index.erase(_index) + if projectile_active_index.has(_index): + projectile_active_index.erase(_index) PS.area_set_shape_disabled(projectile_area_rid, _index, true) projectile_active_index.clear() pass diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_updater_advanced_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_updater_advanced_2d.gd index e17f44db..9b7fe0f0 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_updater_advanced_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_updater_advanced_2d.gd @@ -2,44 +2,44 @@ extends ProjectileUpdater2D class_name ProjectileUpdaterAdvanced2D -var projectile_velocity : Vector2 = Vector2.ZERO - -var projectile_life_time_second_max : float = 10.0 -var projectile_life_distance_max : float = 300.0 - -var destroy_on_body_collide : bool -var destroy_on_area_collide : bool - -var projectile_speed_acceleration : float = 0.0 -var projectile_speed_max : float = 0.0 - -var projectile_is_use_homing : bool = false -var projectile_homing_target_group : String -var projetile_max_homing_distance : float -var projectile_steer_speed : float -var projectile_homing_strength : float -var _homing_group_nodes : Array[Node] -var _homing_nearest_target : Node2D -var _homing_nearest_distance : float -var _homing_distance : float -var _homing_target_position : Vector2 -var _homing_distance_to_target : float -var _homing_desired_direction : Vector2 -var _homing_new_direction : Vector2 -var _homing_final_direction : Vector2 - -var projectile_rotation_speed : float -var projectile_rotation_follow_direction : bool -var projectile_direction_follow_rotation : bool - -var projectile_scale_acceleration : float -var projectile_scale_max : Vector2 - -var projectile_is_use_trigger : bool -var projectile_trigger_name : StringName -var projectile_trigger_amount : int -var projectile_trigger_life_time : float -var projectile_trigger_life_distance : float +var projectile_velocity: Vector2 = Vector2.ZERO + +var projectile_life_time_second_max: float = 10.0 +var projectile_life_distance_max: float = 300.0 + +var destroy_on_body_collide: bool +var destroy_on_area_collide: bool + +var projectile_speed_acceleration: float = 0.0 +var projectile_speed_max: float = 0.0 + +var projectile_is_use_homing: bool = false +var projectile_homing_target_group: String +var projetile_max_homing_distance: float +var projectile_steer_speed: float +var projectile_homing_strength: float +var _homing_group_nodes: Array[Node] +var _homing_nearest_target: Node2D +var _homing_nearest_distance: float +var _homing_distance: float +var _homing_target_position: Vector2 +var _homing_distance_to_target: float +var _homing_desired_direction: Vector2 +var _homing_new_direction: Vector2 +var _homing_final_direction: Vector2 + +var projectile_rotation_speed: float +var projectile_rotation_follow_direction: bool +var projectile_direction_follow_rotation: bool + +var projectile_scale_acceleration: float +var projectile_scale_max: Vector2 + +var projectile_is_use_trigger: bool +var projectile_trigger_name: StringName +var projectile_trigger_amount: int +var projectile_trigger_life_time: float +var projectile_trigger_life_distance: float func init_updater_variable() -> void: @@ -49,8 +49,8 @@ func init_updater_variable() -> void: projectile_rotation_follow_direction = projectile_template_2d.rotation_follow_direction projectile_direction_follow_rotation = projectile_template_2d.direction_follow_rotation - projectile_life_time_second_max = projectile_template_2d.life_time_second_max - projectile_life_distance_max = projectile_template_2d.life_distance_max + projectile_life_time_second_max = projectile_template_2d.life_time_second_max + projectile_life_distance_max = projectile_template_2d.life_distance_max destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide @@ -63,12 +63,12 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) projectile_rotation_follow_direction = projectile_template_2d.rotation_follow_direction projectile_direction_follow_rotation = projectile_template_2d.direction_follow_rotation - projectile_life_time_second_max = projectile_template_2d.life_time_second_max - projectile_life_distance_max = projectile_template_2d.life_distance_max + projectile_life_time_second_max = projectile_template_2d.life_time_second_max + projectile_life_distance_max = projectile_template_2d.life_distance_max destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide - for _pattern_composer_data : PatternComposerData in pattern_composer_pack: + for _pattern_composer_data: PatternComposerData in pattern_composer_pack: _projectile_instance = projectile_instance_array[projectile_pooling_index] _projectile_instance = _projectile_instance as ProjectileInstanceAdvanced2D @@ -85,7 +85,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.direction_rotation_speed = deg_to_rad(projectile_template_2d.direction_rotation_speed) _projectile_instance.texture_rotation = projectile_template_2d.texture_rotation - _projectile_instance.texture_rotation_speed = deg_to_rad(projectile_template_2d.texture_rotation_speed) + _projectile_instance.texture_rotation_speed = deg_to_rad(projectile_template_2d.texture_rotation_speed) _projectile_instance.scale = projectile_template_2d.scale _projectile_instance.scale_acceleration = projectile_template_2d.scale_acceleration @@ -214,7 +214,6 @@ func update_projectile_instances(delta: float) -> void: # projectile_speed = projectile_template_2d.speed # projectile_speed_acceleration = projectile_template_2d.speed_acceleration # projectile_speed_max = projectile_template_2d.speed_max - projectile_is_use_homing = projectile_template_2d.is_use_homing if projectile_is_use_homing: projectile_homing_target_group = projectile_template_2d.target_group @@ -228,9 +227,10 @@ func update_projectile_instances(delta: float) -> void: projectile_trigger_life_time = projectile_template_2d.trigger_life_time projectile_trigger_life_distance = projectile_template_2d.trigger_life_distance + var _overlap_collision_layer: int # Check for projectile destroy condition - for index : int in projectile_active_index: + for index: int in projectile_active_index: _projectile_instance = projectile_instance_array[index] # Life Time & Distance @@ -249,20 +249,22 @@ func update_projectile_instances(delta: float) -> void: if destroy_on_area_collide: if has_overlapping_areas(index): for _overlap_area in get_overlapping_areas(index): - if not _overlap_area.collision_layer & projectile_collision_mask: + _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_area) + if not _overlap_collision_layer & projectile_collision_mask: continue projectile_remove_index.append(index) if destroy_on_body_collide: if has_overlapping_bodies(index): for _overlap_body in get_overlapping_bodies(index): - if not _overlap_body.collision_layer & projectile_collision_mask: + _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_body) + if not _overlap_collision_layer & projectile_collision_mask: continue projectile_remove_index.append(index) # Destroy projectile if projectile_remove_index.size() > 0: - for index : int in projectile_remove_index: + for index: int in projectile_remove_index: projectile_active_index.erase(index) if projectile_template_2d.collision_shape: PS.area_set_shape_disabled(projectile_area_rid, index, true) @@ -270,12 +272,11 @@ func update_projectile_instances(delta: float) -> void: # Update active projectile instances array _active_projectile_instances.clear() - for index : int in projectile_active_index: + for index: int in projectile_active_index: _active_projectile_instances.append(projectile_instance_array[index]) if _active_projectile_instances.size() <= 0: return # Update active projectile - for _active_projectile_instance : ProjectileInstanceAdvanced2D in _active_projectile_instances: - + for _active_projectile_instance: ProjectileInstanceAdvanced2D in _active_projectile_instances: if projectile_is_use_trigger: if _active_projectile_instance.trigger_count < projectile_trigger_amount: if projectile_trigger_life_time > 0: @@ -334,7 +335,7 @@ func update_projectile_instances(delta: float) -> void: ) if _active_projectile_instance.texture_rotation_speed != 0: - _active_projectile_instance.texture_rotation += _active_projectile_instance.texture_rotation_speed * delta + _active_projectile_instance.texture_rotation += _active_projectile_instance.texture_rotation_speed * delta if projectile_direction_follow_rotation: _active_projectile_instance.direction_rotation = _active_projectile_instance.texture_rotation diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_updater_custom_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_updater_custom_2d.gd index adda5966..159bd259 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_updater_custom_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_updater_custom_2d.gd @@ -162,7 +162,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) if projectile_pooling_index >= projectile_max_pooling: projectile_pooling_index = 0 - # update_projectile_instances(get_physics_process_delta_time()) + update_projectile_instances(get_physics_process_delta_time()) #endregion @@ -544,6 +544,9 @@ func process_behavior_context_request( ProjectileEngine.BehaviorContext.DIRECTION: _behavior_context.get_or_add(_behavior_context_request, _projectile_instance.direction) + ProjectileEngine.BehaviorContext.DIRECTION_ROTATION: + _behavior_context.get_or_add(_behavior_context_request, _projectile_instance.direction_rotation) + ProjectileEngine.BehaviorContext.BASE_DIRECTION: _behavior_context.get_or_add(_behavior_context_request, _projectile_instance.base_direction) diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_2d/projectile_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_2d/projectile_2d.gd index 08f44905..a3533d34 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_2d/projectile_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_2d/projectile_2d.gd @@ -5,86 +5,94 @@ class_name Projectile2D signal projectile_pierced(projectile_node: Projectile2D, pierced_node: Node2D) signal projectile_instance_pierced(projectile_node: ProjectileInstance2D, pierced_node: Node2D) -@export var active : bool = false -@export var speed : float = 100 -@export var direction : Vector2 = Vector2.RIGHT -@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation : float -@export var collision_shape : CollisionShape2D +@export var active: bool = false +@export var speed: float = 100 +@export var direction: Vector2 = Vector2.RIGHT +@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float +@export var collision_shape: CollisionShape2D # @export var pooling_amount : int = 200 @export_group("Projectile Behavior") @export_subgroup("Transform") -@export var speed_projectile_behaviors : Array[ProjectileBehaviorSpeed] -@export var direction_projectile_behaviors : Array[ProjectileBehaviorDirection] -@export var rotation_projectile_behaviors : Array[ProjectileBehaviorRotation] -@export var scale_projectile_behaviors : Array[ProjectileBehaviorScale] +@export var speed_projectile_behaviors: Array[ProjectileBehaviorSpeed] +@export var direction_projectile_behaviors: Array[ProjectileBehaviorDirection] +@export var rotation_projectile_behaviors: Array[ProjectileBehaviorRotation] +@export var scale_projectile_behaviors: Array[ProjectileBehaviorScale] @export_subgroup("Special") -@export var destroy_projectile_behaviors : Array[ProjectileBehaviorDestroy] -@export var piercing_projectile_behaviors : Array[ProjectileBehaviorPiercing] -@export var bouncing_projectile_behaviors : Array[ProjectileBehaviorBouncing] -@export var trigger_projectile_behaviors : Array[ProjectileBehaviorTrigger] +@export var destroy_projectile_behaviors: Array[ProjectileBehaviorDestroy] +@export var piercing_projectile_behaviors: Array[ProjectileBehaviorPiercing] +@export var bouncing_projectile_behaviors: Array[ProjectileBehaviorBouncing] +@export var trigger_projectile_behaviors: Array[ProjectileBehaviorTrigger] @export_group("Random") @export var speed_random: Vector3 @export var texture_rotation_random: Vector3 @export var scale_random: Vector3 -var projectile_node_manager : ProjectileNodeManager2D -var projectile_node_index : int +var projectile_template_2d : ProjectileTemplate2D -var velocity : Vector2 +var projectile_node_manager: ProjectileNodeManager2D +var projectile_node_index: int = -1 + +var velocity: Vector2 var life_time_second: float -var life_distance : float +var life_distance: float -var base_speed : float -var speed_final : float -var _speed_addition : float -var _speed_multiply : float +var base_speed: float +var speed_final: float +var speed_clamp : Vector2 +var _speed_addition: float +var _speed_multiply: float # var behavior_values : Dictionary -var _speed_behavior_additions : Dictionary -var _speed_behavior_multiplies : Dictionary -var _speed_multiply_value : float - -var base_direction : Vector2 -var base_direction_rotation : float -var raw_direction : Vector2 -var direction_rotation : float -var direction_final : Vector2 -var _direction_behavior_values : Dictionary -var _direction_behavior_additions : Dictionary -var _direction_behavior_rotations : Dictionary -var _direction_rotation_value : float -var _direction_addition_value : Vector2 -var _direction_addition : Vector2 +var _speed_behavior_additions: Dictionary +var _speed_behavior_multiplies: Dictionary +var _base_speed_behavior_multiplies : Dictionary + +var _speed_multiply_value: float + +var base_direction: Vector2 +var base_direction_rotation: float +var raw_direction: Vector2 +var direction_rotation: float +var direction_final: Vector2 +var _direction_behavior_values: Dictionary +var _direction_behavior_additions: Dictionary +var _direction_behavior_rotations: Dictionary +var _direction_rotation_value: float +var _direction_addition_value: Vector2 +var _direction_addition: Vector2 # var projectile_rotation : float -var base_rotation : float -var rotation_final : float -var behavior_values : Dictionary -var _rotation_behavior_additions : Dictionary -var _rotation_behavior_multiplies : Dictionary -var _rotation_multiply_value : float -var _rotation_multiply : float -var _rotation_addition : float - -var projectile_scale : Vector2 -var base_scale : Vector2 -var scale_final : Vector2 +var base_rotation: float +var rotation_final: float +var behavior_values: Dictionary +var _rotation_behavior_additions: Dictionary +var _rotation_behavior_multiplies: Dictionary +var _rotation_multiply_value: float +var _rotation_multiply: float +var _rotation_addition: float + +var projectile_scale: Vector2 +var base_scale: Vector2 +var scale_final: Vector2 # var behavior_values : Dictionary -var _scale_behavior_additions : Dictionary -var _scale_behavior_multiplies : Dictionary -var _scale_multiply_value : Vector2 -var _scale_multiply : Vector2 -var _scale_addition : Vector2 - -var projectile_behavior_context : Dictionary -var _behavior_context_requests_normal : Array[ProjectileEngine.BehaviorContext] -var _behavior_contest_requests_persist : Array[ProjectileEngine.BehaviorContext] -var _normal_behavior_context : Dictionary -var _persist_behavior_context : Dictionary -var projectile_behaviors : Array[ProjectileBehavior] = [] +var _scale_behavior_additions: Dictionary +var _scale_behavior_multiplies: Dictionary +var _scale_multiply_value: Vector2 +var _scale_multiply: Vector2 +var _scale_addition: Vector2 + +var projectile_behavior_context: Dictionary +var _behavior_context_requests_normal: Array[ProjectileEngine.BehaviorContext] +var _behavior_contest_requests_persist: Array[ProjectileEngine.BehaviorContext] +var _normal_behavior_context: Dictionary +var _persist_behavior_context: Dictionary +var projectile_behaviors: Array[ProjectileBehavior] = [] + +var velocity_addition: Vector2 + func _set(property: StringName, value: Variant) -> bool: match property: @@ -122,6 +130,7 @@ func apply_pattern_composer_data(_pattern_composer_data: PatternComposerData) -> func setup_projectile_2d() -> void: + init_base_properties() setup_projectile_behavior() update_projectile_2d(get_physics_process_delta_time()) @@ -129,6 +138,7 @@ func setup_projectile_2d() -> void: func init_base_properties() -> void: + process_randomness() base_speed = speed base_direction = direction base_rotation = texture_rotation @@ -136,6 +146,15 @@ func init_base_properties() -> void: base_scale = scale projectile_scale = scale +func apply_custom_data() -> void: + if !projectile_template_2d: return + if projectile_template_2d.custom_data.size() <= 0: return + if !projectile_template_2d.custom_data[0] is Dictionary: return + for _key in projectile_template_2d.custom_data[0]: + # print(_key, " - ", projectile_template_2d.custom_data[0].get(_key)) + set(_key, projectile_template_2d.custom_data[0].get(_key)) + # print(get(_key)) + func setup_projectile_behavior() -> void: projectile_behaviors.clear() @@ -195,7 +214,7 @@ func update_projectile_2d(delta: float) -> void: continue if !_trigger_behavior.active: continue - var _trigger_behavior_values : Dictionary = _trigger_behavior.process_behavior(null, projectile_behavior_context) + var _trigger_behavior_values: Dictionary = _trigger_behavior.process_behavior(null, projectile_behavior_context) if _trigger_behavior_values.has("is_trigger"): if _trigger_behavior_values.is_trigger: ProjectileEngine.projectile_node_triggered.emit(_trigger_behavior.trigger_name, self) @@ -210,7 +229,7 @@ func update_projectile_2d(delta: float) -> void: if !_projectile_behavior.active: continue - var _piercing_behavior_values : Dictionary = _projectile_behavior.process_behavior(null, projectile_behavior_context) + var _piercing_behavior_values: Dictionary = _projectile_behavior.process_behavior(null, projectile_behavior_context) if _piercing_behavior_values.size() <= 0: continue @@ -230,10 +249,10 @@ func update_projectile_2d(delta: float) -> void: ProjectileEngine.projectile_environment.projectile_bouncing_helper.collision_layer = self.collision_layer ProjectileEngine.projectile_environment.projectile_bouncing_helper.collision_mask = self.collision_mask - var _bouncing_behavior_values : Dictionary = _projectile_behavior.process_behavior(null, projectile_behavior_context) + var _bouncing_behavior_values: Dictionary = _projectile_behavior.process_behavior(null, projectile_behavior_context) if _bouncing_behavior_values.size() <= 0: continue - if _bouncing_behavior_values.has("is_bouncing"): #and _bouncing_behavior_values.has(ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE): + if _bouncing_behavior_values.has("is_bouncing"): # and _bouncing_behavior_values.has(ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE): direction = _bouncing_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE) pass @@ -255,15 +274,28 @@ func update_projectile_2d(delta: float) -> void: continue if not _projectile_behavior.active: continue - behavior_values = _projectile_behavior.process_behavior(speed, projectile_behavior_context) + behavior_values = _projectile_behavior.process_behavior( + speed, + projectile_behavior_context + ) for _behavior_key in behavior_values.keys(): match _behavior_key: ProjectileEngine.SpeedModify.SPEED_OVERWRITE: speed = behavior_values.get(ProjectileEngine.SpeedModify.SPEED_OVERWRITE) ProjectileEngine.SpeedModify.SPEED_ADDITION: - _speed_behavior_additions.get_or_add(_projectile_behavior, behavior_values.get(ProjectileEngine.SpeedModify.SPEED_ADDITION)) + _speed_behavior_additions.get_or_add( + _projectile_behavior, behavior_values.get(ProjectileEngine.SpeedModify.SPEED_ADDITION) + ) ProjectileEngine.SpeedModify.SPEED_MULTIPLY: - _speed_behavior_multiplies.get_or_add(_projectile_behavior, behavior_values.get(ProjectileEngine.SpeedModify.SPEED_MULTIPLY)) + _speed_behavior_multiplies.get_or_add( + _projectile_behavior, behavior_values.get(ProjectileEngine.SpeedModify.SPEED_MULTIPLY) + ) + ProjectileEngine.SpeedModify.BASE_SPEED_MULTIPLY: + _base_speed_behavior_multiplies.get_or_add( + _projectile_behavior, behavior_values.get(ProjectileEngine.SpeedModify.BASE_SPEED_MULTIPLY) + ) + ProjectileEngine.SpeedModify.SPEED_CLAMP: + speed_clamp = behavior_values.get(ProjectileEngine.SpeedModify.SPEED_CLAMP) if direction_projectile_behaviors.size() > 0: _direction_behavior_rotations.clear() @@ -280,12 +312,12 @@ func update_projectile_2d(delta: float) -> void: direction = _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE) ProjectileEngine.DirectionModify.DIRECTION_ROTATION: _direction_behavior_rotations.get_or_add( - _projectile_behavior, + _projectile_behavior, _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_ROTATION) ) ProjectileEngine.DirectionModify.DIRECTION_ADDITION: _direction_behavior_additions.get_or_add( - _projectile_behavior, + _projectile_behavior, _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_ADDITION) ) @@ -305,7 +337,7 @@ func update_projectile_2d(delta: float) -> void: ProjectileEngine.RotationModify.ROTATION_OVERWRITE) ProjectileEngine.RotationModify.ROTATION_ADDITION: _rotation_behavior_additions.get_or_add( - _projectile_behavior, + _projectile_behavior, behavior_values.get(ProjectileEngine.RotationModify.ROTATION_ADDITION)) if scale_projectile_behaviors.size() > 0: _scale_behavior_additions.clear() @@ -359,23 +391,30 @@ func update_projectile_2d(delta: float) -> void: _direction_rotation_value = 0 for _direction_behavior_rotation in _direction_behavior_rotations.values(): _direction_rotation_value += _direction_behavior_rotation - direction_rotation = base_direction_rotation + _direction_rotation_value + direction_rotation = base_direction_rotation + _direction_rotation_value direction_final = direction_final.rotated(direction_rotation).normalized() + ## Apply Projectile behaviors Speed speed_final = speed - if _speed_behavior_multiplies.size() > 0: - _speed_multiply_value = 0 - for _speed_behavior_multiply in _speed_behavior_multiplies.values(): - _speed_multiply_value += _speed_behavior_multiply - _speed_multiply = base_speed * _speed_multiply_value - speed_final += _speed_multiply if _speed_behavior_additions.size() > 0: _speed_addition = 0 for _speed_behavior_addition in _speed_behavior_additions.values(): _speed_addition += _speed_behavior_addition speed_final += _speed_addition + if _speed_behavior_multiplies.size() > 0: + _speed_multiply_value = 0 + for _speed_behavior_multiply in _speed_behavior_multiplies.values(): + _speed_multiply_value += _speed_behavior_multiply - 1.0 + _speed_multiply = speed * _speed_multiply_value + speed_final += _speed_multiply + if _base_speed_behavior_multiplies.size() > 0: + _speed_multiply_value = 0 + for _base_speed_behavior_multiply in _base_speed_behavior_multiplies.values(): + _speed_multiply_value += _base_speed_behavior_multiply + _speed_multiply = base_speed * _speed_multiply_value + speed_final += _speed_multiply - velocity = speed_final * direction_final * delta + velocity = speed_final * direction_final * delta + velocity_addition global_position += velocity rotation = rotation_final scale = scale_final @@ -440,8 +479,17 @@ func process_behavior_context_request( pass return +func process_randomness() -> void: + if speed_random != Vector3.ZERO: + speed = ProjectileEngine.get_random_float_value(speed_random) + if texture_rotation_random != Vector3.ZERO: + texture_rotation = ProjectileEngine.get_random_float_value(texture_rotation_random) + + func queue_free_projectile() -> void: - projectile_node_manager.active_nodes.erase(self) + if projectile_node_manager: + if projectile_node_manager.active_nodes.has(self): + projectile_node_manager.active_nodes.erase(self) if projectile_node_index >= 0: active = false visible = false diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_laser_2d/projectile_laser_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_laser_2d/projectile_laser_2d.gd index b61bd486..d197d80a 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_laser_2d/projectile_laser_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_laser_2d/projectile_laser_2d.gd @@ -64,7 +64,11 @@ enum LaserType { var laser_line_2d : Line2D +var _current_laser_length: float = 0 + func _ready() -> void: + apply_custom_data() + collision_width = laser_width + 2 super() pass @@ -73,16 +77,22 @@ func setup_projectile_2d() -> void: init_base_properties() setup_projectile_behavior() update_projectile_2d(get_physics_process_delta_time()) + setup_collision_raycast() setup_projectile_laser() pass func _physics_process(delta: float) -> void: super(delta) + + update_collision_raycast() + if start_full_length: laser_line_2d.clear_points() laser_line_2d.add_point(laser_line_2d.position) - laser_line_2d.add_point(laser_line_2d.position + direction.rotated(direction_rotation) * laser_length) - collision_shape.global_position = global_position + direction.rotated(direction_rotation) * laser_length / 2 + laser_line_2d.add_point(laser_line_2d.position + direction * _current_laser_length) + collision_shape.position = laser_line_2d.position + direction * _current_laser_length / 2 + collision_shape.shape.size = Vector2(_current_laser_length, collision_width) + collision_shape.rotation = direction.angle() else: laser_line_2d.clear_points() match laser_type: @@ -93,22 +103,24 @@ func _physics_process(delta: float) -> void: laser_line_2d.add_point(laser_line_2d.position) collision_shape.global_position = global_position - direction_final * life_distance / 2 collision_shape.shape.size = Vector2(life_distance, collision_width) - collision_shape.rotation = direction_rotation + # collision_shape.rotation = direction_rotation else: laser_line_2d.add_point(laser_line_2d.position - direction_final * laser_length) laser_line_2d.add_point(laser_line_2d.position) collision_shape.global_position = global_position - direction_final * laser_length / 2 collision_shape.shape.size = Vector2(laser_length, collision_width) - collision_shape.rotation = direction_rotation + # collision_shape.rotation = direction_rotation _: pass - # update_laser_line_2d() + # print("lazer: ", collision_shape.global_position) + pass func update_laser_line_2d() -> void: if !laser_line_2d: return + update_collision_raycast() laser_line_2d.texture = texture laser_line_2d.texture_mode = texture_mode laser_line_2d.width_curve = width_curve @@ -120,12 +132,13 @@ func update_laser_line_2d() -> void: match laser_type: LaserType.STRAIGHT: laser_line_2d.add_point(laser_line_2d.position) - laser_line_2d.add_point(laser_line_2d.position + direction_final * laser_length) + laser_line_2d.add_point(laser_line_2d.position + direction * _current_laser_length) _: pass - collision_shape.global_position = global_position + direction_final * laser_length / 2 - collision_shape.shape.size = Vector2(laser_length, collision_width) - collision_shape.rotation = direction_rotation + collision_shape.position = laser_line_2d.position + direction * _current_laser_length / 2 + collision_shape.shape.size = Vector2(_current_laser_length, collision_width) + collision_shape.rotation = direction.angle() + # collision_shape.rotation = direction_rotation pass @@ -133,13 +146,6 @@ func setup_projectile_laser() -> void: if laser_line_2d: laser_line_2d.queue_free() laser_line_2d = Line2D.new() - laser_line_2d.texture = texture - laser_line_2d.texture_mode = texture_mode - laser_line_2d.width_curve = width_curve - laser_line_2d.joint_mode = Line2D.LINE_JOINT_ROUND - laser_line_2d.begin_cap_mode = begin_cap_mode - laser_line_2d.end_cap_mode = end_cap_mode - laser_line_2d.width = laser_width add_child(laser_line_2d, true) laser_line_2d.clear_points() if !collision_shape: @@ -151,15 +157,32 @@ func setup_projectile_laser() -> void: var _rect_shape = RectangleShape2D.new() collision_shape.shape = _rect_shape if start_full_length: - laser_line_2d.add_point(laser_line_2d.position) - laser_line_2d.add_point(laser_line_2d.position + direction.rotated(direction_rotation) * laser_length) - collision_shape.shape.size = Vector2(laser_length, laser_width) * 0.8 - collision_shape.global_position = global_position + direction.rotated(direction_rotation) * laser_length / 2 + _current_laser_length = laser_length + pass else: - collision_shape.position = global_position + collision_shape.position = position collision_shape.shape.size = Vector2(1, collision_width) + update_laser_line_2d() + pass + + + +var collision_raycast: RayCast2D + +func setup_collision_raycast() -> void: + collision_raycast = RayCast2D.new() + add_child(collision_raycast) + collision_raycast.set_collision_mask_value(6, true) + pass + + +func update_collision_raycast() -> void: + collision_raycast.global_position = laser_line_2d.global_position + collision_raycast.target_position = direction * laser_length + collision_raycast.force_raycast_update() + if collision_raycast.is_colliding(): + _current_laser_length = collision_raycast.global_position.distance_to(collision_raycast.get_collision_point()) + else: + _current_laser_length = laser_length - collision_shape.rotation = direction_rotation - _: - pass pass diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_node_manager.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_node_manager.gd index 35a3af52..ca0663d6 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_node_manager.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_node_manager.gd @@ -33,7 +33,7 @@ func setup_projectile_manager() -> void: print_debug(_instantiate_node, " is not Projectile2D") _is_valid_projectile_node_2d = false return - + _is_valid_projectile_node_2d = true create_projectile_pool() pass @@ -47,6 +47,7 @@ func create_projectile_pool() -> void: return for _index in projectile_max_pooling: _projectile_node_2d = projectile_node_2d_packedscene.instantiate() + _projectile_node_2d.projectile_template_2d = projectile_template_2d _projectile_node_2d.projectile_node_manager = self _projectile_node_2d.projectile_node_index = _index _projectile_node_2d.active = false @@ -67,6 +68,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) if projectile_max_pooling > 0: for _pattern_composer_data : PatternComposerData in pattern_composer_pack: _projectile_node_2d = projectile_node_array[projectile_pooling_index] + _projectile_node_2d.projectile_template_2d = projectile_template_2d _projectile_node_2d.active = true _projectile_node_2d.visible = true _projectile_node_2d.monitoring = true @@ -85,7 +87,9 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) pass else: for _pattern_composer_data : PatternComposerData in pattern_composer_pack: + _projectile_node_2d = null _projectile_node_2d = projectile_node_2d_packedscene.instantiate() + _projectile_node_2d.projectile_template_2d = projectile_template_2d _projectile_node_2d.projectile_node_manager = self _projectile_node_2d.projectile_node_index = -1 _projectile_node_2d.apply_pattern_composer_data(_pattern_composer_data) diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_updater_simple_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_updater_simple_2d.gd index edcf87c3..fe24e233 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_updater_simple_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_updater_simple_2d.gd @@ -104,11 +104,11 @@ func update_projectile_instances(delta: float) -> void: projectile_life_time_second_max = projectile_template_2d.life_time_second_max projectile_life_distance_max = projectile_template_2d.life_distance_max projectile_texture_rotate_direction = projectile_template_2d.texture_rotate_direction + var _overlap_collision_layer : int # Check for projectile destroy condition for index: int in projectile_active_index: _projectile_instance = projectile_instance_array[index] - # Life Time & Distance if _projectile_instance.life_time_second_max >= 0: _projectile_instance.life_time_second += delta @@ -125,14 +125,22 @@ func update_projectile_instances(delta: float) -> void: if destroy_on_area_collide: if has_overlapping_areas(index): for _overlap_area in get_overlapping_areas(index): - if not _overlap_area.collision_layer & projectile_collision_mask: + # if !ProjectileEngine: return + _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_area) + if not _overlap_collision_layer & projectile_collision_mask: continue projectile_remove_index.append(index) if destroy_on_body_collide: if has_overlapping_bodies(index): for _overlap_body in get_overlapping_bodies(index): - if not _overlap_body.collision_layer & projectile_collision_mask: + # print("ProjectileEngine ProjectileEngine: ", ProjectileEngine) + # print(_overlap_body) + if !_overlap_body: + get_overlapping_bodies(index).erase(_overlap_body) + continue + _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_body) + if !_overlap_collision_layer & projectile_collision_mask: continue projectile_remove_index.append(index) diff --git a/addons/godot_projectile_engine/core/projectile_wrapper/projectile_wrapper_2d.gd b/addons/godot_projectile_engine/core/projectile_wrapper/projectile_wrapper_2d.gd index 4f060fc8..ceb3be68 100644 --- a/addons/godot_projectile_engine/core/projectile_wrapper/projectile_wrapper_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_wrapper/projectile_wrapper_2d.gd @@ -2,14 +2,19 @@ extends Node2D class_name ProjectileWrapper2D +signal projectile_wrapper_finished + @export var active : bool = false: set(value): active = value if is_instance_valid(projectile_spawner_2d): projectile_spawner_2d.active = value + for _spawner in projectile_spawners: + if is_instance_valid(_spawner): + _spawner.active = value @export var projectile_wrapper_name : String @export var projectile_spawner_2d : ProjectileSpawner2D - +@export var projectile_spawners: Array[ProjectileSpawner2D] @@ -21,6 +26,9 @@ func _ready() -> void: _register_projectile_wrapper(projectile_wrapper_name) if active and is_instance_valid(projectile_spawner_2d): projectile_spawner_2d.active = active + if projectile_spawner_2d: + if projectile_spawner_2d.timing_scheduler: + connect_timing_scheduler() func _register_projectile_wrapper(_projectile_wrapper_name: String) -> void: if _projectile_wrapper_name == "": return @@ -39,4 +47,13 @@ func _deregister_projectile_wrapper(_projectile_wrapper_name: String) -> void: _projectile_wrapper_nodes.erase(self) if _projectile_wrapper_nodes.size() <= 0: ProjectileEngine.projectile_wrapper_2d_nodes.erase(_projectile_wrapper_name) - + + +func connect_timing_scheduler() -> void: + projectile_spawner_2d.timing_scheduler.scheduler_completed.connect(_on_timing_scheduler_completed) + pass + + +func _on_timing_scheduler_completed() -> void: + projectile_wrapper_finished.emit() + pass \ No newline at end of file diff --git a/addons/godot_projectile_engine/core/timing_scheduler/base/timing_scheduler_component.gd b/addons/godot_projectile_engine/core/timing_scheduler/base/timing_scheduler_component.gd index 0429d0eb..8b76cd00 100644 --- a/addons/godot_projectile_engine/core/timing_scheduler/base/timing_scheduler_component.gd +++ b/addons/godot_projectile_engine/core/timing_scheduler/base/timing_scheduler_component.gd @@ -10,14 +10,21 @@ enum UpdateMode { INHERIT, ## Inherit the [code]update_mode[/code] from the parent TimingScheduler node. } +enum TimingMode { + INSTANT, ## Timed instantly when process + RELEASE, ## Timed after timing finished + NO, ## No timed emited. +} + @export var active : bool = true: set(value): active = value if !value: clear_timing_timer() - +@export var timing_mode: TimingMode = TimingMode.INSTANT @export var update_mode: UpdateMode = UpdateMode.INHERIT + var timing_timer: Timer var request_stop : bool = false diff --git a/addons/godot_projectile_engine/core/timing_scheduler/cooldown/tsc_cooldown.gd b/addons/godot_projectile_engine/core/timing_scheduler/cooldown/tsc_cooldown.gd index 238ff3af..ebb8e73c 100644 --- a/addons/godot_projectile_engine/core/timing_scheduler/cooldown/tsc_cooldown.gd +++ b/addons/godot_projectile_engine/core/timing_scheduler/cooldown/tsc_cooldown.gd @@ -9,16 +9,19 @@ class_name TSCCooldown ## Starts the cooldown timer with the next timing value func start_next_timing_value() -> void: - tsc_timed.emit() + if timing_mode == TimingMode.INSTANT: + tsc_timed.emit() # If duration is 0 or negative, complete immediately if cooldown_duration <= 0.0: tsc_completed.emit() return - # Start the timer with the cooldown duration timing_timer.start(cooldown_duration) + ## Called when the cooldown timer completes func on_timing_timer_timeout() -> void: + if timing_mode == TimingMode.RELEASE: + tsc_timed.emit() tsc_completed.emit() diff --git a/addons/godot_projectile_engine/core/timing_scheduler/timing_scheduler.gd b/addons/godot_projectile_engine/core/timing_scheduler/timing_scheduler.gd index 1d4153d5..333be1f1 100644 --- a/addons/godot_projectile_engine/core/timing_scheduler/timing_scheduler.gd +++ b/addons/godot_projectile_engine/core/timing_scheduler/timing_scheduler.gd @@ -26,8 +26,10 @@ enum StopMethod { SOFT_STOP, ## Finish current timing scheduler component before stopping } -const _DEFAULT_SEQUENCE_INDEX : int = -1 +const _DEFAULT_SEQUENCE_INDEX: int = -1 + +@export var active: bool = false ## If true, scheduler starts automatically when added to scene tree @export var autostart: bool = false @@ -38,34 +40,37 @@ const _DEFAULT_SEQUENCE_INDEX : int = -1 @export var update_method: UpdateMethod = UpdateMethod.TIMER ## Stop method (HARD_STOP or SOFT_STOP) -@export var stop_method : StopMethod = StopMethod.SOFT_STOP +@export var stop_method: StopMethod = StopMethod.SOFT_STOP ## Array of TimingSchedulerComponent nodes in sequence -var tsc_sequence : Array[TimingSchedulerComponent] +var tsc_sequence: Array[TimingSchedulerComponent] ## Current index in the timing sequence -var tsc_sequence_index : int = _DEFAULT_SEQUENCE_INDEX +var tsc_sequence_index: int = _DEFAULT_SEQUENCE_INDEX ## Currently active timing component -var current_tsc : TimingSchedulerComponent +var current_tsc: TimingSchedulerComponent ## Pause state of the scheduler -var paused : bool = true +var paused: bool = true -var _is_queue_soft_stop : bool = false +var _is_queue_soft_stop: bool = false -var _is_just_started : bool = false +var _is_just_started: bool = false func _ready() -> void: if autostart: call_deferred("start_scheduler") - func _physics_process(delta: float) -> void: - if _is_just_started: - _start_timing_scheduler() - _is_just_started = false + if active: + if paused: + start_scheduler() + start_timing_scheduler() + else: + if !paused: + stop_scheduler() pass @@ -74,22 +79,19 @@ func start_scheduler() -> void: if !paused: return _build_tsc_sequence() - _is_just_started = true ## Stops the timing scheduler using configured stop method func stop_scheduler() -> void: match stop_method: StopMethod.HARD_STOP: - _hard_stop_timing_scheduler() + hard_stop_timing_scheduler() StopMethod.SOFT_STOP: - _soft_stop_timing_scheduler() + soft_stop_timing_scheduler() - -func _start_timing_scheduler() -> void: - if tsc_sequence.is_empty(): +func start_timing_scheduler() -> void: + if tsc_sequence.is_empty(): return - if start_next_tsc(): paused = false else: @@ -97,21 +99,29 @@ func _start_timing_scheduler() -> void: scheduler_completed.emit() -func _hard_stop_timing_scheduler() -> void: +func force_stop_timing_scheduler() -> void: + if current_tsc: + current_tsc.stop_tsc() + _disconnect_tsc_signals(current_tsc) + current_tsc = null + paused = true + tsc_sequence_index = _DEFAULT_SEQUENCE_INDEX + pass + +func hard_stop_timing_scheduler() -> void: if not current_tsc: return - current_tsc.stop_tsc() _disconnect_tsc_signals(current_tsc) current_tsc = null paused = true tsc_sequence_index = _DEFAULT_SEQUENCE_INDEX + scheduler_completed.emit() -func _soft_stop_timing_scheduler() -> void: +func soft_stop_timing_scheduler() -> void: if not current_tsc: return - _disconnect_tsc_signals(current_tsc) current_tsc.request_stop = true if !current_tsc.tsc_completed.is_connected(_on_soft_stop_tsc_completed): @@ -138,8 +148,7 @@ func start_next_tsc() -> bool: current_tsc.stop_tsc() _disconnect_tsc_signals(current_tsc) current_tsc = next_tsc - current_tsc.tsc_timed.connect(_on_tsc_timed) - current_tsc.tsc_completed.connect(_on_tsc_completed) + _connect_tsc_signals(current_tsc) current_tsc.start_tsc() return true @@ -169,11 +178,13 @@ func _on_tsc_timed() -> void: ## Handles completion events from current component func _on_tsc_completed() -> void: - if not start_next_tsc(): + if !start_next_tsc(): _disconnect_tsc_signals(current_tsc) current_tsc = null paused = true + active = false tsc_sequence_index = _DEFAULT_SEQUENCE_INDEX + scheduler_completed.emit() ## Handles completion during soft stop @@ -183,10 +194,20 @@ func _on_soft_stop_tsc_completed() -> void: current_tsc.tsc_completed.disconnect(_on_soft_stop_tsc_completed) current_tsc = null tsc_sequence_index = _DEFAULT_SEQUENCE_INDEX + scheduler_completed.emit() +func _connect_tsc_signals(tsc: TimingSchedulerComponent) -> void: + if !tsc: return + if !tsc.is_connected("tsc_timed", _on_tsc_timed): + tsc.tsc_timed.connect(_on_tsc_timed) + if !tsc.is_connected("tsc_completed", _on_tsc_completed): + tsc.tsc_completed.connect(_on_tsc_completed) + pass + ## Disconnects signals from a timing component func _disconnect_tsc_signals(tsc: TimingSchedulerComponent) -> void: + if !tsc: return if tsc.is_connected("tsc_timed", _on_tsc_timed): tsc.tsc_timed.disconnect(_on_tsc_timed) if tsc.is_connected("tsc_completed", _on_tsc_completed):