Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- extends CharacterBody3D
- # Player Nodes
- @onready var neck = $neck
- @onready var head = $neck/Head
- @onready var eyes = $neck/Head/eyes
- @onready var camera = $neck/Head/eyes/Camera3D
- @onready var standing_collision_shape = $standing_collision_shape
- @onready var crouching_collision_shape = $crouching_collision_shape
- @onready var crouching_raycast = $crouching_raycast
- @onready var animation_player = $neck/Head/eyes/AnimationPlayer
- # Speed Variables
- var current_speed = 5.0
- const walking_speed = 5.0
- const sprinting_speed = 8.0
- const crouching_speed = 3.0
- const wallrun_speed = 4.0
- # States
- var walking = false
- var sprinting = false
- var crouching = false
- var freelooking = false
- var sliding = false
- var jumping = false
- var wallrunning = false
- # Slide Vars
- var slide_timer = 0.0
- var slide_timer_max = 1.0
- var slide_vector = Vector2.ZERO
- var slide_speed = 10.0
- # Headbobbing vars
- const head_bobbing_sprinting_speed = 22.0
- const head_bobbing_walking_speed = 14.0
- const head_bobbing_crouching_speed = 10.0
- const head_bobbing_sprinting_instensity = 0.2
- const head_bobbing_walking_instensity = 0.1
- const head_bobbing_crouching_instensity = 0.05
- var head_bobbing_current_intensity = 0.0
- var head_bobbing_vector = Vector2.ZERO
- var head_bobbing_index = 0.0
- # Wallrunning vars
- var can_wallrun = false
- var wallrun_delay = 0.2
- @onready var wallrun_delay_default = wallrun_delay
- @export var wallrun_angle = 15.0
- var wallrun_current_angle = 0.0
- var side = ""
- var is_wallrun_jumping = false
- var wall_jump_dir = Vector3.ZERO
- @export var wall_jump_horizontal_power = 1.5
- @export var wall_jump_vertical_power = 0.75
- @export var wall_jump_factor = 0.4
- # Movement Variables
- const jump_velocity = 4.5
- var crouching_depth = -0.5
- var freelook_lerp_speed = 15.0
- var lerp_speed = 10.0
- var air_lerp_speed = 3.0
- var freelook_tilt_amount = 6.0
- var last_velocity = Vector3.ZERO
- # Input Variables
- var direction = Vector3.ZERO
- @export var mouse_sens = 0.25
- # Get the gravity from the project settings to be synced with RigidBody nodes.
- var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
- func _ready():
- Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
- func _input(event):
- # Mouse Movement
- if event is InputEventMouseMotion:
- if freelooking:
- neck.rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
- neck.rotation.y = clamp(neck.rotation.y,deg_to_rad(-120),deg_to_rad(120))
- else:
- rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
- head.rotate_x(deg_to_rad(-event.relative.y * mouse_sens))
- head.rotation.x = clamp(head.rotation.x,deg_to_rad(-89),deg_to_rad(89))
- func _process(delta):
- if Input.is_action_just_pressed("quit"):
- get_tree().quit()
- func _physics_process(delta):
- # getting movement input
- var input_dir = Input.get_vector("left", "right", "forward", "backward")
- #Handle movement state
- # crouching
- if Input.is_action_pressed("crouch") || sliding:
- current_speed = lerp(current_speed, crouching_speed, delta * lerp_speed)
- head.position.y = lerp(head.position.y,crouching_depth, delta * lerp_speed)
- # Slide begin logic
- if sprinting && input_dir != Vector2.ZERO:
- sliding = true
- slide_timer = slide_timer_max
- slide_vector = input_dir
- freelooking = true
- standing_collision_shape.disabled = true
- crouching_collision_shape.disabled = false
- walking = false
- sprinting = false
- crouching = true
- elif !crouching_raycast.is_colliding():
- # Standing
- standing_collision_shape.disabled = false
- crouching_collision_shape.disabled = true
- head.position.y = lerp(head.position.y, 0.0, delta * lerp_speed)
- if Input.is_action_pressed("sprint"):
- # Sprinting and Walking
- current_speed = lerp(current_speed, sprinting_speed, delta * lerp_speed)
- walking = false
- sprinting = true
- crouching = false
- else:
- current_speed = lerp(current_speed, walking_speed, delta * lerp_speed)
- walking = true
- sprinting = false
- crouching = false
- # Handle Freelooking
- if Input.is_action_pressed("freelook") || sliding:
- freelooking = true
- if sliding:
- eyes.rotation.z = lerp(eyes.rotation.z, -deg_to_rad(7.0), lerp_speed * delta)
- else:
- eyes.rotation.z = -deg_to_rad(neck.rotation.y*freelook_tilt_amount)
- else:
- freelooking = false
- neck.rotation.y = lerp(neck.rotation.y,0.0,freelook_lerp_speed * delta)
- eyes.rotation.z = lerp(eyes.rotation.y,0.0,freelook_lerp_speed*delta)
- # Add Gravity
- if !is_on_floor():
- velocity.y -= gravity * delta
- # Handle Wallrunning
- if is_on_floor():
- wallrunning = false
- can_wallrun = false
- is_wallrun_jumping = false
- wallrun_delay = wallrun_delay_default
- else:
- wallrun_delay = clamp(wallrun_delay - delta, 0 , wallrun_delay_default)
- if wallrun_delay == 0.0:
- can_wallrun = true
- # Wallrun jump
- if Input.is_action_just_pressed("jump") && wallrunning:
- can_wallrun = false
- wallrunning = false
- velocity.y = jump_velocity * wall_jump_vertical_power
- is_wallrun_jumping = true
- if side == "LEFT":
- wall_jump_dir = global_transform.basis.x * wall_jump_horizontal_power
- elif side == "RIGHT":
- wall_jump_dir = -global_transform.basis.x * wall_jump_horizontal_power
- wall_jump_dir *= wall_jump_factor
- if is_wallrun_jumping:
- direction = (direction * (1 - wall_jump_factor)) + wall_jump_dir
- return
- process_wallrun()
- wallrun_anims(delta)
- # Handle jump.
- if Input.is_action_pressed("jump") and is_on_floor():
- velocity.y = jump_velocity
- jumping = true
- sliding = false
- animation_player.play("jumping")
- elif is_on_floor() && jumping:
- jumping = false
- # Handle Landing
- if is_on_floor():
- if last_velocity.y < -10.0:
- animation_player.play("roll")
- elif last_velocity.y < -4.0:
- animation_player.play("landing")
- # Handle Sliding
- if sliding:
- slide_timer -= delta
- if slide_timer <= 0:
- sliding = false
- freelooking = false
- # Handle Head Bobbing
- if sprinting:
- head_bobbing_current_intensity = head_bobbing_sprinting_instensity
- head_bobbing_index += head_bobbing_sprinting_speed * delta
- elif walking:
- head_bobbing_current_intensity = head_bobbing_walking_instensity
- head_bobbing_index += head_bobbing_walking_speed * delta
- elif crouching:
- head_bobbing_current_intensity = head_bobbing_crouching_instensity
- head_bobbing_index += head_bobbing_crouching_speed * delta
- if is_on_floor() && !sliding && input_dir != Vector2.ZERO:
- head_bobbing_vector.y = sin(head_bobbing_index)
- head_bobbing_vector.x = sin(head_bobbing_index/2) + 0.5
- eyes.position.y = lerp(eyes.position.y, head_bobbing_vector.y * (head_bobbing_current_intensity / 2.0), delta * lerp_speed)
- eyes.position.x = lerp(eyes.position.x, head_bobbing_vector.x * head_bobbing_current_intensity, delta * lerp_speed)
- else:
- eyes.position.y = lerp(eyes.position.y, 0.0, delta * lerp_speed)
- eyes.position.x = lerp(eyes.position.x, 0.0, delta * lerp_speed)
- # Get the input direction and handle the movement/deceleration.
- # As good practice, you should replace UI actions with custom gameplay actions.
- if is_on_floor():
- direction = lerp(direction,(transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(),delta*lerp_speed)
- else:
- if input_dir != Vector2.ZERO:
- direction = lerp(direction,(transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(),delta*air_lerp_speed)
- if sliding:
- direction = (transform.basis * Vector3(slide_vector.x,0,slide_vector.y)).normalized()
- current_speed = direction.x * (slide_timer + 0.1) * slide_speed
- if direction:
- velocity.x = direction.x * current_speed
- velocity.z = direction.z * current_speed
- if sliding:
- velocity.x = direction.x * (slide_timer + 0.1) * slide_speed
- velocity.z = direction.z * (slide_timer + 0.1) * slide_speed
- else:
- velocity.x = move_toward(velocity.x, 0, current_speed)
- velocity.z = move_toward(velocity.z, 0, current_speed)
- last_velocity = velocity
- move_and_slide()
- func process_wallrun():
- if can_wallrun:
- if is_on_wall() && Input.is_action_pressed("forward") && Input.is_action_pressed("sprint"):
- # Get collision data, and its normal
- var collision = get_slide_collision(0)
- var normal = collision.get_normal()
- # Calculate direction on which we have to move
- var wallrun_dir = Vector3.UP.cross(normal)
- var player_view_dir = -camera.global_transform.basis.z
- var dot = wallrun_dir.dot(player_view_dir)
- if dot < 0:
- wallrun_dir = -wallrun_dir
- # Push against wall for stability
- wallrun_dir += -normal * 0.01
- # Enable Wallrunning
- wallrunning = true
- # sets side to a string, thats tells where the wall is
- side = get_side(collision.get_position())
- # Set gravity close to 0, and movement direction to new calculated wallrun direction
- velocity.y = -0.01
- direction = wallrun_dir
- else:
- wallrunning = false
- func wallrun_anims(delta):
- # Tilt the view
- if wallrunning:
- if side == "RIGHT":
- wallrun_current_angle += delta * 60
- wallrun_current_angle = clamp(wallrun_current_angle, -wallrun_angle, wallrun_angle)
- elif side == "LEFT":
- wallrun_current_angle -= delta * 60
- wallrun_current_angle = clamp(wallrun_current_angle, -wallrun_angle, wallrun_angle)
- # Return to normal view
- else:
- if wallrun_current_angle > 0:
- wallrun_current_angle -= delta * 40
- wallrun_current_angle = max(0, wallrun_current_angle)
- elif wallrun_current_angle < 0:
- wallrun_current_angle += delta * 40
- wallrun_current_angle = min(wallrun_current_angle, 0)
- neck.rotation_degrees = Vector3(0, 0, 1) * wallrun_current_angle
- func get_side(point):
- point = to_local(point)
- if point.x > 0:
- return "RIGHT"
- elif point.x < 0:
- return "LEFT"
- else:
- return "CENTER"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement