Separated shot positioning math to helper utility and refactored shoot
component - introduced shot origin issue.
This commit is contained in:
parent
6c5a0a0bae
commit
99a5d9838d
17 changed files with 147 additions and 98 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_mhej7")
|
script = ExtResource("1_mhej7")
|
||||||
|
pattern_name = "fwd"
|
||||||
bullet_count = 5
|
bullet_count = 5
|
||||||
group_delay = 5.0
|
group_delay = 5.0
|
||||||
stagger_offset = 2.0
|
stagger_offset = 2.0
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ddpclu2vdy2ve" path="res://scenes/player_weapons/weapon_stock.tscn" id="1_pn64g"]
|
[ext_resource type="PackedScene" uid="uid://ddpclu2vdy2ve" path="res://scenes/player_weapons/weapon_stock.tscn" id="1_pn64g"]
|
||||||
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_4b7mw"]
|
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_4b7mw"]
|
||||||
|
[ext_resource type="Script" uid="uid://d0ios82vubijg" path="res://scripts/weapon_projectile_group.gd" id="2_ak5x4"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("2_4b7mw")
|
script = ExtResource("2_4b7mw")
|
||||||
|
|
@ -10,8 +11,6 @@ bullet_scene = ExtResource("1_pn64g")
|
||||||
damage = 5
|
damage = 5
|
||||||
speed = 720
|
speed = 720
|
||||||
projectiles = 5
|
projectiles = 5
|
||||||
spacing = 100.0
|
|
||||||
origin = -15
|
|
||||||
horizontal_offset = 8.25
|
horizontal_offset = 8.25
|
||||||
spread_angle = 25.0
|
spread_angle = 25.0
|
||||||
stagger_offset = 0.5
|
stagger_offset = 0.5
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
[gd_resource type="Resource" script_class="WeaponShot" format=3 uid="uid://b75ae840k03dy"]
|
[gd_resource type="Resource" script_class="WeaponShot" format=3 uid="uid://b75ae840k03dy"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ddpclu2vdy2ve" path="res://scenes/player_weapons/weapon_stock.tscn" id="1_lcw6o"]
|
[ext_resource type="PackedScene" uid="uid://ddpclu2vdy2ve" path="res://scenes/player_weapons/weapon_stock.tscn" id="1_lcw6o"]
|
||||||
|
[ext_resource type="Script" uid="uid://d0ios82vubijg" path="res://scripts/weapon_projectile_group.gd" id="2_e245k"]
|
||||||
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_ym48c"]
|
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_ym48c"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
|
|
@ -9,8 +10,6 @@ shot_name = "stock"
|
||||||
bullet_scene = ExtResource("1_lcw6o")
|
bullet_scene = ExtResource("1_lcw6o")
|
||||||
damage = 2
|
damage = 2
|
||||||
speed = 650
|
speed = 650
|
||||||
spacing = 25.0
|
|
||||||
origin = -15
|
|
||||||
horizontal_offset = 12.0
|
horizontal_offset = 12.0
|
||||||
stagger_offset = 0.0
|
stagger_offset = 0.0
|
||||||
metadata/_custom_type_script = "uid://7n1itonn35fm"
|
metadata/_custom_type_script = "uid://7n1itonn35fm"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
[gd_resource type="Resource" script_class="WeaponShot" format=3 uid="uid://cck3gmnhu5agc"]
|
[gd_resource type="Resource" script_class="WeaponShot" format=3 uid="uid://cck3gmnhu5agc"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://clpyd8qfwthk2" path="res://scenes/player_weapons/weapon_spreadshot.tscn" id="1_07hyh"]
|
[ext_resource type="PackedScene" uid="uid://clpyd8qfwthk2" path="res://scenes/player_weapons/weapon_spreadshot.tscn" id="1_07hyh"]
|
||||||
|
[ext_resource type="Script" uid="uid://d0ios82vubijg" path="res://scripts/weapon_projectile_group.gd" id="2_bhv8k"]
|
||||||
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_syw6j"]
|
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_syw6j"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
|
|
@ -10,8 +11,6 @@ bullet_scene = ExtResource("1_07hyh")
|
||||||
damage = 3
|
damage = 3
|
||||||
speed = 700
|
speed = 700
|
||||||
projectiles = 3
|
projectiles = 3
|
||||||
spacing = 45.0
|
|
||||||
origin = -15
|
|
||||||
horizontal_offset = 12.5
|
horizontal_offset = 12.5
|
||||||
stagger_offset = 0.35
|
stagger_offset = 0.35
|
||||||
stagger_animation = true
|
stagger_animation = true
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ bullet_scene = ExtResource("1_lqlv8")
|
||||||
damage = 5
|
damage = 5
|
||||||
speed = 500
|
speed = 500
|
||||||
projectiles = 5
|
projectiles = 5
|
||||||
spacing = 30.0
|
|
||||||
origin = -15
|
|
||||||
horizontal_offset = 8.25
|
horizontal_offset = 8.25
|
||||||
stagger_offset = 0.5
|
stagger_offset = 0.5
|
||||||
stagger_animation = true
|
stagger_animation = true
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ddpclu2vdy2ve" path="res://scenes/player_weapons/weapon_stock.tscn" id="1_hm46f"]
|
[ext_resource type="PackedScene" uid="uid://ddpclu2vdy2ve" path="res://scenes/player_weapons/weapon_stock.tscn" id="1_hm46f"]
|
||||||
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_w7xlm"]
|
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="2_w7xlm"]
|
||||||
|
[ext_resource type="Script" uid="uid://d0ios82vubijg" path="res://scripts/weapon_projectile_group.gd" id="2_xf183"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("2_w7xlm")
|
script = ExtResource("2_w7xlm")
|
||||||
|
|
@ -10,8 +11,6 @@ bullet_scene = ExtResource("1_hm46f")
|
||||||
damage = 5
|
damage = 5
|
||||||
speed = 500
|
speed = 500
|
||||||
projectiles = 5
|
projectiles = 5
|
||||||
spacing = 30.0
|
|
||||||
origin = -15
|
|
||||||
horizontal_offset = 8.25
|
horizontal_offset = 8.25
|
||||||
stagger_offset = 0.5
|
stagger_offset = 0.5
|
||||||
stagger_animation = true
|
stagger_animation = true
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
[ext_resource type="Script" uid="uid://ylmao2ndp22y" path="res://scripts/weapon_component.gd" id="7_d2wvv"]
|
[ext_resource type="Script" uid="uid://ylmao2ndp22y" path="res://scripts/weapon_component.gd" id="7_d2wvv"]
|
||||||
[ext_resource type="Resource" uid="uid://b75ae840k03dy" path="res://resources/player_weapon_resources/stock.tres" id="8_stock"]
|
[ext_resource type="Resource" uid="uid://b75ae840k03dy" path="res://resources/player_weapon_resources/stock.tres" id="8_stock"]
|
||||||
[ext_resource type="Resource" uid="uid://bhc6aja38vyr" path="res://resources/player_weapon_resources/vanguard.tres" id="9_ur7pv"]
|
[ext_resource type="Resource" uid="uid://bhc6aja38vyr" path="res://resources/player_weapon_resources/vanguard.tres" id="9_ur7pv"]
|
||||||
|
[ext_resource type="Script" uid="uid://znfh8unmdxkvv" path="res://scripts/weapon_fire_helper.gd" id="15_firehelper"]
|
||||||
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="10_d2wvv"]
|
[ext_resource type="Script" uid="uid://7n1itonn35fm" path="res://scripts/weapon_shot.gd" id="10_d2wvv"]
|
||||||
[ext_resource type="Resource" uid="uid://cck3gmnhu5agc" path="res://resources/player_weapon_resources/tri.tres" id="11_3v2ag"]
|
[ext_resource type="Resource" uid="uid://cck3gmnhu5agc" path="res://resources/player_weapon_resources/tri.tres" id="11_3v2ag"]
|
||||||
[ext_resource type="Script" uid="uid://65d3hbrpm21x" path="res://scripts/effects_component.gd" id="12_effcomp"]
|
[ext_resource type="Script" uid="uid://65d3hbrpm21x" path="res://scripts/effects_component.gd" id="12_effcomp"]
|
||||||
|
|
@ -151,6 +152,10 @@ player = NodePath("..")
|
||||||
speed = 200.0
|
speed = 200.0
|
||||||
metadata/_custom_type_script = "uid://c0rikbakpcags"
|
metadata/_custom_type_script = "uid://c0rikbakpcags"
|
||||||
|
|
||||||
|
[node name="WeaponFireHelper" type="Node" parent="." unique_id=623642426]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
script = ExtResource("15_firehelper")
|
||||||
|
|
||||||
[node name="ShootComponent" type="Node" parent="." unique_id=623642425]
|
[node name="ShootComponent" type="Node" parent="." unique_id=623642425]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
script = ExtResource("6_y4r1p")
|
script = ExtResource("6_y4r1p")
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ extends Node
|
||||||
|
|
||||||
@warning_ignore_start("unused_signal") # since otherwise Godot will throw a warning that the signal is unused in current scope
|
@warning_ignore_start("unused_signal") # since otherwise Godot will throw a warning that the signal is unused in current scope
|
||||||
|
|
||||||
signal weapon_changed(weapon_name: String, player_node: Node2D, player_sprite_size: Vector2, origin_offset: float)
|
signal weapon_changed(weapon_name: String, player_node: Node2D, player_sprite_size: Vector2, origin_offset: Vector2)
|
||||||
|
|
||||||
@warning_ignore_restore("unused_signal")
|
@warning_ignore_restore("unused_signal")
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ func tick(delta: float):
|
||||||
# Calculate ship to bullet displacement
|
# Calculate ship to bullet displacement
|
||||||
player.ship_displacement = player.position.y - player.previous_position.y
|
player.ship_displacement = player.position.y - player.previous_position.y
|
||||||
player.travel += abs(weapon_system.speed) * delta + (player.ship_displacement)
|
player.travel += abs(weapon_system.speed) * delta + (player.ship_displacement)
|
||||||
player.travel = clamp(player.travel, 0, 1.9 * weapon_system.spacing)
|
player.travel = clamp(player.travel, 0, 1.9 * weapon_system.projectile_vertical_spacing)
|
||||||
|
|
||||||
# Thruster animation in relation to player movement
|
# Thruster animation in relation to player movement
|
||||||
if input.x > 0:
|
if input.x > 0:
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ class_name NotificationDisplay extends Control
|
||||||
|
|
||||||
var _player: Node2D = null
|
var _player: Node2D = null
|
||||||
var _sprite_size: Vector2 = Vector2.ZERO
|
var _sprite_size: Vector2 = Vector2.ZERO
|
||||||
var _origin_offset: float = 0.0
|
var _origin_offset: Vector2 = Vector2.ZERO
|
||||||
var _follow_player: bool = false
|
var _follow_player: bool = false
|
||||||
|
|
||||||
var _connector_line: Line2D = null
|
var _connector_line: Line2D = null
|
||||||
|
|
@ -23,7 +23,7 @@ func _ready() -> void:
|
||||||
_container.add_theme_constant_override("margin_right", 4)
|
_container.add_theme_constant_override("margin_right", 4)
|
||||||
|
|
||||||
|
|
||||||
func show_notification(weapon_name: String, player_node: Node2D, player_sprite_size: Vector2, origin_offset: float) -> void:
|
func show_notification(weapon_name: String, player_node: Node2D, player_sprite_size: Vector2, origin_offset: Vector2) -> void:
|
||||||
modulate.a = 0.0
|
modulate.a = 0.0
|
||||||
|
|
||||||
label.add_theme_font_size_override("font_size", 8)
|
label.add_theme_font_size_override("font_size", 8)
|
||||||
|
|
@ -107,7 +107,7 @@ func _update_position() -> void:
|
||||||
var player_pos = _player.position
|
var player_pos = _player.position
|
||||||
|
|
||||||
# Y position uses the weapon origin offset from player center
|
# Y position uses the weapon origin offset from player center
|
||||||
var notif_y = player_pos.y + _origin_offset - (size.y / 2.0)
|
var notif_y = player_pos.y + _origin_offset.y - (size.y / 2.0)
|
||||||
|
|
||||||
# X position is 10px to the right of player's sprite edge
|
# X position is 10px to the right of player's sprite edge
|
||||||
var right_edge = player_pos.x + (_sprite_size.x / 2.0)
|
var right_edge = player_pos.x + (_sprite_size.x / 2.0)
|
||||||
|
|
@ -164,7 +164,7 @@ func _update_connector() -> void:
|
||||||
|
|
||||||
# Point 2: player's origin + ENDPOINT_OFFSET, converted to notification's local space
|
# Point 2: player's origin + ENDPOINT_OFFSET, converted to notification's local space
|
||||||
const ENDPOINT_OFFSET = Vector2(4, 7) # offset from player's origin to connector endpoint
|
const ENDPOINT_OFFSET = Vector2(4, 7) # offset from player's origin to connector endpoint
|
||||||
var target = _player.position + Vector2(+ENDPOINT_OFFSET.x, _origin_offset + ENDPOINT_OFFSET.y)
|
var target = _player.position + Vector2(+ENDPOINT_OFFSET.x, _origin_offset.y + ENDPOINT_OFFSET.y)
|
||||||
var point2 = target - position
|
var point2 = target - position
|
||||||
|
|
||||||
_connector_line.points = PackedVector2Array([point0, point1, point2])
|
_connector_line.points = PackedVector2Array([point0, point1, point2])
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ func _ready() -> void:
|
||||||
EventBus.weapon_changed.connect(_on_weapon_changed)
|
EventBus.weapon_changed.connect(_on_weapon_changed)
|
||||||
|
|
||||||
|
|
||||||
func _on_weapon_changed(weapon_name: String, player_node: Node2D, player_sprite_size: Vector2, origin_offset: float) -> void:
|
func _on_weapon_changed(weapon_name: String, player_node: Node2D, player_sprite_size: Vector2, origin_offset: Vector2) -> void:
|
||||||
if notification_scene == null:
|
if notification_scene == null:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ class_name ShootComponent extends Node
|
||||||
|
|
||||||
@onready var weapon_component: Node = %WeaponComponent
|
@onready var weapon_component: Node = %WeaponComponent
|
||||||
@onready var player = $".."
|
@onready var player = $".."
|
||||||
|
@onready var ship: Sprite2D = get_node("../Ship")
|
||||||
|
@onready var fire_helper: WeaponFireHelper = %WeaponFireHelper
|
||||||
|
|
||||||
func shoot():
|
func shoot():
|
||||||
var weapon_data = weapon_component.weapon_data
|
var weapon_data = weapon_component.weapon_data
|
||||||
var current_time = Time.get_ticks_msec() / 1000.0
|
var current_time = Time.get_ticks_msec() / 1000.0
|
||||||
|
|
||||||
if player.travel > weapon_data.spacing:
|
if player.travel > weapon_data.projectile_vertical_spacing:
|
||||||
_shoot_standard(weapon_data, current_time)
|
_shoot_standard(weapon_data, current_time)
|
||||||
_shoot_grouped(weapon_data, current_time)
|
_shoot_grouped(weapon_data, current_time)
|
||||||
|
|
||||||
|
|
@ -15,105 +17,61 @@ func shoot():
|
||||||
player.travel = 0.0
|
player.travel = 0.0
|
||||||
|
|
||||||
|
|
||||||
# Standard projectile logic (backward compatible)
|
# Standard projectile logic (delegates to WeaponFireHelper)
|
||||||
func _shoot_standard(weapon_data: WeaponShot, current_time: float):
|
func _shoot_standard(weapon_data: WeaponShot, current_time: float):
|
||||||
var total_projectiles = weapon_data.projectiles
|
var total_projectiles: int = weapon_data.projectiles
|
||||||
var center_index = (total_projectiles - 1) / 2.0
|
|
||||||
|
|
||||||
if total_projectiles > 0:
|
if total_projectiles > 0:
|
||||||
for b in range(total_projectiles):
|
for b in range(total_projectiles):
|
||||||
var bullet := weapon_data.bullet_scene.instantiate() as Area2D
|
var bullet := weapon_data.bullet_scene.instantiate() as Area2D
|
||||||
get_tree().root.add_child(bullet)
|
get_tree().root.add_child(bullet)
|
||||||
|
|
||||||
# Calculate index relative to center (0 = center, -1/+1 = first from center)
|
# Delegate math to the helper, with spawn position offset by sprite height and weapon origin
|
||||||
var index_from_center: float = b - center_index
|
var spawn_position = ship.global_position + Vector2(0, ship.get_texture().get_height() / 2.0) + weapon_data.origin
|
||||||
|
var props = fire_helper.compute_standard_props(weapon_data, b, spawn_position, current_time)
|
||||||
# Calculate timing offset for staggered firing (center-first, pairs outward)
|
bullet.position = props.position
|
||||||
var time_offset: float = abs(index_from_center) * weapon_data.stagger_offset
|
bullet.angle = props.angle
|
||||||
|
bullet.time_offset = props.time_offset
|
||||||
# Calculate horizontal offset for this bullet (symmetrical: left=-ve, right=+ve)
|
bullet.fire_time = props.fire_time
|
||||||
var bullet_horizontal_offset: float = index_from_center * weapon_data.horizontal_offset
|
|
||||||
|
|
||||||
# Calculate vertical offset from center point (symmetrical vertical spread)
|
|
||||||
var distance_from_center: float = abs(index_from_center)
|
|
||||||
var vertical_offset: float = (distance_from_center * weapon_data.origin * -1) / 2
|
|
||||||
|
|
||||||
# Final position combines symmetrical horizontal spread with symmetrical vertical spacing
|
|
||||||
bullet.position = player.position + Vector2(bullet_horizontal_offset, weapon_data.origin + (vertical_offset + weapon_data.origin - total_projectiles))
|
|
||||||
|
|
||||||
# Calculate angle for this bullet (only when projectiles >= 3)
|
|
||||||
var bullet_angle: float = 0.0
|
|
||||||
if total_projectiles >= 3:
|
|
||||||
bullet_angle = (index_from_center / center_index) * (weapon_data.spread_angle / 2.0)
|
|
||||||
|
|
||||||
# Set timing properties on the bullet
|
|
||||||
bullet.time_offset = time_offset
|
|
||||||
bullet.fire_time = current_time + time_offset
|
|
||||||
bullet.angle = bullet_angle
|
|
||||||
|
|
||||||
# Set the bullet data
|
# Set the bullet data
|
||||||
bullet.set_weapon_data(weapon_data.bullet_scene, weapon_data)
|
bullet.set_weapon_data(weapon_data.bullet_scene, weapon_data)
|
||||||
|
|
||||||
# Offset animation playback per projectile if enabled
|
# Offset animation playback per projectile if enabled
|
||||||
if weapon_data.stagger_animation:
|
if weapon_data.stagger_animation:
|
||||||
bullet.set_animation_offset(index_from_center * weapon_data.stagger_offset)
|
bullet.set_animation_offset(props.animation_offset)
|
||||||
|
|
||||||
|
|
||||||
# Grouped projectile logic (new functionality)
|
# Grouped projectile logic (delegates to WeaponFireHelper)
|
||||||
func _shoot_grouped(weapon_data: WeaponShot, current_time: float):
|
func _shoot_grouped(weapon_data: WeaponShot, current_time: float):
|
||||||
for group: WeaponProjectileGroup in weapon_data.groups.filter(func(g): return g != null):
|
for group: WeaponProjectileGroup in weapon_data.groups.filter(func(g): return g != null):
|
||||||
for b in range(group.bullet_count):
|
for b in range(group.bullet_count):
|
||||||
var bullet := weapon_data.bullet_scene.instantiate() as Area2D
|
var bullet := weapon_data.bullet_scene.instantiate() as Area2D
|
||||||
get_tree().root.add_child(bullet)
|
get_tree().root.add_child(bullet)
|
||||||
|
|
||||||
_fire_grouped_bullet(bullet, group, b, current_time, weapon_data, false)
|
# Apply computed properties for the original bullet
|
||||||
|
var spawn_position = ship.global_position + Vector2(0, ship.get_texture().get_height() / 2.0) + weapon_data.origin
|
||||||
|
var props = fire_helper.compute_grouped_props(group, weapon_data, b, spawn_position, current_time, false)
|
||||||
|
bullet.position = props.position
|
||||||
|
bullet.angle = props.angle
|
||||||
|
bullet.time_offset = props.time_offset
|
||||||
|
bullet.fire_time = props.fire_time
|
||||||
|
bullet.set_weapon_data(weapon_data.bullet_scene, weapon_data)
|
||||||
|
if weapon_data.stagger_animation:
|
||||||
|
bullet.set_animation_offset(props.animation_offset)
|
||||||
|
|
||||||
# If mirroring is enabled, fire a mirrored copy
|
# If mirroring is enabled, fire a mirrored copy
|
||||||
if group.mirror:
|
if group.mirror:
|
||||||
var mirror_bullet := weapon_data.bullet_scene.instantiate() as Area2D
|
var mirror_bullet := weapon_data.bullet_scene.instantiate() as Area2D
|
||||||
get_tree().root.add_child(mirror_bullet)
|
get_tree().root.add_child(mirror_bullet)
|
||||||
_fire_grouped_bullet(mirror_bullet, group, b, current_time, weapon_data, true)
|
|
||||||
|
|
||||||
|
# Apply computed properties for the mirrored bullet
|
||||||
# Fire a single grouped bullet (original or mirrored)
|
var mirror_spawn = ship.global_position + Vector2(0, ship.get_texture().get_height() / 2.0) + weapon_data.origin
|
||||||
func _fire_grouped_bullet(bullet: Area2D, group: WeaponProjectileGroup, b: int,
|
var mirror_props = fire_helper.compute_grouped_props(group, weapon_data, b, mirror_spawn, current_time, true)
|
||||||
current_time: float, weapon_data: WeaponShot, mirror: bool):
|
mirror_bullet.position = mirror_props.position
|
||||||
# Calculate index relative to this group's center
|
mirror_bullet.angle = mirror_props.angle
|
||||||
var center_index: float = (group.bullet_count - 1) / 2.0
|
mirror_bullet.time_offset = mirror_props.time_offset
|
||||||
var index_from_center: float = b - center_index
|
mirror_bullet.fire_time = mirror_props.fire_time
|
||||||
|
mirror_bullet.set_weapon_data(weapon_data.bullet_scene, weapon_data)
|
||||||
# Horizontal offset: group offset + within-group spread
|
if weapon_data.stagger_animation:
|
||||||
# Mirror: negate the horizontal offset contribution
|
mirror_bullet.set_animation_offset(mirror_props.animation_offset)
|
||||||
var bullet_horizontal_offset: float = group.horizontal_offset + index_from_center * group.horizontal_spacing
|
|
||||||
if mirror:
|
|
||||||
bullet_horizontal_offset = -bullet_horizontal_offset
|
|
||||||
|
|
||||||
# Base angle for the group, plus within-group spread
|
|
||||||
# Mirror: negate the angle and the spread contribution
|
|
||||||
var bullet_angle: float = group.angle_offset
|
|
||||||
if mirror:
|
|
||||||
bullet_angle = -group.angle_offset
|
|
||||||
if group.bullet_count >= 3:
|
|
||||||
var spread_contribution = (index_from_center / center_index) * (group.spread_angle / 2.0)
|
|
||||||
if mirror:
|
|
||||||
bullet_angle -= spread_contribution
|
|
||||||
else:
|
|
||||||
bullet_angle += spread_contribution
|
|
||||||
|
|
||||||
# Position: apply horizontal offset and vertical origin from weapon data
|
|
||||||
bullet.position = player.position + Vector2(bullet_horizontal_offset, weapon_data.origin)
|
|
||||||
|
|
||||||
# Timing: group delay + within-group stagger
|
|
||||||
var time_offset: float = group.group_delay + abs(index_from_center) * group.stagger_offset
|
|
||||||
|
|
||||||
# Set timing properties on the bullet
|
|
||||||
bullet.time_offset = time_offset
|
|
||||||
bullet.fire_time = current_time + time_offset
|
|
||||||
bullet.angle = bullet_angle
|
|
||||||
|
|
||||||
# Set the bullet data
|
|
||||||
bullet.set_weapon_data(weapon_data.bullet_scene, weapon_data)
|
|
||||||
|
|
||||||
# Offset animation playback per projectile if enabled
|
|
||||||
if weapon_data.stagger_animation:
|
|
||||||
bullet.set_animation_offset(index_from_center * weapon_data.stagger_offset)
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ func _ready() -> void:
|
||||||
func _emit_weapon_changed() -> void:
|
func _emit_weapon_changed() -> void:
|
||||||
var ship: Sprite2D = get_parent().get_node("Ship")
|
var ship: Sprite2D = get_parent().get_node("Ship")
|
||||||
var sprite_size = ship.get_rect().size
|
var sprite_size = ship.get_rect().size
|
||||||
var origin_offset: int = weapon_data.origin if weapon_data else 0
|
var origin_offset: Vector2 = weapon_data.origin if weapon_data else Vector2.ZERO
|
||||||
EventBus.weapon_changed.emit(weapon_data.shot_name, get_parent(), sprite_size, origin_offset)
|
EventBus.weapon_changed.emit(weapon_data.shot_name, get_parent(), sprite_size, origin_offset)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
88
scripts/weapon_fire_helper.gd
Normal file
88
scripts/weapon_fire_helper.gd
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
class_name WeaponFireHelper extends Node
|
||||||
|
|
||||||
|
|
||||||
|
## Compute bullet properties for a standard shot.
|
||||||
|
## Returns a Dictionary with: position, angle, fire_time, time_offset, index_from_center, animation_offset
|
||||||
|
func compute_standard_props(weapon_data: WeaponShot, projectile_index: int, spawn_position: Vector2, current_time: float) -> Dictionary:
|
||||||
|
var total_projectiles: int = weapon_data.projectiles
|
||||||
|
var center_index: float = (total_projectiles - 1) / 2.0
|
||||||
|
|
||||||
|
var index_from_center: float = projectile_index - center_index
|
||||||
|
|
||||||
|
# Horizontal offset (symmetrical: left=-ve, right=+ve)
|
||||||
|
var bullet_horizontal_offset: float = index_from_center * weapon_data.horizontal_offset
|
||||||
|
|
||||||
|
# Timing: center-first, pairs outward
|
||||||
|
var time_offset: float = abs(index_from_center) * weapon_data.stagger_offset
|
||||||
|
|
||||||
|
# Vertical offset: outer projectiles are spaced relative to center, preserving the pattern geometry.
|
||||||
|
var vertical_offset: float = (abs(index_from_center) * weapon_data.projectile_vertical_spacing) / 2.0
|
||||||
|
var position: Vector2 = spawn_position + Vector2(bullet_horizontal_offset, vertical_offset)
|
||||||
|
|
||||||
|
# Angle (only when projectiles >= 3, division-by-zero guard)
|
||||||
|
var bullet_angle: float = 0.0
|
||||||
|
if total_projectiles >= 3:
|
||||||
|
bullet_angle = (index_from_center / center_index) * (weapon_data.spread_angle / 2.0)
|
||||||
|
|
||||||
|
# Fire time
|
||||||
|
var fire_time: float = current_time + time_offset
|
||||||
|
|
||||||
|
# Animation offset (if staggered animation is enabled)
|
||||||
|
var animation_offset: float = index_from_center * weapon_data.stagger_offset
|
||||||
|
|
||||||
|
return {
|
||||||
|
"position": position,
|
||||||
|
"angle": bullet_angle,
|
||||||
|
"fire_time": fire_time,
|
||||||
|
"time_offset": time_offset,
|
||||||
|
"index_from_center": index_from_center,
|
||||||
|
"animation_offset": animation_offset,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## Compute bullet properties for a grouped shot, with optional mirroring.
|
||||||
|
## Returns a Dictionary with: position, angle, fire_time, time_offset, index_from_center, animation_offset
|
||||||
|
func compute_grouped_props(group: WeaponProjectileGroup, weapon_data: WeaponShot,
|
||||||
|
bullet_index: int, spawn_position: Vector2, current_time: float,
|
||||||
|
mirror: bool = false) -> Dictionary:
|
||||||
|
var center_index: float = (group.bullet_count - 1) / 2.0
|
||||||
|
var index_from_center: float = bullet_index - center_index
|
||||||
|
|
||||||
|
# Horizontal offset: group offset + within-group spread
|
||||||
|
var bullet_horizontal_offset: float = group.horizontal_offset + index_from_center * group.horizontal_spacing
|
||||||
|
if mirror:
|
||||||
|
bullet_horizontal_offset = -bullet_horizontal_offset
|
||||||
|
|
||||||
|
# Base angle: group angle (negated when mirrored) + within-group spread
|
||||||
|
var bullet_angle: float = group.angle_offset
|
||||||
|
if mirror:
|
||||||
|
bullet_angle = -group.angle_offset
|
||||||
|
|
||||||
|
# Symmetrical spread (guard against < 3 bullets)
|
||||||
|
if group.bullet_count >= 3:
|
||||||
|
var spread_contribution = (index_from_center / center_index) * (group.spread_angle / 2.0)
|
||||||
|
if mirror:
|
||||||
|
bullet_angle -= spread_contribution
|
||||||
|
else:
|
||||||
|
bullet_angle += spread_contribution
|
||||||
|
|
||||||
|
# Position: horizontal offset only (vertical position comes from spawn_position)
|
||||||
|
var position: Vector2 = spawn_position + Vector2(bullet_horizontal_offset, 0)
|
||||||
|
|
||||||
|
# Timing: group delay + within-group stagger
|
||||||
|
var time_offset: float = group.group_delay + abs(index_from_center) * group.stagger_offset
|
||||||
|
|
||||||
|
# Fire time
|
||||||
|
var fire_time: float = current_time + time_offset
|
||||||
|
|
||||||
|
# Animation offset (if staggered animation is enabled)
|
||||||
|
var animation_offset: float = index_from_center * weapon_data.stagger_offset
|
||||||
|
|
||||||
|
return {
|
||||||
|
"position": position,
|
||||||
|
"angle": bullet_angle,
|
||||||
|
"fire_time": fire_time,
|
||||||
|
"time_offset": time_offset,
|
||||||
|
"index_from_center": index_from_center,
|
||||||
|
"animation_offset": animation_offset,
|
||||||
|
}
|
||||||
1
scripts/weapon_fire_helper.gd.uid
Normal file
1
scripts/weapon_fire_helper.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bpcv2ojtyityc
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
class_name WeaponProjectileGroup
|
class_name WeaponProjectileGroup
|
||||||
extends Resource
|
extends Resource
|
||||||
|
|
||||||
|
@export_category("Identification")
|
||||||
|
@export var pattern_name: String = ""
|
||||||
@export_category("Group Settings")
|
@export_category("Group Settings")
|
||||||
@export var bullet_count: int = 3
|
@export var bullet_count: int = 3
|
||||||
# Horizontal distance between bullets in this group
|
# Horizontal distance between bullets in this group
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ extends Resource
|
||||||
@export var damage: int = 1
|
@export var damage: int = 1
|
||||||
@export var speed: int = 135
|
@export var speed: int = 135
|
||||||
@export var projectiles: int = 2
|
@export var projectiles: int = 2
|
||||||
# Vertical spacing between projectiles
|
# Vertical spacing between projectiles when firing continuously
|
||||||
@export var spacing: float = 35
|
@export var projectile_vertical_spacing: float = 35
|
||||||
# Origin offset from center of player
|
# Spawn offset from center of player (x is usually 0, y controls vertical fire position)
|
||||||
@export var origin: int = -23
|
@export var origin: Vector2 = Vector2(0, -25)
|
||||||
|
|
||||||
@export_category("Spread")
|
@export_category("Spread")
|
||||||
# Horizontal distance between projectiles
|
# Horizontal distance between projectiles
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue