0% found this document useful (0 votes)
5 views

message

This document is a script for a 3D character controller in a game, detailing movement mechanics, camera control, and interaction with objects. It includes variables for player states such as walking, sprinting, and crouching, as well as properties for visual effects like head bobbing and flashlight functionality. The script also handles input events, physics processing, and inventory management within the game environment.

Uploaded by

Stuart YT
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

message

This document is a script for a 3D character controller in a game, detailing movement mechanics, camera control, and interaction with objects. It includes variables for player states such as walking, sprinting, and crouching, as well as properties for visual effects like head bobbing and flashlight functionality. The script also handles input events, physics processing, and inventory management within the game environment.

Uploaded by

Stuart YT
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

extends CharacterBody3D

# NOTICE all comments for work:


#Critical comments: ALERT,ATTENTION,CAUTION,CRITICAL,DANGER,SECURITY
#Warning comments: BUG,DEPRECATED,FIXME,HACK,TASK,TBD,TODO,WARNING
#Notices: INFO,NOTE,NOTICE,TEST,TESTING

@onready var title = "Prometheus Pre-Alpha"

@onready var neck: Node3D = $Neck


@onready var head: Node3D = $Neck/Head
@onready var eye: Node3D = $Neck/Head/Eye
@onready var camera: Camera3D = $Neck/Head/Eye/Camera
@onready var shoulder: Node3D = $Shoulder
@onready var hand: Node3D = $Shoulder/Hand
@onready var flashlight: SpotLight3D = $Shoulder/Hand/Flashlight
@onready var collision_shape: CollisionShape3D = $CollisionShape
@onready var top_cast: ShapeCast3D = $TopCast
@onready var interaction_cast: RayCast3D = $"Neck/Head/Eye/Camera/Interaction cast"
@onready var fps: Label = $"Neck/Head/Eye/Camera/2D overlays/Control/FPS"
@onready var animation_player: AnimationPlayer = $"Neck/Head/Eye/Camera/2D
overlays/CanvasLayer/AnimationPlayer"

@export_category("Movement")

@export var walkSpeed = 5.0


@export var sprintSpeed = 7.0
@export var staminaMax = 6.0
@export var staminaPenalty = 10.0
@export var crouchspeed = 3.0
@export var playerAcceleration = 8.0
@export var airFriction = 1.0

@export var jumpForce = 7.0

@export_category("Visuals")

@export var crouchHeight = 1.0


@export var crouchTransition = 8.0
@export_exp_easing("attenuation") var lerpSpd = 10.0

@export var cameraBaseFOV = 60.0


@export var mouseSens = 0.4
@export var camAcceleration = 10.0

@export_group("Head Bob")
@export var head_bobbing_crouch_speed = 9.0
@export var head_bobbing_walk_speed = 12.0
@export var head_bobbing_sprint_speed = 15.0

@export var head_bobbing_crouch_intensity = 0.1


@export var head_bobbing_sprint_intensity = 0.3
@export var head_bobbing_walk_intensity = 0.2

@export_group("flashlight")

@export_subgroup("Inside")

@export var flashlightInnerEnergy = 2.0


@export var flashlightInnerFogEnergy = 16.0
@export var flashlightInnerRange = 20.0
@export var flashlightInnerAngle = 15.0

@export_subgroup("Outside")

@export var flashlightOuterEnergy = 0.5


@export var flashlightOuterFogEnergy = 8.0
@export var flashlightOuterRange = 20.0
@export var flashlightOuterAngle = 30.0

@export var inventory : Array


@export var inventorySize : int = 5

enum MovementState {
Crouching,
Sprinting,
Walking
}

var i = 0

var isReady : bool

var standHeight : float

var CurrentState: MovementState = MovementState.Walking

var local_velocity
var gravity : Vector3
var headYaxis : float
var camXaxis : float
var currentSpeed : float
var stamina : float

var head_bobbing_vector = Vector2.ZERO


var head_bobbing_rotation = 0.0
var head_bobbing_index = 0.0
var head_bobbing_current_intensity = 0.0

var direction := Vector3.ZERO

const maxStepHeight = 0.5


var snappedToStairLastFrame := false
var lastFrameWasOnFloor = -INF

func _ready() -> void:


standHeight = collision_shape.shape.height
stamina = staminaMax
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _input(event: InputEvent) -> void:


handleCameraMovementEvents(event)

func isSurfaceTooSteep(normal : Vector3) -> bool:


return normal.angle_to(Vector3.UP) > self.floor_max_angle

func runBodyTestMotion(from : Transform3D, motion : Vector3, result = null) ->


bool:
if not result : result = PhysicsTestMotionResult3D.new()
var params = PhysicsTestMotionParameters3D.new()
params.from = from
params.motion = motion
return PhysicsServer3D.body_test_motion(self.get_rid(), params, result)

func snapUpStairsCheck(delta) -> bool:


if not is_on_floor() and not snappedToStairLastFrame: return false
var expectedMoveMotion = self.velocity * Vector3(1,0,1) * delta
var stepPosWithClearance =
self.global_transform.translated(expectedMoveMotion + Vector3(0, maxStepHeight * 2,
0))

var downCheckResult = PhysicsTestMotionResult3D.new()


if (runBodyTestMotion(stepPosWithClearance, Vector3(0,-maxStepHeight * 2,0),
downCheckResult)
and (downCheckResult.get_collider().is_class("StaticBody3D") or
downCheckResult.get_collider().is_class("CSGShape3D"))):
var stepHeight = ((stepPosWithClearance.origin +
downCheckResult.get_travel()) - self.global_position).y

if stepHeight > maxStepHeight or stepHeight <= 0.01 or


(downCheckResult.get_collision_point() - self.global_position).y > maxStepHeight:
return false
%StairAheadRayCast.global_position =
downCheckResult.get_collision_point() + Vector3(0, maxStepHeight, 0) +
expectedMoveMotion.normalized() * 0.1
%StairAheadRayCast.force_raycast_update()
if %StairAheadRayCast.is_colliding() and not
isSurfaceTooSteep(%StairAheadRayCast.get_collision_normal()):
self.global_position = stepPosWithClearance.origin +
downCheckResult.get_travel()
apply_floor_snap()
snappedToStairLastFrame = true
saveCameraGlobalPosForsmoothing()
return true
return false

func snapDownToStairCheck() -> void:


var didSnap = false
var floorBelow : bool = %StairBelowRayCast.is_colliding() and not
isSurfaceTooSteep(%StairBelowRayCast.get_collision_normal())
var wasOnFloorLastFrame = Engine.get_physics_frames() - lastFrameWasOnFloor
== 1
if not is_on_floor() and velocity.y <= 0 and (wasOnFloorLastFrame or
snappedToStairLastFrame) and floorBelow:
var bodyTestResult = PhysicsTestMotionResult3D.new()

if runBodyTestMotion(self.global_transform, Vector3(0, -maxStepHeight,


0), bodyTestResult):
var translateY = bodyTestResult.get_travel().y
self.position.y += translateY
apply_floor_snap()
saveCameraGlobalPosForsmoothing()
didSnap = true
snappedToStairLastFrame = didSnap

var savedCameraGlobalPos = null


func saveCameraGlobalPosForsmoothing():
if savedCameraGlobalPos == null:
savedCameraGlobalPos = %Eye.global_position

func slideEyeBackToOrigin(delta):
if savedCameraGlobalPos == null: return
%Eye.global_position.y = savedCameraGlobalPos.y
%Eye.position.y = clampf(%Eye.position.y, -0.7, 0.7)
var moveAmount = max(self.velocity.length() * delta, walkSpeed/2 * delta)
%Eye.position.y = move_toward(%Eye.position.y, 0.0, moveAmount)
savedCameraGlobalPos = %Eye.global_position
if %Eye.position.y == 0:
savedCameraGlobalPos = null

func _physics_process(delta: float) -> void:

handleMouseModes()

displayFPS()

inventory.resize(inventorySize)

#local velocity calculation


local_velocity = Vector3(velocity.dot(head.basis.x),
velocity.dot(head.basis.y), velocity.dot(head.basis.z))

if is_on_floor:
lastFrameWasOnFloor = Engine.get_physics_frames()

#get gravity
gravity = get_gravity()

handleInteraction()

handleCameraMovement(delta)
handlePlayerInput(delta)
handleCurrentPlayerState(delta)

dynamicHeadTilt(local_velocity, delta)

dynamicFOV(local_velocity, delta)

movement(delta)

headBob(delta)

if not snapUpStairsCheck(delta):
move_and_slide()
snapDownToStairCheck()

slideEyeBackToOrigin(delta)

func handleInventory():
pass # TODO

func displayFPS():
fps.text = "fps: " + str(Engine.get_frames_per_second())

func crouch(delta : float, reverse = false):


var targetHeight : float = crouchHeight if not reverse else standHeight
collision_shape.shape.height = lerp(collision_shape.shape.height,
targetHeight, delta * crouchTransition)
collision_shape.position.y = lerp(collision_shape.position.y, targetHeight *
0.5, delta * crouchTransition)
head.position.y = lerp(head.position.y, targetHeight - 1, delta *
crouchTransition)
shoulder.position.y = lerp(shoulder.position.y, targetHeight - 0.5, delta *
crouchTransition)

func dynamicHeadTilt(local_velocity : Vector3, delta : float):


#head tilt on strafe
if local_velocity.x != 0 && is_on_floor():#2.85
head.rotation.z = clamp(lerp(head.rotation.z, deg_to_rad(-
local_velocity.x/2.85), delta * 15.0), deg_to_rad(-10), deg_to_rad(10))
else:
head.rotation.z = lerp(head.rotation.z, 0.0, delta * 5.0)

#head tilt on jump and fall


if local_velocity.y != 0 && !snappedToStairLastFrame: #1.3
head.rotation.x = clamp(lerp(head.rotation.x, deg_to_rad(-
local_velocity.y/1.3), delta * lerpSpd), deg_to_rad(-30), deg_to_rad(30))
else:
head.rotation.x = lerp(head.rotation.x, 0.0, delta * lerpSpd)

func dynamicFOV(local_velocity : Vector3, delta : float):


#dynamic fov
if local_velocity.z < 0 && direction != Vector3.ZERO: #1.2
camera.fov = lerp(camera.fov, cameraBaseFOV - local_velocity.z *
1.2,delta * 5.0)
else:
camera.fov = lerp(camera.fov, cameraBaseFOV, delta * 5.0)

func movement(delta : float):


#input management
direction = (Input.get_axis("left","right") * head.basis.x +
Input.get_axis("up", "down") * head.basis.z).normalized()

#movement
if is_on_floor() or snappedToStairLastFrame == true:
velocity = velocity.lerp(direction * currentSpeed + velocity.y *
Vector3.UP, playerAcceleration * delta)
else:
velocity = velocity.lerp(direction * currentSpeed + velocity.y *
Vector3.UP, airFriction * delta)

func headBob(delta : float):


if (is_on_floor() or snappedToStairLastFrame and is_on_floor()) &&
direction != Vector3.ZERO:
head_bobbing_vector.y = sin(head_bobbing_index)
head_bobbing_vector.x = sin(head_bobbing_index/2)+0.5

head_bobbing_rotation = sin(head_bobbing_index/2)

head.rotation.z = lerp(head.rotation.z,
deg_to_rad(head_bobbing_rotation + head_bobbing_current_intensity), delta *
lerpSpd)

eye.position.y = lerp(eye.position.y,
head_bobbing_vector.y*(head_bobbing_current_intensity/2.0), delta * lerpSpd)
eye.position.x = lerp(eye.position.x,
head_bobbing_vector.x*head_bobbing_current_intensity, delta * lerpSpd)

else:
head.rotation.z = lerp(head.rotation.z, 0.0, delta * lerpSpd)

eye.position.y = lerp(eye.position.y, 0.0, delta * lerpSpd)


eye.position.x = lerp(eye.position.x, 0.0, delta * lerpSpd)

func handlePlayerInput(delta : float):


#Movement State Management
if Input.is_action_pressed("jump") and (is_on_floor()):
velocity.y = jumpForce
else:
velocity += gravity * delta

if Input.is_action_pressed("crouch"):
CurrentState = MovementState.Crouching
elif not top_cast.is_colliding():
if Input.is_action_pressed("sprint") && isReady:
CurrentState = MovementState.Sprinting
else:
CurrentState = MovementState.Walking

func handleCurrentPlayerState(delta : float):


#State Machine For Movement
match CurrentState:
MovementState.Crouching:
currentSpeed = lerp(currentSpeed, crouchspeed, delta *
playerAcceleration)
head_bobbing_current_intensity = head_bobbing_crouch_intensity
head_bobbing_index += head_bobbing_crouch_speed*delta
crouch(delta)
MovementState.Sprinting:
currentSpeed = lerp(currentSpeed, sprintSpeed, delta *
playerAcceleration)
head_bobbing_current_intensity = head_bobbing_sprint_intensity
head_bobbing_index += head_bobbing_sprint_speed*delta
crouch(delta, true)
MovementState.Walking:
currentSpeed = lerp(currentSpeed, walkSpeed, delta *
playerAcceleration)
head_bobbing_current_intensity = head_bobbing_walk_intensity
head_bobbing_index += head_bobbing_walk_speed*delta
crouch(delta, true)

func handleCameraMovementEvents(event):
if event is InputEventMouseMotion:
headYaxis += event.relative.x * mouseSens
camXaxis += event.relative.y * mouseSens
camXaxis = clamp(camXaxis, -85, 85)

func handleMouseModes():
if Input.is_action_just_pressed("show mouse"):
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
Engine.time_scale = 0.0
elif Input.mouse_mode == Input.MOUSE_MODE_VISIBLE &&
Input.is_action_just_pressed("hide mouse"):
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func handleCameraMovement(delta : float):


#Camera Movement
head.rotation.y = lerp(head.rotation.y, -deg_to_rad(headYaxis),
camAcceleration * delta)
camera.rotation.x = lerp(camera.rotation.x, -deg_to_rad(camXaxis),
camAcceleration * delta)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-80), deg_to_rad(80))

#flashlight movement
shoulder.rotation.y = -deg_to_rad(headYaxis)
hand.rotation.x = -deg_to_rad(camXaxis)

var Obj : Node


var interacting = false

func handleInteraction():
if interaction_cast.is_colliding() &&
Input.is_action_just_pressed("interact"):

var object = interaction_cast.get_collider()


Obj = object
print(object)
print(interacting)

if object is interactable:
if object is Lever:
object.interact(self)
interacting = true
elif object is button:
object.interact(self)
interacting = false
elif object is Pickupable:
object.interact(self)
interacting = false
else:
interacting = false
elif Input.is_action_just_released("interact"):
interacting = false

var pressed : bool

You might also like