yes, they canjj st!
This commit is contained in:
parent
6b92473eeb
commit
a6421235f8
22 changed files with 510 additions and 14 deletions
121
addons/fogwaves_exports/inspectors.gd
Normal file
121
addons/fogwaves_exports/inspectors.gd
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
extends EditorInspectorPlugin
|
||||
|
||||
|
||||
func _can_handle(object: Object) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
|
||||
if type == TYPE_VECTOR2 and hint_string == "direction":
|
||||
add_property_editor(name, DirectionInspector.new(), false)
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
class DirectionInspector extends EditorProperty:
|
||||
var angle_selector: AngleSelector
|
||||
var snap_toggle: TextureButton
|
||||
var snap_spinbox: SpinBox
|
||||
|
||||
var current_value: Vector2
|
||||
var updating := false
|
||||
var snap := false
|
||||
var snap_amount: int = 0
|
||||
|
||||
func _init() -> void:
|
||||
var hbox = HBoxContainer.new()
|
||||
hbox.alignment = BoxContainer.ALIGNMENT_BEGIN
|
||||
add_child(hbox)
|
||||
|
||||
var vbox = VBoxContainer.new()
|
||||
vbox.alignment = BoxContainer.ALIGNMENT_BEGIN
|
||||
vbox.add_theme_constant_override(&"separation", 4)
|
||||
vbox.add_spacer(true)
|
||||
hbox.add_child(vbox)
|
||||
|
||||
snap_toggle = TextureButton.new()
|
||||
snap_toggle.toggle_mode = true
|
||||
snap_toggle.toggled.connect(_on_snap_toggled)
|
||||
snap_toggle.texture_normal = EditorInterface.get_editor_theme().get_icon(&"Snap", &"EditorIcons")
|
||||
snap_toggle.texture_pressed = snap_toggle.texture_normal
|
||||
snap_toggle.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
snap_toggle.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT
|
||||
vbox.add_child(snap_toggle)
|
||||
|
||||
snap_spinbox = SpinBox.new()
|
||||
snap_spinbox.editable = false
|
||||
snap_spinbox.rounded = true
|
||||
snap_spinbox.value_changed.connect(_on_snap_amount_changed)
|
||||
snap_spinbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
snap_spinbox.custom_minimum_size = Vector2.ZERO
|
||||
vbox.add_child(snap_spinbox)
|
||||
|
||||
angle_selector = AngleSelector.new()
|
||||
angle_selector.direction_clicked.connect(_on_direction_clicked)
|
||||
hbox.add_child(angle_selector)
|
||||
add_focusable(angle_selector)
|
||||
|
||||
custom_minimum_size = get_combined_minimum_size()
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
|
||||
_refresh()
|
||||
|
||||
func _update_property() -> void:
|
||||
var new_value: Vector2 = get_edited_object()[get_edited_property()]
|
||||
if new_value == current_value:
|
||||
return
|
||||
|
||||
updating = true
|
||||
current_value = new_value
|
||||
_refresh()
|
||||
updating = false
|
||||
|
||||
func _refresh() -> void:
|
||||
angle_selector.direction = current_value
|
||||
|
||||
func _on_direction_clicked(direction: Vector2) -> void:
|
||||
if updating:
|
||||
return
|
||||
|
||||
current_value = direction
|
||||
if snap and snap_amount > 0:
|
||||
var angle = direction.angle()
|
||||
var steps = PI * 0.5 / float(snap_amount)
|
||||
angle = roundf(angle / steps) * steps
|
||||
current_value = Vector2.from_angle(angle)
|
||||
_refresh()
|
||||
emit_changed(get_edited_property(), current_value)
|
||||
|
||||
func _on_snap_toggled(toggled_on: bool) -> void:
|
||||
snap = toggled_on
|
||||
snap_spinbox.editable = snap
|
||||
if toggled_on:
|
||||
snap_toggle.modulate = EditorInterface.get_editor_theme().get_color(&"accent_color", &"Editor")
|
||||
else:
|
||||
snap_toggle.modulate = Color.WHITE
|
||||
|
||||
func _on_snap_amount_changed(value: float) -> void:
|
||||
snap_amount = maxi(0, int(value))
|
||||
|
||||
class AngleSelector extends Control:
|
||||
signal direction_clicked(direction: Vector2)
|
||||
|
||||
var direction: Vector2:
|
||||
set(value):
|
||||
direction = value.normalized()
|
||||
queue_redraw()
|
||||
|
||||
func _init() -> void:
|
||||
custom_minimum_size = Vector2(48.0, 48.0)
|
||||
focus_mode = Control.FOCUS_CLICK
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton or event is InputEventMouseMotion:
|
||||
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
|
||||
direction_clicked.emit((size * 0.5).direction_to(get_local_mouse_position()))
|
||||
|
||||
func _draw() -> void:
|
||||
var center = size * 0.5
|
||||
var radius = minf(center.x, center.y)
|
||||
draw_circle(center, radius, Color.WHITE, false)
|
||||
draw_line(center, center + direction * radius, Color.RED, 2.0)
|
||||
1
addons/fogwaves_exports/inspectors.gd.uid
Normal file
1
addons/fogwaves_exports/inspectors.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bp816dbdpjcae
|
||||
7
addons/fogwaves_exports/plugin.cfg
Normal file
7
addons/fogwaves_exports/plugin.cfg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="Fogwaves Export Helpers"
|
||||
description="Various custom inspector plugins."
|
||||
author="fogwaves"
|
||||
version=""
|
||||
script="plugin.gd"
|
||||
17
addons/fogwaves_exports/plugin.gd
Normal file
17
addons/fogwaves_exports/plugin.gd
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
const Inspectors = preload("inspectors.gd")
|
||||
|
||||
|
||||
var inspector_plugin: Inspectors
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
inspector_plugin = Inspectors.new()
|
||||
add_inspector_plugin(inspector_plugin)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_inspector_plugin(inspector_plugin)
|
||||
1
addons/fogwaves_exports/plugin.gd.uid
Normal file
1
addons/fogwaves_exports/plugin.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://mgh5g40ugy83
|
||||
|
|
@ -28,12 +28,18 @@ window/size/viewport_width=240
|
|||
window/size/viewport_height=320
|
||||
window/vsync/vsync_mode=0
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/fogwaves_exports/plugin.cfg")
|
||||
|
||||
[file_customization]
|
||||
|
||||
folder_colors={
|
||||
"res://addons/": "gray",
|
||||
"res://globals/": "orange",
|
||||
"res://objects/": "blue",
|
||||
"res://scenes/": "teal"
|
||||
"res://scenes/": "teal",
|
||||
"res://systems/": "red"
|
||||
}
|
||||
|
||||
[input]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,34 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://dxsp66qpvm65b"]
|
||||
[gd_scene load_steps=11 format=3 uid="uid://dxsp66qpvm65b"]
|
||||
|
||||
[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="Script" uid="uid://ntpaank0h0a0" path="res://systems/bullets/bullet.gd" id="3_hlyn7"]
|
||||
[ext_resource type="Texture2D" uid="uid://xe124f1kgf3x" path="res://graphics/bullets/normal_bullet/bullet_2.png" id="4_hlyn7"]
|
||||
[ext_resource type="Script" uid="uid://cj2fj7snls8aa" path="res://systems/bullets/bullet_set.gd" id="3_cf1so"]
|
||||
[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://dtuc6qerbfset" path="res://systems/bullets/spawn_patterns/ring_pattern.gd" id="5_4oowd"]
|
||||
[ext_resource type="Script" uid="uid://vus1a0flwtnm" path="res://systems/bullets/bullet_preset.gd" id="6_sle1e"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_c0i5a"]
|
||||
script = ExtResource("4_t1bs8")
|
||||
acceleration = 64.0
|
||||
metadata/_custom_type_script = "uid://dntp60my5f65m"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_1xo0o"]
|
||||
script = ExtResource("5_4oowd")
|
||||
bullet_count = 5
|
||||
distance_offset = 16.0
|
||||
direction_rotation = 3.9269908169872414
|
||||
metadata/_custom_type_script = "uid://dtuc6qerbfset"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_uu3sg"]
|
||||
script = ExtResource("6_sle1e")
|
||||
behavior = SubResource("Resource_c0i5a")
|
||||
pattern = SubResource("Resource_1xo0o")
|
||||
textures = Array[Texture2D]([ExtResource("4_hlyn7")])
|
||||
hitbox_size = Vector2i(6, 6)
|
||||
rounds = 5
|
||||
round_delay = 1.0
|
||||
metadata/_custom_type_script = "uid://vus1a0flwtnm"
|
||||
|
||||
[node name="TestScene" type="Node"]
|
||||
|
||||
|
|
@ -14,9 +39,8 @@ texture = ExtResource("1_g7g4h")
|
|||
[node name="Player" parent="." instance=ExtResource("2_j8ivh")]
|
||||
position = Vector2(100, 99)
|
||||
|
||||
[node name="Bullet" type="Area2D" parent="."]
|
||||
position = Vector2(169, 130)
|
||||
script = ExtResource("3_hlyn7")
|
||||
texture = ExtResource("4_hlyn7")
|
||||
hitbox_size = Vector2i(6, 6)
|
||||
metadata/_custom_type_script = "uid://ntpaank0h0a0"
|
||||
[node name="BulletSet" type="Node2D" parent="."]
|
||||
position = Vector2(110, 192)
|
||||
script = ExtResource("3_cf1so")
|
||||
preset = SubResource("Resource_uu3sg")
|
||||
metadata/_custom_type_script = "uid://cj2fj7snls8aa"
|
||||
|
|
|
|||
12
systems/bullets/behaviors/bullet_behavior.gd
Normal file
12
systems/bullets/behaviors/bullet_behavior.gd
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
@abstract
|
||||
class_name BulletBehavior
|
||||
extends Resource
|
||||
|
||||
|
||||
## Called when a bullet is spawned with this behavior in order to set up
|
||||
## behavior-specific state.
|
||||
@warning_ignore("unused_parameter")
|
||||
func init_bullet(bullet: Bullet) -> void: pass
|
||||
|
||||
## Called to process a tick of a bullet's movement.
|
||||
@abstract func process_bullet(bullet: Bullet, delta: float) -> void
|
||||
1
systems/bullets/behaviors/bullet_behavior.gd.uid
Normal file
1
systems/bullets/behaviors/bullet_behavior.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://djcajenyac4sd
|
||||
15
systems/bullets/behaviors/simple_linear_behavior.gd
Normal file
15
systems/bullets/behaviors/simple_linear_behavior.gd
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
class_name SimpleLinearBehavior
|
||||
extends BulletBehavior
|
||||
## Makes bullets move in [member Bullet.direction], potentially accelerating.
|
||||
|
||||
|
||||
## Initial speed of the bullet when it is spawned.
|
||||
@export_custom(0, "suffix:px/s") var initial_speed: float = 0.0
|
||||
|
||||
## Rate at which the bullet will speed up.
|
||||
@export_custom(0, "suffix:px/s²") var acceleration: float = 0.0
|
||||
|
||||
|
||||
func process_bullet(bullet: Bullet, delta: float) -> void:
|
||||
var speed = initial_speed + acceleration * bullet.time_elapsed
|
||||
bullet.position += bullet.direction * speed * delta
|
||||
1
systems/bullets/behaviors/simple_linear_behavior.gd.uid
Normal file
1
systems/bullets/behaviors/simple_linear_behavior.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dntp60my5f65m
|
||||
|
|
@ -1,17 +1,22 @@
|
|||
@tool
|
||||
@icon("bullet.svg")
|
||||
class_name Bullet
|
||||
extends Area2D
|
||||
|
||||
|
||||
static var _hitbox_shapes: Dictionary[Vector2i, RectangleShape2D] = {}
|
||||
## The number of bullets to allocate at startup.
|
||||
const INITIAL_ALLOCATED_BULLETS: int = 2000
|
||||
|
||||
|
||||
@export var texture: Texture2D:
|
||||
## Texture to draw for the bullet.
|
||||
@export var texture: Texture2D = null:
|
||||
set(value):
|
||||
texture = value
|
||||
queue_redraw()
|
||||
_update_visibility_notifier()
|
||||
|
||||
@export var hitbox_size: Vector2i:
|
||||
## Size of the bullet's collision box.
|
||||
@export var hitbox_size: Vector2i = Vector2i.ZERO:
|
||||
set(value):
|
||||
hitbox_size = value
|
||||
if not _hitbox_shapes.has(hitbox_size):
|
||||
|
|
@ -20,18 +25,100 @@ static var _hitbox_shapes: Dictionary[Vector2i, RectangleShape2D] = {}
|
|||
_hitbox_shapes[hitbox_size] = new_shape
|
||||
_hitbox.shape = _hitbox_shapes[hitbox_size]
|
||||
|
||||
## The direction that the bullet is travelling.
|
||||
@export_custom(0, "direction") var direction: Vector2 = Vector2.RIGHT
|
||||
|
||||
## If [code]true[/code], the bullet will always rotate to face toward [member direction].
|
||||
@export var face_direction: bool = false
|
||||
|
||||
|
||||
## The amount of time in seconds that the bullet has existed.
|
||||
var time_elapsed: float = 0.0
|
||||
|
||||
|
||||
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(
|
||||
texture: Texture2D = null,
|
||||
hitbox_size: Vector2i = Vector2i.ZERO,
|
||||
direction: Vector2 = Vector2.RIGHT,
|
||||
face_direction: bool = false,
|
||||
) -> Bullet:
|
||||
var bullet: Bullet = _cached_bullets.pop_back()
|
||||
if not bullet:
|
||||
bullet = Bullet.new()
|
||||
|
||||
bullet.texture = texture
|
||||
bullet.hitbox_size = hitbox_size
|
||||
bullet.direction = direction
|
||||
bullet.face_direction = face_direction
|
||||
bullet.time_elapsed = 0.0
|
||||
|
||||
return bullet
|
||||
|
||||
|
||||
## Removes the bullet from the scene tree and returns it to the bullet cache to be
|
||||
## re-used later.
|
||||
func recycle() -> void:
|
||||
get_parent().remove_child(self)
|
||||
_cached_bullets.append(self)
|
||||
|
||||
|
||||
static func _static_init() -> void:
|
||||
for _i in INITIAL_ALLOCATED_BULLETS:
|
||||
_cached_bullets.append(Bullet.new())
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
monitoring = false
|
||||
add_to_group(&"bullets")
|
||||
_hitbox.debug_color.a = 0.0
|
||||
add_child(_hitbox)
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
_update_visibility_notifier()
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
time_elapsed += delta
|
||||
|
||||
if face_direction:
|
||||
rotation = direction.angle()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if texture:
|
||||
draw_texture(texture, -texture.get_size() * 0.5)
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
return []
|
||||
|
||||
|
||||
# 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:
|
||||
if not texture or not is_inside_tree() or Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
# the visibility rect is set to twice the size of the texture to add a little margin
|
||||
# (func(): pass) is the cleanest way i could think of to have a callback that does nothing
|
||||
RenderingServer.canvas_item_set_visibility_notifier(
|
||||
get_canvas_item(), true,
|
||||
Rect2(-texture.get_size(), texture.get_size() * 2.0),
|
||||
(func(): pass), _on_screen_exited
|
||||
)
|
||||
|
||||
|
||||
# called when the bullet leaves the screen.
|
||||
func _on_screen_exited() -> void:
|
||||
recycle()
|
||||
|
|
|
|||
82
systems/bullets/bullet.svg
Normal file
82
systems/bullets/bullet.svg
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="bullet.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
id="a"
|
||||
x2="0"
|
||||
y1="2"
|
||||
y2="14"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(4)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#ff8dbc"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset=".4"
|
||||
stop-color="#7260ff"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset=".6"
|
||||
stop-color="#7260ff"
|
||||
id="stop3" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#74c9ff"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="10.995366"
|
||||
inkscape:cx="8.7309506"
|
||||
inkscape:cy="10.049688"
|
||||
inkscape:window-width="1358"
|
||||
inkscape:window-height="742"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
style="fill:#8da5f3;fill-opacity:1;stroke-width:3.78"
|
||||
d="M 1.3983532,8.3266862 6.414829,13.926473 7.737001,12.526527 2.7594126,7.160064 Z"
|
||||
id="path2"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#8da5f3;fill-opacity:1;stroke-width:3.78"
|
||||
d="M 3.4711505,6.74088 8.3320767,11.951793 13.465215,7.2075289 C 14.904049,5.69092 16.498433,3.3965627 14.554063,1.5299671 13.270778,-0.10330412 11.326407,0.36334478 9.1098249,2.0743908 Z"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:#8da5f3;fill-opacity:1;stroke-width:3.78"
|
||||
d="M 3.2131098,11.837773 1.056944,14.71266 4.1432206,12.810161 Z"
|
||||
id="path5"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:#8da5f3;fill-opacity:1;stroke-width:3.78"
|
||||
d="M 4.8196647,13.40205 2.5789434,15.219994 5.4538311,14.247606 Z"
|
||||
id="path6" />
|
||||
<path
|
||||
style="fill:#8da5f3;fill-opacity:1;stroke-width:3.78"
|
||||
d="M 1.4797216,10.019829 0.42277761,12.979273 2.3252768,10.992217 Z"
|
||||
id="path7"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
43
systems/bullets/bullet.svg.import
Normal file
43
systems/bullets/bullet.svg.import
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://73kflfycjlft"
|
||||
path="res://.godot/imported/bullet.svg-bd5de27a67ea13ec7922f62f013cca2b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://systems/bullets/bullet.svg"
|
||||
dest_files=["res://.godot/imported/bullet.svg-bd5de27a67ea13ec7922f62f013cca2b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
16
systems/bullets/bullet_preset.gd
Normal file
16
systems/bullets/bullet_preset.gd
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
class_name BulletPreset
|
||||
extends Resource
|
||||
|
||||
@export var behavior: BulletBehavior = null
|
||||
|
||||
@export var pattern: BulletSpawnPattern = null
|
||||
|
||||
@export var textures: Array[Texture2D] = []
|
||||
|
||||
@export var hitbox_size: Vector2i = Vector2i.ZERO
|
||||
|
||||
@export var face_direction: bool = false
|
||||
|
||||
@export var rounds: int = 1
|
||||
|
||||
@export var round_delay: float = 0.0
|
||||
1
systems/bullets/bullet_preset.gd.uid
Normal file
1
systems/bullets/bullet_preset.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://vus1a0flwtnm
|
||||
31
systems/bullets/bullet_set.gd
Normal file
31
systems/bullets/bullet_set.gd
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
class_name BulletSet
|
||||
extends Node2D
|
||||
|
||||
|
||||
@export var preset: BulletPreset
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for _n in preset.rounds:
|
||||
preset.pattern.spawn_bullets(self, preset)
|
||||
await get_tree().create_timer(preset.round_delay, false, true).timeout
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
for bullet in get_children():
|
||||
if bullet is Bullet:
|
||||
preset.behavior.process_bullet(bullet, delta)
|
||||
else:
|
||||
push_error("BulletSet does not support having non-bullet children. Removing child: ", bullet)
|
||||
bullet.queue_free()
|
||||
|
||||
|
||||
func add_bullet(bullet: Bullet) -> void:
|
||||
preset.behavior.init_bullet(bullet)
|
||||
add_child(bullet)
|
||||
|
||||
|
||||
func add_bullets(new_bullets: Array[Bullet]) -> void:
|
||||
for bullet in new_bullets:
|
||||
preset.behavior.init_bullet(bullet)
|
||||
add_child(bullet)
|
||||
1
systems/bullets/bullet_set.gd.uid
Normal file
1
systems/bullets/bullet_set.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cj2fj7snls8aa
|
||||
6
systems/bullets/spawn_patterns/bullet_spawn_pattern.gd
Normal file
6
systems/bullets/spawn_patterns/bullet_spawn_pattern.gd
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
@abstract
|
||||
class_name BulletSpawnPattern
|
||||
extends Resource
|
||||
|
||||
|
||||
@abstract func spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bhy0mkwfsi5j8
|
||||
21
systems/bullets/spawn_patterns/ring_pattern.gd
Normal file
21
systems/bullets/spawn_patterns/ring_pattern.gd
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
class_name RingPattern
|
||||
extends BulletSpawnPattern
|
||||
|
||||
|
||||
@export var bullet_count: int
|
||||
@export var distance_offset: float
|
||||
@export_custom(0, "radians_as_degrees") var angle_offset: float
|
||||
@export_custom(0, "radians_as_degrees") var direction_rotation: float
|
||||
|
||||
|
||||
func spawn_bullets(bullet_set: BulletSet, preset: BulletPreset) -> void:
|
||||
for i in bullet_count:
|
||||
var angle = (float(i) / float(bullet_count)) * TAU + angle_offset
|
||||
var bullet = Bullet.create(
|
||||
preset.textures.pick_random(),
|
||||
preset.hitbox_size,
|
||||
Vector2.from_angle(angle + direction_rotation),
|
||||
preset.face_direction
|
||||
)
|
||||
bullet.position = Vector2.from_angle(angle) * distance_offset
|
||||
bullet_set.add_bullet(bullet)
|
||||
1
systems/bullets/spawn_patterns/ring_pattern.gd.uid
Normal file
1
systems/bullets/spawn_patterns/ring_pattern.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dtuc6qerbfset
|
||||
Loading…
Add table
Add a link
Reference in a new issue