fix: fov now linearly increases with speed and first person weapon view no longer clips through walls

This commit is contained in:
DottsGit
2026-06-06 11:16:50 -04:00
parent 10416a83a0
commit 909b25548c
2 changed files with 63 additions and 3 deletions
+60
View File
@@ -7,13 +7,59 @@ var camera: Camera3D
var active_slot: int = 1 # 1: Primary 1, 2: Primary 2, 3: Special, 4: Melee
var weapons: Dictionary = {} # slot_index: Node3D
var canvas_layer: CanvasLayer
var sub_viewport: SubViewport
var vm_camera: Camera3D
func _ready() -> void:
set_process_input(true)
set_process(true)
_setup_viewmodel_viewport()
# Wait one frame for LoadoutManager to be fully ready if needed
await get_tree().process_frame
_build_loadout()
func _setup_viewmodel_viewport() -> void:
if not camera: return
# Remove viewmodel layer (20) from main camera
camera.cull_mask &= ~(1 << 19)
canvas_layer = CanvasLayer.new()
canvas_layer.layer = 0 # On top of 3D, but below UI
add_child(canvas_layer)
var sv_container = SubViewportContainer.new()
sv_container.set_anchors_preset(Control.PRESET_FULL_RECT)
sv_container.stretch = true
sv_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
canvas_layer.add_child(sv_container)
sub_viewport = SubViewport.new()
sub_viewport.transparent_bg = true
# Shared world so it renders main scene's objects that have layer 20
# (In Godot 4, own_world_3d is false by default, but let's be explicit)
sub_viewport.own_world_3d = false
sv_container.add_child(sub_viewport)
vm_camera = Camera3D.new()
vm_camera.cull_mask = 1 << 19 # Only see layer 20
sub_viewport.add_child(vm_camera)
# Add a light specifically for the viewmodel in case main lights don't reach
var dir_light = DirectionalLight3D.new()
dir_light.layers = 1 << 19
dir_light.rotation_degrees = Vector3(-60, 45, 0)
dir_light.light_energy = 0.5
add_child(dir_light)
func _process(delta: float) -> void:
if is_instance_valid(vm_camera) and is_instance_valid(camera):
vm_camera.global_transform = camera.global_transform
vm_camera.fov = camera.fov
func _build_loadout() -> void:
# Clear existing weapons
for w in weapons.values():
@@ -51,6 +97,20 @@ func _spawn_weapon(slot: int, weapon_id: String) -> void:
weapons[slot] = w
w.visible = false
w.set_process_input(false)
# Set weapons to viewmodel layer
_set_layer_recursive(w, 1 << 19)
func _set_layer_recursive(node: Node, layer_mask: int) -> void:
if node is VisualInstance3D:
if node is Light3D:
# Lights (e.g. muzzle flash) illuminate both world and viewmodel
node.layers = 1 | layer_mask
else:
node.layers = layer_mask
for child in node.get_children():
_set_layer_recursive(child, layer_mask)
func _equip_slot(slot: int) -> void:
if weapons.has(active_slot):