bullets bullets bullets bullets

This commit is contained in:
Haze Weathers 2025-12-31 14:09:06 -06:00
parent 846040c0e4
commit 55059788b2
25 changed files with 139 additions and 91 deletions

View file

@ -1,74 +1,47 @@
[gd_scene load_steps=23 format=3 uid="uid://dxsp66qpvm65b"] [gd_scene load_steps=15 format=3 uid="uid://dxsp66qpvm65b"]
[ext_resource type="Texture2D" uid="uid://c50bfqprpitev" path="res://icon.svg" id="1_g7g4h"] [ext_resource type="Texture2D" uid="uid://c50bfqprpitev" path="res://icon.svg" id="1_g7g4h"]
[ext_resource type="PackedScene" uid="uid://c714s5d7d5765" path="res://objects/player/player.tscn" id="2_j8ivh"] [ext_resource type="PackedScene" uid="uid://c714s5d7d5765" path="res://objects/player/player.tscn" id="2_j8ivh"]
[ext_resource type="Script" uid="uid://cj2fj7snls8aa" path="res://systems/bullets/bullet_set.gd" id="3_cf1so"] [ext_resource type="Script" uid="uid://cj2fj7snls8aa" path="res://systems/bullets/bullet_set.gd" id="3_cf1so"]
[ext_resource type="Script" uid="uid://mivkgn34ox41" path="res://systems/bullets/actions/bullet_action.gd" id="4_1xo0o"] [ext_resource type="Script" uid="uid://pn143vuxc7wp" path="res://systems/bullets/bullet_actions/despawn_action.gd" id="4_4oowd"]
[ext_resource type="Script" uid="uid://pn143vuxc7wp" path="res://systems/bullets/actions/despawn_action.gd" id="4_4oowd"]
[ext_resource type="Texture2D" uid="uid://du7gh3nk66mpo" path="res://graphics/bullets/normal_bullet/bullet_1.png" id="4_hlyn7"] [ext_resource type="Texture2D" uid="uid://du7gh3nk66mpo" path="res://graphics/bullets/normal_bullet/bullet_1.png" id="4_hlyn7"]
[ext_resource type="Script" uid="uid://dntp60my5f65m" path="res://systems/bullets/behaviors/simple_linear_behavior.gd" id="4_t1bs8"] [ext_resource type="Script" uid="uid://dntp60my5f65m" path="res://systems/bullets/bullet_behaviors/simple_linear_behavior.gd" id="4_t1bs8"]
[ext_resource type="Script" uid="uid://d238qii8i2byl" path="res://systems/bullets/spawn_patterns/line_pattern.gd" id="5_cf1so"]
[ext_resource type="Script" uid="uid://vus1a0flwtnm" path="res://systems/bullets/bullet_preset.gd" id="6_sle1e"] [ext_resource type="Script" uid="uid://vus1a0flwtnm" path="res://systems/bullets/bullet_preset.gd" id="6_sle1e"]
[ext_resource type="Script" uid="uid://dtuc6qerbfset" path="res://systems/bullets/spawn_patterns/ring_pattern.gd" id="6_uu3sg"] [ext_resource type="Script" uid="uid://dtuc6qerbfset" path="res://systems/bullets/spawn_patterns/ring_pattern.gd" id="6_uu3sg"]
[ext_resource type="Script" uid="uid://oug6n1t6tnor" path="res://systems/bullets/actions/spawn_set_action.gd" id="8_377ep"] [ext_resource type="Script" uid="uid://5scjonwmg8tw" path="res://systems/bullets/set_behaviors/rotation_set_behavior.gd" id="7_t1bs8"]
[ext_resource type="Texture2D" uid="uid://bqn0smy2jio3y" path="res://graphics/bullets/normal_bullet/bullet_3.png" id="8_uu3sg"]
[ext_resource type="Script" uid="uid://mair8nsxn7lp" path="res://systems/bullets/actions/multi_action.gd" id="10_etmxr"]
[sub_resource type="Resource" id="Resource_rbgfd"] [sub_resource type="Resource" id="Resource_sle1e"]
script = ExtResource("4_t1bs8")
acceleration = 64.0
metadata/_custom_type_script = "uid://dntp60my5f65m"
[sub_resource type="Resource" id="Resource_xksnv"]
script = ExtResource("6_uu3sg")
bullet_count = 9
metadata/_custom_type_script = "uid://dtuc6qerbfset"
[sub_resource type="Resource" id="Resource_i8wif"]
script = ExtResource("6_sle1e")
behavior = SubResource("Resource_rbgfd")
pattern = SubResource("Resource_xksnv")
textures = Array[Texture2D]([ExtResource("8_uu3sg")])
hitbox_size = Vector2i(6, 6)
metadata/_custom_type_script = "uid://vus1a0flwtnm"
[sub_resource type="Resource" id="Resource_g0u1t"]
script = ExtResource("8_377ep")
preset = SubResource("Resource_i8wif")
metadata/_custom_type_script = "uid://oug6n1t6tnor"
[sub_resource type="Resource" id="Resource_2fp3d"]
script = ExtResource("4_4oowd") script = ExtResource("4_4oowd")
metadata/_custom_type_script = "uid://pn143vuxc7wp" metadata/_custom_type_script = "uid://pn143vuxc7wp"
[sub_resource type="Resource" id="Resource_ufsqg"]
script = ExtResource("10_etmxr")
actions = Array[ExtResource("4_1xo0o")]([SubResource("Resource_g0u1t"), SubResource("Resource_2fp3d")])
metadata/_custom_type_script = "uid://mair8nsxn7lp"
[sub_resource type="Resource" id="Resource_c0i5a"] [sub_resource type="Resource" id="Resource_c0i5a"]
script = ExtResource("4_t1bs8") script = ExtResource("4_t1bs8")
initial_speed = 128.0 initial_speed = 128.0
acceleration = -64.0 acceleration = -64.0
min_speed = 0.0 min_speed = 0.0
action_speed_clamped = SubResource("Resource_ufsqg") action_speed_clamped = SubResource("Resource_sle1e")
metadata/_custom_type_script = "uid://dntp60my5f65m" metadata/_custom_type_script = "uid://dntp60my5f65m"
[sub_resource type="Resource" id="Resource_t1bs8"] [sub_resource type="Resource" id="Resource_cf1so"]
script = ExtResource("5_cf1so") script = ExtResource("6_uu3sg")
bullet_count = 1 bullet_count = 5
line_width = 128.0 metadata/_custom_type_script = "uid://dtuc6qerbfset"
line_normal = Vector2(0.70710677, -0.70710677)
metadata/_custom_type_script = "uid://d238qii8i2byl" [sub_resource type="Resource" id="Resource_4oowd"]
script = ExtResource("7_t1bs8")
rotation_speed = -1.5707963267948966
spawn_rotation_speed = 6.283185307179586
metadata/_custom_type_script = "uid://5scjonwmg8tw"
[sub_resource type="Resource" id="Resource_uu3sg"] [sub_resource type="Resource" id="Resource_uu3sg"]
script = ExtResource("6_sle1e") script = ExtResource("6_sle1e")
behavior = SubResource("Resource_c0i5a") behavior = SubResource("Resource_c0i5a")
pattern = SubResource("Resource_t1bs8")
textures = Array[Texture2D]([ExtResource("4_hlyn7")]) textures = Array[Texture2D]([ExtResource("4_hlyn7")])
hitbox_size = Vector2i(6, 6) hitbox_size = Vector2i(6, 6)
pattern = SubResource("Resource_cf1so")
rounds = 100000 rounds = 100000
round_delay = 1.0 round_delay = 0.5
set_behavior = SubResource("Resource_4oowd")
metadata/_custom_type_script = "uid://vus1a0flwtnm" metadata/_custom_type_script = "uid://vus1a0flwtnm"
[node name="TestScene" type="Node"] [node name="TestScene" type="Node"]

View file

@ -1,32 +0,0 @@
@abstract
class_name BulletBehavior
extends Resource
## Performs behavior-specific initialization for a [Bullet].
func init_bullet(bullet: Bullet) -> void:
bullet.recycled.connect(deinit_bullet.bind(bullet), CONNECT_ONE_SHOT)
_init_bullet(bullet)
## Cleans up behavior-specific state for a [Bullet].
func deinit_bullet(bullet: Bullet) -> void:
_deinit_bullet(bullet)
## Processes one tick of a [Bullet]'s movement.
func process_bullet(bullet: Bullet, delta: float) -> void:
_process_bullet(bullet, delta)
## Called when a [Bullet] is spawned with this behavior in order to set up
## behavior-specific state.
@abstract func _init_bullet(bullet: Bullet) -> void
## Called when a [Bullet] is recycled in order to clean up behavior-specific state.
@abstract func _deinit_bullet(bullet: Bullet) -> void
## Called to process a tick of a [Bullet]'s movement.
@abstract func _process_bullet(bullet: Bullet, delta: float) -> void

View file

@ -97,8 +97,6 @@ func _enter_tree() -> void:
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if not Engine.is_editor_hint(): if not Engine.is_editor_hint():
time_elapsed += delta
if face_direction: if face_direction:
rotation = direction.angle() rotation = direction.angle()

View file

@ -4,7 +4,7 @@ extends BulletAction
## [BulletAction]s to perform when triggered. ## [BulletAction]s to perform when triggered.
@export var actions: Array[BulletAction] @export var actions: Array[BulletAction] = []
func _perform(bullet: Bullet) -> void: func _perform(bullet: Bullet) -> void:

View file

@ -21,6 +21,10 @@ func _perform(bullet: Bullet) -> void:
bullet_set.preset = preset bullet_set.preset = preset
bullet_set.global_position = bullet.global_position bullet_set.global_position = bullet.global_position
if local_coords: if local_coords:
if match_direction:
bullet_set.rotation = bullet.rotation
bullet.get_parent().add_child(bullet_set) bullet.get_parent().add_child(bullet_set)
else: else:
if match_direction:
bullet_set.global_rotation = bullet.global_rotation
bullet.get_parent().get_parent().add_child(bullet_set) bullet.get_parent().get_parent().add_child(bullet_set)

View file

@ -0,0 +1,57 @@
@abstract
class_name BulletBehavior
extends Resource
@export_group("Actions", "action_")
## Delay in seconds before performing [member action_on_delay].
@export_range(0.0, 1.0, 0.01, "or_greater", "suffix:s") var action_delay: float = 0.0
## Performed once the bullet has existed for [member action_delay] seconds.
@export var action_on_delay: BulletAction
## Interval in seconds at which [member action_on_interval] is performed.
@export_range(0.0, 1.0, 0.01, "or_greater", "suffix:s") var action_interval: float = 0.0
## Performed every [member action_interval] seconds.
@export var action_on_interval: BulletAction
var _bullet_interval_cooldowns: Dictionary[Bullet, float] = {}
## Performs behavior-specific initialization for a [Bullet].
func init_bullet(bullet: Bullet) -> void:
if action_on_interval:
_bullet_interval_cooldowns[bullet] = action_interval
bullet.recycled.connect(deinit_bullet.bind(bullet), CONNECT_ONE_SHOT)
_init_bullet(bullet)
## Cleans up behavior-specific state for a [Bullet].
func deinit_bullet(bullet: Bullet) -> void:
_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_interval:
_bullet_interval_cooldowns[bullet] -= delta
if _bullet_interval_cooldowns[bullet] <= 0.0:
_bullet_interval_cooldowns[bullet] += action_interval
_process_bullet(bullet, delta)
## Called when a [Bullet] is spawned with this behavior in order to set up
## behavior-specific state.
@abstract func _init_bullet(bullet: Bullet) -> void
## Called when a [Bullet] is recycled in order to clean up behavior-specific state.
@abstract func _deinit_bullet(bullet: Bullet) -> void
## Called to process a tick of a [Bullet]'s movement.
@abstract func _process_bullet(bullet: Bullet, delta: float) -> void

View file

@ -15,6 +15,8 @@ extends BulletBehavior
@export_custom(0, "suffix:px/s") var max_speed: float = INF @export_custom(0, "suffix:px/s") var max_speed: float = INF
@export_group("Actions", "action_") @export_group("Actions", "action_")
## Performed when the bullet reaches either [member min_speed] or
## [member max_speed] for the first time.
@export var action_speed_clamped: BulletAction @export var action_speed_clamped: BulletAction

View file

@ -1,16 +1,17 @@
class_name BulletPreset class_name BulletPreset
extends Resource extends Resource
@export_group("Bullets")
@export var behavior: BulletBehavior = null @export var behavior: BulletBehavior = null
@export var pattern: BulletSpawnPattern = null
@export var textures: Array[Texture2D] = [] @export var textures: Array[Texture2D] = []
@export var hitbox_size: Vector2i = Vector2i.ZERO @export var hitbox_size: Vector2i = Vector2i.ZERO
@export var face_direction: bool = false @export var face_direction: bool = false
@export_group("Spawning")
@export var pattern: BulletSpawnPattern = null
@export var rounds: int = 1 @export var rounds: int = 1
@export var round_delay: float = 0.0 @export var round_delay: float = 0.0
@export_group("Bullet Set")
@export var set_behavior: BulletSetBehavior = null

View file

@ -5,6 +5,10 @@ extends Node2D
@export var preset: BulletPreset @export var preset: BulletPreset
var spawn_offset: Vector2 = Vector2.ZERO
var spawn_rotation: float = 0.0
func _ready() -> void: func _ready() -> void:
for _n in preset.rounds: for _n in preset.rounds:
preset.pattern.spawn_bullets(self, preset) preset.pattern.spawn_bullets(self, preset)
@ -14,6 +18,10 @@ func _ready() -> void:
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if get_child_count() == 0: if get_child_count() == 0:
queue_free() queue_free()
if preset.set_behavior:
preset.set_behavior.process_set(self, delta)
for bullet in get_children(): for bullet in get_children():
if bullet is Bullet: if bullet is Bullet:
preset.behavior.process_bullet(bullet, delta) preset.behavior.process_bullet(bullet, delta)

View file

@ -0,0 +1,12 @@
@abstract
class_name BulletSetBehavior
extends Resource
## Process one physics tick for a [BulletSet].
func process_set(bullet_set: BulletSet, delta: float) -> void:
_process_set(bullet_set, delta)
## Called once ever physics tick for the [BulletSet].
@abstract func _process_set(bullet_set: BulletSet, delta: float) -> void

View file

@ -0,0 +1 @@
uid://cu4iq25sb3y5f

View file

@ -0,0 +1,11 @@
class_name MultiSetBehavior
extends BulletSetBehavior
## Processes multiple [BulletSetBehavior]s in order for the [BulletSet].
@export var behaviors: Array[BulletSetBehavior] = []
func _process_set(bullet_set: BulletSet, delta: float) -> void:
for behavior in behaviors:
behavior.process_set(bullet_set, delta)

View file

@ -0,0 +1 @@
uid://cijy4yedxklfd

View file

@ -0,0 +1,11 @@
class_name RotationSetBehavior
extends BulletSetBehavior
@export_custom(0, "radians_as_degrees,suffix:°/s") var rotation_speed: float = 0.0
@export_custom(0, "radians_as_degrees,suffix:°/s") var spawn_rotation_speed: float = 0.0
func _process_set(bullet_set: BulletSet, delta: float) -> void:
bullet_set.rotation += rotation_speed * delta
bullet_set.spawn_rotation += spawn_rotation_speed * delta

View file

@ -0,0 +1 @@
uid://5scjonwmg8tw

View file

@ -16,11 +16,11 @@ func spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void:
preset.face_direction preset.face_direction
) )
var line = line_normal.orthogonal() var line = line_normal.orthogonal().rotated(bullet_set.spawn_rotation)
var weight = float(i) / float(bullet_count - 1) var weight = float(i) / float(bullet_count - 1)
weight -= 0.5 weight -= 0.5
if bullet_count == 1: if bullet_count == 1:
weight = 0.0 weight = 0.0
bullet.position = line * weight * line_width bullet.position = bullet_set.spawn_offset + line * weight * line_width
bullet_set.add_bullet(bullet) bullet_set.add_bullet(bullet)

View file

@ -10,12 +10,12 @@ extends BulletSpawnPattern
func spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void: func spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void:
for i in bullet_count: for i in bullet_count:
var angle = (float(i) / float(bullet_count)) * TAU + angle_offset var angle = (float(i) / float(bullet_count)) * TAU + angle_offset + bullet_set.spawn_rotation
var bullet = Bullet.create( var bullet = Bullet.create(
preset.textures.pick_random(), preset.textures.pick_random(),
preset.hitbox_size, preset.hitbox_size,
Vector2.from_angle(angle + direction_rotation), Vector2.from_angle(angle + direction_rotation),
preset.face_direction preset.face_direction
) )
bullet.position = Vector2.from_angle(angle) * distance_offset bullet.position = bullet_set.spawn_offset + Vector2.from_angle(angle) * distance_offset
bullet_set.add_bullet(bullet) bullet_set.add_bullet(bullet)