extends CharacterBody3D # Movement settings @export var speed: float = 5.0 @export var jump_force: float = 10.0 @export var gravity: float = 20.0 @export var push_force: float = 10.0 # Force applied to RigidBody3D @export var mouse_sensitivity: float = 0.002 # Mouse sensitivity @export var max_look_angle: float = 90.0 # Maximum vertical look angle @export var interaction_range: float = 3.0 # Range for interacting with objects @export var interaction_strenght: int = 10 # Ghost mode settings @export var ghost_mode: bool = false # Toggle ghost mode @export var ghost_speed: float = 10.0 # Movement speed in ghost mode # Collision layers @export var normal_collision_layer: int = 1 # Layer 1: Normal @export var ghost_collision_layer: int = 2 # Layer 2: Ghost # Light flicker settings @export var flicker_interval: float = 0.1 # Time between flickers @export var flicker_intensity: float = 0.5 # Intensity of flicker (0 to 1) @export var flicker_range: float = 10.0 # Range within which lights flicker var flicker_timer: float = 0.0 func _ready() -> void: # Capture the mouse so it doesn't leave the game window Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) # Initialize collision layer based on starting mode update_collision_layer() func _input(event: InputEvent) -> void: if event is InputEventMouseMotion: # Rotate the player horizontally (yaw) rotate_y(-event.relative.x * mouse_sensitivity) # Rotate the camera vertically (pitch) $Camera3D.rotate_x(-event.relative.y * mouse_sensitivity) $Camera3D.rotation_degrees.x = clamp($Camera3D.rotation_degrees.x, -max_look_angle, max_look_angle) # Check for interaction input (e.g., pressing "E") if event.is_action_pressed("interact"): interact_with_object() # Toggle ghost mode (e.g., pressing "G") if event.is_action_pressed("toggle_ghost_mode"): if ghost_mode: interaction_strenght=10 else: interaction_strenght=50 ghost_mode = !ghost_mode print("Ghost mode: ", ghost_mode) # Update collision layer when toggling ghost mode update_collision_layer() func update_collision_layer() -> void: if ghost_mode: # Set collision layer and mask for ghost mode collision_layer = ghost_collision_layer collision_mask = ghost_collision_layer else: # Set collision layer and mask for normal mode collision_layer = normal_collision_layer collision_mask = normal_collision_layer func _physics_process(delta: float) -> void: if ghost_mode: ghost_movement(delta) flicker_lights(delta) else: normal_movement(delta) func normal_movement(delta: float) -> void: var input_direction: Vector3 = Vector3.ZERO # Get input for movement if Input.is_action_pressed("move_forward"): input_direction.z -= 1 if Input.is_action_pressed("move_backward"): input_direction.z += 1 if Input.is_action_pressed("move_left"): input_direction.x -= 1 if Input.is_action_pressed("move_right"): input_direction.x += 1 # Normalize input to prevent faster diagonal movement input_direction = input_direction.normalized() # Apply movement in the camera's direction var direction: Vector3 = (transform.basis * input_direction).normalized() velocity.x = direction.x * speed velocity.z = direction.z * speed # Apply gravity if not is_on_floor(): velocity.y -= gravity * delta # Jumping if Input.is_action_just_pressed("jump") and is_on_floor(): velocity.y = jump_force # Move the player and detect collisions move_and_slide() # Apply force to RigidBody3D objects on collision for index in range(get_slide_collision_count()): var collision = get_slide_collision(index) var collider = collision.get_collider() if collider is RigidBody3D: # Calculate the direction and force to apply var force_direction = -collision.get_normal() var force = force_direction * push_force # Apply the force to the RigidBody3D collider.apply_central_impulse(force) func ghost_movement(delta: float) -> void: var input_direction: Vector3 = Vector3.ZERO # Get input for movement if Input.is_action_pressed("move_forward"): input_direction.z -= 1 # Forward if Input.is_action_pressed("move_backward"): input_direction.z += 1 # Backward if Input.is_action_pressed("move_left"): input_direction.x -= 1 # Left if Input.is_action_pressed("move_right"): input_direction.x += 1 # Right # Normalize input to prevent faster diagonal movement input_direction = input_direction.normalized() # Calculate movement direction relative to the camera var camera_basis = $Camera3D.global_transform.basis var direction: Vector3 = ( camera_basis.z * input_direction.z + # Forward/backward camera_basis.x * input_direction.x # Left/right ).normalized() # Apply movement velocity = direction * ghost_speed # Move the player move_and_slide() func flicker_lights(delta: float) -> void: flicker_timer += delta if flicker_timer >= flicker_interval: flicker_timer = 0.0 # Get all lights in the "flicker_lights" group var lights = get_tree().get_nodes_in_group("flicker_lights") for light in lights: if light is OmniLight3D or light is SpotLight3D: # Check if the light is within range if light.global_transform.origin.distance_to(global_transform.origin) <= flicker_range: # Randomly adjust the light's energy light.light_energy = randf_range(1.0 - flicker_intensity, 1.0 + flicker_intensity) func interact_with_object() -> void: # Raycast to check for interactable objects in front of the player var raycast = $Camera3D/RayCast3D if raycast.is_colliding(): var collider = raycast.get_collider() if collider is RigidBody3D: # Apply a force or torque to flip the object collider.freeze = false var flip_force = Vector3(0, interaction_strenght, 0) # Force to flip the object upward var flip_torque = Vector3(interaction_strenght, 0, 0) # Torque to rotate the object collider.apply_central_impulse(flip_force) collider.apply_torque_impulse(flip_torque)