Advertisement
AriesOnThat

character controller.

Apr 29th, 2024
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
GDScript 10.04 KB | Source Code | 0 0
  1. extends CharacterBody3D
  2.  
  3. # Player Nodes
  4. @onready var neck = $neck
  5. @onready var head = $neck/Head
  6. @onready var eyes = $neck/Head/eyes
  7. @onready var camera = $neck/Head/eyes/Camera3D
  8. @onready var standing_collision_shape = $standing_collision_shape
  9. @onready var crouching_collision_shape = $crouching_collision_shape
  10. @onready var crouching_raycast = $crouching_raycast
  11. @onready var animation_player = $PlayerModel/AnimationPlayer
  12.  
  13.  
  14. # Speed Variables
  15. var current_speed = 5.0
  16.  
  17. const walking_speed = 5.0
  18. const sprinting_speed = 8.0
  19. const crouching_speed = 3.0
  20. const wallrun_speed = 4.0
  21.  
  22. # States
  23. var walking = false
  24. var sprinting = false
  25. var crouching = false
  26. var freelooking = false
  27. var sliding = false
  28. var jumping = false
  29. var wallrunning = false
  30.  
  31. var paused = false
  32.  
  33. # Slide Vars
  34. var slide_timer = 0.0
  35. var slide_timer_max = 1.0
  36. var slide_vector = Vector2.ZERO
  37. var slide_speed = 10.0
  38.  
  39. # Headbobbing vars
  40. const head_bobbing_sprinting_speed = 22.0
  41. const head_bobbing_walking_speed = 14.0
  42. const head_bobbing_crouching_speed = 10.0
  43.  
  44. const head_bobbing_sprinting_instensity = 0.2
  45. const head_bobbing_walking_instensity = 0.1
  46. const head_bobbing_crouching_instensity = 0.05
  47.  
  48. var head_bobbing_current_intensity = 0.0
  49.  
  50. var head_bobbing_vector = Vector2.ZERO
  51. var head_bobbing_index = 0.0
  52.  
  53. # Wallrunning vars
  54. var can_wallrun = false
  55. var wallrun_delay = 0.2
  56. @onready var wallrun_delay_default = wallrun_delay
  57. @export var wallrun_angle = 15.0
  58. var wallrun_current_angle = 0.0
  59. var side = ""
  60. var is_wallrun_jumping = false
  61. var wall_jump_dir = Vector3.ZERO
  62. @export var wall_jump_horizontal_power = 0.75
  63. @export var wall_jump_vertical_power = 1.0
  64. @export var wall_jump_factor = 0.4
  65.  
  66. # Movement Variables
  67. const jump_velocity = 4.5
  68. var crouching_depth = -0.5
  69. var freelook_lerp_speed = 15.0
  70. var lerp_speed = 10.0
  71. var air_lerp_speed = 3.0
  72. var freelook_tilt_amount = 6.0
  73. var last_velocity = Vector3.ZERO
  74.  
  75.  
  76. # Input Variables
  77. var direction = Vector3.ZERO
  78. @export var mouse_sens = 0.25
  79.  
  80. # Pause screen instanctiate vars
  81. var pause_menu = preload("res://scenes/Pause menu.tscn")
  82. var pause_screen_instance = pause_menu.instantiate()
  83.  
  84. # Get the gravity from the project settings to be synced with RigidBody nodes.
  85. var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
  86.  
  87. func _ready():
  88.     Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
  89.  
  90. func _input(event):
  91. # Mouse Movement
  92.     if event is InputEventMouseMotion and !paused:
  93.         if freelooking:
  94.             neck.rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
  95.             neck.rotation.y = clamp(neck.rotation.y,deg_to_rad(-120),deg_to_rad(120))
  96.         else:
  97.             rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
  98.             head.rotate_x(deg_to_rad(-event.relative.y * mouse_sens))
  99.             head.rotation.x = clamp(head.rotation.x,deg_to_rad(-89),deg_to_rad(89))
  100.  
  101. func _process(delta):
  102.     if Input.is_action_just_pressed("quit") and !paused:
  103.         Pause()
  104.     elif Input.is_action_just_pressed("quit") and paused:
  105.         Unpause()
  106.  
  107. func _physics_process(delta):
  108.     # getting movement input
  109.     var input_dir = Input.get_vector("left", "right", "forward", "backward")
  110.  
  111.     #Handle movement state
  112.  
  113.     # crouching
  114.     if Input.is_action_pressed("crouch") || sliding and !wallrunning and !paused:
  115.        
  116.         current_speed = lerp(current_speed, crouching_speed, delta * lerp_speed)
  117.         head.position.y = lerp(head.position.y,crouching_depth, delta * lerp_speed)
  118.  
  119.         # Slide begin logic
  120.  
  121.         if sprinting && input_dir != Vector2.ZERO:
  122.             sliding = true
  123.             slide_timer = slide_timer_max
  124.             slide_vector = input_dir
  125.             freelooking = true
  126.  
  127.         standing_collision_shape.disabled = true
  128.         crouching_collision_shape.disabled = false
  129.  
  130.         walking = false
  131.         sprinting = false
  132.         crouching = true
  133.     else:
  134.         head.position.y = lerp(head.position.y,0.5, delta * lerp_speed)
  135.        
  136.         crouching = false
  137.         standing_collision_shape.disabled = false
  138.         crouching_collision_shape.disabled = true
  139.     if Input.is_action_pressed("sprint"):
  140.     # Sprinting and Walking
  141.         current_speed = lerp(current_speed, sprinting_speed, lerp_speed * delta)
  142.  
  143.         walking = false
  144.         sprinting = true
  145.         crouching = false
  146.     else:
  147.         current_speed = lerp(current_speed, walking_speed, delta * lerp_speed)
  148.  
  149.         walking = true
  150.         sprinting = false
  151.         crouching = false
  152.  
  153.     # Handle Freelooking
  154.     if Input.is_action_pressed("freelook") || sliding:
  155.         freelooking = true
  156.        
  157.         if sliding:
  158.             eyes.rotation.z = lerp(eyes.rotation.z, -deg_to_rad(7.0), lerp_speed * delta)
  159.         else:
  160.             eyes.rotation.z = -deg_to_rad(neck.rotation.y*freelook_tilt_amount)
  161.     else:
  162.         freelooking = false
  163.         neck.rotation.y = lerp(neck.rotation.y,0.0,freelook_lerp_speed * delta)
  164.         eyes.rotation.z = lerp(eyes.rotation.y,0.0,freelook_lerp_speed*delta)
  165.  
  166.     # Add Gravity
  167.     if !is_on_floor():
  168.         velocity.y -= gravity * delta
  169.  
  170.     # Handle Wallrunning
  171.     if is_on_floor():
  172.         wallrunning = false
  173.         can_wallrun = false
  174.         is_wallrun_jumping = false
  175.         wallrun_delay = wallrun_delay_default
  176.     else:
  177.         wallrun_delay = clamp(wallrun_delay - delta, 0 , wallrun_delay_default)
  178.        
  179.         if wallrun_delay == 0.0:
  180.             can_wallrun = true
  181.  
  182.     # Wallrun jump
  183.     if Input.is_action_just_pressed("jump") && wallrunning:
  184.         can_wallrun = false
  185.         wallrunning = false
  186.         is_wallrun_jumping = true
  187.        
  188.         velocity.y = jump_velocity * wall_jump_vertical_power
  189.        
  190.         if side == "LEFT":
  191.             wall_jump_dir = global_transform.basis.x * wall_jump_horizontal_power
  192.         elif side == "RIGHT":
  193.             wall_jump_dir = -global_transform.basis.x * wall_jump_horizontal_power
  194.        
  195.         wall_jump_dir *= wall_jump_factor
  196.  
  197.     if is_wallrun_jumping:
  198.         direction = (direction * (1 - wall_jump_factor)) + wall_jump_dir
  199.  
  200.     process_wallrun()
  201.     wallrun_anims(delta)
  202.  
  203.     # Handle jump.
  204.     if Input.is_action_pressed("jump") and is_on_floor() and !paused:
  205.         velocity.y = jump_velocity
  206.         jumping = true
  207.         sliding = false
  208.     elif is_on_floor() && jumping:
  209.         jumping = false
  210.  
  211.  
  212.     # Handle Sliding
  213.     if sliding:
  214.         slide_timer -= delta
  215.         print(slide_timer)
  216.         if slide_timer <= 0:
  217.             sliding = false
  218.             freelooking = false
  219.  
  220.     # Handle Head Bobbing
  221.     if sprinting:
  222.         head_bobbing_current_intensity = head_bobbing_sprinting_instensity
  223.         head_bobbing_index += head_bobbing_sprinting_speed * delta
  224.     elif walking:
  225.         head_bobbing_current_intensity = head_bobbing_walking_instensity
  226.         head_bobbing_index += head_bobbing_walking_speed * delta
  227.     elif crouching:
  228.         head_bobbing_current_intensity = head_bobbing_crouching_instensity
  229.         head_bobbing_index += head_bobbing_crouching_speed * delta
  230.  
  231.     if is_on_floor() && !sliding && input_dir != Vector2.ZERO:
  232.         head_bobbing_vector.y = sin(head_bobbing_index)
  233.         head_bobbing_vector.x = sin(head_bobbing_index/2) + 0.5
  234.  
  235.         eyes.position.y = lerp(eyes.position.y, head_bobbing_vector.y * (head_bobbing_current_intensity / 2.0), delta * lerp_speed)
  236.         eyes.position.x = lerp(eyes.position.x, head_bobbing_vector.x * head_bobbing_current_intensity, delta * lerp_speed)
  237.     else:
  238.         eyes.position.y = lerp(eyes.position.y, 0.0, delta * lerp_speed)
  239.         eyes.position.x = lerp(eyes.position.x, 0.0, delta * lerp_speed)
  240.  
  241.     # Get the input direction and handle the movement/deceleration.
  242.     # As good practice, you should replace UI actions with custom gameplay actions.
  243.  
  244.     if is_on_floor():
  245.         direction = lerp(direction,(transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(),delta*lerp_speed)
  246.     else:
  247.         if input_dir != Vector2.ZERO:
  248.             direction = lerp(direction,(transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(),delta*air_lerp_speed)
  249.  
  250.     if sliding:
  251.         direction = (transform.basis * Vector3(slide_vector.x,0,slide_vector.y)).normalized()
  252.         current_speed = direction.x * (slide_timer + 0.1) * slide_speed
  253.  
  254.  
  255.  
  256.     if direction and !paused:
  257.         velocity.x = direction.x * current_speed
  258.         velocity.z = direction.z * current_speed
  259.  
  260.  
  261.         if sliding:
  262.             velocity.x = direction.x * (slide_timer + 0.1) * slide_speed
  263.             velocity.z = direction.z * (slide_timer + 0.1) * slide_speed
  264.     else:
  265.         velocity.x = move_toward(velocity.x, 0, current_speed)
  266.         velocity.z = move_toward(velocity.z, 0, current_speed)
  267.  
  268.  
  269.     last_velocity = velocity
  270.  
  271.     move_and_slide()
  272.  
  273. func process_wallrun():
  274.     if can_wallrun:
  275.         if is_on_wall() && Input.is_action_pressed("forward") && Input.is_action_pressed("sprint"):
  276.             # Get collision data, and its normal
  277.             var collision = get_slide_collision(0)
  278.             var normal = collision.get_normal()
  279.            
  280.             # Calculate direction on which we have to move
  281.             var wallrun_dir = Vector3.UP.cross(normal)
  282.            
  283.             var player_view_dir = -camera.global_transform.basis.z
  284.             var dot = wallrun_dir.dot(player_view_dir)
  285.             if dot < 0:
  286.                 wallrun_dir = -wallrun_dir
  287.                
  288.             # Push against wall for stability
  289.             wallrun_dir += -normal * 0.01
  290.            
  291.             # Enable Wallrunning
  292.             wallrunning = true
  293.            
  294.             # sets side to a string, thats tells where the wall is
  295.             side = get_side(collision.get_position())
  296.            
  297.             # Set gravity close to 0, and movement direction to new calculated wallrun direction
  298.             velocity.y = -0.01
  299.             direction = wallrun_dir
  300.         else:
  301.             wallrunning = false
  302.            
  303. func wallrun_anims(delta):
  304.     # Tilt the view
  305.     if wallrunning:
  306.         if side == "RIGHT":
  307.             wallrun_current_angle += delta * 60
  308.             wallrun_current_angle = clamp(wallrun_current_angle, -wallrun_angle, wallrun_angle)
  309.         elif side == "LEFT":
  310.             wallrun_current_angle -= delta * 60
  311.             wallrun_current_angle = clamp(wallrun_current_angle, -wallrun_angle, wallrun_angle)
  312.            
  313.     # Return to normal view
  314.     else:
  315.         if wallrun_current_angle > 0:
  316.             wallrun_current_angle -= delta * 40
  317.             wallrun_current_angle = max(0, wallrun_current_angle)
  318.         elif wallrun_current_angle < 0:
  319.             wallrun_current_angle += delta * 40
  320.             wallrun_current_angle = min(wallrun_current_angle, 0)
  321.            
  322.     neck.rotation_degrees = Vector3(0, 0, 1) * wallrun_current_angle
  323.  
  324. func get_side(point):
  325.     point = to_local(point)
  326.    
  327.     if point.x > 0:
  328.         return "RIGHT"
  329.     elif point.x < 0:
  330.         return "LEFT"
  331.     else:
  332.         return "CENTER"
  333.  
  334. func Pause():
  335.     paused = true
  336.     Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
  337.     add_child(pause_screen_instance)
  338.    
  339. func Unpause():
  340.     paused = false
  341.     Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
  342.     remove_child(pause_screen_instance)
  343.  
  344.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement