diff --git a/addons/BulletUpHell/BuHSpawner.gd b/addons/BulletUpHell/BuHSpawner.gd index 631a662..7e93dd7 100644 --- a/addons/BulletUpHell/BuHSpawner.gd +++ b/addons/BulletUpHell/BuHSpawner.gd @@ -1,79 +1,87 @@ @tool extends Node2D -signal bullet_collided_area(area:Area2D,area_shape_index:int, bullet:Dictionary,local_shape_index:int,shared_area:Area2D) -signal bullet_collided_body(body:Node,body_shape_index:int, bullet:Dictionary, local_shape_index:int,shared_area:Area2D) +signal bullet_collided_area( + area: Area2D, + area_shape_index: int, + bullet: Dictionary, + local_shape_index: int, + shared_area: Area2D +) +signal bullet_collided_body( + body: Node, + body_shape_index: int, + bullet: Dictionary, + local_shape_index: int, + shared_area: Area2D +) const STANDARD_BULLET_RADIUS = 5 -var CUSTOM:customFunctions = customFunctions.new() +var CUSTOM: customFunctions = customFunctions.new() - -@export var GROUP_BOUNCE:String = "Slime" +@export var GROUP_BOUNCE: String = "Slime" @export_group("Resource Lists") -@export var default_idle:animState -@export var default_spawn:animState -@export var default_shoot:animState -@export var default_waiting:animState -@export var default_delete:animState +@export var default_idle: animState +@export var default_spawn: animState +@export var default_shoot: animState +@export var default_waiting: animState +@export var default_delete: animState ## Data Structs -var arrayProps:Dictionary = {} -var arrayTriggers:Dictionary = {} -var arrayPatterns:Dictionary = {} -var arrayContainers:Dictionary = {} -var arrayInstances:Dictionary = {} -var arrayAnim:Dictionary = {} -@onready var textures:SpriteFrames = $ShapeManager.sprite_frames -@onready var arrayShapes:Dictionary = {} # format: id={shape, offset, rotation} +var arrayProps: Dictionary = {} +var arrayTriggers: Dictionary = {} +var arrayPatterns: Dictionary = {} +var arrayContainers: Dictionary = {} +var arrayInstances: Dictionary = {} +var arrayAnim: Dictionary = {} +@onready var textures: SpriteFrames = $ShapeManager.sprite_frames +@onready var arrayShapes: Dictionary = {} # format: id={shape, offset, rotation} @onready var viewrect = get_viewport().get_visible_rect() - -var poolBullets:Dictionary = {} -var shape_indexes:Dictionary = {} -var shape_rids:Dictionary = {} +var poolBullets: Dictionary = {} +var shape_indexes: Dictionary = {} +var shape_rids: Dictionary = {} var Phys = PhysicsServer2D -enum BState{Unactive, Spawning, Spawned, Shooting, Moving, QueuedFree} -const UNACTIVE_ZONE = Vector2(99999,99999) +enum BState { Unactive, Spawning, Spawned, Shooting, Moving, QueuedFree } +const UNACTIVE_ZONE = Vector2(99999, 99999) # pooling -var inactive_pool:Dictionary = {} +var inactive_pool: Dictionary = {} const ACTION_SPAWN = 0 const ACTION_SHOOT = 1 const ACTION_BOTH = 2 -var poolQueue:Array = [] # format : [action:0=spawn1=shoot2=both, arraytospawn, arraytoshoot] -var poolTimes:Array = [] +var poolQueue: Array = [] # format : [action:0=spawn1=shoot2=both, arraytospawn, arraytoshoot] +var poolTimes: Array = [] var loop_length = 9999 var time = 0 var next_in_queue var RAND = RandomNumberGenerator.new() var expression = Expression.new() -var _delta:float = 0 +var _delta: float = 0 var HOMING_MARGIN = 20 -enum GROUP_SELECT{Nearest_on_homing, Nearest_on_spawn, Nearest_on_shoot, Nearest_anywhen, Random} -enum SYMTYPE{ClosedShape,Line} -enum CURVE_TYPE{None, LoopFromStart, OnceThenDie, OnceThenStay, LoopFromEnd} -enum LIST_ENDS{Stop, Loop, Reverse} -enum ANIM{TEXTURE, COLLISION, SFX, SCALE, SKEW} +enum GROUP_SELECT { Nearest_on_homing, Nearest_on_spawn, Nearest_on_shoot, Nearest_anywhen, Random } +enum SYMTYPE { ClosedShape, Line } +enum CURVE_TYPE { None, LoopFromStart, OnceThenDie, OnceThenStay, LoopFromEnd } +enum LIST_ENDS { Stop, Loop, Reverse } +enum ANIM { TEXTURE, COLLISION, SFX, SCALE, SKEW } -var global_reset_counter:int = 0 +var global_reset_counter: int = 0 ## multithreading #var spawn_thread: Thread #var move_thread: Thread #var draw_thread: Thread - - - - #§§§§§§§§§§§§§ GLOBAL §§§§§§§§§§§§§ + func _ready(): - if Engine.is_editor_hint(): return + if Engine.is_editor_hint(): + return #spawn_thread = Thread.new() #move_thread = Thread.new() @@ -84,25 +92,31 @@ func _ready(): $ShapeManager.hide() for s in $ShapeManager.get_children(): assert(s is CollisionShape2D or s is CollisionPolygon2D) - if s.shape: arrayShapes[s.name] = [s.shape,s.position,s.rotation] + if s.shape: + arrayShapes[s.name] = [s.shape, s.position, s.rotation] s.queue_free() for a in $SharedAreas.get_children(): assert(a is Area2D) - a.connect("area_shape_entered",Callable(self,"bullet_collide_area").bind(a)) - a.connect("body_shape_entered",Callable(self,"bullet_collide_body").bind(a)) + a.connect("area_shape_entered", Callable(self, "bullet_collide_area").bind(a)) + a.connect("body_shape_entered", Callable(self, "bullet_collide_body").bind(a)) a.set_meta("ShapeCount", 0) $Bouncy.global_position = UNACTIVE_ZONE - var default_anims:Array[animState] = [default_idle, default_spawn, default_shoot, default_waiting, default_delete] + var default_anims: Array[animState] = [ + default_idle, default_spawn, default_shoot, default_waiting, default_delete + ] for a in default_anims.size(): - default_anims[a].ID = "@"+["anim_idle","anim_spawn","anim_shoot","anim_waiting","anim_delete"][a] + default_anims[a].ID = ( + "@" + ["anim_idle", "anim_spawn", "anim_shoot", "anim_waiting", "anim_delete"][a] + ) set_anim_states(default_anims[a]) #update_viewport() -func reset(minimal:bool=false): + +func reset(minimal: bool = false): # change that in order signal that a reset has been made and stop the currently running func global_reset_counter += 1 # reset bullets @@ -130,9 +144,12 @@ func reset(minimal:bool=false): arrayTriggers.clear() arrayProps.clear() else: - for array in [arrayContainers, arrayInstances, arrayPatterns, arrayProps, arrayTriggers, arrayAnim]: + for array in [ + arrayContainers, arrayInstances, arrayPatterns, arrayProps, arrayTriggers, arrayAnim + ]: for elem in array.keys(): - if elem[0] == "@": continue + if elem[0] == "@": + continue array.erase(elem) @@ -142,16 +159,20 @@ func _exit_tree(): #move_thread.wait_to_finish() pass + func _process(delta: float) -> void: - if Engine.is_editor_hint(): return + if Engine.is_editor_hint(): + return _delta = delta #if not cull_fixed_screen: - #viewrect = Rect2(-get_canvas_transform().get_origin()/get_canvas_transform().get_scale(), \ - #get_viewport_rect().size/get_canvas_transform().get_scale()) + #viewrect = Rect2(-get_canvas_transform().get_origin()/get_canvas_transform().get_scale(), \ + #get_viewport_rect().size/get_canvas_transform().get_scale()) + func _physics_process(delta: float) -> void: - if Engine.is_editor_hint(): return + if Engine.is_editor_hint(): + return if not poolBullets.is_empty(): # if move_thread.is_started(): @@ -162,149 +183,239 @@ func _physics_process(delta: float) -> void: queue_redraw() time += delta - if time == loop_length: time = 0 + if time == loop_length: + time = 0 while not poolQueue.is_empty() and poolTimes[0] < time: next_in_queue = poolQueue[0] match next_in_queue[0]: - ACTION_SPAWN: _spawn(next_in_queue[1]) - ACTION_SHOOT: _shoot(next_in_queue[1]) - ACTION_BOTH: _spawn_and_shoot(next_in_queue[1],next_in_queue[2]) + ACTION_SPAWN: + _spawn(next_in_queue[1]) + ACTION_SHOOT: + _shoot(next_in_queue[1]) + ACTION_BOTH: + _spawn_and_shoot(next_in_queue[1], next_in_queue[2]) poolQueue.pop_front() poolTimes.pop_front() -func change_scene_to_file(file:String): + +func change_scene_to_file(file: String): reset_bullets() get_tree().change_scene_to_file(file) -func change_scene_to_packed(scene:PackedScene): + +func change_scene_to_packed(scene: PackedScene): reset_bullets() get_tree().change_scene_to_packed(scene) + func reset_bullets(): clear_all_bullets() - - #§§§§§§§§§§§§§ RESOURCES §§§§§§§§§§§§§ -func new_instance(id:String, instance:Node2D): + +func new_instance(id: String, instance: Node2D): if arrayInstances.has(id): - push_warning("Warning : New instance ignored. Name "+id+" already exists. Make sure this duplicate isn't an error.") + push_warning( + ( + "Warning : New instance ignored. Name " + + id + + " already exists. Make sure this duplicate isn't an error." + ) + ) return arrayInstances[id] = instance -func new_trigger(id:String, t:RichTextEffect): + + +func new_trigger(id: String, t: RichTextEffect): if arrayTriggers.has(id): - push_warning("Warning : New trigger ignored. Name "+id+" already exists. Make sure this duplicate isn't an error.") + push_warning( + ( + "Warning : New trigger ignored. Name " + + id + + " already exists. Make sure this duplicate isn't an error." + ) + ) return arrayTriggers[id] = t -func new_pattern(id:String, p:Pattern): + + +func new_pattern(id: String, p: Pattern): if arrayPatterns.has(id): - push_warning("Warning : New pattern ignored. Name "+id+" already exists. Make sure this duplicate isn't an error.") + push_warning( + ( + "Warning : New pattern ignored. Name " + + id + + " already exists. Make sure this duplicate isn't an error." + ) + ) return arrayPatterns[id] = p -func new_bullet(id:String, b:Dictionary): + + +func new_bullet(id: String, b: Dictionary): if arrayProps.has(id): - push_warning("Warning : New bullet ignored. Name "+id+" already exists. Make sure this duplicate isn't an error.") + push_warning( + ( + "Warning : New bullet ignored. Name " + + id + + " already exists. Make sure this duplicate isn't an error." + ) + ) return arrayProps[id] = b + + func new_container(node): if arrayContainers.has(node.id): - push_warning("Warning : New container ignored. Name "+node.id+" already exists. Make sure this duplicate isn't an error.") + push_warning( + ( + "Warning : New container ignored. Name " + + node.id + + " already exists. Make sure this duplicate isn't an error." + ) + ) return arrayContainers[node.id] = node -func instance(id:String) -> Node2D: - assert(arrayInstances.has(id), "Trying to get the scene instance named "+id+", which doesn't exist.") + +func instance(id: String) -> Node2D: + assert( + arrayInstances.has(id), + "Trying to get the scene instance named " + id + ", which doesn't exist." + ) return arrayInstances[id] -func trigger(id:String): - assert(arrayTriggers.has(id), "Trying to get the trigger "+id+", which doesn't exist.") + + +func trigger(id: String): + assert(arrayTriggers.has(id), "Trying to get the trigger " + id + ", which doesn't exist.") return arrayTriggers[id] -func pattern(id:String): - assert(arrayPatterns.has(id), "Trying to get the pattern "+id+", which doesn't exist.") + + +func pattern(id: String): + assert(arrayPatterns.has(id), "Trying to get the pattern " + id + ", which doesn't exist.") return arrayPatterns[id] -func bullet(id:String): - assert(arrayProps.has(id), "Trying to get the bulletprops "+id+", which doesn't exist.") + + +func bullet(id: String): + assert(arrayProps.has(id), "Trying to get the bulletprops " + id + ", which doesn't exist.") return arrayProps[id] -func container(id:String): - assert(arrayContainers.has(id), "Trying to get the trigger container "+id+", which doesn't exist.") + + +func container(id: String): + assert( + arrayContainers.has(id), + "Trying to get the trigger container " + id + ", which doesn't exist." + ) return arrayContainers[id] -func set_anim_states(a:animState, P:String="", id:String=""): - if a.ID == "": a.ID = "_"+id+"_"+P +func set_anim_states(a: animState, P: String = "", id: String = ""): + if a.ID == "": + a.ID = "_" + id + "_" + P var col var sfx - if a.texture == "": a.texture = arrayAnim["@"+P][ANIM.TEXTURE] - if a.collision == "": col = arrayAnim["@"+P][ANIM.COLLISION] - else: col = arrayShapes[a.collision] - if a.SFX == "": sfx = null - else: sfx = $SFX.get_node(a.SFX) + if a.texture == "": + a.texture = arrayAnim["@" + P][ANIM.TEXTURE] + if a.collision == "": + col = arrayAnim["@" + P][ANIM.COLLISION] + else: + col = arrayShapes[a.collision] + if a.SFX == "": + sfx = null + else: + sfx = $SFX.get_node(a.SFX) arrayAnim[a.ID] = [a.texture, col, sfx, a.tex_scale, a.tex_skew] return a.ID - - - - #§§§§§§§§§§§§§ POOLING §§§§§§§§§§§§§ -func create_pool(bullet:String, shared_area:String, amount:int, object:bool=false): - var props:Dictionary = arrayProps[bullet] + +func create_pool(bullet: String, shared_area: String, amount: int, object: bool = false): + var props: Dictionary = arrayProps[bullet] if not inactive_pool.has(bullet): inactive_pool[bullet] = [] - inactive_pool["__SIZE__"+bullet] = 0 + inactive_pool["__SIZE__" + bullet] = 0 if object: for i in amount: inactive_pool[bullet].append(instance(props["instance_id"]).duplicate()) else: - var shared_rid:RID = get_shared_area_rid(shared_area) - var count:int = Phys.area_get_shape_count(shared_rid) - var new_rid:RID - $SharedAreas.get_node(shared_area).set_meta("ShapeCount", $SharedAreas.get_node(shared_area).get_meta("ShapeCount",0)+amount) # Warning, bad sync possible ? + var shared_rid: RID = get_shared_area_rid(shared_area) + var count: int = Phys.area_get_shape_count(shared_rid) + var new_rid: RID + $SharedAreas.get_node(shared_area).set_meta( + "ShapeCount", $SharedAreas.get_node(shared_area).get_meta("ShapeCount", 0) + amount + ) # Warning, bad sync possible ? for i in amount: - new_rid = create_shape(shared_rid, arrayAnim[props["anim_spawn"]][ANIM.COLLISION], true, count+i) + new_rid = create_shape( + shared_rid, arrayAnim[props["anim_spawn"]][ANIM.COLLISION], true, count + i + ) # shape_indexes[new_rid] = count+i - _update_shape_indexes(new_rid, count+i, shared_area) + _update_shape_indexes(new_rid, count + i, shared_area) inactive_pool[bullet].append([new_rid, shared_area]) - inactive_pool["__SIZE__"+bullet] += amount + inactive_pool["__SIZE__" + bullet] += amount + # return RID for default bullets OR object reference for scenes -func wake_from_pool(bullet:String, queued_instance:Dictionary, shared_area:String, object:bool=false): +func wake_from_pool( + bullet: String, queued_instance: Dictionary, shared_area: String, object: bool = false +): if not inactive_pool.has(bullet): - push_warning("WARNING : there's no bullet pool for bullet of ID "+bullet+" . Create a pool upon game load to avoid lag by calling Spawning.create_pool()") - create_pool(bullet, queued_instance["shared_area"].name, 50, object) # TODO : 50 is arbitrary, there might be lag if it needs more + push_warning( + ( + "WARNING : there's no bullet pool for bullet of ID " + + bullet + + " . Create a pool upon game load to avoid lag by calling Spawning.create_pool()" + ) + ) + create_pool(bullet, queued_instance["shared_area"].name, 50, object) # TODO : 50 is arbitrary, there might be lag if it needs more elif inactive_pool[bullet].is_empty(): - push_warning("WARNING : bullet pool for bullet of ID "+bullet+" is empty. Create bigger one next time to avoid lag.") - create_pool(bullet, queued_instance["shared_area"].name, max(inactive_pool["__SIZE__"+bullet]/10, 50), object) + push_warning( + ( + "WARNING : bullet pool for bullet of ID " + + bullet + + " is empty. Create bigger one next time to avoid lag." + ) + ) + create_pool( + bullet, + queued_instance["shared_area"].name, + max(inactive_pool["__SIZE__" + bullet] / 10, 50), + object + ) if inactive_pool[bullet][0] is Array: - var i:int = 0 - while inactive_pool[bullet][i][1] != shared_area: i += 1 + var i: int = 0 + while inactive_pool[bullet][i][1] != shared_area: + i += 1 var bID = inactive_pool[bullet].pop_at(i)[0] poolBullets[bID] = queued_instance return bID else: return inactive_pool[bullet].pop_at(0) -func back_to_grave(bullet:String, bID): + +func back_to_grave(bullet: String, bID): inactive_pool[bullet].append([bID, poolBullets[bID]["shared_area"].name]) poolBullets[bID]["state"] = BState.QueuedFree - if bID is Node2D: bID.get_parent().remove_child(bID) + if bID is Node2D: + bID.get_parent().remove_child(bID) -func create_shape(shared_rid:RID, ColID:Array, init:bool=false, count:int=0) -> RID: - var new_shape:RID + +func create_shape(shared_rid: RID, ColID: Array, init: bool = false, count: int = 0) -> RID: + var new_shape: RID var template_shape = ColID[0] if template_shape is CircleShape2D: new_shape = Phys.circle_shape_create() Phys.shape_set_data(new_shape, template_shape.radius) elif template_shape is CapsuleShape2D: new_shape = Phys.capsule_shape_create() - Phys.shape_set_data(new_shape, [template_shape.radius,template_shape.height]) + Phys.shape_set_data(new_shape, [template_shape.radius, template_shape.height]) elif template_shape is ConcavePolygonShape2D: new_shape = Phys.concave_polygon_shape_create() Phys.shape_set_data(new_shape, template_shape.segments) @@ -313,98 +424,139 @@ func create_shape(shared_rid:RID, ColID:Array, init:bool=false, count:int=0) -> Phys.shape_set_data(new_shape, template_shape.points) elif template_shape is WorldBoundaryShape2D: new_shape = Phys.line_shape_create() - Phys.shape_set_data(new_shape, [template_shape.d,template_shape.normal]) + Phys.shape_set_data(new_shape, [template_shape.d, template_shape.normal]) elif template_shape is SeparationRayShape2D: new_shape = Phys.separation_ray_shape_create() - Phys.shape_set_data(new_shape, [template_shape.length,template_shape.slide_on_slope]) + Phys.shape_set_data(new_shape, [template_shape.length, template_shape.slide_on_slope]) elif template_shape is RectangleShape2D: new_shape = Phys.rectangle_shape_create() Phys.shape_set_data(new_shape, template_shape.extents) elif template_shape is SegmentShape2D: new_shape = Phys.segment_shape_create() - Phys.shape_set_data(new_shape, [template_shape.a,template_shape.b]) - - Phys.area_add_shape(shared_rid, new_shape, Transform2D(ColID[2],ColID[1]+(UNACTIVE_ZONE*int(init)))) - if count == 0: count = Phys.area_get_shape_count(shared_rid) - Phys.area_set_shape_disabled(shared_rid, count-1, true) + Phys.shape_set_data(new_shape, [template_shape.a, template_shape.b]) + + Phys.area_add_shape( + shared_rid, new_shape, Transform2D(ColID[2], ColID[1] + (UNACTIVE_ZONE * int(init))) + ) + if count == 0: + count = Phys.area_get_shape_count(shared_rid) + Phys.area_set_shape_disabled(shared_rid, count - 1, true) return new_shape - - - - #§§§§§§§§§§§§§ SPAWN §§§§§§§§§§§§§ ### INIT BULLETS DATA ### -func set_angle(pattern:Pattern, pos:Vector2, queued_instance:Dictionary): + +func set_angle(pattern: Pattern, pos: Vector2, queued_instance: Dictionary): if pattern.forced_target != NodePath() and is_instance_valid(pattern.node_target): - if pattern.forced_pattern_lookat: queued_instance["rotation"] = pos.angle_to_point(pattern.node_target.global_position) - else: queued_instance["rotation"] = (pos+queued_instance["spawn_pos"]).angle_to_point(pattern.node_target.global_position) + if pattern.forced_pattern_lookat: + queued_instance["rotation"] = pos.angle_to_point(pattern.node_target.global_position) + else: + queued_instance["rotation"] = (pos + queued_instance["spawn_pos"]).angle_to_point( + pattern.node_target.global_position + ) elif pattern.forced_lookat_mouse: - if pattern.forced_pattern_lookat: queued_instance["rotation"] = pos.angle_to_point(get_global_mouse_position()) - else: queued_instance["rotation"] = (pos+queued_instance["spawn_pos"]).angle_to_point(get_global_mouse_position()) + if pattern.forced_pattern_lookat: + queued_instance["rotation"] = pos.angle_to_point(get_global_mouse_position()) + else: + queued_instance["rotation"] = (pos + queued_instance["spawn_pos"]).angle_to_point( + get_global_mouse_position() + ) elif pattern.forced_angle != 0.0: queued_instance["rotation"] = pattern.forced_angle -func create_bullet_instance_dict(queued_instance:Dictionary, bullet_props:Dictionary, pattern:Pattern): + +func create_bullet_instance_dict( + queued_instance: Dictionary, bullet_props: Dictionary, pattern: Pattern +): queued_instance["shape_disabled"] = true #if pattern.bullet in no_culling_for: queued_instance["no_culling"] = true queued_instance["speed"] = bullet_props.speed queued_instance["vel"] = Vector2() - if bullet_props.has("groups"): queued_instance["groups"] = bullet_props.get("groups") + if bullet_props.has("groups"): + queued_instance["groups"] = bullet_props.get("groups") return queued_instance -func set_spawn_data(queued_instance:Dictionary, bullet_props:Dictionary, pattern:Pattern, i:int, ori_angle:float): - var angle:float + +func set_spawn_data( + queued_instance: Dictionary, + bullet_props: Dictionary, + pattern: Pattern, + i: int, + ori_angle: float +): + var angle: float match pattern.resource_name: "PatternCircle": - angle = (pattern.angle_total/pattern.nbr)*i + pattern.angle_decal - queued_instance["spawn_pos"] = Vector2(cos(angle)*pattern.radius,sin(angle)*pattern.radius).rotated(pattern.pattern_angle) + angle = (pattern.angle_total / pattern.nbr) * i + pattern.angle_decal + queued_instance["spawn_pos"] = ( + Vector2(cos(angle) * pattern.radius, sin(angle) * pattern.radius) + . rotated(pattern.pattern_angle) + ) queued_instance["rotation"] = angle + bullet_props.angle + ori_angle "PatternLine": - queued_instance["spawn_pos"] = Vector2(pattern.offset.x*(-abs(pattern.center-i-1))-pattern.nbr/2*pattern.offset.x, pattern.offset.y*i-pattern.nbr/2*pattern.offset.y).rotated(pattern.pattern_angle) + queued_instance["spawn_pos"] = ( + Vector2( + ( + pattern.offset.x * (-abs(pattern.center - i - 1)) + - pattern.nbr / 2 * pattern.offset.x + ), + pattern.offset.y * i - pattern.nbr / 2 * pattern.offset.y + ) + . rotated(pattern.pattern_angle) + ) queued_instance["rotation"] = bullet_props.angle + pattern.pattern_angle + ori_angle "PatternOne": queued_instance["spawn_pos"] = Vector2() queued_instance["rotation"] = bullet_props.angle + ori_angle - "PatternCustomShape","PatternCustomPoints": + "PatternCustomShape", "PatternCustomPoints": queued_instance["spawn_pos"] = pattern.pos[i] queued_instance["rotation"] = bullet_props.angle + pattern.angles[i] + ori_angle "PatternCustomArea": - queued_instance["spawn_pos"] = pattern.pos[randi()%pattern.pooling][i] + queued_instance["spawn_pos"] = pattern.pos[randi() % pattern.pooling][i] queued_instance["rotation"] = bullet_props.angle + ori_angle + ### TRIGGER SPAWN ### -func spawn(spawner, id:String, shared_area:String="0"): + +func spawn(spawner, id: String, shared_area: String = "0"): #spawn_thread.start(_thread_spawn.bind(spawner, id, shared_area)) #_thread_spawn(spawner, id, shared_area) #func _thread_spawn(spawner, id:String, shared_area:String="0"): assert(arrayPatterns.has(id)) - var local_reset_counter:int = global_reset_counter - var bullets:Array - var pattern:Pattern = arrayPatterns[id] - var iter:int = pattern.iterations + var local_reset_counter: int = global_reset_counter + var bullets: Array + var pattern: Pattern = arrayPatterns[id] + var iter: int = pattern.iterations var shared_area_node = $SharedAreas.get_node(shared_area) - var pos:Vector2; var ori_angle:float; - var bullet_props:Dictionary; var queued_instance:Dictionary; var bID; var is_object:bool; var is_bullet_node:bool - var tw_endpos:Vector2; - while iter != 0: - if spawner == null: return + var pos: Vector2 + var ori_angle: float + var bullet_props: Dictionary + var queued_instance: Dictionary + var bID + var is_object: bool + var is_bullet_node: bool + var tw_endpos: Vector2 + while iter != 0 and spawner.active: + if spawner == null: + return if spawner is Node2D: ori_angle = spawner.rotation pos = spawner.global_position elif spawner is Dictionary: pos = spawner["position"] ori_angle = spawner["rotation"] - else: push_error("spawner isn't a Node2D or a bullet RID") + else: + push_error("spawner isn't a Node2D or a bullet RID") bullet_props = arrayProps[pattern.bullet] - if bullet_props.get("has_random",false): bullet_props = create_random_props(bullet_props) + if bullet_props.get("has_random", false): + bullet_props = create_random_props(bullet_props) is_object = bullet_props.has("instance_id") is_bullet_node = (is_object and bullet_props.has("speed")) @@ -417,25 +569,40 @@ func spawn(spawner, id:String, shared_area:String="0"): if not is_object: queued_instance["anim"] = arrayAnim[bullet_props["anim_idle"]] queued_instance["colID"] = queued_instance["anim"][ANIM.COLLISION] - queued_instance = create_bullet_instance_dict(queued_instance, bullet_props, pattern) - elif is_bullet_node: queued_instance = create_bullet_instance_dict(queued_instance, bullet_props, pattern) + queued_instance = create_bullet_instance_dict( + queued_instance, bullet_props, pattern + ) + elif is_bullet_node: + queued_instance = create_bullet_instance_dict( + queued_instance, bullet_props, pattern + ) set_spawn_data(queued_instance, bullet_props, pattern, i, ori_angle) if not bullet_props.get("fixed_rotation", false): set_angle(pattern, pos, queued_instance) - else: queued_instance["rotation"] = 0 + else: + queued_instance["rotation"] = 0 if pattern.wait_tween_momentum > 0: - tw_endpos = queued_instance["spawn_pos"]+pos+Vector2(pattern.wait_tween_length, 0).rotated(PI+queued_instance["rotation"]) - queued_instance["momentum_data"] = [pattern.wait_tween_momentum-1, tw_endpos, pattern.wait_tween_time] + tw_endpos = ( + queued_instance["spawn_pos"] + + pos + + Vector2(pattern.wait_tween_length, 0).rotated( + PI + queued_instance["rotation"] + ) + ) + queued_instance["momentum_data"] = [ + pattern.wait_tween_momentum - 1, tw_endpos, pattern.wait_tween_time + ] bID = wake_from_pool(pattern.bullet, queued_instance, shared_area, is_object) bullets.append(bID) poolBullets[bID] = queued_instance if is_object: - if is_bullet_node: bID.b = queued_instance + if is_bullet_node: + bID.b = queued_instance if bullet_props.has("overwrite_groups"): for g in bID.get_groups(): @@ -445,27 +612,54 @@ func spawn(spawner, id:String, shared_area:String="0"): _plan_spawning(pattern, bullets) - if iter > 0: iter -= 1 + if iter > 0: + iter -= 1 await get_tree().create_timer(pattern.cooldown_spawn).timeout - if local_reset_counter != global_reset_counter: return + if local_reset_counter != global_reset_counter: + return + -func _plan_spawning(pattern:Pattern, bullets:Array): +func _plan_spawning(pattern: Pattern, bullets: Array): if pattern.cooldown_next_spawn == 0: _spawn(bullets) - if pattern.cooldown_stasis: return + if pattern.cooldown_stasis: + return var to_shoot = bullets.duplicate() if pattern.cooldown_next_shoot == 0: - if pattern.cooldown_shoot == 0: _shoot(to_shoot) #no add pos - else: plan_shoot(to_shoot, pattern.cooldown_shoot) + if pattern.cooldown_shoot == 0: + _shoot(to_shoot) #no add pos + else: + plan_shoot(to_shoot, pattern.cooldown_shoot) else: var idx for b in to_shoot: idx = to_shoot.find(b) if pattern.symmetric: match pattern.symmetry_type: - SYMTYPE.Line: plan_shoot([b], pattern.cooldown_shoot+(abs(pattern.center-idx))*pattern.cooldown_next_shoot) - SYMTYPE.ClosedShape: plan_shoot([b], pattern.cooldown_shoot+(min(idx-pattern.center,to_shoot.size()-(idx-pattern.center)))*pattern.cooldown_next_shoot) - else: plan_shoot([b], pattern.cooldown_shoot+idx*pattern.cooldown_next_shoot) + SYMTYPE.Line: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + (abs(pattern.center - idx)) * pattern.cooldown_next_shoot + ) + ) + SYMTYPE.ClosedShape: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + ( + (min( + idx - pattern.center, + to_shoot.size() - (idx - pattern.center) + )) + * pattern.cooldown_next_shoot + ) + ) + ) + else: + plan_shoot([b], pattern.cooldown_shoot + idx * pattern.cooldown_next_shoot) else: var idx unactive_spawn(bullets) @@ -474,207 +668,341 @@ func _plan_spawning(pattern:Pattern, bullets:Array): idx = to_spawn.find(b) if pattern.symmetric: match pattern.symmetry_type: - SYMTYPE.Line: plan_spawn([b], abs(pattern.center-idx)*pattern.cooldown_next_spawn) + SYMTYPE.Line: + plan_spawn([b], abs(pattern.center - idx) * pattern.cooldown_next_spawn) SYMTYPE.ClosedShape: - plan_spawn([b], min(idx-pattern.center,to_spawn.size()-(idx-pattern.center))*pattern.cooldown_next_spawn) - else: plan_spawn([b], idx*pattern.cooldown_next_spawn) + plan_spawn( + [b], + ( + min(idx - pattern.center, to_spawn.size() - (idx - pattern.center)) + * pattern.cooldown_next_spawn + ) + ) + else: + plan_spawn([b], idx * pattern.cooldown_next_spawn) - if pattern.cooldown_stasis: return + if pattern.cooldown_stasis: + return if pattern.cooldown_next_shoot == 0 and pattern.cooldown_shoot > 0: - plan_shoot(to_spawn, pattern.cooldown_next_spawn*(to_spawn.size())+pattern.cooldown_shoot) - elif pattern.cooldown_next_shoot == 0: #no add pos + plan_shoot( + to_spawn, pattern.cooldown_next_spawn * (to_spawn.size()) + pattern.cooldown_shoot + ) + elif pattern.cooldown_next_shoot == 0: #no add pos for b in to_spawn: idx = to_spawn.find(b) if pattern.symmetric: match pattern.symmetry_type: - SYMTYPE.Line: plan_shoot([b], pattern.cooldown_shoot+(abs(pattern.center-idx))*pattern.cooldown_next_shoot) - SYMTYPE.ClosedShape: plan_shoot([b], pattern.cooldown_shoot+(min(idx-pattern.center,to_spawn.size()-(idx-pattern.center)))*pattern.cooldown_next_shoot) - else: plan_shoot([b], idx*pattern.cooldown_next_spawn) + SYMTYPE.Line: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + (abs(pattern.center - idx)) * pattern.cooldown_next_shoot + ) + ) + SYMTYPE.ClosedShape: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + ( + (min( + idx - pattern.center, + to_spawn.size() - (idx - pattern.center) + )) + * pattern.cooldown_next_shoot + ) + ) + ) + else: + plan_shoot([b], idx * pattern.cooldown_next_spawn) elif pattern.cooldown_shoot == 0: for b in to_spawn: idx = to_spawn.find(b) if pattern.symmetric: match pattern.symmetry_type: - SYMTYPE.Line: plan_shoot([b], pattern.cooldown_shoot+(abs(pattern.center-idx))*pattern.cooldown_next_shoot) - SYMTYPE.ClosedShape: plan_shoot([b], pattern.cooldown_shoot+(min(idx-pattern.center,to_spawn.size()-(idx-pattern.center)))*pattern.cooldown_next_shoot) - else: plan_shoot([b], idx*(pattern.cooldown_next_shoot+pattern.cooldown_next_spawn)) + SYMTYPE.Line: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + (abs(pattern.center - idx)) * pattern.cooldown_next_shoot + ) + ) + SYMTYPE.ClosedShape: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + ( + (min( + idx - pattern.center, + to_spawn.size() - (idx - pattern.center) + )) + * pattern.cooldown_next_shoot + ) + ) + ) + else: + plan_shoot( + [b], idx * (pattern.cooldown_next_shoot + pattern.cooldown_next_spawn) + ) else: for b in to_spawn: idx = to_spawn.find(b) if pattern.symmetric: match pattern.symmetry_type: - SYMTYPE.Line: plan_shoot([b], pattern.cooldown_shoot+(abs(pattern.center-idx))*pattern.cooldown_next_shoot) - SYMTYPE.ClosedShape: plan_shoot([b], pattern.cooldown_shoot+(min(idx-pattern.center,to_spawn.size()-(idx-pattern.center)))*pattern.cooldown_next_shoot) - else: plan_shoot([b], pattern.cooldown_next_spawn*(to_spawn.size())+pattern.cooldown_shoot+idx*pattern.cooldown_next_shoot) + SYMTYPE.Line: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + (abs(pattern.center - idx)) * pattern.cooldown_next_shoot + ) + ) + SYMTYPE.ClosedShape: + plan_shoot( + [b], + ( + pattern.cooldown_shoot + + ( + (min( + idx - pattern.center, + to_spawn.size() - (idx - pattern.center) + )) + * pattern.cooldown_next_shoot + ) + ) + ) + else: + plan_shoot( + [b], + ( + pattern.cooldown_next_spawn * (to_spawn.size()) + + pattern.cooldown_shoot + + idx * pattern.cooldown_next_shoot + ) + ) bullets.clear() -func plan_spawn(bullets:Array, spawn_delay:float=0): + +func plan_spawn(bullets: Array, spawn_delay: float = 0): var timestamp = getKeyTime(spawn_delay) var insert_index = poolTimes.bsearch(timestamp) poolTimes.insert(insert_index, timestamp) poolQueue.insert(insert_index, [ACTION_SPAWN, bullets]) -func plan_shoot(bullets:Array, shoot_delay:float=0): + +func plan_shoot(bullets: Array, shoot_delay: float = 0): for b in bullets: - if (not b is RID and not poolBullets[b]["props"].has("speed")): bullets.erase(b) + if not b is RID and not poolBullets[b]["props"].has("speed"): + bullets.erase(b) var timestamp = getKeyTime(shoot_delay) var insert_index = poolTimes.bsearch(timestamp) poolTimes.insert(insert_index, timestamp) poolQueue.insert(insert_index, [ACTION_SHOOT, bullets]) + func getKeyTime(delay): - if loop_length < time+delay: return delay-(loop_length-time) - else: return time+delay + if loop_length < time + delay: + return delay - (loop_length - time) + else: + return time + delay + -func _spawn_and_shoot(to_spawn:Array, to_shoot:Array): +func _spawn_and_shoot(to_spawn: Array, to_shoot: Array): _spawn(to_spawn) _shoot(to_shoot) -func unactive_spawn(bullets:Array): - var B:Dictionary + +func unactive_spawn(bullets: Array): + var B: Dictionary for b in bullets: assert(poolBullets.has(b)) B = poolBullets[b] - if B["state"] >= BState.Moving: continue - if B["source_node"] is RID: B["position"] = B["spawn_pos"] + poolBullets[B["source_node"]]["position"] - elif B["source_node"] is Dictionary: B["position"] = B["spawn_pos"] + B["source_node"]["position"] - else: B["position"] = B["spawn_pos"] + B["source_node"].global_position # warning: no idea what this case is - -func _spawn(bullets:Array): - var B:Dictionary - var props:Dictionary + if B["state"] >= BState.Moving: + continue + if B["source_node"] is RID: + B["position"] = B["spawn_pos"] + poolBullets[B["source_node"]]["position"] + elif B["source_node"] is Dictionary: + B["position"] = B["spawn_pos"] + B["source_node"]["position"] + else: + B["position"] = B["spawn_pos"] + B["source_node"].global_position # warning: no idea what this case is + + +func _spawn(bullets: Array): + var B: Dictionary + var props: Dictionary for b in bullets: if not poolBullets.has(b): - push_error("Warning: Bullet of ID "+str(b)+" is missing.") + push_error("Warning: Bullet of ID " + str(b) + " is missing.") continue B = poolBullets[b] - if B["state"] >= BState.Moving: continue - if B["source_node"] is Dictionary: B["position"] = B["spawn_pos"] + B["source_node"]["position"] - else: B["position"] = B["spawn_pos"] + B["source_node"].global_position + if B["state"] >= BState.Moving: + continue + if B["source_node"] is Dictionary: + B["position"] = B["spawn_pos"] + B["source_node"]["position"] + else: + B["position"] = B["spawn_pos"] + B["source_node"].global_position - if b is Node2D: # scene spawning + if b is Node2D: # scene spawning _spawn_object(b, B) props = B["props"] if b is RID or props.has("speed"): - if not change_animation(B,"spawn",b): B["state"] = BState.Spawning - else: B["state"] = BState.Spawned - if arrayAnim[props["anim_spawn"]][ANIM.SFX]: arrayAnim[props["anim_spawn"]][ANIM.SFX].play() + if not change_animation(B, "spawn", b): + B["state"] = BState.Spawning + else: + B["state"] = BState.Spawned + if arrayAnim[props["anim_spawn"]][ANIM.SFX]: + arrayAnim[props["anim_spawn"]][ANIM.SFX].play() - init_special_variables(B,b) - if props.get("homing_select_in_group",-1) == GROUP_SELECT.Nearest_on_spawn: + init_special_variables(B, b) + if props.get("homing_select_in_group", -1) == GROUP_SELECT.Nearest_on_spawn: target_from_options(B) - else: poolBullets.erase(b) + else: + poolBullets.erase(b) + -func _spawn_object(b:Node2D, B:Dictionary): +func _spawn_object(b: Node2D, B: Dictionary): if b is CollisionObject2D: b.collision_layer = B["shared_area"].collision_layer b.collision_mask = B["shared_area"].collision_mask if B["source_node"] is Dictionary: B["source_node"]["source_node"].call_deferred("add_child", b) - b.global_position = B["source_node"]["position"]-B["source_node"]["source_node"].position + b.global_position = B["source_node"]["position"] - B["source_node"]["source_node"].position b.rotation += B["source_node"]["rotation"] else: b.global_position = B["spawn_pos"] b.rotation += B["rotation"] B["source_node"].call_deferred("add_child", b) -func use_momentum(pos:Vector2, B:Dictionary): + +func use_momentum(pos: Vector2, B: Dictionary): B["position"] = pos -func _shoot(bullets:Array): - var B:Dictionary - var props:Dictionary + +func _shoot(bullets: Array): + var B: Dictionary + var props: Dictionary for b in bullets: - if not poolBullets.has(b): continue + if not poolBullets.has(b): + continue B = poolBullets[b] props = B["props"] - if (not b is RID and not props.has("speed")): + if not b is RID and not props.has("speed"): poolBullets.erase(b) continue if B.has("momentum_data"): var tween = get_tree().create_tween() - tween.tween_method(use_momentum.bind(B), B["position"], B["momentum_data"][1], B["momentum_data"][2]).set_trans(B["momentum_data"][0]) + ( + tween + . tween_method( + use_momentum.bind(B), + B["position"], + B["momentum_data"][1], + B["momentum_data"][2] + ) + . set_trans(B["momentum_data"][0]) + ) B["state"] = BState.Moving - if not props.has("curve"): B.erase("spawn_pos") - else: B["spawn_pos"] = B["position"] + if not props.has("curve"): + B.erase("spawn_pos") + else: + B["spawn_pos"] = B["position"] if props.has("homing_target") or props.has("node_homing"): - if props.get("homing_time_start",0) > 0: - get_tree().create_timer(props["homing_time_start"]).connect("timeout",Callable(self,"_on_Homing_timeout").bind(B,true)) - else: _on_Homing_timeout(B, true) - if props.get("homing_select_in_group",-1) == GROUP_SELECT.Nearest_on_shoot: + if props.get("homing_time_start", 0) > 0: + get_tree().create_timer(props["homing_time_start"]).connect( + "timeout", Callable(self, "_on_Homing_timeout").bind(B, true) + ) + else: + _on_Homing_timeout(B, true) + if props.get("homing_select_in_group", -1) == GROUP_SELECT.Nearest_on_shoot: target_from_options(B) - if not change_animation(B,"shoot",b): B["state"] = BState.Shooting - if arrayAnim[props["anim_shoot"]][ANIM.SFX]: arrayAnim[props["anim_shoot"]][ANIM.SFX].play() + if not change_animation(B, "shoot", b): + B["state"] = BState.Shooting + if arrayAnim[props["anim_shoot"]][ANIM.SFX]: + arrayAnim[props["anim_shoot"]][ANIM.SFX].play() + -func init_special_variables(b:Dictionary, rid): +func init_special_variables(b: Dictionary, rid): var bp = b["props"] if bp.has("a_speed_multi_iterations"): - b['speed_multi_iter'] = bp["a_speed_multi_iterations"] - b['speed_interpolate'] = float(0) + b["speed_multi_iter"] = bp["a_speed_multi_iterations"] + b["speed_interpolate"] = float(0) if bp.has("scale_multi_iterations"): - b['scale_multi_iter'] = bp["scale_multi_iterations"] - b['scale_interpolate'] = float(0) + b["scale_multi_iter"] = bp["scale_multi_iterations"] + b["scale_interpolate"] = float(0) if bp.has("spec_bounces"): - b['bounces'] = bp["spec_bounces"] + b["bounces"] = bp["spec_bounces"] if bp.has("a_direction_equation"): - b['curve'] = float(0) - b['curveDir_index'] = float(0) - if bp.has("spec_modulate_loop"): b["modulate_index"] = float(0) - if bp.has("spec_rotating_speed"): b["rot_index"] = float(0) + b["curve"] = float(0) + b["curveDir_index"] = float(0) + if bp.has("spec_modulate_loop"): + b["modulate_index"] = float(0) + if bp.has("spec_rotating_speed"): + b["rot_index"] = float(0) if bp.has("spec_trail_length"): - b["trail"] = [b["position"],b["position"],b["position"],b["position"]] + b["trail"] = [b["position"], b["position"], b["position"], b["position"]] b["trail_counter"] = float(0.0) if bp.has("homing_list"): b["homing_counter"] = int(0) if bp.has("curve"): b["curve_counter"] = float(0.0) - if bp["a_curve_movement"] in [CURVE_TYPE.LoopFromStart,CURVE_TYPE.LoopFromEnd]: + if bp["a_curve_movement"] in [CURVE_TYPE.LoopFromStart, CURVE_TYPE.LoopFromEnd]: b["curve_start"] = bp["curve"].get_point_position(0) - if bp.has("death_after_time"): b["death_counter"] = float(0.0) + if bp.has("death_after_time"): + b["death_counter"] = float(0.0) if bp.has("trigger_container"): - b['trig_container'] = container(bp["trigger_container"]) + b["trig_container"] = container(bp["trigger_container"]) b["trigger_counter"] = int(0) - var trig_types = b['trig_container'].getCurrentTriggers(b, rid) - b['trig_types'] = trig_types - b['trig_iter'] = {} - if trig_types.has("TrigCol"): b["trig_collider"] = null + var trig_types = b["trig_container"].getCurrentTriggers(b, rid) + b["trig_types"] = trig_types + b["trig_iter"] = {} + if trig_types.has("TrigCol"): + b["trig_collider"] = null # if trig_types.has("TrigPos"): b["trig_collider"] = null - if trig_types.has("TrigSig"): b["trig_signal"] = null - if trig_types.has("TrigTime"): b["trig_timeout"] = false + if trig_types.has("TrigSig"): + b["trig_signal"] = null + if trig_types.has("TrigTime"): + b["trig_timeout"] = false + # if bp.has("spec_rotating_speed"): b['bounces'] = bp["spec_rotating_speed"] # if bp.has("homing_target") or bp.has("homing_position"): # b['homing_target'] = bp["homing_target"] - - - - - - #§§§§§§§§§§§§§ MOVEMENT §§§§§§§§§§§§§ -func move_scale(B:Dictionary, props, delta:float): - if B.get("scale_multi_iter",0) == 0: return +func move_scale(B: Dictionary, props, delta: float): + if B.get("scale_multi_iter", 0) == 0: + return B["scale_interpolate"] += delta - var _scale = props["scale"] * props["scale_multiplier"].sample(B["scale_interpolate"]/props["scale_multi_scale"]) - B["scale"] = Vector2(_scale,_scale) - if B["scale_interpolate"]/props["scale_multi_scale"] >= 1 and props["scale_multi_iterations"] != -1: + var _scale = ( + props["scale"] + * props["scale_multiplier"].sample(B["scale_interpolate"] / props["scale_multi_scale"]) + ) + B["scale"] = Vector2(_scale, _scale) + if ( + B["scale_interpolate"] / props["scale_multi_scale"] >= 1 + and props["scale_multi_iterations"] != -1 + ): B["scale_multi_iter"] -= 1 -func move_trail(B:Dictionary, props): - if not B.has("trail_counter"): return + +func move_trail(B: Dictionary, props): + if not B.has("trail_counter"): + return B["trail_counter"] += _delta if B["trail_counter"] >= props["spec_trail_length"]: @@ -682,71 +1010,102 @@ func move_trail(B:Dictionary, props): B["trail"].remove_at(3) B["trail"].insert(0, B["position"]) -func move_speed(B:Dictionary, props, delta:float): - if B.get("speed_multi_iter",0) == 0: return + +func move_speed(B: Dictionary, props, delta: float): + if B.get("speed_multi_iter", 0) == 0: + return B["speed_interpolate"] += delta - B["speed"] = props["a_speed_multiplier"].sample(B["speed_interpolate"]/props["a_speed_multi_scale"]) - if B["speed_interpolate"]/props["a_speed_multi_scale"] >= 1 and props["a_speed_multi_iterations"] != -1: + B["speed"] = props["a_speed_multiplier"].sample( + B["speed_interpolate"] / props["a_speed_multi_scale"] + ) + if ( + B["speed_interpolate"] / props["a_speed_multi_scale"] >= 1 + and props["a_speed_multi_iterations"] != -1 + ): B["speed_multi_iter"] -= 1 B["speed_interpolate"] = 0 -func move_equation(B:Dictionary, props): - if props.get("a_direction_equation","") == "": return - if expression.parse(props["a_direction_equation"],["x"]) != OK: + +func move_equation(B: Dictionary, props): + if props.get("a_direction_equation", "") == "": + return + if expression.parse(props["a_direction_equation"], ["x"]) != OK: push_error(expression.get_error_text()) return - B["curveDir_index"] += 0.05 #TODO add speed - B["curve"] = expression.execute([B["curveDir_index"]])*100 + B["curveDir_index"] += 0.05 #TODO add speed + B["curve"] = expression.execute([B["curveDir_index"]]) * 100 -func move_homing(B:Dictionary, props, delta:float): - if not B.get("homing_target", null): return - var target_pos:Vector2 +func move_homing(B: Dictionary, props, delta: float): + if not B.get("homing_target", null): + return + + var target_pos: Vector2 if typeof(B["homing_target"]) == TYPE_OBJECT: - if not is_instance_valid(B["homing_target"]): return + if not is_instance_valid(B["homing_target"]): + return target_pos = B["homing_target"].global_position - else: target_pos = B["homing_target"] + else: + target_pos = B["homing_target"] if B["position"].distance_to(target_pos) < HOMING_MARGIN: if props.has("homing_list"): - if B["homing_counter"] < props["homing_list"].size()-1: + if B["homing_counter"] < props["homing_list"].size() - 1: B["homing_counter"] += 1 target_from_list(B) else: match props.get("homing_when_list_ends"): - LIST_ENDS.Loop: B["homing_counter"] = 0 + LIST_ENDS.Loop: + B["homing_counter"] = 0 LIST_ENDS.Reverse: B["homing_counter"] = 0 props["homing_list"].reverse() LIST_ENDS.Stop: B["homing_target"] = null - else: B["homing_target"] = null + else: + B["homing_target"] = null - B["vel"] += ((target_pos-B["position"]).normalized()*B["speed"] - B["vel"]).normalized() * props["homing_steer"] * delta + B["vel"] += ( + ((target_pos - B["position"]).normalized() * B["speed"] - B["vel"]).normalized() + * props["homing_steer"] + * delta + ) B["rotation"] = B["vel"].angle() -func move_curve(B:Dictionary, props, delta:float, b): - B["position"] = B["spawn_pos"]+(props["curve"].sample_baked(B["curve_counter"]*B["speed"])-B["curve_start"]).rotated(B["rotation"]) + +func move_curve(B: Dictionary, props, delta: float, b): + B["position"] = ( + B["spawn_pos"] + + (props["curve"].sample_baked(B["curve_counter"] * B["speed"]) - B["curve_start"]).rotated( + B["rotation"] + ) + ) B["curve_counter"] += delta - if B["curve_counter"] * B["speed"] < props["curve"].get_baked_length(): return + if B["curve_counter"] * B["speed"] < props["curve"].get_baked_length(): + return match props["a_curve_movement"]: - CURVE_TYPE.LoopFromStart: B["curve_counter"] = 0 + CURVE_TYPE.LoopFromStart: + B["curve_counter"] = 0 CURVE_TYPE.LoopFromEnd: B["curve_counter"] = 0 B["spawn_pos"] = B["position"] - CURVE_TYPE.OnceThenDie: delete_bullet(b) - CURVE_TYPE.OnceThenStay: B["speed"] = 0 + CURVE_TYPE.OnceThenDie: + delete_bullet(b) + CURVE_TYPE.OnceThenStay: + B["speed"] = 0 -func bullet_movement(delta:float): - var B:Dictionary; var props:Dictionary; +func bullet_movement(delta: float): + var B: Dictionary + var props: Dictionary for b in poolBullets.keys(): B = poolBullets[b] - if B["state"] == BState.Unactive: continue + if B["state"] == BState.Unactive: + continue props = B["props"] if B["state"] == BState.QueuedFree: _apply_movement(B, b, props) @@ -758,14 +1117,17 @@ func bullet_movement(delta:float): delete_bullet(b) _apply_movement(B, b, props) continue - if B.has("rot_index"): B["rot_index"] += props["spec_rotating_speed"] + if B.has("rot_index"): + B["rot_index"] += props["spec_rotating_speed"] #scale curve move_scale(B, props, delta) if B["state"] == BState.Spawned: - if B["source_node"] is Dictionary: B["position"] = B["spawn_pos"] + B["source_node"]["position"] - else: B["position"] = B["source_node"].global_position + B["spawn_pos"] + if B["source_node"] is Dictionary: + B["position"] = B["spawn_pos"] + B["source_node"]["position"] + else: + B["position"] = B["source_node"].global_position + B["spawn_pos"] elif B["state"] == BState.Moving: # trails @@ -781,39 +1143,47 @@ func bullet_movement(delta:float): move_homing(B, props, delta) # follow path2D - if props.get("curve"): move_curve(B, props, delta, b) + if props.get("curve"): + move_curve(B, props, delta, b) else: - B["vel"] = Vector2(B["speed"],B.get("curve",0)).rotated(B["rotation"]) - B["position"] += B["vel"]*delta + B["vel"] = Vector2(B["speed"], B.get("curve", 0)).rotated(B["rotation"]) + B["position"] += B["vel"] * delta - if B.has("spawn_pos") and not props.has("curve"): B["position"] += B["spawn_pos"] + if B.has("spawn_pos") and not props.has("curve"): + B["position"] += B["spawn_pos"] # position triggers - if B.has("trig_container") and B["trig_types"].has("TrigPos") \ - and (B["state"] == BState.Moving or not props["trigger_wait_for_shot"]): - B["trig_container"].checkTriggers(B,b) + if ( + B.has("trig_container") + and B["trig_types"].has("TrigPos") + and (B["state"] == BState.Moving or not props["trigger_wait_for_shot"]) + ): + B["trig_container"].checkTriggers(B, b) # homing on nearest anywhen - if props.get("homing_select_in_group",-1) == GROUP_SELECT.Nearest_anywhen: + if props.get("homing_select_in_group", -1) == GROUP_SELECT.Nearest_anywhen: target_from_options(B) - if not b is RID: - if b.base_scale == null: b.base_scale = b.scale + if b.base_scale == null: + b.base_scale = b.scale # move object scene b.global_position = B["position"] - b.rotation = B["rotation"] + B.get("rot_index",0) + b.rotation = B["rotation"] + B.get("rot_index", 0) b.scale = b.base_scale * B.get("scale", Vector2(props["scale"], props["scale"])) continue else: _apply_movement(B, b, props) -func _apply_movement(B:Dictionary, b:RID, props:Dictionary): - if B.get("state", BState.Unactive) == BState.Unactive or B.is_empty(): return - var shared_rid:RID = B["shared_area"].get_rid() - var bullet_index:int = shape_indexes.get(b, -1) - if bullet_index == -1: return +func _apply_movement(B: Dictionary, b: RID, props: Dictionary): + if B.get("state", BState.Unactive) == BState.Unactive or B.is_empty(): + return + + var shared_rid: RID = B["shared_area"].get_rid() + var bullet_index: int = shape_indexes.get(b, -1) + if bullet_index == -1: + return # erase destroyed bullets if B["state"] == BState.QueuedFree: Phys.area_set_shape_disabled(shared_rid, bullet_index, true) @@ -822,48 +1192,57 @@ func _apply_movement(B:Dictionary, b:RID, props:Dictionary): # move shapes if not props.get("spec_no_collision", false): - Phys.area_set_shape_transform(shared_rid, bullet_index, \ - Transform2D(B["rotation"]+B.get("rot_index",0), \ - B.get("scale",Vector2(props["scale"],props["scale"])), \ - props.get("skew",0), \ - B["position"])) + Phys.area_set_shape_transform( + shared_rid, + bullet_index, + Transform2D( + B["rotation"] + B.get("rot_index", 0), + B.get("scale", Vector2(props["scale"], props["scale"])), + props.get("skew", 0), + B["position"] + ) + ) # active collision for new bullets if B["shape_disabled"]: if not props.get("spec_no_collision", false): Phys.area_set_shape_disabled(shared_rid, shape_indexes[b], false) B["shape_disabled"] = false -func _calculate_bullets_index(from_index:int=-1): - var shared_rid:RID; var Brid:RID; var B:Dictionary; + +func _calculate_bullets_index(from_index: int = -1): + var shared_rid: RID + var Brid: RID + var B: Dictionary if from_index == -1: for area in $SharedAreas.get_children(): shared_rid = area.get_rid() for b_index in area.get_meta("ShapeCount"): - Brid = get_RID_from_index(shared_rid,b_index) + Brid = get_RID_from_index(shared_rid, b_index) _update_shape_indexes(Brid, b_index, B["shared_area"].name) #shape_indexes[Brid] = b_index + + # else: # TODO : add optimisation # for index in shape_indexes.values(): # if -func _update_shape_indexes(rid, index:int, area:String): + +func _update_shape_indexes(rid, index: int, area: String): shape_indexes[rid] = index if not shape_rids.has(area): shape_rids[area] = {} shape_rids[area][index] = rid - - - - #§§§§§§§§§§§§§ DRAW BULLETS §§§§§§§§§§§§§ -func get_texture_frame(b:Dictionary, B, spriteframes:SpriteFrames=textures): - if not b.has("anim_frame"): return spriteframes.get_frame_texture(b["anim"][ANIM.TEXTURE], 0) + +func get_texture_frame(b: Dictionary, B, spriteframes: SpriteFrames = textures): + if not b.has("anim_frame"): + return spriteframes.get_frame_texture(b["anim"][ANIM.TEXTURE], 0) else: b["anim_counter"] += _delta - if b["anim_counter"] >= 1/b["anim_speed"]: + if b["anim_counter"] >= 1 / b["anim_speed"]: b["anim_counter"] = 0 b["anim_frame"] += 1 if b["anim_frame"] >= b["anim_length"]: @@ -877,61 +1256,106 @@ func get_texture_frame(b:Dictionary, B, spriteframes:SpriteFrames=textures): change_animation(b, "waiting", B) return spriteframes.get_frame_texture(b["anim"][ANIM.TEXTURE], b["anim_frame"]) -func modulate_bullet(b:Dictionary, texture:Texture): + +func modulate_bullet(b: Dictionary, texture: Texture): if b["props"].has("spec_modulate_loop"): - draw_texture(texture,-texture.get_size()/2,b["props"]["spec_modulate"].sample(b["modulate_index"])) - b["modulate_index"] = b["modulate_index"]+(_delta/b["props"]["spec_modulate_loop"]) - if b["modulate_index"] >= 1: b["modulate_index"] = 0 - else: draw_texture(texture,-texture.get_size()/2,b["props"]["spec_modulate"].get_color(0)) + draw_texture( + texture, + -texture.get_size() / 2, + b["props"]["spec_modulate"].sample(b["modulate_index"]) + ) + b["modulate_index"] = b["modulate_index"] + (_delta / b["props"]["spec_modulate_loop"]) + if b["modulate_index"] >= 1: + b["modulate_index"] = 0 + else: + draw_texture(texture, -texture.get_size() / 2, b["props"]["spec_modulate"].get_color(0)) + func _draw(): - if Engine.is_editor_hint(): return + if Engine.is_editor_hint(): + return viewrect = get_viewport().get_visible_rect() - var texture:Texture; var b + var texture: Texture + var b for B in poolBullets.keys(): b = poolBullets[B] if B is Node2D: - if b["props"].has("speed"): B.queue_redraw() + if b["props"].has("speed"): + B.queue_redraw() if b.has("trail"): - draw_set_transform(b["position"], b["rotation"]+b.get("rot_index",0),b.get("scale",Vector2(b["props"]["scale"],b["props"]["scale"]))) + draw_set_transform( + b["position"], + b["rotation"] + b.get("rot_index", 0), + b.get("scale", Vector2(b["props"]["scale"], b["props"]["scale"])) + ) for l in 3: - draw_line(b["trail"][l],b["trail"][l+1],b["props"]["spec_trail_modulate"],b["props"]["spec_trail_width"]) + draw_line( + b["trail"][l], + b["trail"][l + 1], + b["props"]["spec_trail_modulate"], + b["props"]["spec_trail_width"] + ) continue elif b.has("trail"): for l in 3: - draw_line(b["trail"][l],b["trail"][l+1],b["props"]["spec_trail_modulate"],b["props"]["spec_trail_width"]) - - if (not (b["state"] >= BState.Spawning and viewrect.has_point(b["position"]))) or \ - (b["props"].has("spec_modulate") and b["props"].has("spec_modulate_loop") and \ - b["props"]["spec_modulate"].get_color(0).a == 0): - continue + draw_line( + b["trail"][l], + b["trail"][l + 1], + b["props"]["spec_trail_modulate"], + b["props"]["spec_trail_width"] + ) + + if ( + (not (b["state"] >= BState.Spawning and viewrect.has_point(b["position"]))) + or ( + b["props"].has("spec_modulate") + and b["props"].has("spec_modulate_loop") + and b["props"]["spec_modulate"].get_color(0).a == 0 + ) + ): + continue texture = get_texture_frame(b, B) - draw_set_transform_matrix(Transform2D(b["rotation"]+b.get("rot_index",0), - b.get("scale", Vector2(b["props"]["scale"]*b["anim"][ANIM.SCALE],b["props"]["scale"]*b["anim"][ANIM.SCALE])), \ - b["anim"][ANIM.SKEW], b["position"])) + draw_set_transform_matrix( + Transform2D( + b["rotation"] + b.get("rot_index", 0), + b.get( + "scale", + Vector2( + b["props"]["scale"] * b["anim"][ANIM.SCALE], + b["props"]["scale"] * b["anim"][ANIM.SCALE] + ) + ), + b["anim"][ANIM.SKEW], + b["position"] + ) + ) if b["props"].has("spec_modulate"): modulate_bullet(b, texture) - else: draw_texture(texture,-texture.get_size()/2) + else: + draw_texture(texture, -texture.get_size() / 2) + # type = "idle","spawn","waiting","delete" -func change_animation(b:Dictionary, type:String, B): - if B is Node2D: return true - var instantly:bool = false - var anim_state:Array - if type in ["spawn","shoot","idle","waiting","delete"]: - anim_state = arrayAnim.get(b["props"].get("anim_"+type, ""), []) - if b["props"]["anim_"+type] == b["props"]["anim_idle"]: +func change_animation(b: Dictionary, type: String, B): + if B is Node2D: + return true + var instantly: bool = false + var anim_state: Array + if type in ["spawn", "shoot", "idle", "waiting", "delete"]: + anim_state = arrayAnim.get(b["props"].get("anim_" + type, ""), []) + if b["props"]["anim_" + type] == b["props"]["anim_idle"]: instantly = true - else: anim_state = arrayAnim[type] + else: + anim_state = arrayAnim[type] - var anim_id:String = anim_state[ANIM.TEXTURE] + var anim_id: String = anim_state[ANIM.TEXTURE] b["anim"] = anim_state - var frame_count:int = textures.get_frame_count(anim_id) + var frame_count: int = textures.get_frame_count(anim_id) if frame_count > 1: b["anim_length"] = frame_count b["anim_counter"] = 0 @@ -946,187 +1370,245 @@ func change_animation(b:Dictionary, type:String, B): b.erase("anim_speed") instantly = true - var col_id:Array = anim_state[ANIM.COLLISION] + var col_id: Array = anim_state[ANIM.COLLISION] if not col_id.is_empty() and col_id != b["colID"]: b["colID"] = col_id - var new_rid:RID = create_shape(b["shared_area"].get_rid(), b["colID"]) + var new_rid: RID = create_shape(b["shared_area"].get_rid(), b["colID"]) poolBullets[new_rid] = b - _update_shape_indexes(new_rid, Phys.area_get_shape_count(b["shared_area"].get_rid())-1, b["shared_area"].name) + _update_shape_indexes( + new_rid, + Phys.area_get_shape_count(b["shared_area"].get_rid()) - 1, + b["shared_area"].name + ) back_to_grave(b["props"]["__ID__"], B) return instantly - - - - #§§§§§§§§§§§§§ USEFUL FUCNTIONS / API §§§§§§§§§§§§§ ### BULLETS + func clear_all_bullets(): - for b in poolBullets.keys(): delete_bullet(b) + for b in poolBullets.keys(): + delete_bullet(b) + # TODO counts radius or not -func clear_bullets_within_dist(target_pos, radius:float=STANDARD_BULLET_RADIUS): +func clear_bullets_within_dist(target_pos, radius: float = STANDARD_BULLET_RADIUS): for b in poolBullets.keys(): if poolBullets[b]["position"].distance_to(target_pos) < radius: delete_bullet(b) + #func clear_all_offscreen_bullets(): - #for b in poolBullets.keys(): check_bullet_culling(poolBullets[b],b) +#for b in poolBullets.keys(): check_bullet_culling(poolBullets[b],b) + func delete_bullet(b): - if not poolBullets.has(b): return + if not poolBullets.has(b): + return var B = poolBullets[b] - if arrayAnim[B["props"]["anim_delete"]][ANIM.SFX]: arrayAnim[B["props"]["anim_delete"]][ANIM.SFX].play() - back_to_grave(B["props"]["__ID__"],b) + if arrayAnim[B["props"]["anim_delete"]][ANIM.SFX]: + arrayAnim[B["props"]["anim_delete"]][ANIM.SFX].play() + back_to_grave(B["props"]["__ID__"], b) + -func get_bullets_in_radius(origin:Vector2, radius:float): - var res:Array +func get_bullets_in_radius(origin: Vector2, radius: float): + var res: Array for b in poolBullets.keys(): if poolBullets[b]["position"].distance_to(origin) < radius: res.append(b) return res + func get_random_bullet(): - return poolBullets[randi()%poolBullets.size()] + return poolBullets[randi() % poolBullets.size()] + ### GROUPS ### -func add_group_to_bullet(b:Dictionary, group:String): - if b.has("groups"): b["groups"].append(group) - else: b["groups"] = [group] -func remove_group_from_bullet(b:Dictionary, group:String): - if not b.has("groups"): return +func add_group_to_bullet(b: Dictionary, group: String): + if b.has("groups"): + b["groups"].append(group) + else: + b["groups"] = [group] + + +func remove_group_from_bullet(b: Dictionary, group: String): + if not b.has("groups"): + return b["groups"].erase(group) -func clear_groups_from_bullet(b:Dictionary): + +func clear_groups_from_bullet(b: Dictionary): b.erase("groups") -func is_bullet_in_group(b:Dictionary, group:String): - if not b.has("groups"): return false + +func is_bullet_in_group(b: Dictionary, group: String): + if not b.has("groups"): + return false return b["groups"].has(group) -func is_bullet_in_grouptype(b:Dictionary, grouptype:String): - if not b.has("groups"): return false + +func is_bullet_in_grouptype(b: Dictionary, grouptype: String): + if not b.has("groups"): + return false for g in b["groups"]: - if not grouptype in g: continue + if not grouptype in g: + continue return true + ### SHARED AREA ### -func get_shared_area_rid(shared_area_name:String): + +func get_shared_area_rid(shared_area_name: String): return $SharedAreas.get_node(shared_area_name).get_rid() -func get_shared_area(shared_area_name:String): + +func get_shared_area(shared_area_name: String): return $SharedAreas.get_node(shared_area_name) -func change_shared_area(b:Dictionary, rid:RID, idx:int, new_area:Area2D): - Phys.area_remove_shape(b["shared_area"].get_rid(),idx) + +func change_shared_area(b: Dictionary, rid: RID, idx: int, new_area: Area2D): + Phys.area_remove_shape(b["shared_area"].get_rid(), idx) Phys.area_add_shape(new_area.get_rid(), rid) b["shared_area"] = new_area _calculate_bullets_index() + func rid_to_bullet(rid): return poolBullets[rid] -func get_RID_from_index(source_area:RID, index:int) -> RID: + +func get_RID_from_index(source_area: RID, index: int) -> RID: return Phys.area_get_shape(source_area, index) -func change_property(type:String, id:String, prop:String, new_value): + +func change_property(type: String, id: String, prop: String, new_value): var res = call(type, id) match type: - "pattern","container","trigger": res.set(prop, new_value) - "bullet": res[prop] = new_value + "pattern", "container", "trigger": + res.set(prop, new_value) + "bullet": + res[prop] = new_value + -func switch_property_of_bullet(b:Dictionary, new_props_id:String): +func switch_property_of_bullet(b: Dictionary, new_props_id: String): b["props"] = bullet(new_props_id) -func switch_property_of_all(replaceby_id:String, replaced_id:String="__ALL__"): + +func switch_property_of_all(replaceby_id: String, replaced_id: String = "__ALL__"): for b in poolBullets.values(): - if not (replaced_id == "__ALL__" or b["props"].hash() == bullet(replaced_id).hash()): continue + if not (replaced_id == "__ALL__" or b["props"].hash() == bullet(replaced_id).hash()): + continue b["props"] = bullet(replaceby_id) + ### RANDOMISATION ### -func random_remove(id:String, prop:String): + +func random_remove(id: String, prop: String): var res = bullet(id) res.remove_at(prop) -func random_change(type:String, id:String, prop:String, new_value): + +func random_change(type: String, id: String, prop: String, new_value): var res = call_deferred(type, id) match type: - "pattern": res.set(prop,new_value) - "bullet": res[prop] = new_value + "pattern": + res.set(prop, new_value) + "bullet": + res[prop] = new_value + -func random_set(type:String, id:String, value:bool): +func random_set(type: String, id: String, value: bool): var res = call_deferred(type, id) match type: - "pattern": res.has_random = value - "bullet": res["has_random"] = value + "pattern": + res.has_random = value + "bullet": + res["has_random"] = value + # call : get_variation(base_prop, v.x, v.y, v.z) -func get_variation(mean:float, variance:float, limit_down=0, limit_up=0): +func get_variation(mean: float, variance: float, limit_down = 0, limit_up = 0): if limit_down != 0 and limit_up != 0: - return min(max(RAND.randfn(mean,variance),limit_down), limit_up) - elif limit_down != 0: return max(RAND.randfn(mean,variance),limit_down) - elif limit_up != 0: return min(RAND.randfn(mean,variance),limit_up) + return min(max(RAND.randfn(mean, variance), limit_down), limit_up) + elif limit_down != 0: + return max(RAND.randfn(mean, variance), limit_down) + elif limit_up != 0: + return min(RAND.randfn(mean, variance), limit_up) else: - print(mean,variance," ",RAND.randfn(mean,variance)) - return RAND.randfn(mean,variance) + print(mean, variance, " ", RAND.randfn(mean, variance)) + return RAND.randfn(mean, variance) -func get_choice_string(list:String): - var res:Array = list.split(";",false) - return res[randi()%res.size()] -func get_choice_array(list:Array): - return list[randi()%list.size()] +func get_choice_string(list: String): + var res: Array = list.split(";", false) + return res[randi() % res.size()] -### HOMING ### -func edit_special_target(var_name:String, path:Node2D): - set_meta("ST_"+var_name, path) # set path to null to remove_at meta variable +func get_choice_array(list: Array): + return list[randi() % list.size()] + -func get_special_target(var_name:String): - return get_meta("ST_"+var_name) +### HOMING ### +func edit_special_target(var_name: String, path: Node2D): + set_meta("ST_" + var_name, path) # set path to null to remove_at meta variable +func get_special_target(var_name: String): + return get_meta("ST_" + var_name) #§§§§§§§§§§§§§ HOMING §§§§§§§§§§§§§ -func _on_Homing_timeout(B:Dictionary, start:bool): + +func _on_Homing_timeout(B: Dictionary, start: bool): if start: var props = B["props"] if not props.has("homing_mouse"): - if props.has("homing_target") or props.has("node_homing"): B["homing_target"] = props["node_homing"] - else: B["homing_target"] = props["homing_position"] + if props.has("homing_target") or props.has("node_homing"): + B["homing_target"] = props["node_homing"] + else: + B["homing_target"] = props["homing_position"] if props["homing_duration"] > 0: - get_tree().create_timer(props["homing_duration"]).connect("timeout",Callable(self,"_on_Homing_timeout").bind(B,false)) - if props.get("homing_select_in_group",-1) == GROUP_SELECT.Nearest_on_homing: + get_tree().create_timer(props["homing_duration"]).connect( + "timeout", Callable(self, "_on_Homing_timeout").bind(B, false) + ) + if props.get("homing_select_in_group", -1) == GROUP_SELECT.Nearest_on_homing: target_from_options(B) - elif props.get("homing_select_in_group",-1) == GROUP_SELECT.Random: - target_from_options(B,true) - elif not B["props"].get("homing_list",[]).is_empty(): target_from_list(B) + elif props.get("homing_select_in_group", -1) == GROUP_SELECT.Random: + target_from_options(B, true) + elif not B["props"].get("homing_list", []).is_empty(): + target_from_list(B) else: B["homing_target"] = Vector2() -func target_from_options(B:Dictionary, random:bool=false): - if B["props"].has("homing_group"): target_from_group(B, random) - elif B["props"].has("homing_surface"): target_from_segments(B, random) - elif B["props"].has("homing_mouse"): B["homing_target"] = get_global_mouse_position() -func target_from_group(B:Dictionary, random:bool=false): +func target_from_options(B: Dictionary, random: bool = false): + if B["props"].has("homing_group"): + target_from_group(B, random) + elif B["props"].has("homing_surface"): + target_from_segments(B, random) + elif B["props"].has("homing_mouse"): + B["homing_target"] = get_global_mouse_position() + + +func target_from_group(B: Dictionary, random: bool = false): var all_nodes = get_tree().get_nodes_in_group(B["props"]["homing_group"]) if random: - B["homing_target"] = all_nodes[randi()%all_nodes.size()] + B["homing_target"] = all_nodes[randi() % all_nodes.size()] return - var res:Node2D; var smaller_dist = INF; var curr_dist; + var res: Node2D + var smaller_dist = INF + var curr_dist for node in all_nodes: curr_dist = B["position"].distance_to(node.global_position) if curr_dist < smaller_dist: @@ -1134,54 +1616,74 @@ func target_from_group(B:Dictionary, random:bool=false): res = node B["homing_target"] = res -func target_from_segments(B:Dictionary, random:bool=false): - var dist:float = INF; var res:Vector2; var new_res:Vector2; var new_dist:float + +func target_from_segments(B: Dictionary, random: bool = false): + var dist: float = INF + var res: Vector2 + var new_res: Vector2 + var new_dist: float for p in B["homing_surface"].size(): - new_res = Geometry2D.get_closest_point_to_segment(B["position"], B["homing_surface"][p], B["homing_surface"][(p+1)%B["homing_surface"].size()]) + new_res = Geometry2D.get_closest_point_to_segment( + B["position"], + B["homing_surface"][p], + B["homing_surface"][(p + 1) % B["homing_surface"].size()] + ) new_dist = B["position"].distance_to(new_res) - if new_dist < dist or (random and randi()%2 == 0): + if new_dist < dist or (random and randi() % 2 == 0): dist = new_dist res = new_res B["homing_target"] = res -func target_from_list(B:Dictionary, do:bool=true): - if not do: return - B["homing_target"] = B["props"]["homing_list"][B["homing_counter"]] - -func trig_timeout(b, rid): - if b is Node: b.trigger_timeout = true - else: b["trig_timeout"] = true - b.get("trig_container").checkTriggers(b,rid) +func target_from_list(B: Dictionary, do: bool = true): + if not do: + return + B["homing_target"] = B["props"]["homing_list"][B["homing_counter"]] +func trig_timeout(b, rid): + if b is Node: + b.trigger_timeout = true + else: + b["trig_timeout"] = true + b.get("trig_container").checkTriggers(b, rid) #§§§§§§§§§§§§§ COLLISIONS §§§§§§§§§§§§§ -func bullet_collide_area(area_rid:RID,area:Area2D,area_shape_index:int,local_shape_index:int,shared_area:Area2D) -> void: + +func bullet_collide_area( + area_rid: RID, area: Area2D, area_shape_index: int, local_shape_index: int, shared_area: Area2D +) -> void: ############## go to CUSTOM if you want to implement custom behavior CUSTOM.bullet_collide_area(area_rid, area, area_shape_index, local_shape_index, shared_area) -func bullet_collide_body(body_rid:RID,body:Node,body_shape_index:int,local_shape_index:int,shared_area:Area2D) -> void: + +func bullet_collide_body( + body_rid: RID, body: Node, body_shape_index: int, local_shape_index: int, shared_area: Area2D +) -> void: var rid = shape_rids.get(shared_area.name, {}).get(local_shape_index) if not poolBullets.has(rid): rid = shared_area - if not poolBullets.has(rid): return + if not poolBullets.has(rid): + return var B = poolBullets[rid] # if B["props"].has("spec_angle_no_collision"): # var angle:float = B["position"].angle_to_point(body.global_position) ############## go to CUSTOM if you want to implement custom behavior - CUSTOM.bullet_collide_body(body_rid, body, body_shape_index, local_shape_index, shared_area, B, rid) + CUSTOM.bullet_collide_body( + body_rid, body, body_shape_index, local_shape_index, shared_area, B, rid + ) bullet_collided_body.emit(body, body_shape_index, B, local_shape_index, shared_area) - if B.get("bounces",0) > 0: + if B.get("bounces", 0) > 0: + bounce(B, shared_area) + B["bounces"] = max(0, B["bounces"] - 1) + elif body.is_in_group(GROUP_BOUNCE): bounce(B, shared_area) - B["bounces"] = max(0, B["bounces"]-1) - elif body.is_in_group(GROUP_BOUNCE): bounce(B, shared_area) if B.get("trig_types", []).has("TrigCol"): B["trig_collider"] = body @@ -1192,13 +1694,15 @@ func bullet_collide_body(body_rid:RID,body:Node,body_shape_index:int,local_shape elif B["props"]["death_from_collision"]: delete_bullet(rid) -func bounce(B:Dictionary, shared_area:Area2D): - if not B.has("colID"): return #TODO support custom bullet nodes + +func bounce(B: Dictionary, shared_area: Area2D): + if not B.has("colID"): + return #TODO support custom bullet nodes $Bouncy/CollisionShape2D.set_deferred("shape", B["colID"][0]) $Bouncy.collision_layer = shared_area.collision_layer $Bouncy.collision_mask = shared_area.collision_mask $Bouncy.global_position = B["position"] - var collision = $Bouncy.move_and_collide(Vector2(0,0)) + var collision = $Bouncy.move_and_collide(Vector2(0, 0)) if collision: B["vel"] = B["vel"].bounce(collision.get_normal()) B["rotation"] = B["vel"].angle() @@ -1206,62 +1710,82 @@ func bounce(B:Dictionary, shared_area:Area2D): $Bouncy.global_position = UNACTIVE_ZONE - - - - - - - - - - #§§§§§§§§§§§§§ RANDOMISATION §§§§§§§§§§§§§ -func create_random_props(original:Dictionary) -> Dictionary: - var r_name:String; var res:Dictionary = original; - var choice:Array; var variation:Vector3; + +func create_random_props(original: Dictionary) -> Dictionary: + var r_name: String + var res: Dictionary = original + var choice: Array + var variation: Vector3 for p in original.keys(): r_name = match_rand_prop(p) - if original.has(r_name+"_choice"): - choice = original[r_name+"_choice"] - variation = original.get(r_name+"_variation",Vector3(0,0,0)) - res[p] = get_variation(choice[randi()%choice.size()].to_float(),variation.x,variation.y,variation.z) - elif original.has(r_name+"_variation"): - variation = original.get(r_name+"_variation",Vector3(0,0,0)) - res[p] = get_variation(original[p],variation.x,variation.y,variation.z) - elif original.has(r_name+"_chance"): - res[p] = randf_range(0,1) < original[r_name+"_chance"] + if original.has(r_name + "_choice"): + choice = original[r_name + "_choice"] + variation = original.get(r_name + "_variation", Vector3(0, 0, 0)) + res[p] = get_variation( + choice[randi() % choice.size()].to_float(), variation.x, variation.y, variation.z + ) + elif original.has(r_name + "_variation"): + variation = original.get(r_name + "_variation", Vector3(0, 0, 0)) + res[p] = get_variation(original[p], variation.x, variation.y, variation.z) + elif original.has(r_name + "_chance"): + res[p] = randf_range(0, 1) < original[r_name + "_chance"] return res -func match_rand_prop(original:String) -> String: + +func match_rand_prop(original: String) -> String: match original: - "speed": return "r_speed" - "scale": return "r_scale" - "angle": return "r_angle" - "groups": return "r_groups" - "death_after_time": return "r_death_after" - "anim_idle_texture": return "r_" #----------------------- - "a_direction_equation": return "r_dir_equation" - "curve": return "r_curve" - "a_speed_multiplier": return "r_speed_multi_curve" - "a_speed_multi_iterations": return "r_speed_multi_iter" - "spec_bounces": return "r_bounce" + "speed": + return "r_speed" + "scale": + return "r_scale" + "angle": + return "r_angle" + "groups": + return "r_groups" + "death_after_time": + return "r_death_after" + "anim_idle_texture": + return "r_" #----------------------- + "a_direction_equation": + return "r_dir_equation" + "curve": + return "r_curve" + "a_speed_multiplier": + return "r_speed_multi_curve" + "a_speed_multi_iterations": + return "r_speed_multi_iter" + "spec_bounces": + return "r_bounce" # "spec_no_collision": return "r_" - "spec_modulate": return "r_modulate" - "spec_rotating_speed": return "r_rotating" + "spec_modulate": + return "r_modulate" + "spec_rotating_speed": + return "r_rotating" # "spec_trail_length": return "r_" # "spec_trail_width": return "r_" # "spec_trail_modulate": return "r_" - "trigger_container": return "r_trigger" - "homing_target": return "r_homing_target" - "homing_special_target": return "r_special_target" - "homing_group": return "r_group_target" - "homing_position": return "r_pos_target" - "homing_steer": return "r_steer" - "homing_duration": return "r_homing_dur" - "homing_time_start": return "r_homing_delay" - "scale_multiplier": return "r_scale_multi_curve" - "scale_multi_iterations": return "r_scale_multi_iter" - "": return "r_" + "trigger_container": + return "r_trigger" + "homing_target": + return "r_homing_target" + "homing_special_target": + return "r_special_target" + "homing_group": + return "r_group_target" + "homing_position": + return "r_pos_target" + "homing_steer": + return "r_steer" + "homing_duration": + return "r_homing_dur" + "homing_time_start": + return "r_homing_delay" + "scale_multiplier": + return "r_scale_multi_curve" + "scale_multi_iterations": + return "r_scale_multi_iter" + "": + return "r_" return "" diff --git a/addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png b/addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png new file mode 100644 index 0000000..3cfc9e5 Binary files /dev/null and b/addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png differ diff --git a/addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png.import b/addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png.import new file mode 100644 index 0000000..0dd644c --- /dev/null +++ b/addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://lqqd05fstex1" +path="res://.godot/imported/Bullet_B&W.png-81c5cdec8abce9e5da8327dcd0236ccd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png" +dest_files=["res://.godot/imported/Bullet_B&W.png-81c5cdec8abce9e5da8327dcd0236ccd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/BulletUpHell/Examples/Example5_Homing.tscn b/addons/BulletUpHell/Examples/Example5_Homing.tscn index 242a37a..b778816 100644 --- a/addons/BulletUpHell/Examples/Example5_Homing.tscn +++ b/addons/BulletUpHell/Examples/Example5_Homing.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=31 format=3 uid="uid://bjq5h23h8qpgb"] +[gd_scene load_steps=32 format=3 uid="uid://bjq5h23h8qpgb"] [ext_resource type="Script" path="res://addons/BulletUpHell/Examples/ExampleScene.gd" id="1_bkhcb"] [ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHPattern.gd" id="2_w6r0j"] [ext_resource type="Script" path="res://addons/BulletUpHell/SpawnPatterns/PatternOne.gd" id="3_p3qtu"] [ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHBulletProperties.gd" id="4_idnoj"] +[ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/animStates.gd" id="5_pd0bx"] [ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/BulletProps.gd" id="5_se254"] [ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHSpawnPoint.gd" id="6_bavsm"] [ext_resource type="Texture2D" uid="uid://7dbxtla24ukm" path="res://addons/BulletUpHell/Sprites/NodeIcons5.png" id="7_h7md5"] @@ -14,226 +15,111 @@ resource_name = "PatternOne" script = ExtResource("3_p3qtu") bullet = "one" +nbr = 1 iterations = -1 -follows_parent = false +pattern_angle = 0.0 +pattern_angle_target = NodePath("") +pattern_angle_mouse = false forced_angle = 0.0 forced_target = NodePath("") +forced_lookat_mouse = false forced_pattern_lookat = true cooldown_stasis = false cooldown_spawn = 5.0 cooldown_shoot = 0.0 cooldown_next_spawn = 0.0 cooldown_next_shoot = 0.0 -wait_latence = 0 wait_tween_momentum = 0 wait_tween_length = 0.0 wait_tween_time = 0.0 -layer_nbr = 1 -layer_cooldown_spawn = 0.0 -layer_pos_offset = 0.0 -layer_speed_offset = 0.0 -layer_angle_offset = 0.0 -r_randomisation_chances = 1.0 -r_bullet_choice = "" -r_bullet_nbr_choice = "" -r_bullet_nbr_variation = Vector3(0, 0, 0) -r_pattern_angle_choice = "" -r_pattern_angle_variation = Vector3(0, 0, 0) -r_infinite_iter_chances = 0.0 -r_iterations_choice = "" -r_iterations_variation = Vector3(0, 0, 0) -r_forced_angle_choice = "" -r_forced_angle_variation = Vector3(0, 0, 0) -r_forced_target_choice = [] -r_stasis_chances = 0.0 -r_cooldown_spawn_choice = "" -r_cooldown_spawn_variation = Vector3(0, 0, 0) -r_cooldown_shoot_choice = "" -r_cooldown_shoot_variation = Vector3(0, 0, 0) -r_cooldown_n_spawn_choice = "" -r_cooldown_n_spawn_variation = Vector3(0, 0, 0) -r_cooldown_n_shoot_choice = "" -r_cooldown_n_shoot_variation = Vector3(0, 0, 0) [sub_resource type="NavigationPolygon" id="NavigationPolygon_crmw6"] resource_name = "PatternOne" script = ExtResource("3_p3qtu") bullet = "two" +nbr = 1 iterations = -1 -follows_parent = false +pattern_angle = 0.0 +pattern_angle_target = NodePath("") +pattern_angle_mouse = false forced_angle = 0.0 forced_target = NodePath("") +forced_lookat_mouse = false forced_pattern_lookat = true cooldown_stasis = false cooldown_spawn = 5.0 cooldown_shoot = 0.0 cooldown_next_spawn = 0.0 cooldown_next_shoot = 0.0 -wait_latence = 0 wait_tween_momentum = 0 wait_tween_length = 0.0 wait_tween_time = 0.0 -layer_nbr = 1 -layer_cooldown_spawn = 0.0 -layer_pos_offset = 0.0 -layer_speed_offset = 0.0 -layer_angle_offset = 0.0 -r_randomisation_chances = 1.0 -r_bullet_choice = "" -r_bullet_nbr_choice = "" -r_bullet_nbr_variation = Vector3(0, 0, 0) -r_pattern_angle_choice = "" -r_pattern_angle_variation = Vector3(0, 0, 0) -r_infinite_iter_chances = 0.0 -r_iterations_choice = "" -r_iterations_variation = Vector3(0, 0, 0) -r_forced_angle_choice = "" -r_forced_angle_variation = Vector3(0, 0, 0) -r_forced_target_choice = [] -r_stasis_chances = 0.0 -r_cooldown_spawn_choice = "" -r_cooldown_spawn_variation = Vector3(0, 0, 0) -r_cooldown_shoot_choice = "" -r_cooldown_shoot_variation = Vector3(0, 0, 0) -r_cooldown_n_spawn_choice = "" -r_cooldown_n_spawn_variation = Vector3(0, 0, 0) -r_cooldown_n_shoot_choice = "" -r_cooldown_n_shoot_variation = Vector3(0, 0, 0) [sub_resource type="NavigationPolygon" id="NavigationPolygon_b10q3"] resource_name = "PatternOne" script = ExtResource("3_p3qtu") bullet = "three" +nbr = 1 iterations = -1 -follows_parent = false +pattern_angle = 0.0 +pattern_angle_target = NodePath("") +pattern_angle_mouse = false forced_angle = 0.0 forced_target = NodePath("") +forced_lookat_mouse = false forced_pattern_lookat = true cooldown_stasis = false cooldown_spawn = 5.0 cooldown_shoot = 0.0 cooldown_next_spawn = 0.0 cooldown_next_shoot = 0.0 -wait_latence = 0 wait_tween_momentum = 0 wait_tween_length = 0.0 wait_tween_time = 0.0 -layer_nbr = 1 -layer_cooldown_spawn = 0.0 -layer_pos_offset = 0.0 -layer_speed_offset = 0.0 -layer_angle_offset = 0.0 -r_randomisation_chances = 1.0 -r_bullet_choice = "" -r_bullet_nbr_choice = "" -r_bullet_nbr_variation = Vector3(0, 0, 0) -r_pattern_angle_choice = "" -r_pattern_angle_variation = Vector3(0, 0, 0) -r_infinite_iter_chances = 0.0 -r_iterations_choice = "" -r_iterations_variation = Vector3(0, 0, 0) -r_forced_angle_choice = "" -r_forced_angle_variation = Vector3(0, 0, 0) -r_forced_target_choice = [] -r_stasis_chances = 0.0 -r_cooldown_spawn_choice = "" -r_cooldown_spawn_variation = Vector3(0, 0, 0) -r_cooldown_shoot_choice = "" -r_cooldown_shoot_variation = Vector3(0, 0, 0) -r_cooldown_n_spawn_choice = "" -r_cooldown_n_spawn_variation = Vector3(0, 0, 0) -r_cooldown_n_shoot_choice = "" -r_cooldown_n_shoot_variation = Vector3(0, 0, 0) [sub_resource type="NavigationPolygon" id="NavigationPolygon_lc7c6"] resource_name = "PatternOne" script = ExtResource("3_p3qtu") bullet = "four" +nbr = 1 iterations = -1 -follows_parent = false +pattern_angle = 0.0 +pattern_angle_target = NodePath("") +pattern_angle_mouse = false forced_angle = 0.0 forced_target = NodePath("") +forced_lookat_mouse = false forced_pattern_lookat = true cooldown_stasis = false cooldown_spawn = 5.0 cooldown_shoot = 0.0 cooldown_next_spawn = 0.0 cooldown_next_shoot = 0.0 -wait_latence = 0 wait_tween_momentum = 0 wait_tween_length = 0.0 wait_tween_time = 0.0 -layer_nbr = 1 -layer_cooldown_spawn = 0.0 -layer_pos_offset = 0.0 -layer_speed_offset = 0.0 -layer_angle_offset = 0.0 -r_randomisation_chances = 1.0 -r_bullet_choice = "" -r_bullet_nbr_choice = "" -r_bullet_nbr_variation = Vector3(0, 0, 0) -r_pattern_angle_choice = "" -r_pattern_angle_variation = Vector3(0, 0, 0) -r_infinite_iter_chances = 0.0 -r_iterations_choice = "" -r_iterations_variation = Vector3(0, 0, 0) -r_forced_angle_choice = "" -r_forced_angle_variation = Vector3(0, 0, 0) -r_forced_target_choice = [] -r_stasis_chances = 0.0 -r_cooldown_spawn_choice = "" -r_cooldown_spawn_variation = Vector3(0, 0, 0) -r_cooldown_shoot_choice = "" -r_cooldown_shoot_variation = Vector3(0, 0, 0) -r_cooldown_n_spawn_choice = "" -r_cooldown_n_spawn_variation = Vector3(0, 0, 0) -r_cooldown_n_shoot_choice = "" -r_cooldown_n_shoot_variation = Vector3(0, 0, 0) [sub_resource type="NavigationPolygon" id="NavigationPolygon_l25jc"] resource_name = "PatternOne" script = ExtResource("3_p3qtu") bullet = "five" +nbr = 1 iterations = -1 -follows_parent = false +pattern_angle = 0.0 +pattern_angle_target = NodePath("") +pattern_angle_mouse = false forced_angle = 0.0 forced_target = NodePath("") +forced_lookat_mouse = false forced_pattern_lookat = true cooldown_stasis = false cooldown_spawn = 5.0 cooldown_shoot = 0.0 cooldown_next_spawn = 0.0 cooldown_next_shoot = 0.0 -wait_latence = 0 wait_tween_momentum = 0 wait_tween_length = 0.0 wait_tween_time = 0.0 -layer_nbr = 1 -layer_cooldown_spawn = 0.0 -layer_pos_offset = 0.0 -layer_speed_offset = 0.0 -layer_angle_offset = 0.0 -r_randomisation_chances = 1.0 -r_bullet_choice = "" -r_bullet_nbr_choice = "" -r_bullet_nbr_variation = Vector3(0, 0, 0) -r_pattern_angle_choice = "" -r_pattern_angle_variation = Vector3(0, 0, 0) -r_infinite_iter_chances = 0.0 -r_iterations_choice = "" -r_iterations_variation = Vector3(0, 0, 0) -r_forced_angle_choice = "" -r_forced_angle_variation = Vector3(0, 0, 0) -r_forced_target_choice = [] -r_stasis_chances = 0.0 -r_cooldown_spawn_choice = "" -r_cooldown_spawn_variation = Vector3(0, 0, 0) -r_cooldown_shoot_choice = "" -r_cooldown_shoot_variation = Vector3(0, 0, 0) -r_cooldown_n_spawn_choice = "" -r_cooldown_n_spawn_variation = Vector3(0, 0, 0) -r_cooldown_n_shoot_choice = "" -r_cooldown_n_shoot_variation = Vector3(0, 0, 0) [sub_resource type="Curve2D" id="Curve2D_ei6h7"] @@ -243,26 +129,15 @@ r_cooldown_n_shoot_variation = Vector3(0, 0, 0) [sub_resource type="PackedDataContainer" id="PackedDataContainer_5y1vw"] script = ExtResource("5_se254") +anim_more = Array[ExtResource("5_pd0bx")]([]) +damage = 1.0 speed = 100.0 -scale = 1 -angle = 0 -groups = [] -anim_idle_texture = "0" -anim_spawn_texture = "" -anim_waiting_texture = "" -anim_delete_texture = "" -anim_idle_collision = "0" -anim_spawn_collision = "" -anim_waiting_collision = "" -anim_delete_collision = "" -anim_idle_sfx = -1 -anim_spawn_sfx = -1 -anim_waiting_sfx = -1 -anim_delete_sfx = -1 +scale = 1.0 +angle = 0.0 +groups = PackedStringArray() spec_bounces = 0 spec_no_collision = false spec_modulate_loop = 0.0 -spec_skew = 0.0 spec_trail_length = 0.0 spec_trail_width = 0.0 spec_trail_modulate = Color(1, 1, 1, 1) @@ -281,49 +156,45 @@ homing_type = 0 homing_target = NodePath("../../Target") homing_steer = 10.0 homing_time_start = 1.0 -homing_duration = 999 +homing_duration = 999.0 scale_multi_iterations = 0 scale_multiplier = SubResource("Curve_f4tjx") -scale_multi_scale = 1 +scale_multi_scale = 1.0 r_randomisation_chances = 1.0 -r_speed_choice = "" +r_speed_choice = PackedFloat32Array() r_speed_variation = Vector3(0, 0, 0) -r_scale_choice = "" +r_scale_choice = PackedFloat32Array() r_scale_variation = Vector3(0, 0, 0) -r_angle_choice = "" +r_angle_choice = PackedFloat32Array() r_angle_variation = Vector3(0, 0, 0) r_group_choice = [] -r_bounce_choice = "" +r_bounce_choice = PackedInt32Array() r_bounce_variation = Vector3(0, 0, 0) r_no_coll_chances = 0.0 r_modulate_variation = Vector3(0, 0, 0) r_trail_length_variation = Vector3(0, 0, 0) r_trail_color_variation = Vector3(0, 0, 0) r_rotating_variation = Vector3(0, 0, 0) -r_death_after_choice = "" +r_death_after_choice = PackedFloat32Array() r_death_after_variation = Vector3(0, 0, 0) r_death_outside_chances = 0.0 -r_dir_equation_choice = "" +r_dir_equation_choice = PackedStringArray() r_curve_choice = [] r_speed_multi_curve_choice = [] r_speed_multi_iter_variation = Vector3(0, 0, 0) r_speed_multi_scale_variation = Vector3(0, 0, 0) -r_trigger_choice = "" +r_trigger_choice = PackedStringArray() r_wait_for_shot_chances = 0.0 r_homing_target_choice = [] -r_special_target_choice = "" -r_group_target_choice = "" -r_pos_target_choice = "" -r_steer_choice = "" +r_special_target_choice = PackedStringArray() +r_group_target_choice = PackedStringArray() +r_pos_target_choice = PackedVector2Array() +r_steer_choice = PackedFloat32Array() r_steer_variation = Vector3(0, 0, 0) -r_homing_delay_choice = "" +r_homing_delay_choice = PackedFloat32Array() r_homing_delay_variation = Vector3(0, 0, 0) -r_homing_dur_choice = "" +r_homing_dur_choice = PackedFloat32Array() r_homing_dur_variation = Vector3(0, 0, 0) -r_beam_length_choice = "" -r_beam_length_variation = Vector3(0, 0, 0) -r_beam_bounce_choice = "" -r_beam_width_variation = Vector3(0, 0, 0) r_scale_multi_curve_choice = [] r_scale_multi_iter_variation = Vector3(0, 0, 0) r_scale_multi_scale_variation = Vector3(0, 0, 0) @@ -334,26 +205,15 @@ r_scale_multi_scale_variation = Vector3(0, 0, 0) [sub_resource type="PackedDataContainer" id="PackedDataContainer_j5lwx"] script = ExtResource("5_se254") +anim_more = Array[ExtResource("5_pd0bx")]([]) +damage = 1.0 speed = 100.0 -scale = 1 -angle = 0 -groups = [] -anim_idle_texture = "0" -anim_spawn_texture = "" -anim_waiting_texture = "" -anim_delete_texture = "" -anim_idle_collision = "0" -anim_spawn_collision = "" -anim_waiting_collision = "" -anim_delete_collision = "" -anim_idle_sfx = -1 -anim_spawn_sfx = -1 -anim_waiting_sfx = -1 -anim_delete_sfx = -1 +scale = 1.0 +angle = 0.0 +groups = PackedStringArray() spec_bounces = 0 spec_no_collision = false spec_modulate_loop = 0.0 -spec_skew = 0.0 spec_trail_length = 0.0 spec_trail_width = 0.0 spec_trail_modulate = Color(1, 1, 1, 1) @@ -372,49 +232,45 @@ homing_type = 0 homing_target = NodePath("../../Target") homing_steer = 100.0 homing_time_start = 1.0 -homing_duration = 999 +homing_duration = 999.0 scale_multi_iterations = 0 scale_multiplier = SubResource("Curve_1ug5p") -scale_multi_scale = 1 +scale_multi_scale = 1.0 r_randomisation_chances = 1.0 -r_speed_choice = "" +r_speed_choice = PackedFloat32Array() r_speed_variation = Vector3(0, 0, 0) -r_scale_choice = "" +r_scale_choice = PackedFloat32Array() r_scale_variation = Vector3(0, 0, 0) -r_angle_choice = "" +r_angle_choice = PackedFloat32Array() r_angle_variation = Vector3(0, 0, 0) r_group_choice = [] -r_bounce_choice = "" +r_bounce_choice = PackedInt32Array() r_bounce_variation = Vector3(0, 0, 0) r_no_coll_chances = 0.0 r_modulate_variation = Vector3(0, 0, 0) r_trail_length_variation = Vector3(0, 0, 0) r_trail_color_variation = Vector3(0, 0, 0) r_rotating_variation = Vector3(0, 0, 0) -r_death_after_choice = "" +r_death_after_choice = PackedFloat32Array() r_death_after_variation = Vector3(0, 0, 0) r_death_outside_chances = 0.0 -r_dir_equation_choice = "" +r_dir_equation_choice = PackedStringArray() r_curve_choice = [] r_speed_multi_curve_choice = [] r_speed_multi_iter_variation = Vector3(0, 0, 0) r_speed_multi_scale_variation = Vector3(0, 0, 0) -r_trigger_choice = "" +r_trigger_choice = PackedStringArray() r_wait_for_shot_chances = 0.0 r_homing_target_choice = [] -r_special_target_choice = "" -r_group_target_choice = "" -r_pos_target_choice = "" -r_steer_choice = "" +r_special_target_choice = PackedStringArray() +r_group_target_choice = PackedStringArray() +r_pos_target_choice = PackedVector2Array() +r_steer_choice = PackedFloat32Array() r_steer_variation = Vector3(0, 0, 0) -r_homing_delay_choice = "" +r_homing_delay_choice = PackedFloat32Array() r_homing_delay_variation = Vector3(0, 0, 0) -r_homing_dur_choice = "" +r_homing_dur_choice = PackedFloat32Array() r_homing_dur_variation = Vector3(0, 0, 0) -r_beam_length_choice = "" -r_beam_length_variation = Vector3(0, 0, 0) -r_beam_bounce_choice = "" -r_beam_width_variation = Vector3(0, 0, 0) r_scale_multi_curve_choice = [] r_scale_multi_iter_variation = Vector3(0, 0, 0) r_scale_multi_scale_variation = Vector3(0, 0, 0) @@ -425,26 +281,15 @@ r_scale_multi_scale_variation = Vector3(0, 0, 0) [sub_resource type="PackedDataContainer" id="PackedDataContainer_ba22m"] script = ExtResource("5_se254") +anim_more = Array[ExtResource("5_pd0bx")]([]) +damage = 1.0 speed = 100.0 -scale = 1 -angle = 0 -groups = [] -anim_idle_texture = "0" -anim_spawn_texture = "" -anim_waiting_texture = "" -anim_delete_texture = "" -anim_idle_collision = "0" -anim_spawn_collision = "" -anim_waiting_collision = "" -anim_delete_collision = "" -anim_idle_sfx = -1 -anim_spawn_sfx = -1 -anim_waiting_sfx = -1 -anim_delete_sfx = -1 +scale = 1.0 +angle = 0.0 +groups = PackedStringArray() spec_bounces = 0 spec_no_collision = false spec_modulate_loop = 0.0 -spec_skew = 0.0 spec_trail_length = 0.0 spec_trail_width = 0.0 spec_trail_modulate = Color(1, 1, 1, 1) @@ -464,49 +309,45 @@ homing_group = "Targets" homing_select_in_group = 0 homing_steer = 300.0 homing_time_start = 3.0 -homing_duration = 999 +homing_duration = 999.0 scale_multi_iterations = 0 scale_multiplier = SubResource("Curve_w2d58") -scale_multi_scale = 1 +scale_multi_scale = 1.0 r_randomisation_chances = 1.0 -r_speed_choice = "" +r_speed_choice = PackedFloat32Array() r_speed_variation = Vector3(0, 0, 0) -r_scale_choice = "" +r_scale_choice = PackedFloat32Array() r_scale_variation = Vector3(0, 0, 0) -r_angle_choice = "" +r_angle_choice = PackedFloat32Array() r_angle_variation = Vector3(0, 0, 0) r_group_choice = [] -r_bounce_choice = "" +r_bounce_choice = PackedInt32Array() r_bounce_variation = Vector3(0, 0, 0) r_no_coll_chances = 0.0 r_modulate_variation = Vector3(0, 0, 0) r_trail_length_variation = Vector3(0, 0, 0) r_trail_color_variation = Vector3(0, 0, 0) r_rotating_variation = Vector3(0, 0, 0) -r_death_after_choice = "" +r_death_after_choice = PackedFloat32Array() r_death_after_variation = Vector3(0, 0, 0) r_death_outside_chances = 0.0 -r_dir_equation_choice = "" +r_dir_equation_choice = PackedStringArray() r_curve_choice = [] r_speed_multi_curve_choice = [] r_speed_multi_iter_variation = Vector3(0, 0, 0) r_speed_multi_scale_variation = Vector3(0, 0, 0) -r_trigger_choice = "" +r_trigger_choice = PackedStringArray() r_wait_for_shot_chances = 0.0 r_homing_target_choice = [] -r_special_target_choice = "" -r_group_target_choice = "" -r_pos_target_choice = "" -r_steer_choice = "" +r_special_target_choice = PackedStringArray() +r_group_target_choice = PackedStringArray() +r_pos_target_choice = PackedVector2Array() +r_steer_choice = PackedFloat32Array() r_steer_variation = Vector3(0, 0, 0) -r_homing_delay_choice = "" +r_homing_delay_choice = PackedFloat32Array() r_homing_delay_variation = Vector3(0, 0, 0) -r_homing_dur_choice = "" +r_homing_dur_choice = PackedFloat32Array() r_homing_dur_variation = Vector3(0, 0, 0) -r_beam_length_choice = "" -r_beam_length_variation = Vector3(0, 0, 0) -r_beam_bounce_choice = "" -r_beam_width_variation = Vector3(0, 0, 0) r_scale_multi_curve_choice = [] r_scale_multi_iter_variation = Vector3(0, 0, 0) r_scale_multi_scale_variation = Vector3(0, 0, 0) @@ -517,26 +358,15 @@ r_scale_multi_scale_variation = Vector3(0, 0, 0) [sub_resource type="PackedDataContainer" id="PackedDataContainer_i6qsh"] script = ExtResource("5_se254") +anim_more = Array[ExtResource("5_pd0bx")]([]) +damage = 1.0 speed = 100.0 -scale = 1 -angle = 0 -groups = [] -anim_idle_texture = "0" -anim_spawn_texture = "" -anim_waiting_texture = "" -anim_delete_texture = "" -anim_idle_collision = "0" -anim_spawn_collision = "" -anim_waiting_collision = "" -anim_delete_collision = "" -anim_idle_sfx = -1 -anim_spawn_sfx = -1 -anim_waiting_sfx = -1 -anim_delete_sfx = -1 +scale = 1.0 +angle = 0.0 +groups = PackedStringArray() spec_bounces = 0 spec_no_collision = false spec_modulate_loop = 0.0 -spec_skew = 0.0 spec_trail_length = 0.0 spec_trail_width = 0.0 spec_trail_modulate = Color(1, 1, 1, 1) @@ -556,49 +386,45 @@ homing_group = "Targets" homing_select_in_group = 2 homing_steer = 300.0 homing_time_start = 2.0 -homing_duration = 999 +homing_duration = 999.0 scale_multi_iterations = 0 scale_multiplier = SubResource("Curve_c2kuj") -scale_multi_scale = 1 +scale_multi_scale = 1.0 r_randomisation_chances = 1.0 -r_speed_choice = "" +r_speed_choice = PackedFloat32Array() r_speed_variation = Vector3(0, 0, 0) -r_scale_choice = "" +r_scale_choice = PackedFloat32Array() r_scale_variation = Vector3(0, 0, 0) -r_angle_choice = "" +r_angle_choice = PackedFloat32Array() r_angle_variation = Vector3(0, 0, 0) r_group_choice = [] -r_bounce_choice = "" +r_bounce_choice = PackedInt32Array() r_bounce_variation = Vector3(0, 0, 0) r_no_coll_chances = 0.0 r_modulate_variation = Vector3(0, 0, 0) r_trail_length_variation = Vector3(0, 0, 0) r_trail_color_variation = Vector3(0, 0, 0) r_rotating_variation = Vector3(0, 0, 0) -r_death_after_choice = "" +r_death_after_choice = PackedFloat32Array() r_death_after_variation = Vector3(0, 0, 0) r_death_outside_chances = 0.0 -r_dir_equation_choice = "" +r_dir_equation_choice = PackedStringArray() r_curve_choice = [] r_speed_multi_curve_choice = [] r_speed_multi_iter_variation = Vector3(0, 0, 0) r_speed_multi_scale_variation = Vector3(0, 0, 0) -r_trigger_choice = "" +r_trigger_choice = PackedStringArray() r_wait_for_shot_chances = 0.0 r_homing_target_choice = [] -r_special_target_choice = "" -r_group_target_choice = "" -r_pos_target_choice = "" -r_steer_choice = "" +r_special_target_choice = PackedStringArray() +r_group_target_choice = PackedStringArray() +r_pos_target_choice = PackedVector2Array() +r_steer_choice = PackedFloat32Array() r_steer_variation = Vector3(0, 0, 0) -r_homing_delay_choice = "" +r_homing_delay_choice = PackedFloat32Array() r_homing_delay_variation = Vector3(0, 0, 0) -r_homing_dur_choice = "" +r_homing_dur_choice = PackedFloat32Array() r_homing_dur_variation = Vector3(0, 0, 0) -r_beam_length_choice = "" -r_beam_length_variation = Vector3(0, 0, 0) -r_beam_bounce_choice = "" -r_beam_width_variation = Vector3(0, 0, 0) r_scale_multi_curve_choice = [] r_scale_multi_iter_variation = Vector3(0, 0, 0) r_scale_multi_scale_variation = Vector3(0, 0, 0) @@ -613,27 +439,16 @@ colors = PackedColorArray(0, 1, 0.203125, 1) [sub_resource type="PackedDataContainer" id="PackedDataContainer_w2wt3"] script = ExtResource("5_se254") +anim_more = Array[ExtResource("5_pd0bx")]([]) +damage = 1.0 speed = 100.0 -scale = 1 -angle = 0 -groups = [] -anim_idle_texture = "0" -anim_spawn_texture = "" -anim_waiting_texture = "" -anim_delete_texture = "" -anim_idle_collision = "0" -anim_spawn_collision = "" -anim_waiting_collision = "" -anim_delete_collision = "" -anim_idle_sfx = -1 -anim_spawn_sfx = -1 -anim_waiting_sfx = -1 -anim_delete_sfx = -1 +scale = 1.0 +angle = 0.0 +groups = PackedStringArray() spec_bounces = 0 spec_no_collision = false spec_modulate = SubResource("Gradient_wclsq") spec_modulate_loop = 0.0 -spec_skew = 0.0 spec_trail_length = 0.0 spec_trail_width = 0.0 spec_trail_modulate = Color(1, 1, 1, 1) @@ -654,49 +469,45 @@ homing_list_ordered = true homing_when_list_ends = 0 homing_steer = 200.0 homing_time_start = 1.0 -homing_duration = 999 +homing_duration = 999.0 scale_multi_iterations = 0 scale_multiplier = SubResource("Curve_ktun3") -scale_multi_scale = 1 +scale_multi_scale = 1.0 r_randomisation_chances = 1.0 -r_speed_choice = "" +r_speed_choice = PackedFloat32Array() r_speed_variation = Vector3(0, 0, 0) -r_scale_choice = "" +r_scale_choice = PackedFloat32Array() r_scale_variation = Vector3(0, 0, 0) -r_angle_choice = "" +r_angle_choice = PackedFloat32Array() r_angle_variation = Vector3(0, 0, 0) r_group_choice = [] -r_bounce_choice = "" +r_bounce_choice = PackedInt32Array() r_bounce_variation = Vector3(0, 0, 0) r_no_coll_chances = 0.0 r_modulate_variation = Vector3(0, 0, 0) r_trail_length_variation = Vector3(0, 0, 0) r_trail_color_variation = Vector3(0, 0, 0) r_rotating_variation = Vector3(0, 0, 0) -r_death_after_choice = "" +r_death_after_choice = PackedFloat32Array() r_death_after_variation = Vector3(0, 0, 0) r_death_outside_chances = 0.0 -r_dir_equation_choice = "" +r_dir_equation_choice = PackedStringArray() r_curve_choice = [] r_speed_multi_curve_choice = [] r_speed_multi_iter_variation = Vector3(0, 0, 0) r_speed_multi_scale_variation = Vector3(0, 0, 0) -r_trigger_choice = "" +r_trigger_choice = PackedStringArray() r_wait_for_shot_chances = 0.0 r_homing_target_choice = [] -r_special_target_choice = "" -r_group_target_choice = "" -r_pos_target_choice = "" -r_steer_choice = "" +r_special_target_choice = PackedStringArray() +r_group_target_choice = PackedStringArray() +r_pos_target_choice = PackedVector2Array() +r_steer_choice = PackedFloat32Array() r_steer_variation = Vector3(0, 0, 0) -r_homing_delay_choice = "" +r_homing_delay_choice = PackedFloat32Array() r_homing_delay_variation = Vector3(0, 0, 0) -r_homing_dur_choice = "" +r_homing_dur_choice = PackedFloat32Array() r_homing_dur_variation = Vector3(0, 0, 0) -r_beam_length_choice = "" -r_beam_length_variation = Vector3(0, 0, 0) -r_beam_bounce_choice = "" -r_beam_width_variation = Vector3(0, 0, 0) r_scale_multi_curve_choice = [] r_scale_multi_iter_variation = Vector3(0, 0, 0) r_scale_multi_scale_variation = Vector3(0, 0, 0) @@ -782,14 +593,7 @@ auto_start_on_cam = true auto_start_after_time = 0.0 auto_start_at_distance = 5.0 auto_distance_from = NodePath("") -trigger_id = null -r_randomisation_chances = 0.0 -r_active_chances = 0.0 -r_shared_area_choice = "" -r_rotating_variation = Vector3(0, 0, 0) -r_pattern_choice = "" -r_start_time_choice = "" -r_start_time_variation = Vector3(0, 0, 0) +trigger_container = NodePath("") [node name="SpawnPoint2" type="Node2D" parent="SpawnPoints"] position = Vector2(80, 56) @@ -803,14 +607,7 @@ auto_start_on_cam = true auto_start_after_time = 0.0 auto_start_at_distance = 5.0 auto_distance_from = NodePath("") -trigger_id = null -r_randomisation_chances = 0.0 -r_active_chances = 0.0 -r_shared_area_choice = "" -r_rotating_variation = Vector3(0, 0, 0) -r_pattern_choice = "" -r_start_time_choice = "" -r_start_time_variation = Vector3(0, 0, 0) +trigger_container = NodePath("") [node name="SpawnPoint3" type="Node2D" parent="SpawnPoints"] position = Vector2(64, 392) @@ -824,14 +621,7 @@ auto_start_on_cam = true auto_start_after_time = 0.0 auto_start_at_distance = 5.0 auto_distance_from = NodePath("") -trigger_id = null -r_randomisation_chances = 0.0 -r_active_chances = 0.0 -r_shared_area_choice = "" -r_rotating_variation = Vector3(0, 0, 0) -r_pattern_choice = "" -r_start_time_choice = "" -r_start_time_variation = Vector3(0, 0, 0) +trigger_container = NodePath("") [node name="SpawnPoint4" type="Node2D" parent="SpawnPoints"] position = Vector2(96, 392) @@ -845,14 +635,7 @@ auto_start_on_cam = true auto_start_after_time = 0.0 auto_start_at_distance = 5.0 auto_distance_from = NodePath("") -trigger_id = null -r_randomisation_chances = 0.0 -r_active_chances = 0.0 -r_shared_area_choice = "" -r_rotating_variation = Vector3(0, 0, 0) -r_pattern_choice = "" -r_start_time_choice = "" -r_start_time_variation = Vector3(0, 0, 0) +trigger_container = NodePath("") [node name="SpawnPoint5" type="Node2D" parent="SpawnPoints"] position = Vector2(864, 40) @@ -866,14 +649,7 @@ auto_start_on_cam = true auto_start_after_time = 0.0 auto_start_at_distance = 5.0 auto_distance_from = NodePath("") -trigger_id = null -r_randomisation_chances = 0.0 -r_active_chances = 0.0 -r_shared_area_choice = "" -r_rotating_variation = Vector3(0, 0, 0) -r_pattern_choice = "" -r_start_time_choice = "" -r_start_time_variation = Vector3(0, 0, 0) +trigger_container = NodePath("") [node name="Target" type="Sprite2D" parent="."] position = Vector2(448, 168) diff --git a/addons/BulletUpHell/Examples/ExampleScene.gd b/addons/BulletUpHell/Examples/ExampleScene.gd index 718a5c6..9953620 100644 --- a/addons/BulletUpHell/Examples/ExampleScene.gd +++ b/addons/BulletUpHell/Examples/ExampleScene.gd @@ -1,8 +1,5 @@ extends Node2D -@onready var spawn_point_1: Node2D = $Circle1/SpawnPoint -@onready var spawn_point_2: Node2D = $Circle2/SpawnPoint - func _process(_delta): $FPS.text = str(Engine.get_frames_per_second()) + " FPS\n" + str(Spawning.poolBullets.size()) diff --git a/addons/BulletUpHell/Nodes/BuHSpawnPoint.gd b/addons/BulletUpHell/Nodes/BuHSpawnPoint.gd index cd64fe8..de4fc73 100644 --- a/addons/BulletUpHell/Nodes/BuHSpawnPoint.gd +++ b/addons/BulletUpHell/Nodes/BuHSpawnPoint.gd @@ -1,188 +1,207 @@ @tool +class_name BuHSpawnPoint extends Node2D +var auto_pattern_id: String = "" +var auto_start_on_cam: bool = true +var auto_start_after_time: float = 0.0 +var auto_start_at_distance: float = 5 +var auto_distance_from: NodePath +var trigger_container: NodePath -var auto_pattern_id:String = "" -var auto_start_on_cam:bool = true -var auto_start_after_time:float = 0.0 -var auto_start_at_distance:float = 5 -var auto_distance_from:NodePath -var trigger_container:NodePath - -var trig_container:TriggerContainer +var trig_container: TriggerContainer var trigger_counter = 0 -var trig_iter:Dictionary -var trigger_timeout:bool = false -var trigger_time:float = 0 +var trig_iter: Dictionary +var trigger_timeout: bool = false +var trigger_time: float = 0 var trig_collider var trig_signal var rotating_speed = 0.0 -var active:bool = true +var active: bool = true var shared_area_name = "0" var shared_area -var pool_amount:int = 50 +var pool_amount: int = 50 + +var r_randomisation_chances: float +var r_active_chances: float +var r_shared_area_choice: String +var r_rotating_variation: Vector3 +var r_pattern_choice: String +var r_start_time_choice: String +var r_start_time_variation: Vector3 -var r_randomisation_chances:float -var r_active_chances:float -var r_shared_area_choice:String -var r_rotating_variation:Vector3 -var r_pattern_choice:String -var r_start_time_choice:String -var r_start_time_variation:Vector3 +var auto_call: bool = false +var can_respawn: bool = true -var auto_call:bool = false -var can_respawn:bool = true func _ready(): - if Engine.is_editor_hint(): return - + if Engine.is_editor_hint(): + return + if shared_area_name != "": shared_area = Spawning.get_shared_area(shared_area_name) - else: push_error("Spawnpoint doesn't have any shared_area") - + else: + push_error("Spawnpoint doesn't have any shared_area") + if auto_start_on_cam: assert(auto_pattern_id != "") var instance = VisibleOnScreenNotifier2D.new() - instance.connect("screen_entered",Callable(self,"on_screen").bind(true)) - instance.connect("screen_exited",Callable(self,"on_screen").bind(false)) - elif auto_distance_from != NodePath(): set_physics_process(true) + instance.connect("screen_entered", Callable(self, "on_screen").bind(true)) + instance.connect("screen_exited", Callable(self, "on_screen").bind(false)) + elif auto_distance_from != NodePath(): + set_physics_process(true) elif auto_pattern_id != "": - if auto_start_after_time > float(0.0): - await get_tree().create_timer(auto_start_after_time).timeout - auto_call = true - set_physics_process(active) - + _start_spawning(true) + if active and auto_pattern_id != "": - if auto_start_after_time > float(0.0): - await get_tree().create_timer(auto_start_after_time).timeout - auto_call = true + _start_spawning(true) + + if rotating_speed > 0: set_physics_process(active) - - if rotating_speed > 0: set_physics_process(active) - + if active and pool_amount > 0: call_deferred("set_pool") - + if trigger_container: trig_container = get_node(trigger_container) + + # set_physics_process(false) + func set_pool(): var props = Spawning.pattern(auto_pattern_id)["bullet"] - Spawning.create_pool(props, shared_area_name, pool_amount, !Spawning.bullet(props).has("anim_idle")) + Spawning.create_pool( + props, shared_area_name, pool_amount, !Spawning.bullet(props).has("anim_idle") + ) + + +var _delta: float + -var _delta:float func _physics_process(delta): - if Engine.is_editor_hint(): return + if Engine.is_editor_hint(): + return _delta = delta rotate(rotating_speed) if trig_container: checkTrigger() return - - if auto_distance_from != NodePath() and global_position.distance_to(get_node(auto_distance_from).global_position) <= auto_start_at_distance: + + if ( + auto_distance_from != NodePath() + and ( + global_position.distance_to(get_node(auto_distance_from).global_position) + <= auto_start_at_distance + ) + ): active = true - + if can_respawn and auto_call and active and auto_pattern_id != "": call_deferred("callAction") can_respawn = false - if not rotating_speed > 0: set_physics_process(false) - + if not rotating_speed > 0: + set_physics_process(false) + func on_screen(is_on): - if is_on and auto_start_after_time > float(0.0): - await get_tree().create_timer(auto_start_after_time).timeout - active = is_on - set_physics_process(active) + _start_spawning(is_on) + func triggerSignal(sig): trig_signal = sig checkTrigger() -func trig_timeout(time:float=0): + +func trig_timeout(time: float = 0): trigger_time += _delta if trigger_time >= time: trigger_timeout = true trigger_time = 0 return true return false + + # checkTrigger() + func checkTrigger(): - if not (active and auto_pattern_id != "" and trig_container): return + if not (active and auto_pattern_id != "" and trig_container): + return trig_container.checkTriggers(self, self) + + # Spawning.spawn(self, auto_pattern_id, shared_area_name) + func callAction(): Spawning.spawn(self, auto_pattern_id, shared_area_name) + func _get_property_list() -> Array: return [ + {name = "active", type = TYPE_BOOL, usage = PROPERTY_USAGE_DEFAULT}, + {name = "auto_pattern_id", type = TYPE_STRING, usage = PROPERTY_USAGE_DEFAULT}, + {name = "shared_area_name", type = TYPE_STRING, usage = PROPERTY_USAGE_DEFAULT}, + {name = "rotating_speed", type = TYPE_FLOAT, usage = PROPERTY_USAGE_DEFAULT}, + {name = "pool_amount", type = TYPE_INT, usage = PROPERTY_USAGE_DEFAULT}, { - name = "active", - type = TYPE_BOOL, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "auto_pattern_id", - type = TYPE_STRING, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "shared_area_name", - type = TYPE_STRING, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "rotating_speed", - type = TYPE_FLOAT, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "pool_amount", - type = TYPE_INT, - usage = PROPERTY_USAGE_DEFAULT - },{ name = "Autostart & Triggering", type = TYPE_NIL, hint_string = "auto_", usage = PROPERTY_USAGE_GROUP - },{ - name = "auto_start_on_cam", - type = TYPE_BOOL, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "auto_start_after_time", - type = TYPE_FLOAT, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "auto_start_at_distance", - type = TYPE_FLOAT, - usage = PROPERTY_USAGE_DEFAULT - },{ - name = "auto_distance_from", - type = TYPE_NODE_PATH, - usage = PROPERTY_USAGE_DEFAULT - },{ + }, + {name = "auto_start_on_cam", type = TYPE_BOOL, usage = PROPERTY_USAGE_DEFAULT}, + {name = "auto_start_after_time", type = TYPE_FLOAT, usage = PROPERTY_USAGE_DEFAULT}, + {name = "auto_start_at_distance", type = TYPE_FLOAT, usage = PROPERTY_USAGE_DEFAULT}, + {name = "auto_distance_from", type = TYPE_NODE_PATH, usage = PROPERTY_USAGE_DEFAULT}, + { name = "Advanced Triggering", type = TYPE_NIL, hint_string = "trigger_", usage = PROPERTY_USAGE_GROUP - },{ - name = "trigger_container", - type = TYPE_NODE_PATH, - usage = PROPERTY_USAGE_DEFAULT - } -# ,{ -# name = "Random", -# type = TYPE_NIL, -# hint_string = "r_", -# usage = PROPERTY_USAGE_GROUP -# }, -# { name = "r_randomisation_chances", type = TYPE_FLOAT, -# hint = PROPERTY_HINT_RANGE, hint_string = "0, 1", usage = PROPERTY_USAGE_DEFAULT }, -# { name = "r_active_chances", type = TYPE_FLOAT, -# hint = PROPERTY_HINT_RANGE, hint_string = "0, 1", usage = PROPERTY_USAGE_DEFAULT }, -# { name = "r_shared_area_choice", type = TYPE_STRING, usage = PROPERTY_USAGE_DEFAULT }, -# { name = "r_rotating_variation", type = TYPE_VECTOR3, usage = PROPERTY_USAGE_DEFAULT }, -# { name = "r_pattern_choice", type = TYPE_ARRAY, usage = PROPERTY_USAGE_DEFAULT }, -# { name = "r_start_time_choice", type = TYPE_STRING, usage = PROPERTY_USAGE_DEFAULT }, -# { name = "r_start_time_variation", type = TYPE_VECTOR3, usage = PROPERTY_USAGE_DEFAULT } + }, + {name = "trigger_container", type = TYPE_NODE_PATH, usage = PROPERTY_USAGE_DEFAULT} + # ,{ + # name = "Random", + # type = TYPE_NIL, + # hint_string = "r_", + # usage = PROPERTY_USAGE_GROUP + # }, + # { name = "r_randomisation_chances", type = TYPE_FLOAT, + # hint = PROPERTY_HINT_RANGE, hint_string = "0, 1", usage = PROPERTY_USAGE_DEFAULT }, + # { name = "r_active_chances", type = TYPE_FLOAT, + # hint = PROPERTY_HINT_RANGE, hint_string = "0, 1", usage = PROPERTY_USAGE_DEFAULT }, + # { name = "r_shared_area_choice", type = TYPE_STRING, usage = PROPERTY_USAGE_DEFAULT }, + # { name = "r_rotating_variation", type = TYPE_VECTOR3, usage = PROPERTY_USAGE_DEFAULT }, + # { name = "r_pattern_choice", type = TYPE_ARRAY, usage = PROPERTY_USAGE_DEFAULT }, + # { name = "r_start_time_choice", type = TYPE_STRING, usage = PROPERTY_USAGE_DEFAULT }, + # { name = "r_start_time_variation", type = TYPE_VECTOR3, usage = PROPERTY_USAGE_DEFAULT } ] + + +################################### +## extensions by TinyTakinTeller ## +################################### + + +func _start_spawning(auto = true) -> void: + if auto_start_after_time > float(0.0): + await get_tree().create_timer(auto_start_after_time).timeout + if not active: + return + auto_call = auto + set_physics_process(active) + + +func start() -> void: + if active: + return + can_respawn = true + active = true + _start_spawning() + + +func stop() -> void: + active = false diff --git a/addons/BulletUpHell/SpawnPatterns/Pattern.gd b/addons/BulletUpHell/SpawnPatterns/Pattern.gd index 36351b3..3b07d97 100644 --- a/addons/BulletUpHell/SpawnPatterns/Pattern.gd +++ b/addons/BulletUpHell/SpawnPatterns/Pattern.gd @@ -35,4 +35,3 @@ enum MOMENTUM{None, TRANS_LINEAR,TRANS_SINE,TRANS_QUINT,TRANS_QUART,TRANS_QUAD,T var has_random var node_target:Node2D - diff --git a/addons/BulletUpHell/Spawning.tscn b/addons/BulletUpHell/Spawning.tscn index 5c4e020..73a6c5a 100644 --- a/addons/BulletUpHell/Spawning.tscn +++ b/addons/BulletUpHell/Spawning.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=15 format=3 uid="uid://gixop20d1d75"] +[gd_scene load_steps=16 format=3 uid="uid://gixop20d1d75"] [ext_resource type="Script" path="res://addons/BulletUpHell/BuHSpawner.gd" id="1"] [ext_resource type="Texture2D" uid="uid://cdvaddoryit2u" path="res://addons/BulletUpHell/Bullet/Sprites/Bullet_3.png" id="2_3slxn"] [ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/animStates.gd" id="2_4dc5c"] [ext_resource type="Texture2D" uid="uid://4qgfs5h6pqtg" path="res://addons/BulletUpHell/Bullet/Sprites/Bullet_06.png" id="3_6fafs"] +[ext_resource type="Texture2D" uid="uid://lqqd05fstex1" path="res://addons/BulletUpHell/Bullet/Sprites/Bullet_B&W.png" id="3_8cgs3"] [ext_resource type="Texture2D" uid="uid://cwlu40lwdvh0m" path="res://addons/BulletUpHell/Bullet/Sprites/Bullet_11.png" id="4_gntuv"] [ext_resource type="AudioStream" uid="uid://nh2ipkhrxyq6" path="res://addons/BulletUpHell/Bullet/Hit Hurt.wav" id="5_rada6"] @@ -61,7 +62,7 @@ animations = [{ }, { "frames": [{ "duration": 1.0, -"texture": ExtResource("2_3slxn") +"texture": ExtResource("3_8cgs3") }], "loop": true, "name": &"0", @@ -102,8 +103,7 @@ default_delete = SubResource("Resource_tl1ht") [node name="ShapeManager" type="AnimatedSprite2D" parent="."] visible = false sprite_frames = SubResource("1") -animation = &"Example" -frame_progress = 0.608517 +animation = &"0" [node name="0" type="CollisionShape2D" parent="ShapeManager"] shape = SubResource("2") diff --git a/assets/image/npc/cat/cat_90_100_shadow.png b/assets/image/npc/cat/cat_90_100_shadow.png new file mode 100644 index 0000000..9e4f318 Binary files /dev/null and b/assets/image/npc/cat/cat_90_100_shadow.png differ diff --git a/assets/image/npc/cat/cat_90_100_shadow.png.import b/assets/image/npc/cat/cat_90_100_shadow.png.import new file mode 100644 index 0000000..643da6d --- /dev/null +++ b/assets/image/npc/cat/cat_90_100_shadow.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4wqq3rdroryo" +path="res://.godot/imported/cat_90_100_shadow.png-05c9687b7959a80575f18d995f17bf29.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/image/npc/cat/cat_90_100_shadow.png" +dest_files=["res://.godot/imported/cat_90_100_shadow.png-05c9687b7959a80575f18d995f17bf29.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/global/const/game.gd b/global/const/game.gd index 181fcd7..3471f64 100644 --- a/global/const/game.gd +++ b/global/const/game.gd @@ -13,6 +13,7 @@ const WEB_EXPORT_WORKAROUNDS: bool = false const PARAMS_DEBUG: Dictionary = { "CLIPBOARD_WEB_WORKAROUND": WEB_EXPORT_WORKAROUNDS, + "cat_boss_battle_fps": true, "soul_disabled": false, "prestige_disabled": false, "reborn_overlay_shader": true, @@ -47,6 +48,7 @@ const PARAMS_DEBUG: Dictionary = { const PARAMS_PROD: Dictionary = { "CLIPBOARD_WEB_WORKAROUND": WEB_EXPORT_WORKAROUNDS, + "cat_boss_battle_fps": true, "soul_disabled": false, "prestige_disabled": false, "reborn_overlay_shader": true, diff --git a/scenes/autostart/soul_screen/soul/soul_sprite.gd b/scenes/autostart/soul_screen/soul/soul_sprite.gd index 051ae90..1fae627 100644 --- a/scenes/autostart/soul_screen/soul/soul_sprite.gd +++ b/scenes/autostart/soul_screen/soul/soul_sprite.gd @@ -1,7 +1,7 @@ class_name SoulSprite extends CharacterBody2D -const DELAY: float = 0.16 +const DELAY: float = 0.1 var min_speed: float = 100 diff --git a/scenes/autostart/soul_screen/soul_screen.gd b/scenes/autostart/soul_screen/soul_screen.gd index 5c938c8..a3ac49b 100644 --- a/scenes/autostart/soul_screen/soul_screen.gd +++ b/scenes/autostart/soul_screen/soul_screen.gd @@ -3,12 +3,13 @@ extends Node @export var shake_shader_component_scene: PackedScene @onready var node_2d: Node2D = %Node2D -@onready var cat_sprite_2d: Sprite2D = %CatSprite2D +@onready var pattern_master: PatternMaster = $Node2D/PatternMaster @onready var soul_sprite: SoulSprite = %SoulSprite +@onready var cat_sprite_2d: Sprite2D = %CatSprite2D + @onready var control: Control = %Control -@onready var label: Label = %Label +@onready var label: Label = $Control/Label -@onready var main_pattern: Node2D = %MainPattern ############### ## overrides ## @@ -16,13 +17,7 @@ extends Node func _physics_process(_delta: float) -> void: - #main_pattern.spawn_point_1.active = true - #main_pattern.spawn_point_2.active = true - - main_pattern.spawn_point_1.position = ( - cat_sprite_2d.position - cat_sprite_2d.get_rect().size / 4 + Vector2(8, -16.0) - ) - main_pattern.spawn_point_2.position = ( + pattern_master.align_patterns( cat_sprite_2d.position - cat_sprite_2d.get_rect().size / 4 + Vector2(8, -16.0) ) @@ -32,9 +27,9 @@ func _ready() -> void: _intro_animation() -func _intro_animation_end() -> void: - _add_shake_effect_to_cat() - label.visible = true +############# +## helpers ## +############# func _intro_animation() -> void: @@ -64,3 +59,14 @@ func _initialize() -> void: cat_sprite_2d.position = SaveFile.cat_sprite_2d_position Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) soul_sprite.position = node_2d.get_global_mouse_position() + + +############# +## signals ## +############# + + +func _intro_animation_end() -> void: + _add_shake_effect_to_cat() + # label.visible = true + pattern_master.start_pattern(0) diff --git a/scenes/autostart/soul_screen/soul_screen.tscn b/scenes/autostart/soul_screen/soul_screen.tscn index ad7a6e8..f091adf 100644 --- a/scenes/autostart/soul_screen/soul_screen.tscn +++ b/scenes/autostart/soul_screen/soul_screen.tscn @@ -4,8 +4,8 @@ [ext_resource type="Theme" uid="uid://d276arnrjws3i" path="res://resources/theme/dark/dark.tres" id="2_ey0j8"] [ext_resource type="PackedScene" uid="uid://dfrws6lo2o7d0" path="res://scenes/autostart/soul_screen/soul/soul_sprite.tscn" id="2_rspx0"] [ext_resource type="PackedScene" uid="uid://bpq246h5ihhck" path="res://scenes/component/shake_shader_component/shake_shader_component.tscn" id="2_whm7q"] -[ext_resource type="Texture2D" uid="uid://cpwmy667e4xpa" path="res://assets/image/npc/cat/cat_90_100.png" id="2_xltfu"] -[ext_resource type="PackedScene" uid="uid://dp27xbynyqp65" path="res://scenes/bullet_up_hell/main_pattern/main_pattern.tscn" id="5_742rc"] +[ext_resource type="PackedScene" uid="uid://dp27xbynyqp65" path="res://scenes/bullet_up_hell/pattern_master/pattern_master.tscn" id="5_742rc"] +[ext_resource type="Texture2D" uid="uid://b4wqq3rdroryo" path="res://assets/image/npc/cat/cat_90_100_shadow.png" id="5_ary8y"] [node name="Soul" type="Node"] script = ExtResource("1_fyd6i") @@ -14,8 +14,7 @@ shake_shader_component_scene = ExtResource("2_whm7q") [node name="Node2D" type="Node2D" parent="."] unique_name_in_owner = true -[node name="MainPattern" parent="Node2D" instance=ExtResource("5_742rc")] -unique_name_in_owner = true +[node name="PatternMaster" parent="Node2D" instance=ExtResource("5_742rc")] rotation = 4.46638e-06 [node name="SoulSprite" parent="Node2D" instance=ExtResource("2_rspx0")] @@ -24,7 +23,7 @@ unique_name_in_owner = true [node name="CatSprite2D" type="Sprite2D" parent="Node2D"] unique_name_in_owner = true position = Vector2(470, 79) -texture = ExtResource("2_xltfu") +texture = ExtResource("5_ary8y") [node name="Control" type="Control" parent="."] unique_name_in_owner = true @@ -37,7 +36,6 @@ grow_vertical = 2 theme = ExtResource("2_ey0j8") [node name="Label" type="Label" parent="Control"] -unique_name_in_owner = true visible = false layout_mode = 1 anchors_preset = 8 diff --git a/scenes/bullet_up_hell/pattern_master/pattern_master.gd b/scenes/bullet_up_hell/pattern_master/pattern_master.gd new file mode 100644 index 0000000..45ddd7b --- /dev/null +++ b/scenes/bullet_up_hell/pattern_master/pattern_master.gd @@ -0,0 +1,44 @@ +class_name PatternMaster +extends Node2D + +var _pattern_list: Array = [] + +@onready var fps: Label = $FPS +@onready var patterns: Node2D = $Patterns + + +func _ready() -> void: + fps.visible = Game.PARAMS["cat_boss_battle_fps"] + + for pattern: Node2D in patterns.get_children(): + var spawners: Array = [] + for subpattern: Node2D in pattern.get_children(): + spawners.append(subpattern.get_child(0) as BuHSpawnPoint) + _pattern_list.append(spawners) + + +func _process(_delta: float) -> void: + if Game.PARAMS["cat_boss_battle_fps"]: + $FPS.text = ( + str(Engine.get_frames_per_second()) + " FPS\n" + str(Spawning.poolBullets.size()) + ) + + +func align_patterns(target: Vector2) -> void: + for index: int in range(_pattern_list.size()): + align_pattern(target, index) + + +func align_pattern(target: Vector2, index: int) -> void: + for spawner: BuHSpawnPoint in _pattern_list[index]: + spawner.position = target + + +func start_pattern(index: int) -> void: + for spawner: BuHSpawnPoint in _pattern_list[index]: + spawner.start() + + +func stop_pattern(index: int) -> void: + for spawner: BuHSpawnPoint in _pattern_list[index]: + spawner.stop() diff --git a/scenes/bullet_up_hell/main_pattern/main_pattern.tscn b/scenes/bullet_up_hell/pattern_master/pattern_master.tscn similarity index 54% rename from scenes/bullet_up_hell/main_pattern/main_pattern.tscn rename to scenes/bullet_up_hell/pattern_master/pattern_master.tscn index 350894b..ed49017 100644 --- a/scenes/bullet_up_hell/main_pattern/main_pattern.tscn +++ b/scenes/bullet_up_hell/pattern_master/pattern_master.tscn @@ -1,25 +1,25 @@ -[gd_scene load_steps=15 format=3 uid="uid://dp27xbynyqp65"] +[gd_scene load_steps=18 format=3 uid="uid://dp27xbynyqp65"] -[ext_resource type="Script" path="res://addons/BulletUpHell/Examples/ExampleScene.gd" id="1_aknba"] -[ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHSpawnPoint.gd" id="2_owqfl"] -[ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHPattern.gd" id="3_qchcn"] -[ext_resource type="Script" path="res://addons/BulletUpHell/SpawnPatterns/PatternCircle.gd" id="4_eldcv"] -[ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHBulletProperties.gd" id="5_h13t5"] -[ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/animStates.gd" id="6_s2cyv"] -[ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/BulletProps.gd" id="7_lhkna"] +[ext_resource type="Script" path="res://scenes/bullet_up_hell/pattern_master/pattern_master.gd" id="1_lkn8h"] +[ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHSpawnPoint.gd" id="2_rai8q"] +[ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHPattern.gd" id="3_molhr"] +[ext_resource type="Script" path="res://addons/BulletUpHell/SpawnPatterns/PatternCircle.gd" id="4_vu88i"] +[ext_resource type="Script" path="res://addons/BulletUpHell/Nodes/BuHBulletProperties.gd" id="5_gfkum"] +[ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/animStates.gd" id="6_4oi1y"] +[ext_resource type="Script" path="res://addons/BulletUpHell/Bullet/BulletProps.gd" id="7_va6hm"] [sub_resource type="Curve2D" id="Curve2D_2blpc"] [sub_resource type="NavigationPolygon" id="NavigationPolygon_xvgbi"] resource_name = "PatternCircle" -script = ExtResource("4_eldcv") +script = ExtResource("4_vu88i") radius = 0 angle_total = 6.28319 angle_decal = 0.0 symmetric = true center = 0 symmetry_type = 0 -bullet = "circle" +bullet = "circle0" nbr = 10 iterations = -1 pattern_angle = 0.0 @@ -44,9 +44,14 @@ wait_tween_time = 0.0 [sub_resource type="Curve" id="Curve_ghta3"] +[sub_resource type="Gradient" id="Gradient_yqb8c"] +interpolation_mode = 1 +offsets = PackedFloat32Array(0) +colors = PackedColorArray(0.999999, 0.984398, 0.669782, 1) + [sub_resource type="PackedDataContainer" id="PackedDataContainer_f8sif"] -script = ExtResource("7_lhkna") -anim_more = Array[ExtResource("6_s2cyv")]([]) +script = ExtResource("7_va6hm") +anim_more = Array[ExtResource("6_4oi1y")]([]) damage = 1.0 speed = 100.0 scale = 1.0 @@ -54,6 +59,7 @@ angle = 0.0 groups = PackedStringArray() spec_bounces = 0 spec_no_collision = false +spec_modulate = SubResource("Gradient_yqb8c") spec_modulate_loop = 0.0 spec_trail_length = 0.0 spec_trail_width = 0.0 @@ -118,14 +124,14 @@ r_scale_multi_scale_variation = Vector3(0, 0, 0) [sub_resource type="NavigationPolygon" id="NavigationPolygon_d7c6k"] resource_name = "PatternCircle" -script = ExtResource("4_eldcv") +script = ExtResource("4_vu88i") radius = 0 angle_total = 6.28319 angle_decal = 1.5708 symmetric = true center = 5 symmetry_type = 0 -bullet = "circle2" +bullet = "circle1" nbr = 10 iterations = -1 pattern_angle = 0.0 @@ -144,18 +150,100 @@ wait_tween_momentum = 0 wait_tween_length = 0.0 wait_tween_time = 0.0 -[node name="MainPattern" type="Node2D"] +[sub_resource type="Gradient" id="Gradient_f3isc"] +interpolation_mode = 1 +offsets = PackedFloat32Array(0) +colors = PackedColorArray(1, 0.952344, 0.952151, 1) + +[sub_resource type="PackedDataContainer" id="PackedDataContainer_5y4sb"] +script = ExtResource("7_va6hm") +anim_more = Array[ExtResource("6_4oi1y")]([]) +damage = 1.0 +speed = 100.0 +scale = 1.0 +angle = 0.0 +groups = PackedStringArray() +spec_bounces = 0 +spec_no_collision = false +spec_modulate = SubResource("Gradient_f3isc") +spec_modulate_loop = 0.0 +spec_trail_length = 0.0 +spec_trail_width = 0.0 +spec_trail_modulate = Color(1, 1, 1, 1) +spec_rotating_speed = 0.0 +death_after_time = 30.0 +death_outside_box = Rect2(0, 0, 0, 0) +death_from_collision = true +a_direction_equation = "" +a_curve_movement = 0 +a_speed_multiplier = SubResource("Curve_ymaju") +a_speed_multi_iterations = 0 +a_speed_multi_scale = 0.0 +trigger_container = "" +trigger_wait_for_shot = true +homing_type = 0 +homing_target = NodePath("") +homing_steer = 0.0 +homing_time_start = 0.0 +homing_duration = 999.0 +scale_multi_iterations = 0 +scale_multiplier = SubResource("Curve_ghta3") +scale_multi_scale = 1.0 +r_randomisation_chances = 1.0 +r_speed_choice = PackedFloat32Array() +r_speed_variation = Vector3(0, 0, 0) +r_scale_choice = PackedFloat32Array() +r_scale_variation = Vector3(0, 0, 0) +r_angle_choice = PackedFloat32Array() +r_angle_variation = Vector3(0, 0, 0) +r_group_choice = [] +r_bounce_choice = PackedInt32Array() +r_bounce_variation = Vector3(0, 0, 0) +r_no_coll_chances = 0.0 +r_modulate_variation = Vector3(0, 0, 0) +r_trail_length_variation = Vector3(0, 0, 0) +r_trail_color_variation = Vector3(0, 0, 0) +r_rotating_variation = Vector3(0, 0, 0) +r_death_after_choice = PackedFloat32Array() +r_death_after_variation = Vector3(0, 0, 0) +r_death_outside_chances = 0.0 +r_dir_equation_choice = PackedStringArray() +r_curve_choice = [] +r_speed_multi_curve_choice = [] +r_speed_multi_iter_variation = Vector3(0, 0, 0) +r_speed_multi_scale_variation = Vector3(0, 0, 0) +r_trigger_choice = PackedStringArray() +r_wait_for_shot_chances = 0.0 +r_homing_target_choice = [] +r_special_target_choice = PackedStringArray() +r_group_target_choice = PackedStringArray() +r_pos_target_choice = PackedVector2Array() +r_steer_choice = PackedFloat32Array() +r_steer_variation = Vector3(0, 0, 0) +r_homing_delay_choice = PackedFloat32Array() +r_homing_delay_variation = Vector3(0, 0, 0) +r_homing_dur_choice = PackedFloat32Array() +r_homing_dur_variation = Vector3(0, 0, 0) +r_scale_multi_curve_choice = [] +r_scale_multi_iter_variation = Vector3(0, 0, 0) +r_scale_multi_scale_variation = Vector3(0, 0, 0) + +[node name="PatternMaster" type="Node2D"] position = Vector2(11, 50) rotation = 6.28319 -script = ExtResource("1_aknba") +script = ExtResource("1_lkn8h") + +[node name="Patterns" type="Node2D" parent="."] -[node name="Circle1" type="Node2D" parent="."] +[node name="Pattern0" type="Node2D" parent="Patterns"] -[node name="SpawnPoint" type="Node2D" parent="Circle1"] +[node name="Circle0" type="Node2D" parent="Patterns/Pattern0"] + +[node name="SpawnPoint" type="Node2D" parent="Patterns/Pattern0/Circle0"] position = Vector2(453, 22.998) -script = ExtResource("2_owqfl") +script = ExtResource("2_rai8q") active = false -auto_pattern_id = "circle" +auto_pattern_id = "circle0" shared_area_name = "0" rotating_speed = 0.0 pool_amount = 200 @@ -165,25 +253,25 @@ auto_start_at_distance = 5.0 auto_distance_from = NodePath("") trigger_container = NodePath("") -[node name="SpawnPattern" type="Path2D" parent="Circle1"] +[node name="SpawnPattern" type="Path2D" parent="Patterns/Pattern0/Circle0"] curve = SubResource("Curve2D_2blpc") -script = ExtResource("3_qchcn") -id = "circle" +script = ExtResource("3_molhr") +id = "circle0" pattern = SubResource("NavigationPolygon_xvgbi") -[node name="BulletPattern" type="Path2D" parent="Circle1"] +[node name="BulletPattern" type="Path2D" parent="Patterns/Pattern0/Circle0"] curve = SubResource("Curve2D_4yvwo") -script = ExtResource("5_h13t5") -id = "circle" +script = ExtResource("5_gfkum") +id = "circle0" props = SubResource("PackedDataContainer_f8sif") -[node name="Circle2" type="Node2D" parent="."] +[node name="Circle1" type="Node2D" parent="Patterns/Pattern0"] -[node name="SpawnPoint" type="Node2D" parent="Circle2"] +[node name="SpawnPoint" type="Node2D" parent="Patterns/Pattern0/Circle1"] position = Vector2(454, 21.998) -script = ExtResource("2_owqfl") +script = ExtResource("2_rai8q") active = false -auto_pattern_id = "circle2" +auto_pattern_id = "circle1" shared_area_name = "0" rotating_speed = 0.0 pool_amount = 200 @@ -193,17 +281,17 @@ auto_start_at_distance = 5.0 auto_distance_from = NodePath("") trigger_container = NodePath("") -[node name="SpawnPattern" type="Path2D" parent="Circle2"] +[node name="SpawnPattern" type="Path2D" parent="Patterns/Pattern0/Circle1"] curve = SubResource("Curve2D_2blpc") -script = ExtResource("3_qchcn") -id = "circle2" +script = ExtResource("3_molhr") +id = "circle1" pattern = SubResource("NavigationPolygon_d7c6k") -[node name="BulletPattern" type="Path2D" parent="Circle2"] +[node name="BulletPattern" type="Path2D" parent="Patterns/Pattern0/Circle1"] curve = SubResource("Curve2D_4yvwo") -script = ExtResource("5_h13t5") -id = "circle2" -props = SubResource("PackedDataContainer_f8sif") +script = ExtResource("5_gfkum") +id = "circle1" +props = SubResource("PackedDataContainer_5y4sb") [node name="Walls" type="StaticBody2D" parent="."] collision_layer = 17