Implements modifier system for weapons
Adds a modifier system allowing dynamic modification of weapon stats and behavior. This includes: - Creating ModifierLibrary to manage available modifiers. - Adds ModifierManager to handle equipping and unequipping modifiers - Adds a new RangedWeaponComponent to handle firing projectiles and managing modifiers. - Introduces a DebugUI for in-game modifier management. - Introduces an "Unlimited Power" modifier that changes the projectile scene. - Modifies stats components to work with the new modifier system. This system allows for more flexible and customizable weapon functionality.
This commit is contained in:
parent
9f66ab0a73
commit
70839387ca
22 changed files with 432 additions and 40 deletions
85
UI/DebugUI.tscn
Normal file
85
UI/DebugUI.tscn
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://b0w0oxbtax5si"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bblhlxj8sqtql" path="res://UI/_scripts/debug_ui.gd" id="1_pwlud"]
|
||||
|
||||
[node name="DebugUi" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
script = ExtResource("1_pwlud")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
offset_left = 13.0
|
||||
offset_top = 15.0
|
||||
offset_right = 91.0
|
||||
offset_bottom = 173.0
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_bottom = 5
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="FPS" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="FPSLabel" type="Label" parent="MarginContainer/VBoxContainer/FPS"]
|
||||
layout_mode = 2
|
||||
text = "FPS: "
|
||||
|
||||
[node name="FPSValue" type="Label" parent="MarginContainer/VBoxContainer/FPS"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "123"
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PlayerWeapon" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="PlayerWeaponLabel" type="Label" parent="MarginContainer/VBoxContainer/PlayerWeapon"]
|
||||
layout_mode = 2
|
||||
text = "Player Weapon:"
|
||||
|
||||
[node name="PlayerWeaponValue" type="Label" parent="MarginContainer/VBoxContainer/PlayerWeapon"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PlayerWeaponMods" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 2
|
||||
|
||||
[node name="PlayerWeaponModsLabel" type="Label" parent="MarginContainer/VBoxContainer/PlayerWeaponMods"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Mods:"
|
||||
|
||||
[node name="PlayerWeaponModsValue" type="Label" parent="MarginContainer/VBoxContainer/PlayerWeaponMods"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "123
|
||||
456
|
||||
678"
|
||||
|
||||
[node name="ModifierButtons" type="VBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer/ModifierButtons"]
|
||||
layout_mode = 2
|
||||
text = "123"
|
||||
|
||||
[node name="PlayerStats" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 2
|
||||
|
||||
[node name="PlayerStatsValue" type="Label" parent="MarginContainer/VBoxContainer/PlayerStats"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "123
|
||||
456
|
||||
678"
|
||||
107
UI/_scripts/debug_ui.gd
Normal file
107
UI/_scripts/debug_ui.gd
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
extends Control
|
||||
class_name DebugUI
|
||||
|
||||
var fps_label: Label
|
||||
var player_weapon_mods_label: Label
|
||||
|
||||
var player: Player
|
||||
var was_debug_key_pressed: bool = false
|
||||
|
||||
var is_mouse_over_ui: bool = false
|
||||
|
||||
func _ready():
|
||||
self.visible = false
|
||||
player = get_tree().get_first_node_in_group("player")
|
||||
|
||||
fps_label = %FPSValue
|
||||
player_weapon_mods_label = %PlayerWeaponModsValue
|
||||
|
||||
self.position = Vector2.ZERO
|
||||
self.size = get_viewport_rect().size
|
||||
self.scale = Vector2(1.2, 1.2)
|
||||
|
||||
# Connect the mouse entered/exited signals to track when mouse is over UI
|
||||
self.mouse_entered.connect(_on_mouse_entered)
|
||||
self.mouse_exited.connect(_on_mouse_exited)
|
||||
|
||||
# Make the UI control consume input events
|
||||
self.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
|
||||
func _on_mouse_entered() -> void:
|
||||
is_mouse_over_ui = true
|
||||
|
||||
func _on_mouse_exited() -> void:
|
||||
is_mouse_over_ui = false
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
# Only process if debug UI is visible
|
||||
if not self.visible:
|
||||
return
|
||||
|
||||
# Check if it's a mouse button event and if mouse is over UI
|
||||
if event is InputEventMouseButton:
|
||||
if is_mouse_over_ui:
|
||||
# Consume the event so it doesn't propagate to the game
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func _process(_delta):
|
||||
if Input.is_action_pressed("debug_menu"):
|
||||
if not was_debug_key_pressed:
|
||||
populate_modifier_buttons()
|
||||
was_debug_key_pressed = true
|
||||
self.visible = !self.visible
|
||||
else:
|
||||
was_debug_key_pressed = false
|
||||
|
||||
var current_fps = Engine.get_frames_per_second()
|
||||
fps_label.text = str(current_fps)
|
||||
|
||||
var player_stats = player.stats.get_nested_stat("ranged")
|
||||
var player_stats_label = %PlayerStatsValue
|
||||
player_stats_label.text = ""
|
||||
for stat in player_stats:
|
||||
player_stats_label.text += str(stat) + ": " + str(player_stats[stat]) + "\n"
|
||||
|
||||
|
||||
var player_mods = player.ranged.modifier_manager.modifiers
|
||||
player_weapon_mods_label.text = ""
|
||||
for mod in player_mods:
|
||||
player_weapon_mods_label.text += str(mod.id) + " (" + str(mod.description) + ") \n"
|
||||
|
||||
|
||||
func populate_modifier_buttons() -> void:
|
||||
# Clear existing buttons
|
||||
for child in %ModifierButtons.get_children():
|
||||
if child is Button:
|
||||
child.queue_free()
|
||||
|
||||
# Create buttons for each modifier
|
||||
for modifier in ModLib.get_all_modifiers():
|
||||
var button = Button.new()
|
||||
button.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
button.toggle_mode = true
|
||||
button.text = modifier.id + " [" + modifier.description + "]"
|
||||
|
||||
# If the modifier exists in the player's weapon, set the button to "pressed"
|
||||
if player.ranged.modifier_manager.has_modifier(modifier.id):
|
||||
button.button_pressed = true
|
||||
else:
|
||||
button.button_pressed = false
|
||||
|
||||
# Store modifier id in the button's metadata for reference in the callback
|
||||
button.set_meta("modifier_id", modifier.id)
|
||||
|
||||
# Connect the toggled signal to a callback function
|
||||
button.toggled.connect(_on_modifier_button_toggled.bind(modifier.id))
|
||||
|
||||
%ModifierButtons.add_child(button)
|
||||
|
||||
func _on_modifier_button_toggled(button_pressed: bool, modifier_id: String) -> void:
|
||||
if button_pressed:
|
||||
# Add the modifier if the button is pressed
|
||||
var modifier = ModLib.get_modifier_by_id(modifier_id)
|
||||
if modifier:
|
||||
player.ranged.modifier_manager.add_modifier(modifier)
|
||||
else:
|
||||
# Remove the modifier if the button is unpressed
|
||||
player.ranged.modifier_manager.remove_modifier(modifier_id)
|
||||
1
UI/_scripts/debug_ui.gd.uid
Normal file
1
UI/_scripts/debug_ui.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bblhlxj8sqtql
|
||||
Loading…
Add table
Add a link
Reference in a new issue