feat: add state machine movement classes, double barrel shotgun weapon, and test level builder utility

This commit is contained in:
DottsGit
2026-06-04 01:21:50 -04:00
parent a54b3d89b1
commit 45fb7f0f38
6 changed files with 177 additions and 42 deletions
+119
View File
@@ -0,0 +1,119 @@
extends Node3D
class_name DoubleBarrelShotgun
@export var reload_time: float = 1.0
var shells: int = 2
var reloading: bool = false
var reload_timer: float = 0.0
var player: CharacterBody3D
var camera: Camera3D
func _ready() -> void:
set_process_input(true)
set_process(true)
_build_model()
func _build_model() -> void:
# Simple FPS weapon placement (bottom right)
position = Vector3(0.3, -0.3, -0.6)
# Stock
var stock = MeshInstance3D.new()
var stock_mesh = BoxMesh.new()
stock_mesh.size = Vector3(0.1, 0.1, 0.4)
var stock_mat = StandardMaterial3D.new()
stock_mat.albedo_color = Color(0.4, 0.2, 0.1) # Brown wood
stock_mesh.material = stock_mat
stock.mesh = stock_mesh
stock.position = Vector3(0, 0, 0.2)
add_child(stock)
# Left Barrel
var barrel_l = MeshInstance3D.new()
var barrel_mesh = CylinderMesh.new()
barrel_mesh.top_radius = 0.03
barrel_mesh.bottom_radius = 0.03
barrel_mesh.height = 0.6
var barrel_mat = StandardMaterial3D.new()
barrel_mat.albedo_color = Color(0.2, 0.2, 0.2) # Dark grey metal
barrel_mat.metallic = 0.8
barrel_mat.roughness = 0.4
barrel_mesh.material = barrel_mat
barrel_l.mesh = barrel_mesh
barrel_l.rotation.x = deg_to_rad(90)
barrel_l.position = Vector3(-0.04, 0.03, -0.1)
add_child(barrel_l)
# Right Barrel
var barrel_r = MeshInstance3D.new()
barrel_r.mesh = barrel_mesh
barrel_r.rotation.x = deg_to_rad(90)
barrel_r.position = Vector3(0.04, 0.03, -0.1)
add_child(barrel_r)
func _process(delta: float) -> void:
if reloading:
reload_timer -= delta
# Spin vertically (flip) over the duration of the reload
var spin_speed = (PI * 2.0) / reload_time
rotation.x += spin_speed * delta
if reload_timer <= 0.0:
shells = 2
reloading = false
rotation.x = 0.0 # Snap back to perfectly level
print("Shotgun Reloaded!")
func _input(event: InputEvent) -> void:
if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
return
if event.is_action_pressed("fire"):
_try_fire()
elif event.is_action_released("fire"):
_try_fire()
if event.is_action_pressed("reload"):
if shells < 2 and not reloading:
reloading = true
reload_timer = reload_time
func _try_fire() -> void:
if shells > 0 and not reloading:
shells -= 1
print("BANG! Shells left: ", shells)
_apply_impulse()
# Start reload timer if we just shot the LAST shell
if shells == 0:
reloading = true
reload_timer = reload_time
elif shells == 0 and not reloading:
# Empty click, force reload
reloading = true
reload_timer = reload_time
func _apply_impulse() -> void:
if not player or not camera:
return
# Get the shotgun impulse parameter from the player's movement controller
var impulse_strength = 20.0
if player.has_method("get") and "params" in player:
if player.params and "shotgun_jump_impulse" in player.params:
impulse_strength = player.params.shotgun_jump_impulse
# Impulse direction is opposite to the camera's forward direction
var push_dir = camera.global_transform.basis.z.normalized()
# Apply impulse to player velocity
player.velocity += push_dir * impulse_strength
# Small hack to ensure we aren't considered on floor if we shoot down
if push_dir.y > 0:
# Just slightly lift the player to break floor contact immediately
player.position.y += 0.05
+1
View File
@@ -0,0 +1 @@
uid://chgdeglyrlf07