Feat/2 weapons foundation #6
@@ -64,8 +64,8 @@ func _build_input_map() -> void:
|
|||||||
"sprint": [KEY_SHIFT],
|
"sprint": [KEY_SHIFT],
|
||||||
"crouch": [KEY_CTRL],
|
"crouch": [KEY_CTRL],
|
||||||
"dash": [KEY_SHIFT],
|
"dash": [KEY_SHIFT],
|
||||||
"fire": [MOUSE_BUTTON_RIGHT, KEY_F],
|
"fire": [MOUSE_BUTTON_LEFT, KEY_F],
|
||||||
"fire_alt": [MOUSE_BUTTON_LEFT],
|
"fire_alt": [MOUSE_BUTTON_RIGHT],
|
||||||
"reload": [KEY_R],
|
"reload": [KEY_R],
|
||||||
"interact": [KEY_E],
|
"interact": [KEY_E],
|
||||||
"move_forward": [KEY_W],
|
"move_forward": [KEY_W],
|
||||||
@@ -262,8 +262,9 @@ func _build_lighting() -> void:
|
|||||||
func _build_player() -> void:
|
func _build_player() -> void:
|
||||||
var player := CharacterBody3D.new()
|
var player := CharacterBody3D.new()
|
||||||
player.name = "Player"
|
player.name = "Player"
|
||||||
player.position = Vector3(0, 1.0, 8)
|
player.position = Vector3(0, 1.0, 0)
|
||||||
add_child(player)
|
add_child(player)
|
||||||
|
_player = player
|
||||||
|
|
||||||
# Collision shape
|
# Collision shape
|
||||||
var col_shape := CollisionShape3D.new()
|
var col_shape := CollisionShape3D.new()
|
||||||
@@ -316,6 +317,16 @@ func _build_player() -> void:
|
|||||||
camera.current = true
|
camera.current = true
|
||||||
camera.fov = 90.0
|
camera.fov = 90.0
|
||||||
head_pivot.add_child(camera)
|
head_pivot.add_child(camera)
|
||||||
|
|
||||||
|
# ── Temporary Weapon Setup ──────────────────────────────────────────────────
|
||||||
|
# TODO: Change how the player is given weapons in the future to a loadout schema.
|
||||||
|
var shotgun_script = preload("res://weapons/double_barrel_shotgun.gd")
|
||||||
|
if shotgun_script:
|
||||||
|
var shotgun = shotgun_script.new()
|
||||||
|
shotgun.name = "DoubleBarrelShotgun"
|
||||||
|
shotgun.player = player
|
||||||
|
shotgun.camera = camera
|
||||||
|
camera.add_child(shotgun)
|
||||||
|
|
||||||
var rig_script = preload("res://characters/player/fps_camera_rig.gd")
|
var rig_script = preload("res://characters/player/fps_camera_rig.gd")
|
||||||
if rig_script:
|
if rig_script:
|
||||||
|
|||||||
@@ -31,20 +31,23 @@ func update(delta: float) -> void:
|
|||||||
# ── Air control ───────────────────────────────────────────────────────
|
# ── Air control ───────────────────────────────────────────────────────
|
||||||
var wish_dir: Vector3 = machine.wish_dir_world
|
var wish_dir: Vector3 = machine.wish_dir_world
|
||||||
var hvel := Vector3(vel.x, 0.0, vel.z)
|
var hvel := Vector3(vel.x, 0.0, vel.z)
|
||||||
var current_speed := hvel.length()
|
|
||||||
|
|
||||||
if wish_dir.length_squared() > 0.01:
|
if wish_dir.length_squared() > 0.01:
|
||||||
var target_speed := maxf(current_speed, params.walk_speed)
|
wish_dir = wish_dir.normalized()
|
||||||
target_speed = minf(target_speed, params.max_air_speed)
|
var current_speed = hvel.length()
|
||||||
|
|
||||||
var target_vel := wish_dir * target_speed
|
# Add a strong force in the wish direction
|
||||||
var new_hvel = hvel.lerp(target_vel, 1.0 - exp(-params.air_control * params.air_acceleration * delta))
|
var air_accel = params.air_strafe_accel * delta
|
||||||
|
var new_hvel = hvel + wish_dir * air_accel
|
||||||
|
|
||||||
# Prevent speed loss during sharp turns, but allow braking if holding backward
|
# Limit the speed so we don't gain speed purely from air control.
|
||||||
if hvel.dot(target_vel) >= 0.0 and current_speed > params.walk_speed:
|
# We only allow air control to change our direction (strafing)
|
||||||
if new_hvel.length_squared() > 0.01:
|
# or to accelerate us up to our walk speed if we started slow.
|
||||||
new_hvel = new_hvel.normalized() * current_speed
|
var max_allowed_speed = maxf(current_speed, params.walk_speed)
|
||||||
|
|
||||||
|
if new_hvel.length() > max_allowed_speed:
|
||||||
|
new_hvel = new_hvel.normalized() * max_allowed_speed
|
||||||
|
|
||||||
hvel = new_hvel
|
hvel = new_hvel
|
||||||
else:
|
else:
|
||||||
# No input: slight air drag (very subtle)
|
# No input: slight air drag (very subtle)
|
||||||
@@ -64,7 +67,7 @@ func update(delta: float) -> void:
|
|||||||
# Bunny hop: if jump was buffered or pressed on landing frame
|
# Bunny hop: if jump was buffered or pressed on landing frame
|
||||||
if machine.input_jump_pressed or machine.jump_buffer_time > 0.0:
|
if machine.input_jump_pressed or machine.jump_buffer_time > 0.0:
|
||||||
var land_speed := Vector3(player.velocity.x, 0.0, player.velocity.z).length()
|
var land_speed := Vector3(player.velocity.x, 0.0, player.velocity.z).length()
|
||||||
var bhop_speed := minf(land_speed + params.bunny_hop_speed_gain, params.bunny_hop_speed_cap)
|
var bhop_speed := maxf(land_speed, minf(land_speed + params.bunny_hop_speed_gain, params.bunny_hop_speed_cap))
|
||||||
# Maintain horizontal direction, boost speed
|
# Maintain horizontal direction, boost speed
|
||||||
var hdir := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
var hdir := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
||||||
if hdir.length_squared() > 0.01:
|
if hdir.length_squared() > 0.01:
|
||||||
|
|||||||
@@ -26,6 +26,33 @@ func update(delta: float) -> void:
|
|||||||
var player := machine.player
|
var player := machine.player
|
||||||
var vel: Vector3 = player.velocity
|
var vel: Vector3 = player.velocity
|
||||||
|
|
||||||
|
# ── Jump (coyote time + jump buffer) ──────────────────────────────────
|
||||||
|
if machine.input_jump_just_pressed and machine.coyote_timer > 0.0:
|
||||||
|
player.velocity.y = params.jump_velocity
|
||||||
|
machine.current_jump_count = 1
|
||||||
|
machine.on_ground = false
|
||||||
|
machine.coyote_timer = 0.0
|
||||||
|
machine.register_chain_mechanic("jump")
|
||||||
|
machine.switch_to("air")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Jump buffer: player pressed jump just before landing
|
||||||
|
if machine.on_ground and machine.jump_buffer_time > 0.0:
|
||||||
|
player.velocity.y = params.jump_velocity
|
||||||
|
machine.current_jump_count = 1
|
||||||
|
machine.on_ground = false
|
||||||
|
machine.jump_buffer_time = 0.0
|
||||||
|
machine.register_chain_mechanic("jump")
|
||||||
|
machine.switch_to("air")
|
||||||
|
return
|
||||||
|
|
||||||
|
# ── Slide (crouch while moving fast enough) ───────────────────────────
|
||||||
|
if machine.input_crouch and machine.slide_cooldown_timer <= 0.0:
|
||||||
|
var hspeed := Vector3(player.velocity.x, 0.0, player.velocity.z).length()
|
||||||
|
if hspeed > params.slide_min_speed:
|
||||||
|
machine.switch_to("slide")
|
||||||
|
return
|
||||||
|
|
||||||
# ── Determine target speed ────────────────────────────────────────────
|
# ── Determine target speed ────────────────────────────────────────────
|
||||||
var wish_dir: Vector3 = machine.wish_dir_world
|
var wish_dir: Vector3 = machine.wish_dir_world
|
||||||
var speed := params.walk_speed
|
var speed := params.walk_speed
|
||||||
@@ -66,38 +93,11 @@ func update(delta: float) -> void:
|
|||||||
else:
|
else:
|
||||||
machine.on_ground = false
|
machine.on_ground = false
|
||||||
|
|
||||||
# ── Jump (coyote time + jump buffer) ──────────────────────────────────
|
|
||||||
if machine.input_jump_just_pressed and machine.coyote_timer > 0.0:
|
|
||||||
player.velocity.y = params.jump_velocity
|
|
||||||
machine.current_jump_count = 1
|
|
||||||
machine.on_ground = false
|
|
||||||
machine.coyote_timer = 0.0
|
|
||||||
machine.register_chain_mechanic("jump")
|
|
||||||
machine.switch_to("air")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Jump buffer: player pressed jump just before landing
|
|
||||||
if machine.on_ground and machine.jump_buffer_time > 0.0:
|
|
||||||
player.velocity.y = params.jump_velocity
|
|
||||||
machine.current_jump_count = 1
|
|
||||||
machine.on_ground = false
|
|
||||||
machine.jump_buffer_time = 0.0
|
|
||||||
machine.register_chain_mechanic("jump")
|
|
||||||
machine.switch_to("air")
|
|
||||||
return
|
|
||||||
|
|
||||||
# ── Falling off ledge → air state ─────────────────────────────────────
|
# ── Falling off ledge → air state ─────────────────────────────────────
|
||||||
if not machine.on_ground and machine.coyote_timer <= 0.0:
|
if not machine.on_ground and machine.coyote_timer <= 0.0:
|
||||||
machine.switch_to("air")
|
machine.switch_to("air")
|
||||||
return
|
return
|
||||||
|
|
||||||
# ── Slide (crouch while moving fast enough) ───────────────────────────
|
|
||||||
if machine.input_crouch and machine.slide_cooldown_timer <= 0.0:
|
|
||||||
var hspeed := Vector3(player.velocity.x, 0.0, player.velocity.z).length()
|
|
||||||
if hspeed > params.slide_min_speed:
|
|
||||||
machine.switch_to("slide")
|
|
||||||
return
|
|
||||||
|
|
||||||
# ── Wall run check ────────────────────────────────────────────────────
|
# ── Wall run check ────────────────────────────────────────────────────
|
||||||
var wall_n := machine.detect_wall_horizontal()
|
var wall_n := machine.detect_wall_horizontal()
|
||||||
if wall_n != Vector3.ZERO and machine.input_dir.length() > 0.1:
|
if wall_n != Vector3.ZERO and machine.input_dir.length() > 0.1:
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ func update(delta: float) -> void:
|
|||||||
var hvel := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
var hvel := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
||||||
if hvel.length_squared() > 0.01:
|
if hvel.length_squared() > 0.01:
|
||||||
var dir := hvel.normalized()
|
var dir := hvel.normalized()
|
||||||
var jump_speed := minf(hvel.length() + params.slide_jump_speed_boost, params.bunny_hop_speed_cap)
|
var current_speed := hvel.length()
|
||||||
|
var jump_speed := maxf(current_speed, minf(current_speed + params.slide_jump_speed_boost, params.bunny_hop_speed_cap))
|
||||||
player.velocity.x = dir.x * jump_speed
|
player.velocity.x = dir.x * jump_speed
|
||||||
player.velocity.z = dir.z * jump_speed
|
player.velocity.z = dir.z * jump_speed
|
||||||
machine.current_jump_count = 1
|
machine.current_jump_count = 1
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://chgdeglyrlf07
|
||||||
Reference in New Issue
Block a user