fix: awp fov #11
@@ -56,9 +56,9 @@ func _process(delta: float) -> void:
|
|||||||
_target_fov = params.base_fov
|
_target_fov = params.base_fov
|
||||||
var hspeed := Vector2(player.velocity.x, player.velocity.z).length()
|
var hspeed := Vector2(player.velocity.x, player.velocity.z).length()
|
||||||
|
|
||||||
# Dash FOV (highest priority)
|
# Smoothly scale FOV based on speed above walking speed
|
||||||
if hspeed > params.walk_speed * 1.5:
|
var speed_factor = clampf((hspeed - params.walk_speed) / (params.walk_speed * 0.5), 0.0, 1.0)
|
||||||
_target_fov = params.dash_fov
|
_target_fov = lerpf(params.base_fov, params.dash_fov, speed_factor)
|
||||||
|
|
||||||
if _weapon_fov_override > 0.0:
|
if _weapon_fov_override > 0.0:
|
||||||
_target_fov = _weapon_fov_override
|
_target_fov = _weapon_fov_override
|
||||||
|
|||||||
@@ -7,13 +7,59 @@ var camera: Camera3D
|
|||||||
var active_slot: int = 1 # 1: Primary 1, 2: Primary 2, 3: Special, 4: Melee
|
var active_slot: int = 1 # 1: Primary 1, 2: Primary 2, 3: Special, 4: Melee
|
||||||
var weapons: Dictionary = {} # slot_index: Node3D
|
var weapons: Dictionary = {} # slot_index: Node3D
|
||||||
|
|
||||||
|
var canvas_layer: CanvasLayer
|
||||||
|
var sub_viewport: SubViewport
|
||||||
|
var vm_camera: Camera3D
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
set_process_input(true)
|
set_process_input(true)
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
_setup_viewmodel_viewport()
|
||||||
|
|
||||||
# Wait one frame for LoadoutManager to be fully ready if needed
|
# Wait one frame for LoadoutManager to be fully ready if needed
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
_build_loadout()
|
_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:
|
func _build_loadout() -> void:
|
||||||
# Clear existing weapons
|
# Clear existing weapons
|
||||||
for w in weapons.values():
|
for w in weapons.values():
|
||||||
@@ -52,6 +98,20 @@ func _spawn_weapon(slot: int, weapon_id: String) -> void:
|
|||||||
w.visible = false
|
w.visible = false
|
||||||
w.set_process_input(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:
|
func _equip_slot(slot: int) -> void:
|
||||||
if weapons.has(active_slot):
|
if weapons.has(active_slot):
|
||||||
var w = weapons[active_slot]
|
var w = weapons[active_slot]
|
||||||
|
|||||||
Reference in New Issue
Block a user