From 6ed75d227b54bdc2e6f94a6608a1731fa4b08a91 Mon Sep 17 00:00:00 2001 From: superhighlevel Date: Mon, 27 Oct 2025 19:18:35 +0700 Subject: [PATCH 1/3] Change Render from _draw to Using Canvas Item --- .../projectile_instance.gd | 1 + .../projectile_updater_2d.gd | 160 ++++++++++++------ .../projectile_template_advanced_2d.gd | 2 +- .../projectile_template_custom_2d.gd | 47 +++-- .../projectile_instance_simple.gd | 2 + .../projectile_template_simple_2d.gd | 44 ++++- .../projectile_updater_simple_2d.gd | 119 +++++++------ 7 files changed, 234 insertions(+), 141 deletions(-) diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd index b8a7ae1d..ab0ec17d 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd @@ -17,6 +17,7 @@ var texture_rotation: float = 0 var scale: Vector2 = Vector2.ONE var skew: float = 0.0 var transform: Transform2D +var canvas_item_rid: RID var life_time_second: float = 0.0 var life_time_tick: float = 0.0 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 8cd0f8d6..9c2e4a99 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 @@ -2,81 +2,101 @@ extends Node2D class_name ProjectileUpdater2D -var projectile_template_2d : ProjectileTemplate2D +var projectile_template_2d: ProjectileTemplate2D -var projectile_speed : float = 100.0 +var projectile_speed: float = 100.0 -var projectile_texture : Texture2D -var projectile_texture_rotation : float -var projectile_texture_visible : bool -var projectile_texture_modulate : Color +var projectile_texture: Texture2D +var projectile_texture_rotation: float +var projectile_texture_visible: bool +var projectile_texture_modulate: Color -var projectile_texture_draw_offset : Vector2 +var projectile_texture_draw_offset: Vector2 var PS := PhysicsServer2D -var projectile_area_rid : RID -var projectile_collision_shape : Shape2D -var projectile_collision_layer : int = 0 -var projectile_collision_mask : int = 0 +var projectile_area_rid: RID +var projectile_collision_shape: Shape2D +var projectile_collision_layer: int = 0 +var projectile_collision_mask: int = 0 -var projectile_pooling_index : int = 0 -var projectile_max_pooling : int +var projectile_pooling_index: int = 0 +var projectile_max_pooling: int -var projectile_instance_array : Array[ProjectileInstance2D] -var projectile_active_index : Array[int] -var projectile_remove_index : Array[int] +var projectile_instance_array: Array[ProjectileInstance2D] +var projectile_active_index: Array[int] +var projectile_remove_index: Array[int] -var spawner_destroyed : bool = false +var spawner_destroyed: bool = false -var custom_data : Array[Variant] +var custom_data: Array[Variant] -var _active_projectile_instances : Array[ProjectileInstance2D] +var _active_projectile_instances: Array[ProjectileInstance2D] -var _projectile_instance : ProjectileInstance2D -var _new_projectile_instance : Callable - -var _overlapping_areas : Dictionary -var _overlapping_bodies : Dictionary +var _projectile_instance: ProjectileInstance2D +var _new_projectile_instance: Callable +var _overlapping_areas: Dictionary +var _overlapping_bodies: Dictionary +var _reverse_z_index: bool = false func _ready() -> void: setup_projectile_updater() + projectile_template_2d.changed.connect(_on_projectile_template_changed) func _physics_process(delta: float) -> void: update_projectile_instances(delta) - # Free Projectile Updater when spawner destroyed and there are no active projectile instances - # if spawner_destroyed and projectile_active_index.size() <= 0: - # clear_projectile_updater() - # # queue_free() - - queue_redraw() pass func _draw() -> void: - if !projectile_template_2d.texture: return - if !projectile_template_2d.texture_visible: return - draw_projectile_texture() + # if !projectile_template_2d.texture: return + # if !projectile_template_2d.texture_visible: return + # draw_projectile_texture() + pass + + +func _on_projectile_template_changed() -> void: + z_index = projectile_template_2d.texture_z_index + 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 + if _reverse_z_index != projectile_template_2d.reverse_z_index: + _reverse_z_index = projectile_template_2d.reverse_z_index + if !_reverse_z_index: + for _index in projectile_max_pooling: + RenderingServer.canvas_item_set_draw_index(projectile_instance_array[_index].canvas_item_rid, _index) + else: + for _index in projectile_max_pooling: + RenderingServer.canvas_item_set_draw_index(projectile_instance_array[_index].canvas_item_rid, -_index) + + + pass #region Setup Projectile func setup_projectile_updater() -> void: - projectile_collision_layer = projectile_template_2d.collision_layer - projectile_collision_mask = projectile_template_2d.collision_mask - projectile_collision_shape = projectile_template_2d.collision_shape init_updater_variable() setup_projectile_area_rid() create_projectile_pool() + setup_canvas_item() pass func init_updater_variable() -> void: + projectile_collision_layer = projectile_template_2d.collision_layer + projectile_collision_mask = projectile_template_2d.collision_mask + projectile_collision_shape = projectile_template_2d.collision_shape + z_index = projectile_template_2d.texture_z_index + projectile_texture = projectile_template_2d.texture + projectile_texture_modulate = projectile_template_2d.texture_modulate + if projectile_template_2d.texture: + projectile_texture_draw_offset = Vector2.ZERO - projectile_template_2d.texture.get_size() * 0.5 + _reverse_z_index = projectile_template_2d.reverse_z_index pass func setup_projectile_area_rid() -> void: - projectile_area_rid = PS.area_create() PS.area_set_space(projectile_area_rid, get_world_2d().space) @@ -91,11 +111,12 @@ func setup_projectile_area_rid() -> void: func create_projectile_pool() -> void: var _transform := Transform2D() - var _collision_rid : RID + var _collision_rid: RID + var _temp_canvas_item_id: RID if projectile_template_2d.collision_shape: _collision_rid = projectile_template_2d.collision_shape.get_rid() - projectile_max_pooling = projectile_template_2d.projectile_pooling_amount + for _index in range(projectile_max_pooling): if _collision_rid: PS.area_add_shape(projectile_area_rid, _collision_rid, _transform, true) @@ -104,16 +125,41 @@ func create_projectile_pool() -> void: _projectile_instance.custom_data = custom_data _projectile_instance.area_rid = projectile_area_rid _projectile_instance.area_index = _index - projectile_instance_array.append(_projectile_instance) + ## Create Canvas Item for projectile + _temp_canvas_item_id = RenderingServer.canvas_item_create() + RenderingServer.canvas_item_set_parent(_temp_canvas_item_id, get_canvas_item()) + projectile_canvas_item_ids.append(_temp_canvas_item_id) + _projectile_instance.canvas_item_rid = _temp_canvas_item_id + + RenderingServer.canvas_item_set_z_index(_temp_canvas_item_id, z_index) + + if projectile_template_2d.reverse_z_index: + RenderingServer.canvas_item_set_draw_index(_temp_canvas_item_id, -_index) + else: + RenderingServer.canvas_item_set_draw_index(_temp_canvas_item_id, _index) + + RenderingServer.canvas_item_set_z_as_relative_to_parent(_temp_canvas_item_id, false) + RenderingServer.canvas_item_set_modulate(_temp_canvas_item_id, projectile_texture_modulate) + RenderingServer.canvas_item_set_visible(_temp_canvas_item_id, false) + if projectile_texture: + RenderingServer.canvas_item_add_texture_rect( + _temp_canvas_item_id, + Rect2(-projectile_texture.get_size() / 2, + projectile_texture.get_size()), + projectile_texture + ) + # RenderingServer.canvas_item_set_transform(_temp_canvas_item_id, _projectile_instance.transform) + + func setup_area_callback(_projectile_area: RID) -> void: PS.area_set_area_monitor_callback(_projectile_area, _area_monitor_callback) PS.area_set_monitor_callback(_projectile_area, _body_monitor_callback) pass -func _area_monitor_callback(status: int, area_rid : RID, instance_id: int, area_shape_idx: int, self_shape_idx: int) -> void: - var _instance_node : Area2D = instance_from_id(instance_id) +func _area_monitor_callback(status: int, area_rid: RID, instance_id: int, area_shape_idx: int, self_shape_idx: int) -> void: + var _instance_node: Area2D = instance_from_id(instance_id) if !is_instance_valid(_instance_node): return match status: @@ -151,8 +197,8 @@ func _area_monitor_callback(status: int, area_rid : RID, instance_id: int, area_ _overlapping_areas.erase(self_shape_idx) 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 : Node = instance_from_id(instance_id) +func _body_monitor_callback(status: int, body_rid: RID, instance_id: int, body_shape_idx: int, self_shape_idx: int) -> void: + var _instance_node: Node = instance_from_id(instance_id) if !is_instance_valid(_instance_node): return match status: @@ -166,6 +212,7 @@ func _body_monitor_callback(status: int, body_rid : RID, instance_id: int, body_ ProjectileEngine.projectile_instance_body_entered.emit( projectile_instance_array[self_shape_idx], instance_from_id(instance_id) ) + if _overlapping_bodies.has(self_shape_idx): _overlapping_bodies[self_shape_idx].append(_instance_node) else: @@ -190,8 +237,6 @@ func _body_monitor_callback(status: int, body_rid : RID, instance_id: int, body_ pass - - func process_projectile_collided(instance_index: int) -> void: if instance_index not in projectile_remove_index: projectile_remove_index.append(instance_index) @@ -215,14 +260,9 @@ func update_projectile_instances(delta: float) -> void: #endregion - #region Draw Projectile func draw_projectile_texture() -> void: - z_index = projectile_template_2d.texture_z_index - 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 if not projectile_template_2d.reverse_z_index: for index in projectile_active_index: draw_set_transform_matrix(projectile_instance_array[index].transform) @@ -232,17 +272,31 @@ func draw_projectile_texture() -> void: draw_set_transform_matrix(projectile_instance_array[projectile_active_index[i]].transform) draw_texture(projectile_texture, projectile_texture_draw_offset, projectile_texture_modulate) +var projectile_canvas_item_ids: Array[RID] + +func setup_canvas_item() -> void: + pass + +func update_canvas_item() -> void: + for index in projectile_active_index: + RenderingServer.canvas_item_set_transform( + projectile_canvas_item_ids[index], + projectile_instance_array[index].transform + ) + pass + + #endregion func clear_projectile_updater() -> void: - for instance : ProjectileInstanceCustom2D in projectile_instance_array: + for instance: ProjectileInstanceCustom2D in projectile_instance_array: instance.queue_free() PS.area_clear_shapes(projectile_area_rid) func get_active_projectile_count() -> int: - return _active_projectile_instances.size() + return projectile_active_index.size() pass diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd index 183fb984..1ad38644 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd @@ -25,7 +25,7 @@ class_name ProjectileTemplateAdvanced2D @export var texture_visible: bool = true ## Render layer for the texture (higher values render on top) @export var texture_z_index: int = 0 -## Render newer bullets underneath older bullets? +## Reverse Z in dex, make new bullet render underneath older bullet @export var reverse_z_index: bool = false ## Color modulation applied to the texture (RGBA) @export var texture_modulate: Color = Color(1, 1, 1, 1) diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd index eb863916..8165f3f9 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd @@ -4,49 +4,49 @@ class_name ProjectileTemplateCustom2D ## Template for Custom Projectile 2D that using ProjectileBehavior ## Movement speed of the projectile in pixels per second -@export var speed : float = 100 +@export var speed: float = 100 # ## The normalized Direction of the projectile moving toward # @export var direction : Vector2 = Vector2.RIGHT ## Number of projectiles to preload in the object pool for better performance -@export var projectile_pooling_amount : int = 500 +@export var projectile_pooling_amount: int = 500 @export_group("Texture") ## The Projectile Instance Texture -@export var texture : Texture2D +@export var texture: Texture2D ## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] -@export_custom(PROPERTY_HINT_LINK, "") var scale : Vector2 = Vector2.ONE +@export_custom(PROPERTY_HINT_LINK, "") var scale: Vector2 = Vector2.ONE ## Initial rotation of the texture in degrees -@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation : float +@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float ## Skew/shear effect applied to texture (-89.9 to 89.9 degrees) -@export_range(-89.9, 89.9, 0.1) var skew : float = 0.0 +@export_range(-89.9, 89.9, 0.1) var skew: float = 0.0 ## Toggles visibility of the projectile's texture -@export var texture_visible : bool = true +@export var texture_visible: bool = true ## Render layer for the texture (higher values render on top) -@export var texture_z_index : int = 0 -## Render newer bullets underneath older bullets? +@export var texture_z_index: int = 0 +## Reverse Z in dex, make new bullet render underneath older bullet @export var reverse_z_index: bool = false ## Color modulation applied to the texture (RGBA) -@export var texture_modulate : Color = Color(1, 1, 1, 1) +@export var texture_modulate: Color = Color(1, 1, 1, 1) @export_group("Collision") ## Collision shape used for physics detection -@export var collision_shape : Shape2D +@export var collision_shape: Shape2D ## Physics layers this projectile can collide with (bitmask) -@export_flags_2d_physics var collision_layer : int = 0 +@export_flags_2d_physics var collision_layer: int = 0 ## Physics layers that can detect collisions with this projectile (bitmask) -@export_flags_2d_physics var collision_mask : int = 0 +@export_flags_2d_physics var collision_mask: int = 0 @export_group("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_group("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 @@ -55,7 +55,4 @@ class_name ProjectileTemplateCustom2D ## Internal RID (Rendering ID) for the projectile's collision area -var projectile_area_rid : RID - - - +var projectile_area_rid: RID diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_instance_simple.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_instance_simple.gd index 3903b7f0..2dcfca20 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_instance_simple.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_instance_simple.gd @@ -1,2 +1,4 @@ extends ProjectileInstance2D class_name ProjectileInstanceSimple2D + +var velocity_length: float \ No newline at end of file diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd index 2146370a..e983915a 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd @@ -4,13 +4,19 @@ class_name ProjectileTemplateSimple2D ## Template for Simple Projectile 2D that will move at the direction and speed defined. ## Movement speed of the projectile in pixels per second -@export var speed: float = 100 +@export var speed: float = 100: + set(value): + speed = value + emit_changed() ## Number of projectiles to preload in the object pool for better performance @export var projectile_pooling_amount: int = 500 ## The Projectile Instance Texture -@export var texture: Texture2D +@export var texture: Texture2D: + set(value): + texture = value + emit_changed() ## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] @export_custom(PROPERTY_HINT_LINK, "suffix:") var scale: Vector2 = Vector2.ONE @@ -21,11 +27,21 @@ class_name ProjectileTemplateSimple2D ## Toggles visibility of the projectile's texture @export var texture_visible: bool = true ## Render layer for the texture (higher values render on top) -@export var texture_z_index: int = 0 -## Render newer bullets underneath older bullets? -@export var reverse_z_index: bool = false +@export var texture_z_index: int = 0: + set(value): + texture_z_index = value + emit_changed() +## Reverse Z in dex, make new bullet render underneath older bullet +@export var reverse_z_index: bool = false: + set(value): + reverse_z_index = value + emit_changed() + ## Color modulation applied to the texture (RGBA) -@export var texture_modulate: Color = Color(1, 1, 1, 1) +@export var texture_modulate: Color = Color(1, 1, 1, 1): + set(value): + texture_modulate = value + emit_changed() ## Collision shape used for physics detection @export var collision_shape: Shape2D @@ -33,17 +49,27 @@ class_name ProjectileTemplateSimple2D @export_flags_2d_physics var collision_layer: int = 0 ## Physics layers that can detect collisions with this projectile (bitmask) @export_flags_2d_physics var collision_mask: int = 0 -@export var texture_rotate_direction: bool = false +@export var texture_rotate_direction: bool = false: + set(value): + texture_rotate_direction = value + emit_changed() + ## Destroy when collided with a body @export var destroy_on_body_collide: bool = true ## Destroy when collided with a area @export var destroy_on_area_collide: bool = true ## Maximum lifetime of projectile in seconds before it's automatically destroyed ## [code] life_time_max < 0 [/code] for unlimited life time -@export var life_time_second_max: float = 10.0 +@export var life_time_second_max: float = 10.0: + set(value): + life_time_second_max = value + emit_changed() ## Maximum travel distance in pixels before projectile is automatically destroyed [br] ## [code] life_distance_max < 0 [/code] for unlimited distance -@export var life_distance_max: float = 1000.0 +@export var life_distance_max: float = 1000.0: + set(value): + life_distance_max = value + emit_changed() @export_group("Random") @export var speed_random: Vector3 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 ed3cd17d..20487d58 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 @@ -13,24 +13,28 @@ var destroy_on_area_collide: bool var projectile_texture_rotate_direction: bool func init_updater_variable() -> void: + super () + projectile_template_2d = projectile_template_2d as ProjectileTemplateSimple2D + projectile_speed = projectile_template_2d.speed destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide + projectile_life_time_second_max = projectile_template_2d.life_time_second_max + projectile_life_distance_max = projectile_template_2d.life_distance_max + _new_projectile_instance = Callable(ProjectileInstanceSimple2D, "new") #region Spawn Projectile - func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) -> void: projectile_template_2d = projectile_template_2d as ProjectileTemplateSimple2D - for _pattern_composer_data: PatternComposerData in pattern_composer_pack: _projectile_instance = projectile_instance_array[projectile_pooling_index] + _projectile_instance.global_position = _pattern_composer_data.position _projectile_instance.direction = _pattern_composer_data.direction _projectile_instance.direction_rotation = _pattern_composer_data.direction_rotation - _projectile_instance.texture_rotation = projectile_template_2d.texture_rotation _projectile_instance.scale = projectile_template_2d.scale _projectile_instance.life_time_second_max = projectile_template_2d.life_time_second_max @@ -41,6 +45,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) var _scale_value_float: float var _scale_value: Vector2 = projectile_template_2d.scale var _rotation_value: float = _projectile_instance.texture_rotation + if projectile_template_2d.speed_random != Vector3.ZERO: _speed_value = ProjectileEngine.get_random_float_value(projectile_template_2d.speed_random) if projectile_template_2d.scale_random != Vector3.ZERO: @@ -80,6 +85,10 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.global_position ) + RenderingServer.canvas_item_set_visible(_projectile_instance.canvas_item_rid, true) + RenderingServer.canvas_item_set_transform(_projectile_instance.canvas_item_rid, _projectile_instance.transform) + + if projectile_template_2d.collision_shape: PS.area_set_shape_transform(projectile_area_rid, projectile_pooling_index, _projectile_instance.transform) PS.area_set_shape_disabled(projectile_area_rid, projectile_pooling_index, false) @@ -91,6 +100,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) if projectile_pooling_index not in projectile_active_index: projectile_active_index.append(projectile_pooling_index) projectile_pooling_index += 1 + if projectile_pooling_index >= projectile_max_pooling: projectile_pooling_index = 0 @@ -99,80 +109,83 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) #region Update Projectile -func update_projectile_instances(delta: float) -> void: - projectile_speed = projectile_template_2d.speed - 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 +var _overlap_collision_layer: int +var _active_projectile_instance: ProjectileInstanceSimple2D +# var _velocity_length: float +func update_projectile_instances(delta: float) -> void: # 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: + if projectile_life_time_second_max > 0: _projectile_instance.life_time_second += delta - if _projectile_instance.life_time_second >= _projectile_instance.life_time_second_max: + if _projectile_instance.life_time_second >= projectile_life_time_second_max: projectile_remove_index.append(index) - continue - if _projectile_instance.life_distance_max >= 0: - _projectile_instance.life_distance += _projectile_instance.velocity.length() - if _projectile_instance.life_distance >= _projectile_instance.life_distance_max: + if projectile_life_distance_max > 0: + _projectile_instance.life_distance += _projectile_instance.velocity_length + if _projectile_instance.life_distance >= projectile_life_distance_max: projectile_remove_index.append(index) continue - if destroy_on_area_collide: if has_overlapping_areas(index): - for _overlap_area in get_overlapping_areas(index): - _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_area) - if not _overlap_collision_layer & projectile_collision_mask: - continue - projectile_remove_index.append(index) + projectile_remove_index.append(index) if destroy_on_body_collide: if has_overlapping_bodies(index): - for _overlap_body in get_overlapping_bodies(index): - 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) + projectile_remove_index.append(index) + + + ## Update Transform and texture + _projectile_instance.global_position += _projectile_instance.velocity + + _projectile_instance.transform = Transform2D( + _projectile_instance.texture_rotation, + _projectile_instance.scale, + _projectile_instance.skew, + _projectile_instance.global_position + ) + + RenderingServer.canvas_item_set_transform( + projectile_canvas_item_ids[index], + _projectile_instance.transform + ) + + if projectile_template_2d.collision_shape: + PS.area_set_shape_transform( + projectile_area_rid, + _projectile_instance.area_index, + _projectile_instance.transform + ) # Destroy projectile if projectile_remove_index.size() > 0: for index: int in projectile_remove_index: projectile_active_index.erase(index) + RenderingServer.canvas_item_set_visible(projectile_instance_array[index].canvas_item_rid, false) if projectile_template_2d.collision_shape: PS.area_set_shape_disabled(projectile_area_rid, index, true) projectile_remove_index.clear() - # Update active projectile instances array - _active_projectile_instances.clear() - 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: ProjectileInstanceSimple2D in _active_projectile_instances: - _active_projectile_instance.global_position += _active_projectile_instance.velocity - - _active_projectile_instance.transform = Transform2D( - _active_projectile_instance.texture_rotation, - _active_projectile_instance.scale, - _active_projectile_instance.skew, - _active_projectile_instance.global_position - ) +#endregion - # if _active_projectile_instance.area_rid: - if projectile_template_2d.collision_shape: - PS.area_set_shape_transform( - projectile_area_rid, - _active_projectile_instance.area_index, - _active_projectile_instance.transform - ) +func _on_projectile_template_changed() -> void: + super () + projectile_speed = projectile_template_2d.speed + 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 -#endregion + projectile_life_time_second_max = projectile_template_2d.life_time_second_max + projectile_life_distance_max = projectile_template_2d.life_distance_max + + for index in projectile_active_index: + _active_projectile_instance = projectile_instance_array[index] + _active_projectile_instance.velocity = ( + projectile_speed * + _active_projectile_instance.direction * + (1.0 / Engine.physics_ticks_per_second) + ) + _active_projectile_instance.velocity_length = _projectile_instance.velocity.length() From bbb9c0de4a484692d5d7fab3e89bded452c4fb76 Mon Sep 17 00:00:00 2001 From: superhighlevel Date: Tue, 28 Oct 2025 15:16:41 +0700 Subject: [PATCH 2/3] Improve variable name and perfomance --- .../GodotProjectileEngine.gd | 4 +- .../projectile_environment.gd | 6 - .../projectile_spawner/projectile_spawner.gd | 6 +- .../base/projectile_behavior_piercing.gd | 16 +- .../base/projectile_custom_data.gd | 4 + .../base/projectile_custom_data.gd.uid | 1 + .../behaviors/projectile_bouncing_reflect.gd | 8 +- .../behaviors/projectile_destroy_collision.gd | 20 +- .../projectile_instance.gd | 19 +- .../projectile_template_2d.gd | 2 +- .../projectile_template_object_2d.gd | 92 ++++ .../projectile_template_object_2d.gd.uid | 1 + .../projectile_updater_2d.gd | 285 ++++++----- .../projectile_updater_advanced_2d.gd | 272 +++++----- .../projectile_updater_custom_2d.gd | 474 +++++++++--------- .../projectile_2d/projectile_2d.gd | 12 +- .../projectile_template_simple_2d.gd | 79 +-- .../projectile_updater_simple_2d.gd | 86 ++-- project.godot | 2 + 19 files changed, 693 insertions(+), 696 deletions(-) create mode 100644 addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd create mode 100644 addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd.uid create mode 100644 addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd create mode 100644 addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd.uid diff --git a/addons/godot_projectile_engine/GodotProjectileEngine.gd b/addons/godot_projectile_engine/GodotProjectileEngine.gd index c9960198..0afecc28 100644 --- a/addons/godot_projectile_engine/GodotProjectileEngine.gd +++ b/addons/godot_projectile_engine/GodotProjectileEngine.gd @@ -150,9 +150,9 @@ func get_projectile_instance(area_rid: RID, area_shape_index: int) -> Projectile var _projectile_updater_2d_node : ProjectileUpdater2D = projectile_updater_2d_nodes.get(area_rid) if !_projectile_updater_2d_node: return null - if _projectile_updater_2d_node.projectile_instance_array.size() < area_shape_index: + if _projectile_updater_2d_node.projectile_instances.size() < area_shape_index: return null - return _projectile_updater_2d_node.projectile_instance_array[area_shape_index] + return _projectile_updater_2d_node.projectile_instances[area_shape_index] pass diff --git a/addons/godot_projectile_engine/core/projectile_environment/projectile_environment.gd b/addons/godot_projectile_engine/core/projectile_environment/projectile_environment.gd index e78ab893..62aec48e 100644 --- a/addons/godot_projectile_engine/core/projectile_environment/projectile_environment.gd +++ b/addons/godot_projectile_engine/core/projectile_environment/projectile_environment.gd @@ -20,12 +20,6 @@ func _physics_process(delta: float) -> void: pass -func spawner_destroyed(area_rid: RID) -> void: - if !ProjectileEngine.projectile_updater_2d_nodes.get(area_rid): return - ProjectileEngine.projectile_updater_2d_nodes.get(area_rid).spawner_destroyed = true - pass - - func projectile_collided(projectile_area_rid: RID, shape_idx: int) -> void: if !ProjectileEngine.projectile_updater_2d_nodes.has(projectile_area_rid): return if !is_instance_valid(ProjectileEngine.projectile_updater_2d_nodes[projectile_area_rid]): 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 1412a438..18477610 100644 --- a/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd +++ b/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd @@ -163,7 +163,8 @@ func create_projectile_updater() -> void: var _projectile_updater := ProjectileUpdater2D.new() _projectile_updater.projectile_template_2d = projectile_template_2d - _projectile_updater.custom_data = projectile_template_2d.custom_data + if projectile_template_2d.custom_data: + _projectile_updater.custom_data = projectile_template_2d.custom_data ProjectileEngine.projectile_environment.add_child(_projectile_updater, true) projectile_area = _projectile_updater.projectile_area_rid @@ -180,7 +181,8 @@ func create_projectile_updater_simple_2d() -> void: var _projectile_updater := ProjectileUpdaterSimple2D.new() _projectile_updater.projectile_template_2d = projectile_template_2d - _projectile_updater.custom_data = projectile_template_2d.custom_data + if projectile_template_2d.custom_data: + _projectile_updater.custom_data = projectile_template_2d.custom_data ProjectileEngine.projectile_environment.add_child(_projectile_updater, true) projectile_area = _projectile_updater.projectile_area_rid diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_behavior_piercing.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_behavior_piercing.gd index 43c1cdeb..2bef94b5 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_behavior_piercing.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_behavior_piercing.gd @@ -77,8 +77,8 @@ func process_behavior(_value, _context: Dictionary) -> Dictionary: if _behavior_owner is Projectile2D: if pierce_area: - if _behavior_owner.has_overlapping_areas(): - var _overlap_areas : Array[Area2D] = _behavior_owner.get_overlapping_areas() + if _behavior_owner.hasprojectile_overlapping_areas(): + var _overlap_areas : Array[Area2D] = _behavior_owner.getprojectile_overlapping_areas() for _overlap_area in _overlap_areas: if _behavior_variable_piercing.pierced_targets.has(_overlap_area): continue @@ -100,8 +100,8 @@ func process_behavior(_value, _context: Dictionary) -> Dictionary: else: _behavior_variable_piercing.is_overlap_piercing = false if pierce_body: - if _behavior_owner.has_overlapping_bodies(): - var _overlap_bobies : Array[Area2D] = _behavior_owner.get_overlapping_bodies() + if _behavior_owner.hasprojectile_overlapping_bodies(): + var _overlap_bobies : Array[Area2D] = _behavior_owner.getprojectile_overlapping_bodies() for _overlap_body in _overlap_bobies: if _behavior_variable_piercing.pierced_targets.has(_overlap_body): continue @@ -127,8 +127,8 @@ func process_behavior(_value, _context: Dictionary) -> Dictionary: var _projectile_updater: ProjectileUpdater2D = _behavior_owner.projectile_updater _behavior_variable_piercing.is_overlap_piercing = false if pierce_area: - if _projectile_updater.has_overlapping_areas(_behavior_owner.area_index): - for _overlap_area in _projectile_updater.get_overlapping_areas(_behavior_owner.area_index): + if _projectile_updater.hasprojectile_overlapping_areas(_behavior_owner.area_index): + for _overlap_area in _projectile_updater.getprojectile_overlapping_areas(_behavior_owner.area_index): if not _overlap_area.collision_layer & _projectile_updater.projectile_collision_mask: continue if _behavior_variable_piercing.pierced_targets.has(_overlap_area): @@ -148,8 +148,8 @@ func process_behavior(_value, _context: Dictionary) -> Dictionary: if _behavior_variable_piercing.current_piercing_count > piercing_count: _behavior_variable_piercing.is_piercing_just_done = true if pierce_body: - if _projectile_updater.has_overlapping_bodies(_behavior_owner.area_index): - for _overlap_body in _projectile_updater.get_overlapping_bodies(_behavior_owner.area_index): + if _projectile_updater.hasprojectile_overlapping_bodies(_behavior_owner.area_index): + for _overlap_body in _projectile_updater.getprojectile_overlapping_bodies(_behavior_owner.area_index): if not _overlap_body.collision_layer & _projectile_updater.projectile_collision_mask: continue if _behavior_variable_piercing.pierced_targets.has(_overlap_body): diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd new file mode 100644 index 00000000..3e2830ff --- /dev/null +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd @@ -0,0 +1,4 @@ +extends Resource +class_name ProjectileCustomData + +var custom_data: Dictionary \ No newline at end of file diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd.uid b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd.uid new file mode 100644 index 00000000..14d4eea6 --- /dev/null +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd.uid @@ -0,0 +1 @@ +uid://d2u1cn78hhbf4 diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/bouncing/behaviors/projectile_bouncing_reflect.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/bouncing/behaviors/projectile_bouncing_reflect.gd index 21480c45..9229122d 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/bouncing/behaviors/projectile_bouncing_reflect.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/bouncing/behaviors/projectile_bouncing_reflect.gd @@ -62,8 +62,8 @@ func process_behavior(_value, _context: Dictionary) -> Dictionary: var _new_direction : Vector2 if _behavior_owner is Projectile2D: - if _behavior_owner.has_overlapping_bodies(): - for _overlap_body in _behavior_owner.get_overlapping_bodies(): + if _behavior_owner.hasprojectile_overlapping_bodies(): + for _overlap_body in _behavior_owner.getprojectile_overlapping_bodies(): if _behavior_variable_bouncing_reflect.bounced_targets.has(_overlap_body): continue if not _overlap_body.collision_layer & _behavior_owner.collision_mask: @@ -92,8 +92,8 @@ func process_behavior(_value, _context: Dictionary) -> Dictionary: if _behavior_owner is ProjectileInstance2D: var _projectile_updater : ProjectileUpdater2D = _behavior_owner.projectile_updater - if _projectile_updater.has_overlapping_bodies(_behavior_owner.area_index): - for _overlap_body in _projectile_updater.get_overlapping_bodies(_behavior_owner.area_index): + if _projectile_updater.hasprojectile_overlapping_bodies(_behavior_owner.area_index): + for _overlap_body in _projectile_updater.getprojectile_overlapping_bodies(_behavior_owner.area_index): if _behavior_variable_bouncing_reflect.bounced_targets.has(_overlap_body): continue if not _overlap_body.collision_layer & _projectile_updater.projectile_collision_mask: 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 bd3062a5..4a87c8e6 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 @@ -56,8 +56,8 @@ func process_behavior(_value, _context: Dictionary) -> bool: if !_behavior_owner.monitorable or !_behavior_owner.monitoring: return false if destroy_on_area_collide: - if _behavior_owner.has_overlapping_areas(): - for _overlap_area in _behavior_owner.get_overlapping_areas(): + if _behavior_owner.hasprojectile_overlapping_areas(): + for _overlap_area in _behavior_owner.getprojectile_overlapping_areas(): if not _overlap_area.collision_layer & _behavior_owner.collision_mask: continue if wait_projectile_piercing: @@ -94,8 +94,8 @@ func process_behavior(_value, _context: Dictionary) -> bool: return true if destroy_on_body_collide: - if _behavior_owner.has_overlapping_bodies(): - for _overlap_body in _behavior_owner.get_overlapping_bodies(): + if _behavior_owner.hasprojectile_overlapping_bodies(): + for _overlap_body in _behavior_owner.getprojectile_overlapping_bodies(): var _overlap_body_collision_layer : int = ProjectileEngine.get_collider_collision_layer(_overlap_body) if not _overlap_body_collision_layer & _behavior_owner.collision_mask: continue @@ -136,10 +136,10 @@ func process_behavior(_value, _context: Dictionary) -> bool: if _behavior_owner is ProjectileInstance2D: if destroy_on_area_collide: _projectile_updater = _behavior_owner.projectile_updater - if _projectile_updater.has_overlapping_areas(_behavior_owner.area_index): - for _overlap_area in _projectile_updater.get_overlapping_areas(_behavior_owner.area_index): + if _projectile_updater.hasprojectile_overlapping_areas(_behavior_owner.area_index): + for _overlap_area in _projectile_updater.getprojectile_overlapping_areas(_behavior_owner.area_index): if !_overlap_area: - _projectile_updater.get_overlapping_areas(_behavior_owner.area_index).erase(_overlap_area) + _projectile_updater.getprojectile_overlapping_areas(_behavior_owner.area_index).erase(_overlap_area) continue _overlap_area_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_area) if not _overlap_area_collision_layer & _projectile_updater.projectile_collision_mask: @@ -179,10 +179,10 @@ func process_behavior(_value, _context: Dictionary) -> bool: return true 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 _projectile_updater.hasprojectile_overlapping_bodies(_behavior_owner.area_index): + for _overlap_body in _projectile_updater.getprojectile_overlapping_bodies(_behavior_owner.area_index): if !_overlap_body: - _projectile_updater.get_overlapping_bodies(_behavior_owner.body_index).erase(_overlap_body) + _projectile_updater.getprojectile_overlapping_bodies(_behavior_owner.body_index).erase(_overlap_body) continue _overlap_body_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_body) if not _overlap_body_collision_layer & _projectile_updater.projectile_collision_mask: diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd index ab0ec17d..0e9f7fca 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_instance/projectile_instance.gd @@ -1,10 +1,12 @@ extends Object class_name ProjectileInstance2D -var projectile_updater: ProjectileUpdater2D +var projectile_template_2d : ProjectileTemplate2D +var projectile_updater_2d: ProjectileUpdater2D var area_rid: RID var area_index: int +var canvas_item_rid: RID var speed: float var direction: Vector2 = Vector2.RIGHT @@ -12,19 +14,14 @@ var direction_rotation: float = 0 var velocity: Vector2 = Vector2.ZERO +var transform_2d: Transform2D var global_position: Vector2 = Vector2.ZERO var texture_rotation: float = 0 -var scale: Vector2 = Vector2.ONE -var skew: float = 0.0 -var transform: Transform2D -var canvas_item_rid: RID +var texture_scale: Vector2 = Vector2.ONE +var texture_skew: float = 0.0 var life_time_second: float = 0.0 -var life_time_tick: float = 0.0 +var life_time_tick: int = 0.0 var life_distance: float = 0.0 -var life_time_second_max: float = 0.0 -var life_time_tick_max: float = 0.0 -var life_distance_max: float = 0.0 - -var custom_data: Array[Variant] \ No newline at end of file +var custom_data: ProjectileCustomData \ No newline at end of file diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd index c47b8ea1..e18bb017 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd @@ -1,4 +1,4 @@ extends Resource class_name ProjectileTemplate2D -@export var custom_data : Array[Variant] \ No newline at end of file +@export var custom_data : ProjectileCustomData \ No newline at end of file diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd new file mode 100644 index 00000000..6fb431d8 --- /dev/null +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd @@ -0,0 +1,92 @@ +extends ProjectileTemplate2D +class_name ProjectileTemplateObject2D +## Movement speed of the projectile in pixels per second +@export var speed: float = 100: + set(value): + speed = value + emit_changed() + +## Number of projectiles to preload in the object pool for better performance +@export var projectile_pooling_amount: int = 500: + set(value): + projectile_pooling_amount = value + emit_changed() + +@export_group("Texture - Transform") +## The Projectile Instance Texture +@export var texture: Texture2D: + set(value): + texture = value + emit_changed() + +## Initial rotation of the texture in degrees +@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float: + set(value): + texture_rotation = value + emit_changed() + +## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] +@export_custom(PROPERTY_HINT_LINK, "suffix:") var texture_scale: Vector2 = Vector2.ONE: + set(value): + texture_scale = value + emit_changed() + +## Skew/shear effect applied to texture (-89.9 to 89.9 degrees) +@export_range(-89.9, 89.9, 0.1) var texture_skew: float = 0.0: + set(value): + texture_skew = value + emit_changed() +## Toggles visibility of the projectile's texture +@export var texture_visible: bool = true: + set(value): + texture_visible = value + emit_changed() +## Render layer for the texture (higher values render on top) +@export var texture_z_index: int = 0: + set(value): + texture_z_index = value + emit_changed() +## Reverse Z in dex, make new bullet render underneath older bullet +@export var reverse_z_index: bool = false: + set(value): + reverse_z_index = value + emit_changed() + +## Color modulation applied to the texture (RGBA) +@export var texture_modulate: Color = Color(1, 1, 1, 1): + set(value): + texture_modulate = value + emit_changed() + +@export_group("Collision") +## Collision shape used for physics detection +@export var collision_shape: Shape2D +## Physics layers this projectile can collide with (bitmask) +@export_flags_2d_physics var collision_layer: int = 0 +## Physics layers that can detect collisions with this projectile (bitmask) +@export_flags_2d_physics var collision_mask: int = 0 +@export var texture_rotate_direction: bool = false: + set(value): + texture_rotate_direction = value + emit_changed() + +## Destroy when collided with a body +@export var destroy_on_body_collide: bool = true +## Destroy when collided with a area +@export var destroy_on_area_collide: bool = true +## Maximum lifetime of projectile in seconds before it's automatically destroyed +## [code] life_time_max < 0 [/code] for unlimited life time +@export var life_time_second_max: float = 10.0: + set(value): + life_time_second_max = value + emit_changed() +## Maximum travel distance in pixels before projectile is automatically destroyed [br] +## [code] life_distance_max < 0 [/code] for unlimited distance +@export var life_distance_max: float = 1000.0: + set(value): + life_distance_max = value + emit_changed() + + +## Internal RID (Rendering ID) for the projectile's collision area +var projectile_area_rid: RID diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd.uid b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd.uid new file mode 100644 index 00000000..b4ad4822 --- /dev/null +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd.uid @@ -0,0 +1 @@ +uid://bxxteh75p7exo 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 9c2e4a99..8a37690b 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 @@ -2,47 +2,50 @@ extends Node2D class_name ProjectileUpdater2D +var PS := PhysicsServer2D +var RS := RenderingServer + var projectile_template_2d: ProjectileTemplate2D +var projectile_custom_data: ProjectileCustomData -var projectile_speed: float = 100.0 +var projectile_max_pooling: int +var projectile_pooling_index: int = 0 +var projectile_speed: float = 100.0 var projectile_texture: Texture2D var projectile_texture_rotation: float +var projectile_texture_scale: Vector2 +var projectile_texture_skew: float + var projectile_texture_visible: bool var projectile_texture_modulate: Color +var projectile_texture_z_index: int +var projectile_reverse_z_index: bool = false -var projectile_texture_draw_offset: Vector2 - -var PS := PhysicsServer2D -var projectile_area_rid: RID var projectile_collision_shape: Shape2D var projectile_collision_layer: int = 0 var projectile_collision_mask: int = 0 -var projectile_pooling_index: int = 0 -var projectile_max_pooling: int +var projectile_life_time_second_max: float +var projectile_life_distance_max: float -var projectile_instance_array: Array[ProjectileInstance2D] -var projectile_active_index: Array[int] -var projectile_remove_index: Array[int] +var projectile_area_rid: RID -var spawner_destroyed: bool = false +var projectile_overlapping_areas: Dictionary +var projectile_overlapping_bodies: Dictionary -var custom_data: Array[Variant] +var projectile_instances: Array[ProjectileInstance2D] +var projectile_canvas_item_rids: Array[RID] +var projectile_active_indexes: Array[int] +var projectile_remove_indexes: Array[int] -var _active_projectile_instances: Array[ProjectileInstance2D] +var projectile_instance_callable: Callable var _projectile_instance: ProjectileInstance2D -var _new_projectile_instance: Callable -var _overlapping_areas: Dictionary -var _overlapping_bodies: Dictionary - -var _reverse_z_index: bool = false func _ready() -> void: setup_projectile_updater() - projectile_template_2d.changed.connect(_on_projectile_template_changed) func _physics_process(delta: float) -> void: @@ -50,58 +53,65 @@ func _physics_process(delta: float) -> void: pass -func _draw() -> void: - # if !projectile_template_2d.texture: return - # if !projectile_template_2d.texture_visible: return - # draw_projectile_texture() +#region Setup Projectile + +func setup_projectile_updater() -> void: + update_updater_variables() + setup_projectile_area_rid() + create_projectile_pool() + + projectile_template_2d.changed.connect(_on_projectile_template_changed) pass +func update_updater_variables() -> void: + projectile_template_2d = projectile_template_2d as ProjectileTemplateObject2D + projectile_speed = projectile_template_2d.speed -func _on_projectile_template_changed() -> void: - z_index = projectile_template_2d.texture_z_index projectile_texture = projectile_template_2d.texture + projectile_texture_rotation = projectile_template_2d.texture_rotation + projectile_texture_scale = projectile_template_2d.texture_scale + projectile_texture_skew = projectile_template_2d.texture_skew + + projectile_texture_visible = projectile_template_2d.texture_visible projectile_texture_modulate = projectile_template_2d.texture_modulate - projectile_texture_draw_offset = Vector2.ZERO - projectile_template_2d.texture.get_size() * 0.5 - if _reverse_z_index != projectile_template_2d.reverse_z_index: - _reverse_z_index = projectile_template_2d.reverse_z_index - if !_reverse_z_index: - for _index in projectile_max_pooling: - RenderingServer.canvas_item_set_draw_index(projectile_instance_array[_index].canvas_item_rid, _index) - else: - for _index in projectile_max_pooling: - RenderingServer.canvas_item_set_draw_index(projectile_instance_array[_index].canvas_item_rid, -_index) + projectile_texture_z_index = projectile_template_2d.texture_z_index + projectile_reverse_z_index = projectile_template_2d.reverse_z_index - - pass + projectile_collision_shape = projectile_template_2d.collision_shape + projectile_collision_layer = projectile_template_2d.collision_layer + projectile_collision_mask = projectile_template_2d.collision_mask + projectile_life_time_second_max = projectile_template_2d.life_time_second_max + projectile_life_distance_max = projectile_template_2d.life_distance_max + pass -#region Setup Projectile -func setup_projectile_updater() -> void: - init_updater_variable() - setup_projectile_area_rid() - create_projectile_pool() - setup_canvas_item() +func _on_projectile_template_changed() -> void: + update_updater_variables() + if projectile_reverse_z_index != projectile_template_2d.reverse_z_index: + if !projectile_reverse_z_index: + for _index in projectile_max_pooling: + RS.canvas_item_set_draw_index( + projectile_instances[_index].canvas_item_rid, _index + ) + else: + for _index in projectile_max_pooling: + RS.canvas_item_set_draw_index( + projectile_instances[_index].canvas_item_rid, -_index + ) pass -func init_updater_variable() -> void: - projectile_collision_layer = projectile_template_2d.collision_layer - projectile_collision_mask = projectile_template_2d.collision_mask - projectile_collision_shape = projectile_template_2d.collision_shape - z_index = projectile_template_2d.texture_z_index - projectile_texture = projectile_template_2d.texture - projectile_texture_modulate = projectile_template_2d.texture_modulate - if projectile_template_2d.texture: - projectile_texture_draw_offset = Vector2.ZERO - projectile_template_2d.texture.get_size() * 0.5 - _reverse_z_index = projectile_template_2d.reverse_z_index - pass func setup_projectile_area_rid() -> void: projectile_area_rid = PS.area_create() PS.area_set_space(projectile_area_rid, get_world_2d().space) - PS.area_set_collision_layer(projectile_area_rid, projectile_template_2d.collision_layer) - PS.area_set_collision_mask(projectile_area_rid, projectile_template_2d.collision_mask) + PS.area_set_collision_layer( + projectile_area_rid, projectile_template_2d.collision_layer + ) + PS.area_set_collision_mask( + projectile_area_rid, projectile_template_2d.collision_mask + ) PS.area_set_monitorable(projectile_area_rid, true) PS.area_set_transform(projectile_area_rid, Transform2D()) setup_area_callback(projectile_area_rid) @@ -110,47 +120,54 @@ func setup_projectile_area_rid() -> void: projectile_template_2d.projectile_area_rid = projectile_area_rid func create_projectile_pool() -> void: - var _transform := Transform2D() + var _transform_2d := Transform2D() var _collision_rid: RID - var _temp_canvas_item_id: RID + var _canvas_item_id: RID + if projectile_template_2d.collision_shape: _collision_rid = projectile_template_2d.collision_shape.get_rid() projectile_max_pooling = projectile_template_2d.projectile_pooling_amount for _index in range(projectile_max_pooling): if _collision_rid: - PS.area_add_shape(projectile_area_rid, _collision_rid, _transform, true) - _projectile_instance = _new_projectile_instance.call() - _projectile_instance.projectile_updater = self - _projectile_instance.custom_data = custom_data + PS.area_add_shape(projectile_area_rid, _collision_rid, _transform_2d, true) + _projectile_instance = projectile_instance_callable.call() + + _projectile_instance.projectile_template_2d = projectile_template_2d + _projectile_instance.projectile_updater_2d = self + + if projectile_custom_data: + _projectile_instance.projectile_custom_data = projectile_custom_data + _projectile_instance.area_rid = projectile_area_rid _projectile_instance.area_index = _index - projectile_instance_array.append(_projectile_instance) + projectile_instances.append(_projectile_instance) ## Create Canvas Item for projectile - _temp_canvas_item_id = RenderingServer.canvas_item_create() - RenderingServer.canvas_item_set_parent(_temp_canvas_item_id, get_canvas_item()) - projectile_canvas_item_ids.append(_temp_canvas_item_id) - _projectile_instance.canvas_item_rid = _temp_canvas_item_id - - RenderingServer.canvas_item_set_z_index(_temp_canvas_item_id, z_index) + _canvas_item_id = RS.canvas_item_create() + RS.canvas_item_set_parent(_canvas_item_id, get_canvas_item()) + RS.canvas_item_set_z_index(_canvas_item_id, projectile_texture_z_index) + ## Apply reverse z index if projectile_template_2d.reverse_z_index: - RenderingServer.canvas_item_set_draw_index(_temp_canvas_item_id, -_index) + RS.canvas_item_set_draw_index(_canvas_item_id, -_index) else: - RenderingServer.canvas_item_set_draw_index(_temp_canvas_item_id, _index) + RS.canvas_item_set_draw_index(_canvas_item_id, _index) + + RS.canvas_item_set_z_as_relative_to_parent(_canvas_item_id, false) + RS.canvas_item_set_modulate(_canvas_item_id, projectile_texture_modulate) + RS.canvas_item_set_visible(_canvas_item_id, false) - RenderingServer.canvas_item_set_z_as_relative_to_parent(_temp_canvas_item_id, false) - RenderingServer.canvas_item_set_modulate(_temp_canvas_item_id, projectile_texture_modulate) - RenderingServer.canvas_item_set_visible(_temp_canvas_item_id, false) if projectile_texture: - RenderingServer.canvas_item_add_texture_rect( - _temp_canvas_item_id, + RS.canvas_item_add_texture_rect( + _canvas_item_id, Rect2(-projectile_texture.get_size() / 2, projectile_texture.get_size()), projectile_texture ) - # RenderingServer.canvas_item_set_transform(_temp_canvas_item_id, _projectile_instance.transform) + + _projectile_instance.canvas_item_rid = _canvas_item_id + projectile_canvas_item_rids.append(_canvas_item_id) func setup_area_callback(_projectile_area: RID) -> void: @@ -158,88 +175,97 @@ func setup_area_callback(_projectile_area: RID) -> void: PS.area_set_monitor_callback(_projectile_area, _body_monitor_callback) pass -func _area_monitor_callback(status: int, area_rid: RID, instance_id: int, area_shape_idx: int, self_shape_idx: int) -> void: + +func _area_monitor_callback( + status: int, area_rid: RID, + instance_id: int, area_shape_idx: int, self_shape_idx: int + ) -> void: var _instance_node: Area2D = instance_from_id(instance_id) if !is_instance_valid(_instance_node): return match status: PS.AREA_BODY_ADDED: ProjectileEngine.projectile_instance_area_shape_entered.emit( - projectile_instance_array[self_shape_idx], + projectile_instances[self_shape_idx], area_rid, _instance_node, area_shape_idx, projectile_area_rid, self_shape_idx ) ProjectileEngine.projectile_instance_area_entered.emit( - projectile_instance_array[self_shape_idx], _instance_node + projectile_instances[self_shape_idx], _instance_node ) - if _overlapping_areas.has(self_shape_idx): - _overlapping_areas[self_shape_idx].append(_instance_node) + if projectile_overlapping_areas.has(self_shape_idx): + projectile_overlapping_areas[self_shape_idx].append(_instance_node) else: - _overlapping_areas.get_or_add(self_shape_idx, [_instance_node]) + projectile_overlapping_areas.get_or_add( + self_shape_idx, [_instance_node] + ) PS.AREA_BODY_REMOVED: ProjectileEngine.projectile_instance_area_shape_exited.emit( - projectile_instance_array[self_shape_idx], + projectile_instances[self_shape_idx], area_rid, _instance_node, area_shape_idx, projectile_area_rid, self_shape_idx ) ProjectileEngine.projectile_instance_area_exited.emit( - projectile_instance_array[self_shape_idx], _instance_node + projectile_instances[self_shape_idx], _instance_node ) - if _overlapping_areas.has(self_shape_idx): - _overlapping_areas[self_shape_idx].erase(_instance_node) + if projectile_overlapping_areas.has(self_shape_idx): + projectile_overlapping_areas[self_shape_idx].erase(_instance_node) - if _overlapping_areas[self_shape_idx].size() <= 0: - _overlapping_areas.erase(self_shape_idx) + if projectile_overlapping_areas[self_shape_idx].size() <= 0: + projectile_overlapping_areas.erase(self_shape_idx) pass -func _body_monitor_callback(status: int, body_rid: RID, instance_id: int, body_shape_idx: int, self_shape_idx: int) -> void: + +func _body_monitor_callback(status: int, body_rid: RID, + instance_id: int, body_shape_idx: int, self_shape_idx: int + ) -> void: var _instance_node: Node = instance_from_id(instance_id) if !is_instance_valid(_instance_node): return match status: PS.AREA_BODY_ADDED: ProjectileEngine.projectile_instance_body_shape_entered.emit( - projectile_instance_array[self_shape_idx], + projectile_instances[self_shape_idx], body_rid, instance_from_id(instance_id), body_shape_idx, projectile_area_rid, self_shape_idx ) ProjectileEngine.projectile_instance_body_entered.emit( - projectile_instance_array[self_shape_idx], instance_from_id(instance_id) + projectile_instances[self_shape_idx], instance_from_id(instance_id) ) - if _overlapping_bodies.has(self_shape_idx): - _overlapping_bodies[self_shape_idx].append(_instance_node) + if projectile_overlapping_bodies.has(self_shape_idx): + projectile_overlapping_bodies[self_shape_idx].append(_instance_node) else: - _overlapping_bodies.get_or_add(self_shape_idx, [_instance_node]) + projectile_overlapping_bodies.get_or_add(self_shape_idx, [_instance_node]) PS.AREA_BODY_REMOVED: ProjectileEngine.projectile_instance_body_shape_exited.emit( - projectile_instance_array[self_shape_idx], + projectile_instances[self_shape_idx], body_rid, instance_from_id(instance_id), body_shape_idx, projectile_area_rid, self_shape_idx ) ProjectileEngine.projectile_instance_body_exited.emit( - projectile_instance_array[self_shape_idx], instance_from_id(instance_id) + projectile_instances[self_shape_idx], instance_from_id(instance_id) ) - if _overlapping_bodies.has(self_shape_idx): - _overlapping_bodies[self_shape_idx].erase(_instance_node) + if projectile_overlapping_bodies.has(self_shape_idx): + projectile_overlapping_bodies[self_shape_idx].erase(_instance_node) - if _overlapping_bodies[self_shape_idx].size() <= 0: - _overlapping_bodies.erase(self_shape_idx) + if projectile_overlapping_bodies[self_shape_idx].size() <= 0: + projectile_overlapping_bodies.erase(self_shape_idx) pass func process_projectile_collided(instance_index: int) -> void: - if instance_index not in projectile_remove_index: - projectile_remove_index.append(instance_index) + if instance_index not in projectile_remove_indexes: + projectile_remove_indexes.append(instance_index) pass #endregion @@ -260,67 +286,38 @@ func update_projectile_instances(delta: float) -> void: #endregion -#region Draw Projectile - -func draw_projectile_texture() -> void: - if not projectile_template_2d.reverse_z_index: - for index in projectile_active_index: - draw_set_transform_matrix(projectile_instance_array[index].transform) - draw_texture(projectile_texture, projectile_texture_draw_offset, projectile_texture_modulate) - else: - for i in range(projectile_active_index.size() - 1, -1, -1): - draw_set_transform_matrix(projectile_instance_array[projectile_active_index[i]].transform) - draw_texture(projectile_texture, projectile_texture_draw_offset, projectile_texture_modulate) - -var projectile_canvas_item_ids: Array[RID] - -func setup_canvas_item() -> void: - pass - -func update_canvas_item() -> void: - for index in projectile_active_index: - RenderingServer.canvas_item_set_transform( - projectile_canvas_item_ids[index], - projectile_instance_array[index].transform - ) - pass - - -#endregion - - func clear_projectile_updater() -> void: - for instance: ProjectileInstanceCustom2D in projectile_instance_array: + for instance: ProjectileInstanceCustom2D in projectile_instances: instance.queue_free() PS.area_clear_shapes(projectile_area_rid) func get_active_projectile_count() -> int: - return projectile_active_index.size() + return projectile_active_indexes.size() pass ## Clear all ProjectileInstances in this ProjectileUpdater func clear_projectiles() -> void: for _index in range(projectile_max_pooling): - if projectile_active_index.has(_index): - projectile_active_index.erase(_index) + if projectile_active_indexes.has(_index): + projectile_active_indexes.erase(_index) PS.area_set_shape_disabled(projectile_area_rid, _index, true) - projectile_active_index.clear() + projectile_active_indexes.clear() pass -func has_overlapping_areas(area_idx: int = -1) -> bool: - return _overlapping_areas.has(area_idx) +func hasprojectile_overlapping_areas(area_idx: int = -1) -> bool: + return projectile_overlapping_areas.has(area_idx) -func get_overlapping_areas(area_idx: int = -1) -> Array: - return _overlapping_areas.get(area_idx) +func getprojectile_overlapping_areas(area_idx: int = -1) -> Array: + return projectile_overlapping_areas.get(area_idx) -func has_overlapping_bodies(area_idx: int = -1) -> bool: - return _overlapping_bodies.has(area_idx) +func hasprojectile_overlapping_bodies(area_idx: int = -1) -> bool: + return projectile_overlapping_bodies.has(area_idx) -func get_overlapping_bodies(area_idx: int = -1) -> Array: - return _overlapping_bodies.get(area_idx) as Array +func getprojectile_overlapping_bodies(area_idx: int = -1) -> Array: + return projectile_overlapping_bodies.get(area_idx) as Array 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 9b7fe0f0..ee5f560e 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 @@ -4,9 +4,6 @@ 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 @@ -42,9 +39,9 @@ var projectile_trigger_life_time: float var projectile_trigger_life_distance: float -func init_updater_variable() -> void: +func update_updater_variables() -> void: projectile_template_2d = projectile_template_2d as ProjectileTemplateAdvanced2D - _new_projectile_instance = Callable(ProjectileInstanceAdvanced2D, "new") + projectile_instance_callable = Callable(ProjectileInstanceAdvanced2D, "new") projectile_rotation_follow_direction = projectile_template_2d.rotation_follow_direction @@ -69,7 +66,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide for _pattern_composer_data: PatternComposerData in pattern_composer_pack: - _projectile_instance = projectile_instance_array[projectile_pooling_index] + _projectile_instance = projectile_instances[projectile_pooling_index] _projectile_instance = _projectile_instance as ProjectileInstanceAdvanced2D _projectile_instance.global_position = _pattern_composer_data.position @@ -87,9 +84,9 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _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.scale = projectile_template_2d.scale - _projectile_instance.scale_acceleration = projectile_template_2d.scale_acceleration - _projectile_instance.scale_max = projectile_template_2d.scale_max + _projectile_instance.texture_scale = projectile_template_2d.texture_scale + _projectile_instance.texture_scale_acceleration = projectile_template_2d.texture_scale_acceleration + _projectile_instance.texture_scale_max = projectile_template_2d.texture_scale_max _projectile_instance.life_time_second_max = projectile_template_2d.life_time_second_max _projectile_instance.life_distance_max = projectile_template_2d.life_distance_max @@ -135,22 +132,22 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) ) ) - if projectile_template_2d.scale_random != Vector3.ZERO: + if projectile_template_2d.texture_scale_random != Vector3.ZERO: _scale_float = ProjectileEngine.get_random_float_value( - projectile_template_2d.scale_random + projectile_template_2d.texture_scale_random ) - _projectile_instance.scale = Vector2(_scale_float, _scale_float) + _projectile_instance.texture_scale = Vector2(_scale_float, _scale_float) - if projectile_template_2d.scale_acceleration_random != Vector3.ZERO: - _projectile_instance.scale_acceleration = ProjectileEngine.get_random_float_value( - projectile_template_2d.scale_acceleration_random + if projectile_template_2d.texture_scale_acceleration_random != Vector3.ZERO: + _projectile_instance.texture_scale_acceleration = ProjectileEngine.get_random_float_value( + projectile_template_2d.texture_scale_acceleration_random ) - if projectile_template_2d.scale_max_random != Vector3.ZERO: + if projectile_template_2d.texture_scale_max_random != Vector3.ZERO: _scale_max_float = ProjectileEngine.get_random_float_value( - projectile_template_2d.scale_max_random + projectile_template_2d.texture_scale_max_random ) - _projectile_instance.scale_max = Vector2(_scale_max_float, _scale_max_float) + _projectile_instance.texture_scale_max = Vector2(_scale_max_float, _scale_max_float) if projectile_template_2d.life_time_second_random != Vector3.ZERO: _projectile_instance.life_time_second_max = ProjectileEngine.get_random_float_value( @@ -172,10 +169,10 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) if projectile_rotation_follow_direction: _projectile_instance.texture_rotation = _projectile_instance.direction_rotation - _projectile_instance.transform = Transform2D( + _projectile_instance.transform_2d = Transform2D( _projectile_instance.texture_rotation, - _projectile_instance.scale, - _projectile_instance.skew, + _projectile_instance.texture_scale, + _projectile_instance.texture_skew, _projectile_instance.global_position ) @@ -183,7 +180,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) PS.area_set_shape_transform( projectile_area_rid, projectile_pooling_index, - _projectile_instance.transform + _projectile_instance.transform_2d ) PS.area_set_shape_disabled( projectile_area_rid, @@ -195,10 +192,10 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.life_distance = 0.0 _projectile_instance.trigger_count = 0 - projectile_instance_array[projectile_pooling_index] = _projectile_instance + projectile_instances[projectile_pooling_index] = _projectile_instance - if projectile_pooling_index not in projectile_active_index: - projectile_active_index.append(projectile_pooling_index) + if projectile_pooling_index not in projectile_active_indexes: + projectile_active_indexes.append(projectile_pooling_index) projectile_pooling_index += 1 @@ -230,147 +227,142 @@ func update_projectile_instances(delta: float) -> void: var _overlap_collision_layer: int # Check for projectile destroy condition - for index: int in projectile_active_index: - _projectile_instance = projectile_instance_array[index] + for index: int in projectile_active_indexes: + _projectile_instance = projectile_instances[index] # Life Time & Distance if projectile_life_time_second_max >= 0: _projectile_instance.life_time_second += delta if _projectile_instance.life_time_second >= projectile_life_time_second_max: - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) continue if projectile_life_distance_max >= 0: _projectile_instance.life_distance += _projectile_instance.velocity.length() if _projectile_instance.life_distance >= projectile_life_distance_max: - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) continue if destroy_on_area_collide: - if has_overlapping_areas(index): - for _overlap_area in get_overlapping_areas(index): + if hasprojectile_overlapping_areas(index): + for _overlap_area in getprojectile_overlapping_areas(index): _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_area) if not _overlap_collision_layer & projectile_collision_mask: continue - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) if destroy_on_body_collide: - if has_overlapping_bodies(index): - for _overlap_body in get_overlapping_bodies(index): + if hasprojectile_overlapping_bodies(index): + for _overlap_body in getprojectile_overlapping_bodies(index): _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_body) if not _overlap_collision_layer & projectile_collision_mask: continue - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) # Destroy projectile - if projectile_remove_index.size() > 0: - for index: int in projectile_remove_index: - projectile_active_index.erase(index) + if projectile_remove_indexes.size() > 0: + for index: int in projectile_remove_indexes: + projectile_active_indexes.erase(index) if projectile_template_2d.collision_shape: PS.area_set_shape_disabled(projectile_area_rid, index, true) - projectile_remove_index.clear() - - # Update active projectile instances array - _active_projectile_instances.clear() - 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: - if projectile_is_use_trigger: - if _active_projectile_instance.trigger_count < projectile_trigger_amount: - if projectile_trigger_life_time > 0: - if _active_projectile_instance.life_time_second >= projectile_trigger_life_time * _active_projectile_instance.trigger_count: - ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _active_projectile_instance) - _active_projectile_instance.trigger_count += 1 - if projectile_trigger_life_distance > 0: - if _active_projectile_instance.life_distance >= projectile_trigger_life_distance * _active_projectile_instance.trigger_count: - ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _active_projectile_instance) - _active_projectile_instance.trigger_count += 1 - - if projectile_is_use_homing: - _homing_group_nodes = get_tree().get_nodes_in_group(projectile_homing_target_group) - if !_homing_group_nodes.is_empty(): - _homing_nearest_target = null - _homing_nearest_distance = INF - - for node in _homing_group_nodes: - if node is Node2D and is_instance_valid(node): - _homing_distance = _active_projectile_instance.global_position.distance_to(node.global_position) - if _homing_distance < _homing_nearest_distance: - _homing_nearest_distance = _homing_distance - _homing_nearest_target = node - - if _homing_nearest_target: - _homing_target_position = _homing_nearest_target.global_position - - # Calculate distance to target - _homing_distance_to_target = _active_projectile_instance.global_position.distance_to(_homing_target_position) - - # Check distance constraint - if projetile_max_homing_distance <= 0.0 or _homing_distance_to_target <= projetile_max_homing_distance: - # Calculate desired direction toward target - _homing_desired_direction = _active_projectile_instance.global_position.direction_to(_homing_target_position) - - # Gradually steer toward target - _homing_new_direction = _active_projectile_instance.direction.move_toward(_homing_desired_direction, projectile_steer_speed * delta) - _homing_final_direction = _homing_new_direction.normalized() * projectile_homing_strength + _active_projectile_instance.direction * (1.0 - projectile_homing_strength) - - _active_projectile_instance.direction = _homing_final_direction.normalized() - - if projectile_speed_acceleration == 0: - _active_projectile_instance.velocity = _active_projectile_instance.speed * _active_projectile_instance.direction * delta - - if _active_projectile_instance.texture_rotation_speed != 0: - _active_projectile_instance.texture_rotation += _active_projectile_instance.texture_rotation_speed * delta - - if _active_projectile_instance.scale_acceleration != 0: - if _active_projectile_instance.scale < _active_projectile_instance.scale_max: - _active_projectile_instance.scale = _active_projectile_instance.scale.move_toward(_active_projectile_instance.scale_max, _active_projectile_instance.scale_acceleration * delta) + projectile_remove_indexes.clear() + + # # Update active projectile + # 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: + # if _active_projectile_instance.life_time_second >= projectile_trigger_life_time * _active_projectile_instance.trigger_count: + # ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _active_projectile_instance) + # _active_projectile_instance.trigger_count += 1 + # if projectile_trigger_life_distance > 0: + # if _active_projectile_instance.life_distance >= projectile_trigger_life_distance * _active_projectile_instance.trigger_count: + # ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _active_projectile_instance) + # _active_projectile_instance.trigger_count += 1 + + # if projectile_is_use_homing: + # _homing_group_nodes = get_tree().get_nodes_in_group(projectile_homing_target_group) + # if !_homing_group_nodes.is_empty(): + # _homing_nearest_target = null + # _homing_nearest_distance = INF + + # for node in _homing_group_nodes: + # if node is Node2D and is_instance_valid(node): + # _homing_distance = _active_projectile_instance.global_position.distance_to(node.global_position) + # if _homing_distance < _homing_nearest_distance: + # _homing_nearest_distance = _homing_distance + # _homing_nearest_target = node + + # if _homing_nearest_target: + # _homing_target_position = _homing_nearest_target.global_position + + # # Calculate distance to target + # _homing_distance_to_target = _active_projectile_instance.global_position.distance_to(_homing_target_position) + + # # Check distance constraint + # if projetile_max_homing_distance <= 0.0 or _homing_distance_to_target <= projetile_max_homing_distance: + # # Calculate desired direction toward target + # _homing_desired_direction = _active_projectile_instance.global_position.direction_to(_homing_target_position) + + # # Gradually steer toward target + # _homing_new_direction = _active_projectile_instance.direction.move_toward(_homing_desired_direction, projectile_steer_speed * delta) + # _homing_final_direction = _homing_new_direction.normalized() * projectile_homing_strength + _active_projectile_instance.direction * (1.0 - projectile_homing_strength) + + # _active_projectile_instance.direction = _homing_final_direction.normalized() + + # if projectile_speed_acceleration == 0: + # _active_projectile_instance.velocity = _active_projectile_instance.speed * _active_projectile_instance.direction * delta + + # if _active_projectile_instance.texture_rotation_speed != 0: + # _active_projectile_instance.texture_rotation += _active_projectile_instance.texture_rotation_speed * delta + + # if _active_projectile_instance.texture_scale_acceleration != 0: + # if _active_projectile_instance.texture_scale < _active_projectile_instance.texture_scale_max: + # _active_projectile_instance.texture_scale = _active_projectile_instance.texture_scale.move_toward(_active_projectile_instance.texture_scale_max, _active_projectile_instance.texture_scale_acceleration * delta) - if _active_projectile_instance.speed_acceleration != 0: - if _active_projectile_instance.speed < _active_projectile_instance.speed_max: - _active_projectile_instance.speed = move_toward( - _active_projectile_instance.speed, _active_projectile_instance.speed_max, _active_projectile_instance.speed_acceleration * delta - ) - - if _active_projectile_instance.texture_rotation_speed != 0: - _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 - - # Update Projectile Instance Properties - # print("direction rotation: ", _active_projectile_instance.direction_rotation_speed) - if _active_projectile_instance.direction_rotation_speed != 0: - _active_projectile_instance.direction_rotation += _active_projectile_instance.direction_rotation_speed * delta - # print(_active_projectile_instance.direction_rotation) - - if _active_projectile_instance.direction_rotation != 0: - _active_projectile_instance.direction = _active_projectile_instance.base_direction.rotated( - _active_projectile_instance.direction_rotation - ) - - if projectile_rotation_follow_direction: - _active_projectile_instance.texture_rotation = _active_projectile_instance.direction_rotation - - _active_projectile_instance.velocity = _active_projectile_instance.speed * _active_projectile_instance.direction * delta - - _active_projectile_instance.global_position += _active_projectile_instance.velocity - - _active_projectile_instance.transform = Transform2D( - _active_projectile_instance.texture_rotation, - _active_projectile_instance.scale, - _active_projectile_instance.skew, - _active_projectile_instance.global_position - ) - - if projectile_template_2d.collision_shape: - PS.area_set_shape_transform( - projectile_area_rid, - _active_projectile_instance.area_index, - _active_projectile_instance.transform - ) + # if _active_projectile_instance.speed_acceleration != 0: + # if _active_projectile_instance.speed < _active_projectile_instance.speed_max: + # _active_projectile_instance.speed = move_toward( + # _active_projectile_instance.speed, _active_projectile_instance.speed_max, _active_projectile_instance.speed_acceleration * delta + # ) + + # if _active_projectile_instance.texture_rotation_speed != 0: + # _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 + + # # Update Projectile Instance Properties + # # print("direction rotation: ", _active_projectile_instance.direction_rotation_speed) + # if _active_projectile_instance.direction_rotation_speed != 0: + # _active_projectile_instance.direction_rotation += _active_projectile_instance.direction_rotation_speed * delta + # # print(_active_projectile_instance.direction_rotation) + + # if _active_projectile_instance.direction_rotation != 0: + # _active_projectile_instance.direction = _active_projectile_instance.base_direction.rotated( + # _active_projectile_instance.direction_rotation + # ) + + # if projectile_rotation_follow_direction: + # _active_projectile_instance.texture_rotation = _active_projectile_instance.direction_rotation + + # _active_projectile_instance.velocity = _active_projectile_instance.speed * _active_projectile_instance.direction * delta + + # _active_projectile_instance.global_position += _active_projectile_instance.velocity + + # _active_projectile_instance.transform_2d = Transform2D( + # _active_projectile_instance.texture_rotation, + # _active_projectile_instance.texture_scale, + # _active_projectile_instance.texture_skew, + # _active_projectile_instance.global_position + # ) + + # if projectile_template_2d.collision_shape: + # PS.area_set_shape_transform( + # projectile_area_rid, + # _active_projectile_instance.area_index, + # _active_projectile_instance.transform_2d + # ) #endregion 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 771e9c67..a2f754fc 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 @@ -51,15 +51,15 @@ var _behavior_contest_requests_persist: Array[ProjectileEngine.BehaviorContext] var projectile_behaviors: Array[ProjectileBehavior] = [] -func init_updater_variable() -> void: +func update_updater_variables() -> void: projectile_template_2d = projectile_template_2d as ProjectileTemplateCustom2D - _new_projectile_instance = Callable(ProjectileInstanceCustom2D, "new") + projectile_instance_callable = Callable(ProjectileInstanceCustom2D, "new") projectile_behaviors = [] projectile_behaviors.append_array(projectile_template_2d.speed_projectile_behaviors) projectile_behaviors.append_array(projectile_template_2d.direction_projectile_behaviors) projectile_behaviors.append_array(projectile_template_2d.rotation_projectile_behaviors) - projectile_behaviors.append_array(projectile_template_2d.scale_projectile_behaviors) + projectile_behaviors.append_array(projectile_template_2d.texture_scale_projectile_behaviors) projectile_behaviors.append_array(projectile_template_2d.destroy_projectile_behaviors) projectile_behaviors.append_array(projectile_template_2d.bouncing_projectile_behaviors) projectile_behaviors.append_array(projectile_template_2d.piercing_projectile_behaviors) @@ -76,7 +76,7 @@ func init_updater_variable() -> void: func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) -> void: projectile_template_2d = projectile_template_2d as ProjectileTemplateCustom2D for _pattern_composer_data: PatternComposerData in pattern_composer_pack: - _projectile_instance = projectile_instance_array[projectile_pooling_index] + _projectile_instance = projectile_instances[projectile_pooling_index] _projectile_instance = _projectile_instance as ProjectileInstanceCustom2D _projectile_instance.global_position = _pattern_composer_data.position @@ -84,7 +84,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.direction = _pattern_composer_data.direction _projectile_instance.direction_rotation = _pattern_composer_data.direction_rotation _projectile_instance.texture_rotation = projectile_template_2d.texture_rotation - _projectile_instance.scale = projectile_template_2d.scale + _projectile_instance.texture_scale = projectile_template_2d.texture_scale # # Check and update random variables @@ -105,16 +105,16 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) projectile_template_2d.texture_rotation_random ) - if projectile_template_2d.scale_random != Vector3.ZERO: + if projectile_template_2d.texture_scale_random != Vector3.ZERO: _scale_float = ProjectileEngine.get_random_float_value( - projectile_template_2d.scale_random + projectile_template_2d.texture_scale_random ) - _projectile_instance.scale = Vector2(_scale_float, _scale_float) + _projectile_instance.texture_scale = Vector2(_scale_float, _scale_float) - _projectile_instance.transform = Transform2D( + _projectile_instance.transform_2d = Transform2D( _projectile_instance.texture_rotation, - _projectile_instance.scale, - _projectile_instance.skew, + _projectile_instance.texture_scale, + _projectile_instance.texture_skew, _projectile_instance.global_position ) @@ -122,13 +122,13 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.base_direction = _projectile_instance.direction _projectile_instance.base_direction_rotation = _projectile_instance.direction_rotation _projectile_instance.base_texture_rotation = _projectile_instance.texture_rotation - _projectile_instance.base_scale = _projectile_instance.scale + _projectile_instance.base_scale = _projectile_instance.texture_scale if projectile_template_2d.collision_shape: PS.area_set_shape_transform( projectile_area_rid, projectile_pooling_index, - _projectile_instance.transform + _projectile_instance.transform_2d ) PS.area_set_shape_disabled( projectile_area_rid, @@ -140,10 +140,10 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.life_distance = 0.0 _projectile_instance.trigger_count = 0 - projectile_instance_array[projectile_pooling_index] = _projectile_instance + projectile_instances[projectile_pooling_index] = _projectile_instance - if projectile_pooling_index not in projectile_active_index: - projectile_active_index.append(projectile_pooling_index) + if projectile_pooling_index not in projectile_active_indexes: + projectile_active_indexes.append(projectile_pooling_index) projectile_pooling_index += 1 @@ -158,8 +158,8 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) func update_projectile_instances(delta: float) -> void: # Check for projectile destroy condition - for index: int in projectile_active_index: - _projectile_instance = projectile_instance_array[index] + for index: int in projectile_active_indexes: + _projectile_instance = projectile_instances[index] _projectile_instance.behavior_context.clear() _projectile_instance.behavior_update_context.clear() @@ -211,7 +211,7 @@ func update_projectile_instances(delta: float) -> void: ) if _trigger_behavior_values.has("is_destroy"): if _trigger_behavior_values.is_destroy: - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) continue # Projectile Piercing Behaviors @@ -266,236 +266,230 @@ func update_projectile_instances(delta: float) -> void: continue if _projectile_behavior.process_behavior(null, _projectile_instance.behavior_context): - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) # Destroy projectile - if projectile_remove_index.size() > 0: - for index: int in projectile_remove_index: - projectile_active_index.erase(index) + if projectile_remove_indexes.size() > 0: + for index: int in projectile_remove_indexes: + projectile_active_indexes.erase(index) if projectile_template_2d.collision_shape: PS.area_set_shape_disabled(projectile_area_rid, index, true) - projectile_remove_index.clear() - - # Update active projectile instances array - _active_projectile_instances.clear() - for index: int in projectile_active_index: - _active_projectile_instances.append(projectile_instance_array[index]) - if _active_projectile_instances.size() <= 0: return + projectile_remove_indexes.clear() - ## Update Active Projectile Instances - for _active_projectile_instance: ProjectileInstanceCustom2D in _active_projectile_instances: - ## Process Projectile Transform Behaviors - ## Projectile Behavior Speed - if projectile_template_2d.speed_projectile_behaviors.size() > 0: - _speed_behavior_additions.clear() - _speed_behavior_multiplies.clear() - _base_speed_behavior_multiplies.clear() - for _projectile_behavior in projectile_template_2d.speed_projectile_behaviors: - if !_projectile_behavior: - continue - if not _projectile_behavior.active: - continue - behavior_values = _projectile_behavior.process_behavior( - _active_projectile_instance.speed, - _active_projectile_instance.behavior_context - ) - for _behavior_key in behavior_values.keys(): - match _behavior_key: - ProjectileEngine.SpeedModify.SPEED_OVERWRITE: - _active_projectile_instance.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) - ) - 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: - _projectile_instance.speed_clamp = behavior_values.get(ProjectileEngine.SpeedModify.SPEED_CLAMP) + # ## Update Active Projectile Instances + # for _active_projectile_instance: ProjectileInstanceCustom2D in _active_projectile_instances: + # ## Process Projectile Transform Behaviors + # ## Projectile Behavior Speed + # if projectile_template_2d.speed_projectile_behaviors.size() > 0: + # _speed_behavior_additions.clear() + # _speed_behavior_multiplies.clear() + # _base_speed_behavior_multiplies.clear() + # for _projectile_behavior in projectile_template_2d.speed_projectile_behaviors: + # if !_projectile_behavior: + # continue + # if not _projectile_behavior.active: + # continue + # behavior_values = _projectile_behavior.process_behavior( + # _active_projectile_instance.speed, + # _active_projectile_instance.behavior_context + # ) + # for _behavior_key in behavior_values.keys(): + # match _behavior_key: + # ProjectileEngine.SpeedModify.SPEED_OVERWRITE: + # _active_projectile_instance.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) + # ) + # 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: + # _projectile_instance.speed_clamp = behavior_values.get(ProjectileEngine.SpeedModify.SPEED_CLAMP) - ## Projectile Behavior Direction - if projectile_template_2d.direction_projectile_behaviors.size() > 0: - _direction_behavior_rotations.clear() - _direction_behavior_additions.clear() - for _projectile_behavior in projectile_template_2d.direction_projectile_behaviors: - if !_projectile_behavior: - continue - if not _projectile_behavior.active: - continue - _direction_behavior_values = _projectile_behavior.process_behavior( - _active_projectile_instance.direction, - _active_projectile_instance.behavior_context - ) - for _behavior_key in _direction_behavior_values.keys(): - match _behavior_key: - ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE: - _active_projectile_instance.direction = _direction_behavior_values.get( - ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE - ) - ProjectileEngine.DirectionModify.DIRECTION_ROTATION: - _direction_behavior_rotations.get_or_add( - _projectile_behavior, - _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_ROTATION) - ) - ProjectileEngine.DirectionModify.DIRECTION_ADDITION: - _direction_behavior_additions.get_or_add( - _projectile_behavior, - _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_ADDITION) - ) - - ## Projectile Behavior Rotation - if projectile_template_2d.rotation_projectile_behaviors.size() > 0: - _rotation_behavior_additions.clear() - _rotation_behavior_multiplies.clear() - for _projectile_behavior in projectile_template_2d.rotation_projectile_behaviors: - if !_projectile_behavior: - continue - if not _projectile_behavior.active: - continue - behavior_values = _projectile_behavior.process_behavior( - _active_projectile_instance.texture_rotation, - _active_projectile_instance.behavior_context - ) - for _behavior_key in behavior_values.keys(): - match _behavior_key: - ProjectileEngine.RotationModify.ROTATION_OVERWRITE: - _active_projectile_instance.texture_rotation = behavior_values.get(ProjectileEngine.RotationModify.ROTATION_OVERWRITE) - ProjectileEngine.RotationModify.ROTATION_ADDITION: - _rotation_behavior_additions.get_or_add( - _projectile_behavior, - behavior_values.get(ProjectileEngine.RotationModify.ROTATION_ADDITION) - ) - "rotation_multiply": - _rotation_behavior_multiplies.get_or_add( - _projectile_behavior, - behavior_values.get("rotation_multiply") - ) + # ## Projectile Behavior Direction + # if projectile_template_2d.direction_projectile_behaviors.size() > 0: + # _direction_behavior_rotations.clear() + # _direction_behavior_additions.clear() + # for _projectile_behavior in projectile_template_2d.direction_projectile_behaviors: + # if !_projectile_behavior: + # continue + # if not _projectile_behavior.active: + # continue + # _direction_behavior_values = _projectile_behavior.process_behavior( + # _active_projectile_instance.direction, + # _active_projectile_instance.behavior_context + # ) + # for _behavior_key in _direction_behavior_values.keys(): + # match _behavior_key: + # ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE: + # _active_projectile_instance.direction = _direction_behavior_values.get( + # ProjectileEngine.DirectionModify.DIRECTION_OVERWRITE + # ) + # ProjectileEngine.DirectionModify.DIRECTION_ROTATION: + # _direction_behavior_rotations.get_or_add( + # _projectile_behavior, + # _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_ROTATION) + # ) + # ProjectileEngine.DirectionModify.DIRECTION_ADDITION: + # _direction_behavior_additions.get_or_add( + # _projectile_behavior, + # _direction_behavior_values.get(ProjectileEngine.DirectionModify.DIRECTION_ADDITION) + # ) + + # ## Projectile Behavior Rotation + # if projectile_template_2d.rotation_projectile_behaviors.size() > 0: + # _rotation_behavior_additions.clear() + # _rotation_behavior_multiplies.clear() + # for _projectile_behavior in projectile_template_2d.rotation_projectile_behaviors: + # if !_projectile_behavior: + # continue + # if not _projectile_behavior.active: + # continue + # behavior_values = _projectile_behavior.process_behavior( + # _active_projectile_instance.texture_rotation, + # _active_projectile_instance.behavior_context + # ) + # for _behavior_key in behavior_values.keys(): + # match _behavior_key: + # ProjectileEngine.RotationModify.ROTATION_OVERWRITE: + # _active_projectile_instance.texture_rotation = behavior_values.get(ProjectileEngine.RotationModify.ROTATION_OVERWRITE) + # ProjectileEngine.RotationModify.ROTATION_ADDITION: + # _rotation_behavior_additions.get_or_add( + # _projectile_behavior, + # behavior_values.get(ProjectileEngine.RotationModify.ROTATION_ADDITION) + # ) + # "rotation_multiply": + # _rotation_behavior_multiplies.get_or_add( + # _projectile_behavior, + # behavior_values.get("rotation_multiply") + # ) - ## Projectile Behavior Scale - if projectile_template_2d.scale_projectile_behaviors.size() > 0: - _scale_behavior_additions.clear() - _scale_behavior_multiplies.clear() - for _projectile_behavior in projectile_template_2d.scale_projectile_behaviors: - if !_projectile_behavior: - continue - if not _projectile_behavior.active: - continue - behavior_values = _projectile_behavior.process_behavior( - _active_projectile_instance.projectile_scale, - _active_projectile_instance.behavior_context - ) - if behavior_values.size() <= 0: - continue - for _behavior_key in behavior_values.keys(): - match _behavior_key: - ProjectileEngine.ScaleModify.SCALE_OVERWRITE: - _active_projectile_instance.projectile_scale = behavior_values.get(ProjectileEngine.ScaleModify.SCALE_OVERWRITE) - ProjectileEngine.ScaleModify.SCALE_ADDITION: - _scale_behavior_additions.get_or_add( - _projectile_behavior, - behavior_values.get(ProjectileEngine.ScaleModify.SCALE_ADDITION) - ) - ProjectileEngine.ScaleModify.SCALE_MULTIPLY: - _scale_behavior_multiplies.get_or_add( - _projectile_behavior, - behavior_values.get(ProjectileEngine.ScaleModify.SCALE_MULTIPLY) - ) - - ## Apply Projectile behaviors - - ## Apply Projectile behaviors Rotation - rotation_final = _active_projectile_instance.texture_rotation - if _rotation_behavior_multiplies.size() > 0: - _rotation_multiply_value = 0.0 - for _rotation_behavior_multiply in _rotation_behavior_multiplies.values(): - _rotation_multiply_value += _rotation_behavior_multiply - _rotation_multiply = base_rotation * _rotation_multiply_value - rotation_final += _rotation_multiply - if _rotation_behavior_additions.size() > 0: - _rotation_addition = 0.0 - for _rotation_behavior_addition in _rotation_behavior_additions.values(): - _rotation_addition += _rotation_behavior_addition - rotation_final += _rotation_addition - _active_projectile_instance.texture_rotation = rotation_final - - ## Apply Projectile behaviors Scale - scale_final = _active_projectile_instance.scale - if _scale_behavior_multiplies.size() > 0: - _scale_multiply_value = Vector2.ZERO - for _scale_behavior_multiply in _scale_behavior_multiplies.values(): - _scale_multiply_value += _scale_behavior_multiply - _scale_multiply = base_scale * _scale_multiply_value - scale_final += _scale_multiply - if _scale_behavior_additions.size() > 0: - _scale_addition = Vector2.ZERO - for _scale_behavior_addition in _scale_behavior_additions.values(): - _scale_addition += _scale_behavior_addition - scale_final += _scale_addition - _active_projectile_instance.scale = scale_final - - ## Apply Projectile behaviors Direction - var _direction_rotation_final := _active_projectile_instance.direction_rotation - if _direction_behavior_rotations.size() > 0: - for _direction_behavior_rotation in _direction_behavior_rotations.values(): - _direction_rotation_final += _direction_behavior_rotation - _active_projectile_instance.direction_rotation = _direction_rotation_final + # ## Projectile Behavior Scale + # if projectile_template_2d.texture_scale_projectile_behaviors.size() > 0: + # _scale_behavior_additions.clear() + # _scale_behavior_multiplies.clear() + # for _projectile_behavior in projectile_template_2d.texture_scale_projectile_behaviors: + # if !_projectile_behavior: + # continue + # if not _projectile_behavior.active: + # continue + # behavior_values = _projectile_behavior.process_behavior( + # _active_projectile_instance.projectile_scale, + # _active_projectile_instance.behavior_context + # ) + # if behavior_values.size() <= 0: + # continue + # for _behavior_key in behavior_values.keys(): + # match _behavior_key: + # ProjectileEngine.ScaleModify.SCALE_OVERWRITE: + # _active_projectile_instance.projectile_scale = behavior_values.get(ProjectileEngine.ScaleModify.SCALE_OVERWRITE) + # ProjectileEngine.ScaleModify.SCALE_ADDITION: + # _scale_behavior_additions.get_or_add( + # _projectile_behavior, + # behavior_values.get(ProjectileEngine.ScaleModify.SCALE_ADDITION) + # ) + # ProjectileEngine.ScaleModify.SCALE_MULTIPLY: + # _scale_behavior_multiplies.get_or_add( + # _projectile_behavior, + # behavior_values.get(ProjectileEngine.ScaleModify.SCALE_MULTIPLY) + # ) + + # ## Apply Projectile behaviors + + # ## Apply Projectile behaviors Rotation + # rotation_final = _active_projectile_instance.texture_rotation + # if _rotation_behavior_multiplies.size() > 0: + # _rotation_multiply_value = 0.0 + # for _rotation_behavior_multiply in _rotation_behavior_multiplies.values(): + # _rotation_multiply_value += _rotation_behavior_multiply + # _rotation_multiply = base_rotation * _rotation_multiply_value + # rotation_final += _rotation_multiply + # if _rotation_behavior_additions.size() > 0: + # _rotation_addition = 0.0 + # for _rotation_behavior_addition in _rotation_behavior_additions.values(): + # _rotation_addition += _rotation_behavior_addition + # rotation_final += _rotation_addition + # _active_projectile_instance.texture_rotation = rotation_final + + # ## Apply Projectile behaviors Scale + # scale_final = _active_projectile_instance.texture_scale + # if _scale_behavior_multiplies.size() > 0: + # _scale_multiply_value = Vector2.ZERO + # for _scale_behavior_multiply in _scale_behavior_multiplies.values(): + # _scale_multiply_value += _scale_behavior_multiply + # _scale_multiply = base_scale * _scale_multiply_value + # scale_final += _scale_multiply + # if _scale_behavior_additions.size() > 0: + # _scale_addition = Vector2.ZERO + # for _scale_behavior_addition in _scale_behavior_additions.values(): + # _scale_addition += _scale_behavior_addition + # scale_final += _scale_addition + # _active_projectile_instance.texture_scale = scale_final + + # ## Apply Projectile behaviors Direction + # var _direction_rotation_final := _active_projectile_instance.direction_rotation + # if _direction_behavior_rotations.size() > 0: + # for _direction_behavior_rotation in _direction_behavior_rotations.values(): + # _direction_rotation_final += _direction_behavior_rotation + # _active_projectile_instance.direction_rotation = _direction_rotation_final - ## Apply Projectile behaviors Speed - _active_projectile_instance.speed_final = _active_projectile_instance.speed - if _speed_behavior_additions.size() > 0: - _speed_addition = 0 - for _speed_behavior_addition in _speed_behavior_additions.values(): - _speed_addition += _speed_behavior_addition - _active_projectile_instance.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 = _active_projectile_instance.speed * _speed_multiply_value - _active_projectile_instance.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 = _active_projectile_instance.base_speed * _speed_multiply_value - _active_projectile_instance.speed_final += _speed_multiply + # ## Apply Projectile behaviors Speed + # _active_projectile_instance.speed_final = _active_projectile_instance.speed + # if _speed_behavior_additions.size() > 0: + # _speed_addition = 0 + # for _speed_behavior_addition in _speed_behavior_additions.values(): + # _speed_addition += _speed_behavior_addition + # _active_projectile_instance.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 = _active_projectile_instance.speed * _speed_multiply_value + # _active_projectile_instance.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 = _active_projectile_instance.base_speed * _speed_multiply_value + # _active_projectile_instance.speed_final += _speed_multiply - # _active_projectile_instance.speed_final _projectile_instance.speed_clamp - if _projectile_instance.speed_clamp != Vector2.ZERO: - _active_projectile_instance.speed_final = clamp( - _active_projectile_instance.speed_final, - _projectile_instance.speed_clamp.x, - _projectile_instance.speed_clamp.y - ) - - ## Update Velocity - if _active_projectile_instance.direction_rotation != 0: - _active_projectile_instance.direction = _active_projectile_instance.base_direction.rotated( - _active_projectile_instance.direction_rotation - ) - - _active_projectile_instance.velocity = _active_projectile_instance.speed_final * _active_projectile_instance.direction * delta - _active_projectile_instance.global_position += _active_projectile_instance.velocity - - _active_projectile_instance.transform = Transform2D( - _active_projectile_instance.texture_rotation, - _active_projectile_instance.scale, - _active_projectile_instance.skew, - _active_projectile_instance.global_position - ) - - if projectile_template_2d.collision_shape: - PS.area_set_shape_transform( - projectile_area_rid, - _active_projectile_instance.area_index, - _active_projectile_instance.transform - ) + # # _active_projectile_instance.speed_final _projectile_instance.speed_clamp + # if _projectile_instance.speed_clamp != Vector2.ZERO: + # _active_projectile_instance.speed_final = clamp( + # _active_projectile_instance.speed_final, + # _projectile_instance.speed_clamp.x, + # _projectile_instance.speed_clamp.y + # ) + + # ## Update Velocity + # if _active_projectile_instance.direction_rotation != 0: + # _active_projectile_instance.direction = _active_projectile_instance.base_direction.rotated( + # _active_projectile_instance.direction_rotation + # ) + + # _active_projectile_instance.velocity = _active_projectile_instance.speed_final * _active_projectile_instance.direction * delta + # _active_projectile_instance.global_position += _active_projectile_instance.velocity + + # _active_projectile_instance.transform_2d = Transform2D( + # _active_projectile_instance.texture_rotation, + # _active_projectile_instance.texture_scale, + # _active_projectile_instance.texture_skew, + # _active_projectile_instance.global_position + # ) + + # if projectile_template_2d.collision_shape: + # PS.area_set_shape_transform( + # projectile_area_rid, + # _active_projectile_instance.area_index, + # _active_projectile_instance.transform_2d + # ) func update_projectile_behavior_context() -> void: pass @@ -542,7 +536,7 @@ func process_behavior_context_request( _behavior_context.get_or_add(_behavior_context_request, _projectile_instance.texture_rotation) ProjectileEngine.BehaviorContext.BASE_SCALE: - _behavior_context.get_or_add(_behavior_context_request, _projectile_instance.scale) + _behavior_context.get_or_add(_behavior_context_request, _projectile_instance.texture_scale) ProjectileEngine.BehaviorContext.RANDOM_NUMBER_GENERATOR: var _rng_array := [] 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 a3533d34..5a1a7154 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 @@ -148,12 +148,12 @@ func init_base_properties() -> void: 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)) + #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: diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd index e983915a..f83b0c6e 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd @@ -1,84 +1,11 @@ -extends ProjectileTemplate2D +extends ProjectileTemplateObject2D class_name ProjectileTemplateSimple2D ## Template for Simple Projectile 2D that will move at the direction and speed defined. - -## Movement speed of the projectile in pixels per second -@export var speed: float = 100: - set(value): - speed = value - emit_changed() - -## Number of projectiles to preload in the object pool for better performance -@export var projectile_pooling_amount: int = 500 - -## The Projectile Instance Texture -@export var texture: Texture2D: - set(value): - texture = value - emit_changed() -## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] -@export_custom(PROPERTY_HINT_LINK, "suffix:") var scale: Vector2 = Vector2.ONE - -## Initial rotation of the texture in degrees -@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float -## Skew/shear effect applied to texture (-89.9 to 89.9 degrees) -@export_range(-89.9, 89.9, 0.1) var skew: float = 0.0 -## Toggles visibility of the projectile's texture -@export var texture_visible: bool = true -## Render layer for the texture (higher values render on top) -@export var texture_z_index: int = 0: - set(value): - texture_z_index = value - emit_changed() -## Reverse Z in dex, make new bullet render underneath older bullet -@export var reverse_z_index: bool = false: - set(value): - reverse_z_index = value - emit_changed() - -## Color modulation applied to the texture (RGBA) -@export var texture_modulate: Color = Color(1, 1, 1, 1): - set(value): - texture_modulate = value - emit_changed() - -## Collision shape used for physics detection -@export var collision_shape: Shape2D -## Physics layers this projectile can collide with (bitmask) -@export_flags_2d_physics var collision_layer: int = 0 -## Physics layers that can detect collisions with this projectile (bitmask) -@export_flags_2d_physics var collision_mask: int = 0 -@export var texture_rotate_direction: bool = false: - set(value): - texture_rotate_direction = value - emit_changed() - -## Destroy when collided with a body -@export var destroy_on_body_collide: bool = true -## Destroy when collided with a area -@export var destroy_on_area_collide: bool = true -## Maximum lifetime of projectile in seconds before it's automatically destroyed -## [code] life_time_max < 0 [/code] for unlimited life time -@export var life_time_second_max: float = 10.0: - set(value): - life_time_second_max = value - emit_changed() -## Maximum travel distance in pixels before projectile is automatically destroyed [br] -## [code] life_distance_max < 0 [/code] for unlimited distance -@export var life_distance_max: float = 1000.0: - set(value): - life_distance_max = value - emit_changed() - @export_group("Random") @export var speed_random: Vector3 @export var texture_rotation_random: Vector3 @export var texture_rotation_speed_random: Vector3 -@export var scale_random: Vector3 +@export var texture_scale_random: Vector3 @export var life_time_second_random : Vector3 -@export var life_distance_random : Vector3 -# @export var hue_variation : Vector3 - -## Internal RID (Rendering ID) for the projectile's collision area -var projectile_area_rid: RID +@export var life_distance_random : Vector3 \ No newline at end of file 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 20487d58..c05c1c0b 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 @@ -3,55 +3,49 @@ class_name ProjectileUpdaterSimple2D 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_texture_rotate_direction: bool -func init_updater_variable() -> void: - super () +func update_updater_variables() -> void: + super() projectile_template_2d = projectile_template_2d as ProjectileTemplateSimple2D projectile_speed = projectile_template_2d.speed destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide - projectile_life_time_second_max = projectile_template_2d.life_time_second_max - projectile_life_distance_max = projectile_template_2d.life_distance_max - - _new_projectile_instance = Callable(ProjectileInstanceSimple2D, "new") + projectile_instance_callable = Callable(ProjectileInstanceSimple2D, "new") #region Spawn Projectile func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) -> void: projectile_template_2d = projectile_template_2d as ProjectileTemplateSimple2D + for _pattern_composer_data: PatternComposerData in pattern_composer_pack: - _projectile_instance = projectile_instance_array[projectile_pooling_index] + _projectile_instance = projectile_instances[projectile_pooling_index] _projectile_instance.global_position = _pattern_composer_data.position _projectile_instance.direction = _pattern_composer_data.direction _projectile_instance.direction_rotation = _pattern_composer_data.direction_rotation _projectile_instance.texture_rotation = projectile_template_2d.texture_rotation - _projectile_instance.scale = projectile_template_2d.scale - _projectile_instance.life_time_second_max = projectile_template_2d.life_time_second_max - _projectile_instance.life_distance_max = projectile_template_2d.life_distance_max + _projectile_instance.texture_scale = projectile_template_2d.texture_scale # Check and update random variables var _speed_value: float = projectile_speed var _scale_value_float: float - var _scale_value: Vector2 = projectile_template_2d.scale + var _scale_value: Vector2 = projectile_template_2d.texture_scale var _rotation_value: float = _projectile_instance.texture_rotation if projectile_template_2d.speed_random != Vector3.ZERO: _speed_value = ProjectileEngine.get_random_float_value(projectile_template_2d.speed_random) - if projectile_template_2d.scale_random != Vector3.ZERO: - _scale_value_float = ProjectileEngine.get_random_float_value(projectile_template_2d.scale_random) + if projectile_template_2d.texture_scale_random != Vector3.ZERO: + _scale_value_float = ProjectileEngine.get_random_float_value(projectile_template_2d.texture_scale_random) _scale_value = Vector2(_scale_value_float, _scale_value_float) - _projectile_instance.scale = _scale_value + _projectile_instance.texture_scale = _scale_value if projectile_template_2d.texture_rotation_random != Vector3.ZERO: _projectile_instance.texture_rotation = ProjectileEngine.get_random_float_value( @@ -78,27 +72,27 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) if projectile_texture_rotate_direction: _projectile_instance.texture_rotation = _projectile_instance.direction.angle() - _projectile_instance.transform = Transform2D( + _projectile_instance.transform_2d = Transform2D( _projectile_instance.texture_rotation, - _projectile_instance.scale, - projectile_template_2d.skew, + _projectile_instance.texture_scale, + projectile_template_2d.texture_skew, _projectile_instance.global_position ) RenderingServer.canvas_item_set_visible(_projectile_instance.canvas_item_rid, true) - RenderingServer.canvas_item_set_transform(_projectile_instance.canvas_item_rid, _projectile_instance.transform) + RenderingServer.canvas_item_set_transform(_projectile_instance.canvas_item_rid, _projectile_instance.transform_2d) if projectile_template_2d.collision_shape: - PS.area_set_shape_transform(projectile_area_rid, projectile_pooling_index, _projectile_instance.transform) + PS.area_set_shape_transform(projectile_area_rid, projectile_pooling_index, _projectile_instance.transform_2d) PS.area_set_shape_disabled(projectile_area_rid, projectile_pooling_index, false) _projectile_instance.life_time_second = 0.0 _projectile_instance.life_distance = 0.0 - projectile_instance_array[projectile_pooling_index] = _projectile_instance - if projectile_pooling_index not in projectile_active_index: - projectile_active_index.append(projectile_pooling_index) + projectile_instances[projectile_pooling_index] = _projectile_instance + if projectile_pooling_index not in projectile_active_indexes: + projectile_active_indexes.append(projectile_pooling_index) projectile_pooling_index += 1 if projectile_pooling_index >= projectile_max_pooling: @@ -115,59 +109,59 @@ var _active_projectile_instance: ProjectileInstanceSimple2D func update_projectile_instances(delta: float) -> void: # Check for projectile destroy condition - for index: int in projectile_active_index: - _projectile_instance = projectile_instance_array[index] + for index: int in projectile_active_indexes: + _projectile_instance = projectile_instances[index] # Life Time & Distance if projectile_life_time_second_max > 0: _projectile_instance.life_time_second += delta if _projectile_instance.life_time_second >= projectile_life_time_second_max: - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) if projectile_life_distance_max > 0: _projectile_instance.life_distance += _projectile_instance.velocity_length if _projectile_instance.life_distance >= projectile_life_distance_max: - projectile_remove_index.append(index) + projectile_remove_indexes.append(index) continue if destroy_on_area_collide: - if has_overlapping_areas(index): - projectile_remove_index.append(index) + if hasprojectile_overlapping_areas(index): + projectile_remove_indexes.append(index) if destroy_on_body_collide: - if has_overlapping_bodies(index): - projectile_remove_index.append(index) + if hasprojectile_overlapping_bodies(index): + projectile_remove_indexes.append(index) ## Update Transform and texture _projectile_instance.global_position += _projectile_instance.velocity - _projectile_instance.transform = Transform2D( + _projectile_instance.transform_2d = Transform2D( _projectile_instance.texture_rotation, - _projectile_instance.scale, - _projectile_instance.skew, + _projectile_instance.texture_scale, + _projectile_instance.texture_skew, _projectile_instance.global_position ) RenderingServer.canvas_item_set_transform( - projectile_canvas_item_ids[index], - _projectile_instance.transform + projectile_canvas_item_rids[index], + _projectile_instance.transform_2d ) if projectile_template_2d.collision_shape: PS.area_set_shape_transform( projectile_area_rid, _projectile_instance.area_index, - _projectile_instance.transform + _projectile_instance.transform_2d ) # Destroy projectile - if projectile_remove_index.size() > 0: - for index: int in projectile_remove_index: - projectile_active_index.erase(index) - RenderingServer.canvas_item_set_visible(projectile_instance_array[index].canvas_item_rid, false) + if projectile_remove_indexes.size() > 0: + for index: int in projectile_remove_indexes: + projectile_active_indexes.erase(index) + RenderingServer.canvas_item_set_visible(projectile_instances[index].canvas_item_rid, false) if projectile_template_2d.collision_shape: PS.area_set_shape_disabled(projectile_area_rid, index, true) - projectile_remove_index.clear() + projectile_remove_indexes.clear() #endregion @@ -181,8 +175,8 @@ func _on_projectile_template_changed() -> void: projectile_life_time_second_max = projectile_template_2d.life_time_second_max projectile_life_distance_max = projectile_template_2d.life_distance_max - for index in projectile_active_index: - _active_projectile_instance = projectile_instance_array[index] + for index in projectile_active_indexes: + _active_projectile_instance = projectile_instances[index] _active_projectile_instance.velocity = ( projectile_speed * _active_projectile_instance.direction * diff --git a/project.godot b/project.godot index 7fc6fcf3..097d151a 100644 --- a/project.godot +++ b/project.godot @@ -21,6 +21,8 @@ ProjectileEngine="*res://addons/godot_projectile_engine/GodotProjectileEngine.gd [debug] gdscript/warnings/untyped_declaration=2 +gdscript/warnings/unsafe_property_access=2 +gdscript/warnings/unsafe_method_access=2 [display] From f00c793f790abb5751d89f0f38db5c667ae4a8db Mon Sep 17 00:00:00 2001 From: superhighlevel Date: Mon, 8 Dec 2025 17:55:34 +0700 Subject: [PATCH 3/3] update projectile template --- .../projectile_spawner/projectile_spawner.gd | 43 +- .../base/projectile_custom_data.gd | 2 +- .../projectile_template_2d.gd | 8 +- .../projectile_template_object_2d.gd | 92 +--- .../projectile_updater_2d.gd | 113 +++-- .../projectile_instance_advanced.gd | 4 + .../projectile_template_advanced_2d.gd | 157 +++--- .../projectile_updater_advanced_2d.gd | 445 +++++++++++------- .../projectile_template_custom_2d.gd | 5 - .../projectile_updater_custom_2d.gd | 2 +- .../projectile_node_manager.gd | 12 +- .../projectile_template_node_2d.gd | 1 - .../projectile_template_simple_2d.gd | 93 +++- .../projectile_updater_simple_2d.gd | 105 ++--- docs/manual/projectile_node_manager.md | 2 +- docs/manual/projectile_updater.md | 2 +- project.godot | 1 - 17 files changed, 618 insertions(+), 469 deletions(-) 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 18477610..0fb2f2ce 100644 --- a/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd +++ b/addons/godot_projectile_engine/core/projectile_spawner/projectile_spawner.gd @@ -74,15 +74,7 @@ func setup_projectile_spawner() -> void: ) ProjectileTemplateAdvanced2D: - if !is_instance_valid( - ProjectileEngine.projectile_updater_2d_nodes.get( - projectile_template_2d.projectile_area_rid - ) - ): - create_projectile_updater_advanced_2d() - projectile_updater_2d = ProjectileEngine.projectile_updater_2d_nodes.get( - projectile_template_2d.projectile_area_rid - ) + create_projectile_updater_advanced_2d() ProjectileTemplateCustom2D: if !is_instance_valid( @@ -178,17 +170,16 @@ func create_projectile_updater_simple_2d() -> void: if !ProjectileEngine.projectile_environment: return - var _projectile_updater := ProjectileUpdaterSimple2D.new() + projectile_updater_2d = ProjectileUpdaterSimple2D.new() - _projectile_updater.projectile_template_2d = projectile_template_2d + projectile_updater_2d.projectile_template_2d = projectile_template_2d if projectile_template_2d.custom_data: - _projectile_updater.custom_data = projectile_template_2d.custom_data + projectile_updater_2d.projectile_custom_data = projectile_template_2d.custom_data - ProjectileEngine.projectile_environment.add_child(_projectile_updater, true) - projectile_area = _projectile_updater.projectile_area_rid - projectile_template_2d.projectile_area_rid = _projectile_updater.projectile_area_rid - ProjectileEngine.projectile_updater_2d_nodes.get_or_add(projectile_area, _projectile_updater) - projectile_updater_2d = _projectile_updater + ProjectileEngine.projectile_environment.add_child(projectile_updater_2d, true) + projectile_area = projectile_updater_2d.projectile_area_rid + projectile_template_2d.projectile_area_rid = projectile_updater_2d.projectile_area_rid + ProjectileEngine.projectile_updater_2d_nodes.get_or_add(projectile_area, projectile_updater_2d) pass @@ -196,16 +187,16 @@ func create_projectile_updater_advanced_2d() -> void: if !ProjectileEngine.projectile_environment: return - var _projectile_updater := ProjectileUpdaterAdvanced2D.new() + projectile_updater_2d = ProjectileUpdaterAdvanced2D.new() - _projectile_updater.projectile_template_2d = projectile_template_2d - _projectile_updater.custom_data = projectile_template_2d.custom_data + projectile_updater_2d.projectile_template_2d = projectile_template_2d + if projectile_template_2d.custom_data: + projectile_updater_2d.projectile_custom_data = projectile_template_2d.custom_data - ProjectileEngine.projectile_environment.add_child(_projectile_updater, true) - projectile_area = _projectile_updater.projectile_area_rid - projectile_template_2d.projectile_area_rid = _projectile_updater.projectile_area_rid - ProjectileEngine.projectile_updater_2d_nodes.get_or_add(projectile_area, _projectile_updater) - projectile_updater_2d = _projectile_updater + ProjectileEngine.projectile_environment.add_child(projectile_updater_2d, true) + projectile_area = projectile_updater_2d.projectile_area_rid + projectile_template_2d.projectile_area_rid = projectile_updater_2d.projectile_area_rid + ProjectileEngine.projectile_updater_2d_nodes.get_or_add(projectile_area, projectile_updater_2d) pass @@ -216,7 +207,7 @@ func create_projectile_updater_custom_2d() -> void: var _projectile_updater := ProjectileUpdaterCustom2D.new() _projectile_updater.projectile_template_2d = projectile_template_2d - _projectile_updater.custom_data = projectile_template_2d.custom_data + _projectile_updater.projectile_custom_data = projectile_template_2d.custom_data ProjectileEngine.projectile_environment.add_child(_projectile_updater, true) projectile_area = _projectile_updater.projectile_area_rid diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd index 3e2830ff..38cecb62 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_behaviors/base/projectile_custom_data.gd @@ -1,4 +1,4 @@ extends Resource class_name ProjectileCustomData -var custom_data: Dictionary \ No newline at end of file +@export var custom_data: Array[Variant] \ No newline at end of file diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd index e18bb017..94d07da1 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_2d.gd @@ -1,4 +1,10 @@ extends Resource class_name ProjectileTemplate2D -@export var custom_data : ProjectileCustomData \ No newline at end of file +## Number of projectiles to preload in the object pool for better performance +@export var projectile_pooling_amount: int = 500: + set(value): + projectile_pooling_amount = value + emit_changed() + +@export var custom_data : ProjectileCustomData diff --git a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd index 6fb431d8..13ba181d 100644 --- a/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/base/projectile_template/projectile_template_object_2d.gd @@ -1,92 +1,2 @@ extends ProjectileTemplate2D -class_name ProjectileTemplateObject2D -## Movement speed of the projectile in pixels per second -@export var speed: float = 100: - set(value): - speed = value - emit_changed() - -## Number of projectiles to preload in the object pool for better performance -@export var projectile_pooling_amount: int = 500: - set(value): - projectile_pooling_amount = value - emit_changed() - -@export_group("Texture - Transform") -## The Projectile Instance Texture -@export var texture: Texture2D: - set(value): - texture = value - emit_changed() - -## Initial rotation of the texture in degrees -@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float: - set(value): - texture_rotation = value - emit_changed() - -## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] -@export_custom(PROPERTY_HINT_LINK, "suffix:") var texture_scale: Vector2 = Vector2.ONE: - set(value): - texture_scale = value - emit_changed() - -## Skew/shear effect applied to texture (-89.9 to 89.9 degrees) -@export_range(-89.9, 89.9, 0.1) var texture_skew: float = 0.0: - set(value): - texture_skew = value - emit_changed() -## Toggles visibility of the projectile's texture -@export var texture_visible: bool = true: - set(value): - texture_visible = value - emit_changed() -## Render layer for the texture (higher values render on top) -@export var texture_z_index: int = 0: - set(value): - texture_z_index = value - emit_changed() -## Reverse Z in dex, make new bullet render underneath older bullet -@export var reverse_z_index: bool = false: - set(value): - reverse_z_index = value - emit_changed() - -## Color modulation applied to the texture (RGBA) -@export var texture_modulate: Color = Color(1, 1, 1, 1): - set(value): - texture_modulate = value - emit_changed() - -@export_group("Collision") -## Collision shape used for physics detection -@export var collision_shape: Shape2D -## Physics layers this projectile can collide with (bitmask) -@export_flags_2d_physics var collision_layer: int = 0 -## Physics layers that can detect collisions with this projectile (bitmask) -@export_flags_2d_physics var collision_mask: int = 0 -@export var texture_rotate_direction: bool = false: - set(value): - texture_rotate_direction = value - emit_changed() - -## Destroy when collided with a body -@export var destroy_on_body_collide: bool = true -## Destroy when collided with a area -@export var destroy_on_area_collide: bool = true -## Maximum lifetime of projectile in seconds before it's automatically destroyed -## [code] life_time_max < 0 [/code] for unlimited life time -@export var life_time_second_max: float = 10.0: - set(value): - life_time_second_max = value - emit_changed() -## Maximum travel distance in pixels before projectile is automatically destroyed [br] -## [code] life_distance_max < 0 [/code] for unlimited distance -@export var life_distance_max: float = 1000.0: - set(value): - life_distance_max = value - emit_changed() - - -## Internal RID (Rendering ID) for the projectile's collision area -var projectile_area_rid: RID +class_name ProjectileTemplateObject2D \ No newline at end of file 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 8a37690b..ce4708f1 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 @@ -8,7 +8,7 @@ var RS := RenderingServer var projectile_template_2d: ProjectileTemplate2D var projectile_custom_data: ProjectileCustomData -var projectile_max_pooling: int +var projectile_pooling_amount: int var projectile_pooling_index: int = 0 var projectile_speed: float = 100.0 @@ -22,12 +22,14 @@ var projectile_texture_modulate: Color var projectile_texture_z_index: int var projectile_reverse_z_index: bool = false +var projectile_life_time_second_max: float +var projectile_life_distance_max: float + var projectile_collision_shape: Shape2D var projectile_collision_layer: int = 0 var projectile_collision_mask: int = 0 - -var projectile_life_time_second_max: float -var projectile_life_distance_max: float +var destroy_on_body_collide: bool +var destroy_on_area_collide: bool var projectile_area_rid: RID @@ -36,8 +38,8 @@ var projectile_overlapping_bodies: Dictionary var projectile_instances: Array[ProjectileInstance2D] var projectile_canvas_item_rids: Array[RID] -var projectile_active_indexes: Array[int] -var projectile_remove_indexes: Array[int] +var projectile_active_indexes: PackedInt32Array +var projectile_remove_indexes: PackedInt32Array var projectile_instance_callable: Callable @@ -45,9 +47,15 @@ var _projectile_instance: ProjectileInstance2D func _ready() -> void: + print("setup Projectile Updater") setup_projectile_updater() +func _exit_tree(): + if projectile_template_2d and projectile_template_2d.changed.is_connected(_on_projectile_template_changed): + projectile_template_2d.changed.disconnect(_on_projectile_template_changed) + + func _physics_process(delta: float) -> void: update_projectile_instances(delta) pass @@ -64,7 +72,8 @@ func setup_projectile_updater() -> void: pass func update_updater_variables() -> void: - projectile_template_2d = projectile_template_2d as ProjectileTemplateObject2D + # projectile_template_2d = projectile_template_2d as ProjectileTemplateObject2D + projectile_pooling_amount = projectile_template_2d.projectile_pooling_amount projectile_speed = projectile_template_2d.speed projectile_texture = projectile_template_2d.texture @@ -83,6 +92,9 @@ func update_updater_variables() -> void: 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 pass @@ -90,12 +102,12 @@ func _on_projectile_template_changed() -> void: update_updater_variables() if projectile_reverse_z_index != projectile_template_2d.reverse_z_index: if !projectile_reverse_z_index: - for _index in projectile_max_pooling: + for _index in projectile_pooling_amount: RS.canvas_item_set_draw_index( projectile_instances[_index].canvas_item_rid, _index ) else: - for _index in projectile_max_pooling: + for _index in projectile_pooling_amount: RS.canvas_item_set_draw_index( projectile_instances[_index].canvas_item_rid, -_index ) @@ -116,19 +128,24 @@ func setup_projectile_area_rid() -> void: PS.area_set_transform(projectile_area_rid, Transform2D()) setup_area_callback(projectile_area_rid) - projectile_template_2d.projectile_area_rid = projectile_area_rid func create_projectile_pool() -> void: var _transform_2d := Transform2D() var _collision_rid: RID var _canvas_item_id: RID + var _texture_rect2: Rect2 + + if projectile_collision_shape: + _collision_rid = projectile_collision_shape.get_rid() - if projectile_template_2d.collision_shape: - _collision_rid = projectile_template_2d.collision_shape.get_rid() - projectile_max_pooling = projectile_template_2d.projectile_pooling_amount + if projectile_texture: + _texture_rect2 = Rect2( + - projectile_texture.get_size() / 2, + projectile_texture.get_size() + ) - for _index in range(projectile_max_pooling): + for _index in range(projectile_pooling_amount): if _collision_rid: PS.area_add_shape(projectile_area_rid, _collision_rid, _transform_2d, true) _projectile_instance = projectile_instance_callable.call() @@ -137,7 +154,7 @@ func create_projectile_pool() -> void: _projectile_instance.projectile_updater_2d = self if projectile_custom_data: - _projectile_instance.projectile_custom_data = projectile_custom_data + _projectile_instance.custom_data = projectile_custom_data _projectile_instance.area_rid = projectile_area_rid _projectile_instance.area_index = _index @@ -149,7 +166,7 @@ func create_projectile_pool() -> void: RS.canvas_item_set_z_index(_canvas_item_id, projectile_texture_z_index) ## Apply reverse z index - if projectile_template_2d.reverse_z_index: + if projectile_reverse_z_index: RS.canvas_item_set_draw_index(_canvas_item_id, -_index) else: RS.canvas_item_set_draw_index(_canvas_item_id, _index) @@ -161,15 +178,13 @@ func create_projectile_pool() -> void: if projectile_texture: RS.canvas_item_add_texture_rect( _canvas_item_id, - Rect2(-projectile_texture.get_size() / 2, - projectile_texture.get_size()), + _texture_rect2, projectile_texture ) _projectile_instance.canvas_item_rid = _canvas_item_id projectile_canvas_item_rids.append(_canvas_item_id) - func setup_area_callback(_projectile_area: RID) -> void: PS.area_set_area_monitor_callback(_projectile_area, _area_monitor_callback) PS.area_set_monitor_callback(_projectile_area, _body_monitor_callback) @@ -177,7 +192,7 @@ func setup_area_callback(_projectile_area: RID) -> void: func _area_monitor_callback( - status: int, area_rid: RID, + status: int, area_rid: RID, instance_id: int, area_shape_idx: int, self_shape_idx: int ) -> void: var _instance_node: Area2D = instance_from_id(instance_id) @@ -221,7 +236,7 @@ func _area_monitor_callback( pass -func _body_monitor_callback(status: int, body_rid: RID, +func _body_monitor_callback(status: int, body_rid: RID, instance_id: int, body_shape_idx: int, self_shape_idx: int ) -> void: var _instance_node: Node = instance_from_id(instance_id) @@ -264,7 +279,7 @@ func _body_monitor_callback(status: int, body_rid: RID, func process_projectile_collided(instance_index: int) -> void: - if instance_index not in projectile_remove_indexes: + if !projectile_remove_indexes.has(instance_index): projectile_remove_indexes.append(instance_index) pass @@ -273,6 +288,7 @@ func process_projectile_collided(instance_index: int) -> void: #region Spawn Projectile +## Spawn projectiles using output from PatternComposer Nodes func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) -> void: pass @@ -281,43 +297,56 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) #region Update Projectile +## Update all active Projetile instances func update_projectile_instances(delta: float) -> void: pass #endregion +## Clear and free all Projectile instances and other RIDs func clear_projectile_updater() -> void: - for instance: ProjectileInstanceCustom2D in projectile_instances: - instance.queue_free() + # Disconnect signals + if projectile_template_2d and projectile_template_2d.changed.is_connected(_on_projectile_template_changed): + projectile_template_2d.changed.disconnect(_on_projectile_template_changed) + + # Free physics resources + if projectile_area_rid != RID(): PS.area_clear_shapes(projectile_area_rid) + PS.free_rid(projectile_area_rid) + projectile_area_rid = RID() + + # Free rendering resources + for rid in projectile_canvas_item_rids: + if rid != RID(): + RS.free_rid(rid) + projectile_canvas_item_rids.clear() + + # Clear instances + for instance in projectile_instances: + if is_instance_valid(instance): + instance.free() + projectile_instances.clear() + + # Reset tracking + projectile_active_indexes.clear() + projectile_remove_indexes.clear() + projectile_overlapping_areas.clear() + projectile_overlapping_bodies.clear() + # Nullify references + projectile_template_2d = null +## Get current active Projetile count func get_active_projectile_count() -> int: return projectile_active_indexes.size() pass -## Clear all ProjectileInstances in this ProjectileUpdater +## Clear all Projectile instances in this ProjectileUpdater func clear_projectiles() -> void: - for _index in range(projectile_max_pooling): + for _index in range(projectile_pooling_amount): if projectile_active_indexes.has(_index): projectile_active_indexes.erase(_index) PS.area_set_shape_disabled(projectile_area_rid, _index, true) projectile_active_indexes.clear() pass - - -func hasprojectile_overlapping_areas(area_idx: int = -1) -> bool: - return projectile_overlapping_areas.has(area_idx) - - -func getprojectile_overlapping_areas(area_idx: int = -1) -> Array: - return projectile_overlapping_areas.get(area_idx) - - -func hasprojectile_overlapping_bodies(area_idx: int = -1) -> bool: - return projectile_overlapping_bodies.has(area_idx) - - -func getprojectile_overlapping_bodies(area_idx: int = -1) -> Array: - return projectile_overlapping_bodies.get(area_idx) as Array diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_instance_advanced.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_instance_advanced.gd index 493890c2..808790fc 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_instance_advanced.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_instance_advanced.gd @@ -3,6 +3,10 @@ class_name ProjectileInstanceAdvanced2D var base_speed: float +var base_rotation: float +var base_scale: Vector2 +var base_skew: float + var speed_max: float var speed_acceleration: float var direction_rotation_speed: float diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd index 1ad38644..0f8145d5 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_advanced_2d/projectile_template_advanced_2d.gd @@ -2,62 +2,125 @@ extends ProjectileTemplate2D class_name ProjectileTemplateAdvanced2D ## Template for Advanced Projectile 2D for more Projectile Behavior options +@export_group("Velocity") +@export_subgroup("Speed") +## Movement speed of the projectile - pixels per second +@export var speed: float = 50: + set(value): + speed = value + emit_changed() +## Speed Acceleration to the Max Speed - pixels per second per second +@export var speed_acceleration: float = 0: + set(value): + speed_acceleration = value + emit_changed() +## Maximum speed the projectile can reach - pixels per second +@export var speed_max: float = 100.0: + set(value): + speed_max = value + emit_changed() +@export_subgroup("Direction") +@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var direction_rotation: float: + set(value): + direction_rotation = value + emit_changed() +@export_custom(PROPERTY_HINT_NONE, "suffix:°") var direction_rotation_speed: float = 0.0: + set(value): + direction_rotation_speed = value + emit_changed() +## If true, direction will rotate to match projectile's texture rotation +@export var direction_follow_rotation: bool = false: + set(value): + direction_follow_rotation = value + emit_changed() +@export_group("Texture - Transform") +## The Projectile Instance Texture +@export var texture: Texture2D: + set(value): + texture = value + emit_changed() -## Movement speed of the projectile in pixels per second -@export var speed: float = 100 - -# ## The normalized Direction of the projectile moving toward -# @export var direction : Vector2 = Vector2.RIGHT -## Number of projectiles to preload in the object pool for better performance -@export var projectile_pooling_amount: int = 500 +@export_subgroup("Rotation") +## Initial rotation of the texture in degrees +@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float: + set(value): + texture_rotation = value + emit_changed() +@export_custom(PROPERTY_HINT_NONE, "suffix:°") var texture_rotation_speed: float = 0.0 +## If true, texture rotation will rotate to match projectile's direction +@export var rotation_follow_direction: bool = false -@export_group("Texture") -## The Projectile Instance Texture -@export var texture: Texture2D +@export_subgroup("Scale") ## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] -@export_custom(PROPERTY_HINT_LINK, "suffix:") var scale: Vector2 = Vector2.ONE +@export_custom(PROPERTY_HINT_LINK, "suffix:") var texture_scale: Vector2 = Vector2.ONE: + set(value): + texture_scale = value + emit_changed() +## Acceleration rate in units per second squared (how quickly speed increases) +@export var scale_acceleration: float = 0.0 +## Maximum speed the projectile can reach (in units per second) +@export var scale_max: Vector2 = Vector2.ONE * 2 -## Initial rotation of the texture in degrees -@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float +@export_subgroup("Skew") ## Skew/shear effect applied to texture (-89.9 to 89.9 degrees) -@export_range(-89.9, 89.9, 0.1) var skew: float = 0.0 +@export_range(-89.9, 89.9, 0.1) var texture_skew: float = 0.0: + set(value): + texture_skew = value + emit_changed() +@export_subgroup("Visibility - Ordering") ## Toggles visibility of the projectile's texture -@export var texture_visible: bool = true +@export var texture_visible: bool = true: + set(value): + texture_visible = value + emit_changed() ## Render layer for the texture (higher values render on top) -@export var texture_z_index: int = 0 +@export var texture_z_index: int = 0: + set(value): + texture_z_index = value + emit_changed() ## Reverse Z in dex, make new bullet render underneath older bullet -@export var reverse_z_index: bool = false +@export var reverse_z_index: bool = false: + set(value): + reverse_z_index = value + emit_changed() + ## Color modulation applied to the texture (RGBA) -@export var texture_modulate: Color = Color(1, 1, 1, 1) +@export var texture_modulate: Color = Color(1, 1, 1, 1): + set(value): + texture_modulate = value + emit_changed() -@export_group("Collision") +@export_group("Destroy - Collision") ## Collision shape used for physics detection @export var collision_shape: Shape2D ## Physics layers this projectile can collide with (bitmask) @export_flags_2d_physics var collision_layer: int = 0 ## Physics layers that can detect collisions with this projectile (bitmask) @export_flags_2d_physics var collision_mask: int = 0 +@export var texture_rotate_direction: bool = false: + set(value): + texture_rotate_direction = value + emit_changed() -@export_group("Transform") -@export_subgroup("Speed") -@export var speed_acceleration: float -## Maximum speed the projectile can reach (in units per second) -@export var speed_max: float = 200.0 -@export_subgroup("Direction") -@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var direction_rotation: float -@export_custom(PROPERTY_HINT_NONE, "suffix:°") var direction_rotation_speed: float = 0.0 -## If true, direction will rotate to match projectile's texture rotation -@export var direction_follow_rotation: bool = false -@export_subgroup("Rotation") -## Initial rotation of the texture in degrees -@export_custom(PROPERTY_HINT_NONE, "suffix:°") var texture_rotation_speed: float = 0.0 -## If true, texture rotation will rotate to match projectile's direction -@export var rotation_follow_direction: bool = false -@export_subgroup("Scale") -## Acceleration rate in units per second squared (how quickly speed increases) -@export var scale_acceleration: float = 0.0 -## Maximum speed the projectile can reach (in units per second) -@export var scale_max: Vector2 = Vector2.ONE * 2 +## Destroy when collided with a body +@export var destroy_on_body_collide: bool = true +## Destroy when collided with a area +@export var destroy_on_area_collide: bool = true + +## Maximum lifetime of projectile in seconds before it's automatically destroyed +## [code] life_time_max < 0 [/code] for unlimited life time +@export var life_time_second_max: float = 10.0: + set(value): + life_time_second_max = value + emit_changed() +## Maximum travel distance in pixels before projectile is automatically destroyed [br] +## [code] life_distance_max < 0 [/code] for unlimited distance +@export var life_distance_max: float = 1000.0: + set(value): + life_distance_max = value + emit_changed() + +@export_group("Special") @export_subgroup("Homing") ## Group name to target @export var is_use_homing: bool = false @@ -72,18 +135,6 @@ class_name ProjectileTemplateAdvanced2D ## Maximum distance at which homing is active (0 = unlimited) @export var max_homing_distance: float = 0.0 -@export_group("Special") -@export_subgroup("Destroy") -## Destroy when collided with a body -@export var destroy_on_body_collide: bool = true -## Destroy when collided with a area -@export var destroy_on_area_collide: bool = true -## Maximum travel time in second before projectile is automatically destroyed [br] -## [code] life_time_second_max < 0 [/code] for unlimited distance -@export var life_time_second_max: float = 10.0 -## Maximum travel distance in pixels before projectile is automatically destroyed [br] -## [code] life_distance_max < 0 [/code] for unlimited distance -@export var life_distance_max: float = 1000.0 @export_subgroup("Trigger") @export var is_use_trigger: bool = false @export var trigger_name: StringName @@ -104,8 +155,8 @@ class_name ProjectileTemplateAdvanced2D @export var scale_random: Vector3 @export var scale_max_random: Vector3 @export var scale_acceleration_random: Vector3 -@export var life_time_second_random: Vector3 -@export var life_distance_random: Vector3 +# @export var life_time_second_random: Vector3 +# @export var life_distance_random: Vector3 ## Internal RID (Rendering ID) for the projectile's collision area 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 ee5f560e..3d94c180 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 @@ -1,14 +1,21 @@ extends ProjectileUpdater2D class_name ProjectileUpdaterAdvanced2D +## Velocity Variables var projectile_velocity: Vector2 = Vector2.ZERO - -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 +## Transfrom Variables + +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 + +## Homing Variables var projectile_is_use_homing: bool = false var projectile_homing_target_group: String @@ -25,12 +32,8 @@ 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 +## Trigger Variables var projectile_is_use_trigger: bool var projectile_trigger_name: StringName @@ -39,18 +42,33 @@ var projectile_trigger_life_time: float var projectile_trigger_life_distance: float +## Random Variables +var is_random_speed: bool = false +var is_random_speed_acceleration: bool = false +var is_random_speed_max: bool = false +var random_direction_rotation: bool = false + +var is_texture_rotation: bool = false +var is_texture_scale: bool = false +var is_texture_skew: bool = false +var is_random_texture_rotation_speed: bool = false + + func update_updater_variables() -> void: + super () projectile_template_2d = projectile_template_2d as ProjectileTemplateAdvanced2D projectile_instance_callable = Callable(ProjectileInstanceAdvanced2D, "new") - - - 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 - destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide - destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide - + projectile_speed_acceleration = projectile_template_2d.speed_acceleration * (1.0 / Engine.physics_ticks_per_second) + projectile_speed_max = projectile_template_2d.speed_max + projectile_rotation_speed = projectile_template_2d.texture_rotation_speed * (1.0 / Engine.physics_ticks_per_second) + if projectile_rotation_speed != 0: + is_texture_rotation = true + # 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 + # destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide + # destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide pass #region Spawn Projectile @@ -64,7 +82,6 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) 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: _projectile_instance = projectile_instances[projectile_pooling_index] _projectile_instance = _projectile_instance as ProjectileInstanceAdvanced2D @@ -73,163 +90,150 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.speed = projectile_template_2d.speed _projectile_instance.base_speed = projectile_template_2d.speed - _projectile_instance.speed_acceleration = projectile_template_2d.speed_acceleration _projectile_instance.speed_max = projectile_template_2d.speed_max + _projectile_instance.speed_acceleration = projectile_template_2d.speed_acceleration - _projectile_instance.direction = _pattern_composer_data.direction + _projectile_instance.direction = _pattern_composer_data.direction.normalized() _projectile_instance.base_direction = _pattern_composer_data.direction - _projectile_instance.direction_rotation = _pattern_composer_data.direction_rotation - _projectile_instance.direction_rotation_speed = deg_to_rad(projectile_template_2d.direction_rotation_speed) + # _projectile_instance.direction_rotation = _pattern_composer_data.direction_rotation + # _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 = projectile_template_2d.texture_rotation + # _projectile_instance.texture_rotation_speed = deg_to_rad(projectile_template_2d.texture_rotation_speed) - _projectile_instance.texture_scale = projectile_template_2d.texture_scale - _projectile_instance.texture_scale_acceleration = projectile_template_2d.texture_scale_acceleration - _projectile_instance.texture_scale_max = projectile_template_2d.texture_scale_max + # _projectile_instance.texture_scale = projectile_template_2d.texture_scale + # _projectile_instance.texture_scale_acceleration = projectile_template_2d.texture_scale_acceleration + # _projectile_instance.texture_scale_max = projectile_template_2d.texture_scale_max - _projectile_instance.life_time_second_max = projectile_template_2d.life_time_second_max - _projectile_instance.life_distance_max = projectile_template_2d.life_distance_max + # _projectile_instance.life_time_second_max = projectile_template_2d.life_time_second_max + # _projectile_instance.life_distance_max = projectile_template_2d.life_distance_max ## Check and update random variables - var _scale_float: float - var _scale_max_float: float + # var _scale_float: float + # var _scale_max_float: float if projectile_template_2d.speed_random != Vector3.ZERO: + is_random_speed = true _projectile_instance.speed = ProjectileEngine.get_random_float_value( projectile_template_2d.speed_random ) - if projectile_template_2d.speed_max_random != Vector3.ZERO: - _projectile_instance.speed_max = ProjectileEngine.get_random_float_value( - projectile_template_2d.speed_max_random - ) + if projectile_template_2d.speed_acceleration_random != Vector3.ZERO: + is_random_speed_acceleration = true _projectile_instance.speed_acceleration = ProjectileEngine.get_random_float_value( projectile_template_2d.speed_acceleration_random ) - if projectile_template_2d.direction_rotation_random != Vector3.ZERO: - _projectile_instance.direction_rotation = ProjectileEngine.get_random_float_value( - projectile_template_2d.direction_rotation_random + if projectile_template_2d.speed_max_random != Vector3.ZERO: + is_random_speed_max = true + _projectile_instance.speed_max = ProjectileEngine.get_random_float_value( + projectile_template_2d.speed_max_random ) - if projectile_template_2d.direction_rotation_speed_random != Vector3.ZERO: - _projectile_instance.direction_rotation_speed = deg_to_rad( - ProjectileEngine.get_random_float_value( - projectile_template_2d.direction_rotation_speed_random - ) - ) + # if projectile_template_2d.direction_rotation_random != Vector3.ZERO: + # _projectile_instance.direction_rotation = ProjectileEngine.get_random_float_value( + # projectile_template_2d.direction_rotation_random + # ) + + # if projectile_template_2d.direction_rotation_speed_random != Vector3.ZERO: + # _projectile_instance.direction_rotation_speed = deg_to_rad( + # ProjectileEngine.get_random_float_value( + # projectile_template_2d.direction_rotation_speed_random + # ) + # ) if projectile_template_2d.texture_rotation_random != Vector3.ZERO: + is_texture_rotation = true _projectile_instance.texture_rotation = ProjectileEngine.get_random_float_value( projectile_template_2d.texture_rotation_random ) if projectile_template_2d.texture_rotation_speed_random != Vector3.ZERO: + is_texture_rotation = true + is_random_texture_rotation_speed = true _projectile_instance.texture_rotation_speed = deg_to_rad( ProjectileEngine.get_random_float_value( projectile_template_2d.texture_rotation_speed_random ) ) - if projectile_template_2d.texture_scale_random != Vector3.ZERO: - _scale_float = ProjectileEngine.get_random_float_value( - projectile_template_2d.texture_scale_random - ) - _projectile_instance.texture_scale = Vector2(_scale_float, _scale_float) - - if projectile_template_2d.texture_scale_acceleration_random != Vector3.ZERO: - _projectile_instance.texture_scale_acceleration = ProjectileEngine.get_random_float_value( - projectile_template_2d.texture_scale_acceleration_random - ) - - if projectile_template_2d.texture_scale_max_random != Vector3.ZERO: - _scale_max_float = ProjectileEngine.get_random_float_value( - projectile_template_2d.texture_scale_max_random - ) - _projectile_instance.texture_scale_max = Vector2(_scale_max_float, _scale_max_float) - - if projectile_template_2d.life_time_second_random != Vector3.ZERO: - _projectile_instance.life_time_second_max = ProjectileEngine.get_random_float_value( - projectile_template_2d.life_time_second_random + # if projectile_template_2d.texture_scale_random != Vector3.ZERO: + # _scale_float = ProjectileEngine.get_random_float_value( + # projectile_template_2d.texture_scale_random + # ) + # _projectile_instance.texture_scale = Vector2(_scale_float, _scale_float) + + # if projectile_template_2d.texture_scale_acceleration_random != Vector3.ZERO: + # _projectile_instance.texture_scale_acceleration = ProjectileEngine.get_random_float_value( + # projectile_template_2d.texture_scale_acceleration_random + # ) + + # if projectile_template_2d.texture_scale_max_random != Vector3.ZERO: + # _scale_max_float = ProjectileEngine.get_random_float_value( + # projectile_template_2d.texture_scale_max_random + # ) + # _projectile_instance.texture_scale_max = Vector2(_scale_max_float, _scale_max_float) + if is_random_speed: + _projectile_instance.velocity = ( + _projectile_instance.direction.normalized() * _projectile_instance.speed * + get_physics_process_delta_time() ) - if projectile_template_2d.life_distance_random != Vector3.ZERO: - _projectile_instance.life_distance_max = ProjectileEngine.get_random_float_value( - projectile_template_2d.life_distance_random + else: + _projectile_instance.velocity = ( + _projectile_instance.direction.normalized() * projectile_speed * + get_physics_process_delta_time() ) - - if projectile_direction_follow_rotation: - _projectile_instance.direction_rotation = _projectile_instance.texture_rotation - - if _projectile_instance.direction_rotation != 0: - _projectile_instance.direction = _projectile_instance.base_direction.rotated( - _projectile_instance.direction_rotation - ) - - if projectile_rotation_follow_direction: - _projectile_instance.texture_rotation = _projectile_instance.direction_rotation - _projectile_instance.transform_2d = Transform2D( _projectile_instance.texture_rotation, _projectile_instance.texture_scale, - _projectile_instance.texture_skew, + projectile_template_2d.texture_skew, _projectile_instance.global_position ) - + RS.canvas_item_set_visible(_projectile_instance.canvas_item_rid, true) + RS.canvas_item_set_transform(_projectile_instance.canvas_item_rid, _projectile_instance.transform_2d) + if projectile_template_2d.collision_shape: - PS.area_set_shape_transform( - projectile_area_rid, - projectile_pooling_index, - _projectile_instance.transform_2d - ) - PS.area_set_shape_disabled( - projectile_area_rid, - projectile_pooling_index, - false - ) + PS.area_set_shape_transform(projectile_area_rid, projectile_pooling_index, _projectile_instance.transform_2d) + PS.area_set_shape_disabled(projectile_area_rid, projectile_pooling_index, false) _projectile_instance.life_time_second = 0.0 _projectile_instance.life_distance = 0.0 - _projectile_instance.trigger_count = 0 projectile_instances[projectile_pooling_index] = _projectile_instance - if projectile_pooling_index not in projectile_active_indexes: projectile_active_indexes.append(projectile_pooling_index) projectile_pooling_index += 1 - - if projectile_pooling_index >= projectile_max_pooling: + if projectile_pooling_index >= projectile_pooling_amount: projectile_pooling_index = 0 #endregion +#endregion + + #region Update Projectile 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 - projetile_max_homing_distance = projectile_template_2d.max_homing_distance - projectile_steer_speed = projectile_template_2d.steer_speed - projectile_homing_strength = projectile_template_2d.homing_strength - - projectile_is_use_trigger = projectile_template_2d.is_use_trigger - projectile_trigger_name = projectile_template_2d.trigger_name - projectile_trigger_amount = projectile_template_2d.trigger_amount - 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 - + # projectile_is_use_homing = projectile_template_2d.is_use_homing + # if projectile_is_use_homing: + # projectile_homing_target_group = projectile_template_2d.target_group + # projetile_max_homing_distance = projectile_template_2d.max_homing_distance + # projectile_steer_speed = projectile_template_2d.steer_speed + # projectile_homing_strength = projectile_template_2d.homing_strength + # projectile_is_use_trigger = projectile_template_2d.is_use_trigger + # projectile_trigger_name = projectile_template_2d.trigger_name + # projectile_trigger_amount = projectile_template_2d.trigger_amount + # 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_indexes: - _projectile_instance = projectile_instances[index] - + _projectile_instance = projectile_instances[index] as ProjectileInstanceAdvanced2D # Life Time & Distance if projectile_life_time_second_max >= 0: _projectile_instance.life_time_second += delta @@ -243,21 +247,126 @@ func update_projectile_instances(delta: float) -> void: projectile_remove_indexes.append(index) continue + if destroy_on_area_collide: - if hasprojectile_overlapping_areas(index): - for _overlap_area in getprojectile_overlapping_areas(index): - _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_area) - if not _overlap_collision_layer & projectile_collision_mask: - continue + if projectile_overlapping_areas.has(index): + if !projectile_remove_indexes.has(index): projectile_remove_indexes.append(index) + continue if destroy_on_body_collide: - if hasprojectile_overlapping_bodies(index): - for _overlap_body in getprojectile_overlapping_bodies(index): - _overlap_collision_layer = ProjectileEngine.get_collider_collision_layer(_overlap_body) - if not _overlap_collision_layer & projectile_collision_mask: - continue + if projectile_overlapping_bodies.has(index): + if !projectile_remove_indexes.has(index): projectile_remove_indexes.append(index) + continue + + if projectile_speed_acceleration != 0: + if is_random_speed_max: + if ((projectile_speed_max > 0 and _projectile_instance.speed < _projectile_instance.speed_max) or + (projectile_speed_max < 0 and _projectile_instance.speed > _projectile_instance.speed_max)): + _projectile_instance.speed += projectile_speed_acceleration + _projectile_instance.velocity = ( + _projectile_instance.speed * + _projectile_instance.direction * delta + ) + elif ((projectile_speed_max > 0 and _projectile_instance.speed < projectile_speed_max) or + (projectile_speed_max < 0 and _projectile_instance.speed > projectile_speed_max)): + _projectile_instance.speed += projectile_speed_acceleration + _projectile_instance.velocity = ( + _projectile_instance.speed * + _projectile_instance.direction * delta + ) + elif is_random_speed_acceleration: + if is_random_speed_max: + if ((projectile_speed_max > 0 and _projectile_instance.speed < _projectile_instance.speed_max) or + (projectile_speed_max < 0 and _projectile_instance.speed > _projectile_instance.speed_max)): + _projectile_instance.speed += _projectile_instance.speed_acceleration + _projectile_instance.velocity = ( + _projectile_instance.speed * + _projectile_instance.direction * delta + ) + elif ((projectile_speed_max > 0 and _projectile_instance.speed < projectile_speed_max) or + (projectile_speed_max < 0 and _projectile_instance.speed > projectile_speed_max)): + _projectile_instance.speed += _projectile_instance.speed_acceleration + _projectile_instance.velocity = ( + _projectile_instance.speed * + _projectile_instance.direction * delta + ) + + if is_random_texture_rotation_speed: + _projectile_instance.texture_rotation += _projectile_instance.texture_rotation_speed + elif projectile_rotation_speed != 0: + _projectile_instance.texture_rotation += projectile_rotation_speed + + + + _projectile_instance.global_position += _projectile_instance.velocity + + ## Update Projetiles Transform + if is_texture_scale and is_texture_skew and is_texture_rotation: + _projectile_instance.transform_2d = Transform2D( + _projectile_instance.texture_rotation, + _projectile_instance.texture_scale, + _projectile_instance.texture_skew, + _projectile_instance.global_position + ) + elif is_texture_rotation and is_texture_scale: + _projectile_instance.transform_2d = Transform2D( + _projectile_instance.texture_rotation, + _projectile_instance.texture_scale, + projectile_texture_skew, + _projectile_instance.global_position + ) + elif is_texture_rotation and is_texture_skew: + _projectile_instance.transform_2d = Transform2D( + _projectile_instance.texture_rotation, + projectile_texture_scale, + _projectile_instance.texture_skew, + _projectile_instance.global_position + ) + elif is_texture_scale and is_texture_skew: + _projectile_instance.transform_2d = Transform2D( + projectile_texture_rotation, + _projectile_instance.texture_scale, + _projectile_instance.texture_skew, + _projectile_instance.global_position + ) + elif is_texture_rotation: + _projectile_instance.transform_2d = Transform2D( + _projectile_instance.texture_rotation, + projectile_texture_scale, + projectile_texture_skew, + _projectile_instance.global_position + ) + elif is_texture_scale: + _projectile_instance.transform_2d = Transform2D( + projectile_texture_rotation, + _projectile_instance.texture_scale, + projectile_texture_skew, + _projectile_instance.global_position + ) + elif is_texture_skew: + _projectile_instance.transform_2d = Transform2D( + projectile_texture_rotation, + projectile_texture_scale, + _projectile_instance.texture_skew, + _projectile_instance.global_position + ) + else: + _projectile_instance.transform_2d.origin = _projectile_instance.global_position + + _projectile_instance.transform_2d.translated(_projectile_instance.velocity) + RS.canvas_item_set_transform( + projectile_canvas_item_rids[index], + _projectile_instance.transform_2d + ) + + if projectile_template_2d.collision_shape: + PS.area_set_shape_transform( + projectile_area_rid, + _projectile_instance.area_index, + _projectile_instance.transform_2d + ) # Destroy projectile if projectile_remove_indexes.size() > 0: @@ -268,17 +377,17 @@ func update_projectile_instances(delta: float) -> void: projectile_remove_indexes.clear() # # Update active projectile - # for _active_projectile_instance: ProjectileInstanceAdvanced2D in _active_projectile_instances: + # for _projectile_instance: ProjectileInstanceAdvanced2D in _projectile_instances: # if projectile_is_use_trigger: - # if _active_projectile_instance.trigger_count < projectile_trigger_amount: + # if _projectile_instance.trigger_count < projectile_trigger_amount: # if projectile_trigger_life_time > 0: - # if _active_projectile_instance.life_time_second >= projectile_trigger_life_time * _active_projectile_instance.trigger_count: - # ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _active_projectile_instance) - # _active_projectile_instance.trigger_count += 1 + # if _projectile_instance.life_time_second >= projectile_trigger_life_time * _projectile_instance.trigger_count: + # ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _projectile_instance) + # _projectile_instance.trigger_count += 1 # if projectile_trigger_life_distance > 0: - # if _active_projectile_instance.life_distance >= projectile_trigger_life_distance * _active_projectile_instance.trigger_count: - # ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _active_projectile_instance) - # _active_projectile_instance.trigger_count += 1 + # if _projectile_instance.life_distance >= projectile_trigger_life_distance * _projectile_instance.trigger_count: + # ProjectileEngine.projectile_instance_triggered.emit(projectile_trigger_name, _projectile_instance) + # _projectile_instance.trigger_count += 1 # if projectile_is_use_homing: # _homing_group_nodes = get_tree().get_nodes_in_group(projectile_homing_target_group) @@ -288,7 +397,7 @@ func update_projectile_instances(delta: float) -> void: # for node in _homing_group_nodes: # if node is Node2D and is_instance_valid(node): - # _homing_distance = _active_projectile_instance.global_position.distance_to(node.global_position) + # _homing_distance = _projectile_instance.global_position.distance_to(node.global_position) # if _homing_distance < _homing_nearest_distance: # _homing_nearest_distance = _homing_distance # _homing_nearest_target = node @@ -297,71 +406,71 @@ func update_projectile_instances(delta: float) -> void: # _homing_target_position = _homing_nearest_target.global_position # # Calculate distance to target - # _homing_distance_to_target = _active_projectile_instance.global_position.distance_to(_homing_target_position) + # _homing_distance_to_target = _projectile_instance.global_position.distance_to(_homing_target_position) # # Check distance constraint # if projetile_max_homing_distance <= 0.0 or _homing_distance_to_target <= projetile_max_homing_distance: # # Calculate desired direction toward target - # _homing_desired_direction = _active_projectile_instance.global_position.direction_to(_homing_target_position) + # _homing_desired_direction = _projectile_instance.global_position.direction_to(_homing_target_position) # # Gradually steer toward target - # _homing_new_direction = _active_projectile_instance.direction.move_toward(_homing_desired_direction, projectile_steer_speed * delta) - # _homing_final_direction = _homing_new_direction.normalized() * projectile_homing_strength + _active_projectile_instance.direction * (1.0 - projectile_homing_strength) + # _homing_new_direction = _projectile_instance.direction.move_toward(_homing_desired_direction, projectile_steer_speed * delta) + # _homing_final_direction = _homing_new_direction.normalized() * projectile_homing_strength + _projectile_instance.direction * (1.0 - projectile_homing_strength) - # _active_projectile_instance.direction = _homing_final_direction.normalized() + # _projectile_instance.direction = _homing_final_direction.normalized() # if projectile_speed_acceleration == 0: - # _active_projectile_instance.velocity = _active_projectile_instance.speed * _active_projectile_instance.direction * delta + # _projectile_instance.velocity = _projectile_instance.speed * _projectile_instance.direction * delta - # if _active_projectile_instance.texture_rotation_speed != 0: - # _active_projectile_instance.texture_rotation += _active_projectile_instance.texture_rotation_speed * delta + # if _projectile_instance.texture_rotation_speed != 0: + # _projectile_instance.texture_rotation += _projectile_instance.texture_rotation_speed * delta - # if _active_projectile_instance.texture_scale_acceleration != 0: - # if _active_projectile_instance.texture_scale < _active_projectile_instance.texture_scale_max: - # _active_projectile_instance.texture_scale = _active_projectile_instance.texture_scale.move_toward(_active_projectile_instance.texture_scale_max, _active_projectile_instance.texture_scale_acceleration * delta) + # if _projectile_instance.texture_scale_acceleration != 0: + # if _projectile_instance.texture_scale < _projectile_instance.texture_scale_max: + # _projectile_instance.texture_scale = _projectile_instance.texture_scale.move_toward(_projectile_instance.texture_scale_max, _projectile_instance.texture_scale_acceleration * delta) - # if _active_projectile_instance.speed_acceleration != 0: - # if _active_projectile_instance.speed < _active_projectile_instance.speed_max: - # _active_projectile_instance.speed = move_toward( - # _active_projectile_instance.speed, _active_projectile_instance.speed_max, _active_projectile_instance.speed_acceleration * delta + # if _projectile_instance.speed_acceleration != 0: + # if _projectile_instance.speed < _projectile_instance.speed_max: + # _projectile_instance.speed = move_toward( + # _projectile_instance.speed, _projectile_instance.speed_max, _projectile_instance.speed_acceleration * delta # ) - # if _active_projectile_instance.texture_rotation_speed != 0: - # _active_projectile_instance.texture_rotation += _active_projectile_instance.texture_rotation_speed * delta + # if _projectile_instance.texture_rotation_speed != 0: + # _projectile_instance.texture_rotation += _projectile_instance.texture_rotation_speed * delta # if projectile_direction_follow_rotation: - # _active_projectile_instance.direction_rotation = _active_projectile_instance.texture_rotation + # _projectile_instance.direction_rotation = _projectile_instance.texture_rotation # # Update Projectile Instance Properties - # # print("direction rotation: ", _active_projectile_instance.direction_rotation_speed) - # if _active_projectile_instance.direction_rotation_speed != 0: - # _active_projectile_instance.direction_rotation += _active_projectile_instance.direction_rotation_speed * delta - # # print(_active_projectile_instance.direction_rotation) - - # if _active_projectile_instance.direction_rotation != 0: - # _active_projectile_instance.direction = _active_projectile_instance.base_direction.rotated( - # _active_projectile_instance.direction_rotation + # # print("direction rotation: ", _projectile_instance.direction_rotation_speed) + # if _projectile_instance.direction_rotation_speed != 0: + # _projectile_instance.direction_rotation += _projectile_instance.direction_rotation_speed * delta + # # print(_projectile_instance.direction_rotation) + + # if _projectile_instance.direction_rotation != 0: + # _projectile_instance.direction = _projectile_instance.base_direction.rotated( + # _projectile_instance.direction_rotation # ) # if projectile_rotation_follow_direction: - # _active_projectile_instance.texture_rotation = _active_projectile_instance.direction_rotation + # _projectile_instance.texture_rotation = _projectile_instance.direction_rotation - # _active_projectile_instance.velocity = _active_projectile_instance.speed * _active_projectile_instance.direction * delta + # _projectile_instance.velocity = _projectile_instance.speed * _projectile_instance.direction * delta - # _active_projectile_instance.global_position += _active_projectile_instance.velocity + # _projectile_instance.global_position += _projectile_instance.velocity - # _active_projectile_instance.transform_2d = Transform2D( - # _active_projectile_instance.texture_rotation, - # _active_projectile_instance.texture_scale, - # _active_projectile_instance.texture_skew, - # _active_projectile_instance.global_position + # _projectile_instance.transform_2d = Transform2D( + # _projectile_instance.texture_rotation, + # _projectile_instance.texture_scale, + # _projectile_instance.texture_skew, + # _projectile_instance.global_position # ) # if projectile_template_2d.collision_shape: # PS.area_set_shape_transform( # projectile_area_rid, - # _active_projectile_instance.area_index, - # _active_projectile_instance.transform_2d + # _projectile_instance.area_index, + # _projectile_instance.transform_2d # ) diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd index 8165f3f9..9d798394 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_custom_2d/projectile_template_custom_2d.gd @@ -5,11 +5,6 @@ class_name ProjectileTemplateCustom2D ## Movement speed of the projectile in pixels per second @export var speed: float = 100 -# ## The normalized Direction of the projectile moving toward -# @export var direction : Vector2 = Vector2.RIGHT -## Number of projectiles to preload in the object pool for better performance -@export var projectile_pooling_amount: int = 500 - @export_group("Texture") ## The Projectile Instance Texture @export var texture: Texture2D 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 a2f754fc..09ec87e2 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 @@ -147,7 +147,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) projectile_pooling_index += 1 - if projectile_pooling_index >= projectile_max_pooling: + if projectile_pooling_index >= projectile_pooling_amount: projectile_pooling_index = 0 update_projectile_instances(get_physics_process_delta_time()) 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 ca0663d6..92c60180 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 @@ -5,7 +5,7 @@ class_name ProjectileNodeManager2D var projectile_template_2d : ProjectileTemplate2D var projectile_pooling_index : int = 0 -var projectile_max_pooling : int +var projectile_pooling_amount : int var projectile_node_array : Array[Projectile2D] var active_nodes : Array[Projectile2D] @@ -40,12 +40,12 @@ func setup_projectile_manager() -> void: func create_projectile_pool() -> void: - projectile_max_pooling = projectile_template_2d.projectile_pooling_amount + projectile_pooling_amount = projectile_template_2d.projectile_pooling_amount projectile_node_array.clear() if projectile_template_2d.projectile_pooling_amount <= 0: - projectile_max_pooling = -1 + projectile_pooling_amount = -1 return - for _index in projectile_max_pooling: + for _index in projectile_pooling_amount: _projectile_node_2d = projectile_node_2d_packedscene.instantiate() _projectile_node_2d.projectile_template_2d = projectile_template_2d _projectile_node_2d.projectile_node_manager = self @@ -65,7 +65,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) if !_is_valid_projectile_node_2d: push_warning("ProjectileNode2D is not vailid") return - if projectile_max_pooling > 0: + if projectile_pooling_amount > 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 @@ -80,7 +80,7 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_node_2d.setup_projectile_2d() projectile_pooling_index += 1 - if projectile_pooling_index >= projectile_max_pooling: + if projectile_pooling_index >= projectile_pooling_amount: projectile_pooling_index = 0 active_nodes.append(_projectile_node_2d) diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_template_node_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_template_node_2d.gd index 43acf6dc..d73f87dd 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_template_node_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_node_2d/projectile_template_node_2d.gd @@ -3,4 +3,3 @@ class_name ProjectileTemplateNode2D ## Path to Projectile2D Scene @export var projectile_2d_path : StringName -@export var projectile_pooling_amount: int = 100 diff --git a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd index f83b0c6e..5326bcce 100644 --- a/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd +++ b/addons/godot_projectile_engine/core/projectile_template/projectile_template_simple_2d/projectile_template_simple_2d.gd @@ -1,11 +1,98 @@ -extends ProjectileTemplateObject2D +extends ProjectileTemplate2D class_name ProjectileTemplateSimple2D +## Movement speed of the projectile in pixels per second +@export var speed: float = 100: + set(value): + speed = value + emit_changed() + +@export_group("Texture - Transform") +## The Projectile Instance Texture +@export var texture: Texture2D: + set(value): + texture = value + emit_changed() + +## Initial rotation of the texture in degrees +@export_range(-360, 360, 0.1, "radians_as_degrees", "suffix:°") var texture_rotation: float: + set(value): + texture_rotation = value + emit_changed() + +## The Projectile Instance Scale, default scale: [code](1.0, 1.0)[/code] +@export_custom(PROPERTY_HINT_LINK, "suffix:") var texture_scale: Vector2 = Vector2.ONE: + set(value): + texture_scale = value + emit_changed() + +## Skew/shear effect applied to texture (-89.9 to 89.9 degrees) +@export_range(-89.9, 89.9, 0.1) var texture_skew: float = 0.0: + set(value): + texture_skew = value + emit_changed() + +## Toggles visibility of the projectile's texture +@export var texture_visible: bool = true: + set(value): + texture_visible = value + emit_changed() + +## Render layer for the texture (higher values render on top) +@export var texture_z_index: int = 0: + set(value): + texture_z_index = value + emit_changed() + +## Reverse Z in dex, make new bullet render underneath older bullet +@export var reverse_z_index: bool = false: + set(value): + reverse_z_index = value + emit_changed() + +## Color modulation applied to the texture (RGBA) +@export var texture_modulate: Color = Color(1, 1, 1, 1): + set(value): + texture_modulate = value + emit_changed() + +@export_group("Collision") +## Collision shape used for physics detection +@export var collision_shape: Shape2D +## Physics layers this projectile can collide with (bitmask) +@export_flags_2d_physics var collision_layer: int = 0 +## Physics layers that can detect collisions with this projectile (bitmask) +@export_flags_2d_physics var collision_mask: int = 0 +@export var texture_rotate_direction: bool = false: + set(value): + texture_rotate_direction = value + emit_changed() + +## Destroy when collided with a body +@export var destroy_on_body_collide: bool = true +## Destroy when collided with a area +@export var destroy_on_area_collide: bool = true +## Maximum lifetime of projectile in seconds before it's automatically destroyed +## [code] life_time_max < 0 [/code] for unlimited life time +@export var life_time_second_max: float = 10.0: + set(value): + life_time_second_max = value + emit_changed() +## Maximum travel distance in pixels before projectile is automatically destroyed [br] +## [code] life_distance_max < 0 [/code] for unlimited distance +@export var life_distance_max: float = 1000.0: + set(value): + life_distance_max = value + emit_changed() +## Internal RID (Rendering ID) for the projectile's collision area +var projectile_area_rid: RID + + ## Template for Simple Projectile 2D that will move at the direction and speed defined. @export_group("Random") @export var speed_random: Vector3 @export var texture_rotation_random: Vector3 @export var texture_rotation_speed_random: Vector3 @export var texture_scale_random: Vector3 -@export var life_time_second_random : Vector3 -@export var life_distance_random : Vector3 \ No newline at end of file +@export var life_time_second_random: Vector3 +@export var life_distance_random: Vector3 \ No newline at end of file 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 c05c1c0b..30237bb3 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 @@ -1,30 +1,17 @@ extends ProjectileUpdater2D class_name ProjectileUpdaterSimple2D -var projectile_velocity: Vector2 = Vector2.ZERO - - - -var destroy_on_body_collide: bool -var destroy_on_area_collide: bool var projectile_texture_rotate_direction: bool func update_updater_variables() -> void: - super() - projectile_template_2d = projectile_template_2d as ProjectileTemplateSimple2D - - projectile_speed = projectile_template_2d.speed - destroy_on_body_collide = projectile_template_2d.destroy_on_body_collide - destroy_on_area_collide = projectile_template_2d.destroy_on_area_collide - + super () projectile_instance_callable = Callable(ProjectileInstanceSimple2D, "new") #region Spawn Projectile +var _scale_value_float: float func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) -> void: - projectile_template_2d = projectile_template_2d as ProjectileTemplateSimple2D - for _pattern_composer_data: PatternComposerData in pattern_composer_pack: _projectile_instance = projectile_instances[projectile_pooling_index] @@ -35,38 +22,25 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.texture_scale = projectile_template_2d.texture_scale # Check and update random variables - var _speed_value: float = projectile_speed - var _scale_value_float: float - var _scale_value: Vector2 = projectile_template_2d.texture_scale - var _rotation_value: float = _projectile_instance.texture_rotation - if projectile_template_2d.speed_random != Vector3.ZERO: - _speed_value = ProjectileEngine.get_random_float_value(projectile_template_2d.speed_random) + projectile_speed = ProjectileEngine.get_random_float_value(projectile_template_2d.speed_random) + if projectile_template_2d.texture_scale_random != Vector3.ZERO: _scale_value_float = ProjectileEngine.get_random_float_value(projectile_template_2d.texture_scale_random) - _scale_value = Vector2(_scale_value_float, _scale_value_float) - _projectile_instance.texture_scale = _scale_value + _projectile_instance.texture_scale = Vector2(_scale_value_float, _scale_value_float) if projectile_template_2d.texture_rotation_random != Vector3.ZERO: _projectile_instance.texture_rotation = ProjectileEngine.get_random_float_value( projectile_template_2d.texture_rotation_random ) - if projectile_template_2d.life_time_second_random != Vector3.ZERO: - _projectile_instance.life_time_second_max = ProjectileEngine.get_random_float_value( - projectile_template_2d.life_time_second_random - ) - if projectile_template_2d.life_distance_random != Vector3.ZERO: - _projectile_instance.life_distance_max = ProjectileEngine.get_random_float_value( - projectile_template_2d.life_distance_random - ) - + _projectile_instance.direction = _projectile_instance.direction.rotated( _projectile_instance.direction_rotation ) _projectile_instance.velocity = ( - _projectile_instance.direction * _speed_value * - (1.0 / Engine.physics_ticks_per_second) + _projectile_instance.direction.normalized() * projectile_speed * + get_physics_process_delta_time() ) if projectile_texture_rotate_direction: @@ -79,9 +53,8 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) _projectile_instance.global_position ) - RenderingServer.canvas_item_set_visible(_projectile_instance.canvas_item_rid, true) - RenderingServer.canvas_item_set_transform(_projectile_instance.canvas_item_rid, _projectile_instance.transform_2d) - + RS.canvas_item_set_visible(_projectile_instance.canvas_item_rid, true) + RS.canvas_item_set_transform(_projectile_instance.canvas_item_rid, _projectile_instance.transform_2d) if projectile_template_2d.collision_shape: PS.area_set_shape_transform(projectile_area_rid, projectile_pooling_index, _projectile_instance.transform_2d) @@ -93,9 +66,9 @@ func spawn_projectile_pattern(pattern_composer_pack: Array[PatternComposerData]) projectile_instances[projectile_pooling_index] = _projectile_instance if projectile_pooling_index not in projectile_active_indexes: projectile_active_indexes.append(projectile_pooling_index) - projectile_pooling_index += 1 - if projectile_pooling_index >= projectile_max_pooling: + projectile_pooling_index += 1 + if projectile_pooling_index >= projectile_pooling_amount: projectile_pooling_index = 0 #endregion @@ -108,45 +81,46 @@ var _active_projectile_instance: ProjectileInstanceSimple2D # var _velocity_length: float func update_projectile_instances(delta: float) -> void: - # Check for projectile destroy condition for index: int in projectile_active_indexes: _projectile_instance = projectile_instances[index] + # Life Time & Distance if projectile_life_time_second_max > 0: _projectile_instance.life_time_second += delta if _projectile_instance.life_time_second >= projectile_life_time_second_max: - projectile_remove_indexes.append(index) + if !projectile_remove_indexes.has(index): + projectile_remove_indexes.append(index) + continue if projectile_life_distance_max > 0: _projectile_instance.life_distance += _projectile_instance.velocity_length if _projectile_instance.life_distance >= projectile_life_distance_max: - projectile_remove_indexes.append(index) + if !projectile_remove_indexes.has(index): + projectile_remove_indexes.append(index) continue if destroy_on_area_collide: - if hasprojectile_overlapping_areas(index): - projectile_remove_indexes.append(index) + if projectile_overlapping_areas.has(index): + if !projectile_remove_indexes.has(index): + projectile_remove_indexes.append(index) + continue if destroy_on_body_collide: - if hasprojectile_overlapping_bodies(index): - projectile_remove_indexes.append(index) - + if projectile_overlapping_bodies.has(index): + if !projectile_remove_indexes.has(index): + projectile_remove_indexes.append(index) + continue - ## Update Transform and texture + ## Update Projetiles Transform _projectile_instance.global_position += _projectile_instance.velocity + _projectile_instance.transform_2d.origin = _projectile_instance.global_position - _projectile_instance.transform_2d = Transform2D( - _projectile_instance.texture_rotation, - _projectile_instance.texture_scale, - _projectile_instance.texture_skew, - _projectile_instance.global_position - ) - - RenderingServer.canvas_item_set_transform( + _projectile_instance.transform_2d.translated(_projectile_instance.velocity) + RS.canvas_item_set_transform( projectile_canvas_item_rids[index], _projectile_instance.transform_2d ) - + if projectile_template_2d.collision_shape: PS.area_set_shape_transform( projectile_area_rid, @@ -154,11 +128,11 @@ func update_projectile_instances(delta: float) -> void: _projectile_instance.transform_2d ) - # Destroy projectile + # Destroy Projectiles if projectile_remove_indexes.size() > 0: for index: int in projectile_remove_indexes: projectile_active_indexes.erase(index) - RenderingServer.canvas_item_set_visible(projectile_instances[index].canvas_item_rid, false) + RS.canvas_item_set_visible(projectile_instances[index].canvas_item_rid, false) if projectile_template_2d.collision_shape: PS.area_set_shape_disabled(projectile_area_rid, index, true) projectile_remove_indexes.clear() @@ -167,19 +141,14 @@ func update_projectile_instances(delta: float) -> void: func _on_projectile_template_changed() -> void: super () - projectile_speed = projectile_template_2d.speed - 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 - - projectile_life_time_second_max = projectile_template_2d.life_time_second_max - projectile_life_distance_max = projectile_template_2d.life_distance_max for index in projectile_active_indexes: _active_projectile_instance = projectile_instances[index] _active_projectile_instance.velocity = ( projectile_speed * - _active_projectile_instance.direction * - (1.0 / Engine.physics_ticks_per_second) + _active_projectile_instance.direction.normalized() * + get_physics_process_delta_time() ) _active_projectile_instance.velocity_length = _projectile_instance.velocity.length() + + # Todo: Reapply any transform if Template Change diff --git a/docs/manual/projectile_node_manager.md b/docs/manual/projectile_node_manager.md index 9c3e79c7..d2c4e71e 100644 --- a/docs/manual/projectile_node_manager.md +++ b/docs/manual/projectile_node_manager.md @@ -8,7 +8,7 @@ Manages pooling and lifecycle of [ProjectileNode2D](/manual/projectile_template_ | Projectile Template | `projectile_template_2d` | `ProjectileTemplate2D` | Associated template configuration | | Node Array | `projectile_node_array` | `Array[Projectile2D]` | Pooled node instances | | Active Nodes | `active_nodes` | `Array[Projectile2D]` | Currently active projectiles | -| Max Pooling | `projectile_max_pooling` | `int` | Maximum pooled instances | +| Max Pooling | `projectile_pooling_amount` | `int` | Maximum pooled instances | ## Key Methods - `setup_projectile_manager()` - Initializes pooling system from template diff --git a/docs/manual/projectile_updater.md b/docs/manual/projectile_updater.md index 3a585187..4d4bc77a 100644 --- a/docs/manual/projectile_updater.md +++ b/docs/manual/projectile_updater.md @@ -10,7 +10,7 @@ Base class for update, physics interactions, and rendering [ProjectileInstance2D | Base Speed | `projectile_speed` | `float` | Base movement speed | | Collision Layer | `projectile_collision_layer` | `int` | Physics collision layer bits | | Collision Mask | `projectile_collision_mask` | `int` | Physics collision mask bits | -| Max Pooling | `projectile_max_pooling` | `int` | Maximum pooled projectile instances | +| Max Pooling | `projectile_pooling_amount` | `int` | Maximum pooled projectile instances | | Instance Array | `projectile_instance_array` | `Array[ProjectileInstance2D]` | All pooled instances | | Active Indices | `projectile_active_index` | `Array[int]` | Indices of active projectiles | diff --git a/project.godot b/project.godot index 097d151a..e0da419e 100644 --- a/project.godot +++ b/project.godot @@ -37,7 +37,6 @@ enabled=PackedStringArray("res://addons/godot_projectile_engine/plugin.cfg", "re settings/test/test_lookup_folder="tests" ui/inspector/tree_view_mode=1 ui/toolbar/run_overall=true -report/godot/push_error=true hooks/session_hooks=Dictionary[String, bool]({ "res://addons/gdUnit4/src/core/hooks/GdUnitHtmlReporterTestSessionHook.gd": false, "res://addons/gdUnit4/src/core/hooks/GdUnitXMLReporterTestSessionHook.gd": false