documentation pass before moving on

This commit is contained in:
Haze Weathers 2026-01-02 20:30:18 -06:00
parent c6923a3133
commit ddf3590c96
17 changed files with 84 additions and 44 deletions

View file

@ -8,19 +8,21 @@ extends Area2D
signal recycled()
# ## The number of bullets to allocate at startup.
#const INITIAL_ALLOCATED_BULLETS: int = 2000
# cached shapes for each hitbox size
static var _hitbox_shapes: Dictionary[Vector2i, RectangleShape2D] = {}
## Texture to draw for the bullet.
## Base graphic/animation to display, modulated by [member color].
@export var base_graphic: AnimationStrip = null:
set(value):
base_graphic = value
queue_redraw()
_update_visibility_notifier()
## The color that [member base_graphic] will be modulated by.
@export var color: Color
## Extra graphic drawn over [member base_graphic] and not modulated by [member color].
@export var overlay_graphic: AnimationStrip = null:
set(value):
overlay_graphic = value
@ -49,22 +51,13 @@ var time_elapsed: float = 0.0
## Whether the bullet has already been grazed by the player.
var grazed: bool = false
#static var _cached_bullets: Array[Bullet] = []
static var _hitbox_shapes: Dictionary[Vector2i, RectangleShape2D] = {}
var _hitbox: CollisionShape2D = CollisionShape2D.new()
## Returns a new [Bullet], which may be sourced from the cached bullets.
@warning_ignore("shadowed_variable")
static func create(
preset: BulletPreset,
direction: Vector2 = Vector2.RIGHT,
) -> Bullet:
#var bullet: Bullet = _cached_bullets.pop_back()
#if not bullet:
#bullet = Bullet.new()
static func create(preset: BulletPreset, direction: Vector2 = Vector2.RIGHT) -> Bullet:
var bullet := Bullet.new()
if not preset.base_graphics.is_empty():
@ -84,21 +77,6 @@ static func create(
return bullet
## Removes the bullet from the scene tree and returns it to the bullet cache to be
## re-used later.
func recycle() -> void:
#if is_inside_tree():
#get_parent().remove_child(self)
#_cached_bullets.append(self)
queue_free()
recycled.emit()
#static func _static_init() -> void:
#for _i in INITIAL_ALLOCATED_BULLETS:
#_cached_bullets.append(Bullet.new())
func _init() -> void:
monitoring = false
collision_layer = 1 << 3
@ -130,6 +108,13 @@ func _get_configuration_warnings() -> PackedStringArray:
return []
## Removes the bullet from the scene tree and returns it to the bullet cache to be
## re-used later.
func recycle() -> void:
queue_free()
recycled.emit()
# sets the canvas item up to notify when it leaves the screen
# this essentially mimics `VisibleOnScreenNotifier` without an additional node
func _update_visibility_notifier() -> void:

View file

@ -1,6 +1,7 @@
@abstract
class_name BulletAction
extends Resource
## An action that a bullet can perform when triggered.
## Performs the action on a given [Bullet].

View file

@ -1,6 +1,7 @@
@abstract
class_name BulletBehavior
extends Resource
## Controls the movment and actions of a [Bullet].
@export_group("Actions", "action_")
@ -14,11 +15,14 @@ extends Resource
@export var action_on_interval: BulletAction
var _bullet_delay_cooldowns: Dictionary[Bullet, float] = {}
var _bullet_interval_cooldowns: Dictionary[Bullet, float] = {}
## Performs behavior-specific initialization for a [Bullet].
func init_bullet(bullet: Bullet) -> void:
if action_on_delay:
_bullet_delay_cooldowns[bullet] = action_delay
if action_on_interval:
_bullet_interval_cooldowns[bullet] = action_interval
bullet.recycled.connect(deinit_bullet.bind(bullet), CONNECT_ONE_SHOT)
@ -27,20 +31,23 @@ func init_bullet(bullet: Bullet) -> void:
## Cleans up behavior-specific state for a [Bullet].
func deinit_bullet(bullet: Bullet) -> void:
_bullet_delay_cooldowns.erase(bullet)
_bullet_interval_cooldowns.erase(bullet)
_deinit_bullet(bullet)
## Processes one tick of a [Bullet]'s movement.
func process_bullet(bullet: Bullet, delta: float) -> void:
#var last_time = bullet.time_elapsed
#bullet.time_elapsed += delta
#if last_time < action_delay and bullet.time_elapsed >= action_delay and action_on_delay:
#action_on_delay.perform(bullet)
if action_on_delay and _bullet_delay_cooldowns.has(bullet):
_bullet_delay_cooldowns[bullet] -= delta
if _bullet_delay_cooldowns[bullet] <= 0.0:
_bullet_delay_cooldowns.erase(bullet)
action_on_delay.perform(bullet)
if action_on_interval:
_bullet_interval_cooldowns[bullet] -= delta
if _bullet_interval_cooldowns[bullet] <= 0.0:
_bullet_interval_cooldowns[bullet] += action_interval
action_on_interval.perform(bullet)
_process_bullet(bullet, delta)

View file

@ -1,4 +1,4 @@
class_name SimpleLinearBehavior
class_name LinearMotionBehavior
extends BulletBehavior
## Makes bullets move in [member Bullet.direction], potentially accelerating.

View file

@ -4,27 +4,43 @@ extends Resource
@export_group("Bullets")
## Behavior used to control the motion and actions of the bullets.
@export var behavior: BulletBehavior = null
## Size in pixels of the bullets' hitboxes.
@export var hitbox_size: Vector2i = Vector2i.ZERO
## If [code]true[/code], the bullets will rotate to face their direction.
@export var face_direction: bool = false
## Array of graphics that will be picked from randomly for
## each bullet and modulated by the picked color.
@export var base_graphics: Array[AnimationStrip] = []:
set(value):
base_graphics = value
if base_graphics.size() != overlay_graphics.size():
overlay_graphics.resize(base_graphics.size())
notify_property_list_changed()
## Array of graphics that will be picked based on the chosen graphic from
## [member base_graphics] and drawn over top without being modulated.
@export var overlay_graphics: Array[AnimationStrip] = []:
set(value):
overlay_graphics = value
if base_graphics.size() != overlay_graphics.size():
overlay_graphics.resize(base_graphics.size())
notify_property_list_changed()
## Array of colors that will be picked from randomly to
## modulate the graphic chosen from [member base_graphics].
@export var colors: Array[Color] = [Color.WHITE]
@export var hitbox_size: Vector2i = Vector2i.ZERO
@export var face_direction: bool = false
@export_group("Spawning")
## The pattern to use for positioning each "round" of bullets.
@export var pattern: BulletSpawnPattern = null
## How many rounds of bullets to spawn before stopping.
@export var rounds: int = 1
## The time to wait after each "round" of bullets before spawning the next.
@export var round_delay: float = 0.0
@export_group("Bullet Set")
## Behavior that controls the movement and actions of the [BulletSet].
@export var set_behavior: BulletSetBehavior = null

View file

@ -2,10 +2,14 @@ class_name BulletSet
extends Node2D
## Preset that determines how bullets are spawned, look, and behave.
@export var preset: BulletPreset
## Offset in pixels from the set's [member position] where
## a [BulletSpawnPattern] should spawn bullets.
var spawn_offset: Vector2 = Vector2.ZERO
## Offset from the set's [member rotation] that a [BulletSpawnPattern] should rotate itself by.
var spawn_rotation: float = 0.0

View file

@ -1,6 +1,7 @@
@abstract
class_name BulletSetBehavior
extends Resource
## Controls the movement and actions of a [BulletSet].
## Process one physics tick for a [BulletSet].

View file

@ -3,6 +3,7 @@ extends BulletSetBehavior
## Processes multiple [BulletSetBehavior]s in order for the [BulletSet].
## Behaviors to process for the [BulletSet].
@export var behaviors: Array[BulletSetBehavior] = []

View file

@ -1,24 +1,29 @@
@tool
class_name RandomSpawnSetBehavior
extends BulletSetBehavior
## Randomizes the spawn position for each round of spawning.
## Minimum possible value of [code]spawn_offset[/code].
@export var spawn_offset_min: Vector2:
set(value):
if spawn_offset_min != value:
spawn_offset_min = value
spawn_offset_max = spawn_offset_max.max(spawn_offset_min)
## Maximum possible value of [code]spawn_offset[/code].
@export var spawn_offset_max: Vector2:
set(value):
if spawn_offset_max != value:
spawn_offset_max = value
spawn_offset_min = spawn_offset_min.min(spawn_offset_max)
## Minimum possible value of [code]spawn_rotation[/code].
@export_custom(0, "radians_as_degrees") var spawn_rotation_min: float:
set(value):
spawn_rotation_min = value
if spawn_rotation_max < spawn_rotation_min:
spawn_rotation_max = maxf(spawn_rotation_min, spawn_rotation_max)
## Maximum possible value of [code]spawn_rotation[/code].
@export_custom(0, "radians_as_degrees") var spawn_rotation_max: float:
set(value):
spawn_rotation_max = value

View file

@ -1,8 +1,11 @@
class_name RotationSetBehavior
extends BulletSetBehavior
## Applies rotational motion to a [BulletSet].
## Speed at which the set rotates, including existing child [Bullet]s and [BulletSet]s.
@export_custom(0, "radians_as_degrees,suffix:°/s") var rotation_speed: float = 0.0
## Speed at which the rotation offset of spawned bullet patterns will change.
@export_custom(0, "radians_as_degrees,suffix:°/s") var spawn_rotation_speed: float = 0.0

View file

@ -1,6 +1,7 @@
@abstract
class_name BulletSpawnPattern
extends Resource
## Defines the placement of spawned bullets.
## The amount of times to spawning this pattern for one "round".
@ -9,6 +10,7 @@ extends Resource
@export_range(1, 1, 1, "or_greater") var iterations: int = 1
## Creates and adds bullets to the passed [BulletSet].
func spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void:
for _n in iterations:
_spawn_bullets(bullet_set, preset)

View file

@ -1,15 +1,19 @@
class_name LinePattern
extends BulletSpawnPattern
## Spawns bullets evenly spaced out along a line segment.
## Number of bullets to spawn along the line.
@export var bullet_count: int
## Distance between the first and last bullet in the line.
@export var line_width: float
## The direction that spawned bullets will travel, orthogonal to the line of bullets.
@export_custom(0, "direction") var line_normal: Vector2 = Vector2.RIGHT
func _spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void:
for i in bullet_count:
var bullet = Bullet.create(preset, line_normal)
var bullet = Bullet.create(preset, line_normal.rotated(bullet_set.spawn_rotation))
var line = line_normal.orthogonal().rotated(bullet_set.spawn_rotation)
var weight = float(i) / float(bullet_count - 1)

View file

@ -1,10 +1,15 @@
class_name RingPattern
extends BulletSpawnPattern
## Spawns bullets evenly spaced out around a circle.
@export var bullet_count: int
@export var distance_offset: float
## The number of bullets to spawn along the circle.
@export var bullet_count: int = 3
## Radius of the circle that bullets spawn along the edge of.
@export var radius: float
## Rotation of the entire ring pattern.
@export_custom(0, "radians_as_degrees") var angle_offset: float
## Rotation of each bullet's travel direction.
@export_custom(0, "radians_as_degrees") var direction_rotation: float
@ -12,5 +17,5 @@ func _spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void:
for i in bullet_count:
var angle = (float(i) / float(bullet_count)) * TAU + angle_offset + bullet_set.spawn_rotation
var bullet = Bullet.create(preset, Vector2.from_angle(angle + direction_rotation))
bullet.position = bullet_set.spawn_offset + Vector2.from_angle(angle) * distance_offset
bullet.position = bullet_set.spawn_offset + Vector2.from_angle(angle) * radius
bullet_set.add_bullet(bullet)

View file

@ -1,12 +1,19 @@
class_name AnimationStrip
extends Resource
## A texture sliced into a number of horizontal frames and played at a
## certain fps.
## Texture containing all frames in one row.
@export var texture: Texture
## Number of frames to slice the texture into.
@export var frames: int = 1
## How many frames should be displayed per second.
@export var fps: float = 1.0
## Draws the frame that should be visible at a given point in time. This must be
## called during the [method CanvasItem._draw] of [param canvas_item].
func draw(canvas_item: CanvasItem, time: float, modulate: Color = Color.WHITE) -> void:
var frame_size = Vector2((texture.get_width() / frames), float(texture.get_height()))
var current_frame = fmod(floorf(time * fps), frames)