Advertisement
CirilXD

Godot 3D Jetpack + First Person Movement + Head bobbing

Jan 29th, 2024 (edited)
1,287
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
GDScript 16.29 KB | None | 0 0
  1. extends CharacterBody3D
  2.  
  3. enum WalkState{
  4.     NORMAL,
  5.     SPRINT,
  6.     CROUCH,
  7.     PRONE,
  8.     SLIDE,
  9.     JETPACK
  10. }
  11.  
  12. #movement attribute values
  13. const TARGET_LERP = .8
  14. const JETPACK_TARGER_LERP = .6
  15.  
  16. const SPRINT_SPEED = 10.0
  17. const SPRINT_LERP_ACC = 2.0
  18. const SPRINT_LERP_DEC = 8.0
  19.  
  20. const WALK_SPEED = 6.0
  21. const WALK_LERP_ACC = 3.5
  22. const WALK_LERP_DEC = 10.0
  23.  
  24. const CROUCH_SPEED = 3.0
  25. const CROUCH_LERP_ACC = 8.0
  26. const CROUCH_LERP_DEC = 14.0
  27.  
  28. const PRONE_SPEED = 1.5
  29. const PRONE_LERP_ACC = 12.0
  30. const PRONE_LERP_DEC = 22.0
  31.  
  32. const JETPACK_SPEED = 6.0
  33. const JETPACK_LERP_ACC = 6.0
  34. const JETPACK_LERP_DEC = 12.0
  35. const JETPACK_VERTICAL_FORCE = 5.0
  36. const JETPACK_VERTICAL_VELOCITY_MAX = 2.5
  37. const JETPACK_VERTICAL_DIFFERENCE_MAX = 5.0
  38. var current_jetpack_vertical = 0.0
  39. const JETPACK_VELOCITY_THRESHOLD = .5
  40. const ENERGY_MAX = 100.0
  41. const ENERGY_DRAIN_JETPACK_START = 10
  42. const ENERGY_DRAIN_JETPACK_MULT = 10.0
  43. const ENERGY_DRAIN_SPRINT_MULT = 5.0
  44. const ENERGY_REGEN_MULT = 30.0
  45. const ENERGY_REGEN_COOLDOWN = 2.5
  46. var current_energy_regen_cooldown = 0.0
  47. var current_energy = ENERGY_MAX
  48. const JETPACK_START_TIMER = 0.65
  49. var current_jetpack_start_timer = 0
  50.  
  51. const SLIDE_SPEED = 30
  52. const SLIDE_TIME_MAX = .7
  53. const SLIDE_DAMPEN_RATE = .05
  54. const SLIDE_FLAT_DAMPEN_RATE = .001
  55. const SLOPE_SLIDE_THRESHOLD = .1
  56. var current_slide_time = 0
  57. var current_slide_vector : Vector3 = Vector3.ZERO
  58.  
  59. var SPRINT_CD_MAX = .2
  60. var current_sprint_cd = 0
  61.  
  62. const FALL_SPEED_MAX = 15
  63. const JUMP_VELOCITY = 6
  64. const JUMP_HANG_TIME_THRESHOLD = .3
  65. const JUMP_HANG_TIME_SPEED_MULT = 1.05
  66. const JUMP_HANG_TIME_ACC_MULT = 3
  67.  
  68. const COYOTE_TIME_MAX = .1
  69. var current_coyote_time = 0
  70. const JUMP_CD_MAX = .25
  71. var current_jump_cd = 0
  72.  
  73.  
  74.  
  75. # Get the gravity from the project settings to be synced with RigidBody nodes.
  76. var gravity_default = ProjectSettings.get_setting("physics/3d/default_gravity")
  77. var gravity_falling = 2 * gravity_default
  78. var gravity_hang_time = .5 * gravity_default
  79. var current_gravity = gravity_default
  80.  
  81. @export var camera_sensitivity = .25
  82.  
  83. var input_dir = Vector2.ZERO
  84. var direction = Vector3.ZERO
  85.  
  86. @onready var collider = $Collider
  87. const COLLIDER_HEIGHT_NORMAL = 2
  88. const COLLIDER_HEIGHT_CROUCH = 1.1
  89. const COLLIDER_HEIGHT_PRONE = .5
  90.  
  91. const CAMERA_HEIGHT_NORMAL = 1.8
  92. const CAMERA_HEIGHT_CROUCH = .9
  93. const CAMERA_HEIGHT_PRONE = .3
  94.  
  95. const HEAD_BOB_INTENSITY_SPRINT = .15
  96. const HEAD_BOB_INTENSITY_NORMAL = .12
  97. const HEAD_BOB_INTENSITY_CROUCH = .08
  98. const HEAD_BOB_INTENSITY_PRONE = .04
  99.  
  100. const HEAD_BOB_FREQUENCY_SPRINT = 18
  101. const HEAD_BOB_FREQUENCY_NORMAL = 14
  102. const HEAD_BOB_FREQUENCY_CROUCH = 10
  103. const HEAD_BOB_FREQUENCY_PRONE = 8
  104.  
  105. const HEAD_BOB_LERP_RATE = 50
  106.  
  107. var head_bob_var = 0
  108. var is_head_bob_active = true
  109. var current_head_bob_intensity = 0
  110. var current_head_bob_frequency = 0
  111.  
  112. const CAMERA_LERP = 10
  113. const CAMERA_FOV_NORMAL = 70.0
  114. const CAMERA_FOV_MAX_SPEED = 100.0
  115.  
  116. @onready var camera_pivot = $CameraPivot
  117. @onready var debug_label = $DebugLabel
  118. @onready var energy_bar = $EnergyBar
  119. @onready var energy_bar_bar = $EnergyBar/Bar
  120. @onready var energy_bar_label = $EnergyBar/Bar/Label
  121. @onready var height_raycast = $HeightRaycast
  122. @onready var camera_3d = $CameraPivot/HeadBobPivot/Camera3D
  123. @onready var head_bob_pivot = $CameraPivot/HeadBobPivot
  124. @onready var jetpack_stream = $jetpackStream
  125.  
  126. var current_max_speed : float = 0
  127. var current_lerp_acc : float = 0
  128. var current_lerp_dec : float = 0
  129. var current_camera_height : float = 0
  130.  
  131.  
  132. const JETPACK_VOLUME_LERP_MULT = 5
  133. const JETPACK_STREAM_STOP_THRESHOLD = .01
  134.  
  135. var current_walk_state : WalkState = WalkState.NORMAL
  136.  
  137.  
  138. var floor_angle
  139.  
  140. var debug = null
  141. var debug1 = null
  142. var debug2 = null
  143. var debug3 = null
  144.  
  145. func _ready():
  146.     Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
  147.     _UpdateCollider()
  148.     debug =  get_tree().root.get_node("ROOT/raycasts")
  149.     debug1 = debug.get_node("DebugRaycast")
  150.     debug2 = debug.get_node("DebugRaycast2")
  151.     debug3 = debug.get_node("DebugRaycast3")
  152.     floor_angle = 0
  153.    
  154.     energy_bar_bar.min_value = 0
  155.     energy_bar_bar.max_value = ENERGY_MAX
  156.     _UpdateEnergyLabel()
  157.    
  158. func _input(event):
  159.     if event is InputEventMouseMotion:
  160.         rotate_y(deg_to_rad(camera_sensitivity * -event.relative.x))
  161.         camera_pivot.rotate_x(deg_to_rad(camera_sensitivity * -event.relative.y))
  162.         camera_pivot.rotation.x = clamp(camera_pivot.rotation.x, deg_to_rad(-89), deg_to_rad(89))
  163.  
  164.  
  165. func _process(delta):
  166.     input_dir = Input.get_vector("left", "right", "forward", "back")
  167.  
  168.     direction = transform.basis * Vector3(input_dir.x, 0, input_dir.y).normalized()
  169.  
  170.     if WalkState.SLIDE != current_walk_state && WalkState.JETPACK != current_walk_state:
  171.         if Input.is_action_pressed("prone") && is_on_floor():
  172.             if current_walk_state != WalkState.PRONE:
  173.                 current_walk_state = WalkState.PRONE
  174.                 _UpdateCollider()
  175.         elif Input.is_action_pressed("crouch") and !height_raycast.is_colliding() && is_on_floor():
  176.             if current_walk_state != WalkState.CROUCH:
  177.                 if current_sprint_cd > 0:
  178.                     current_walk_state = WalkState.SLIDE
  179.                     current_slide_time = SLIDE_TIME_MAX
  180.                     current_slide_vector = abs(velocity) * direction
  181.                     current_slide_vector.y = 0
  182.                     _UpdateCollider()
  183.                 else:
  184.                     current_walk_state = WalkState.CROUCH
  185.                     _UpdateCollider()
  186.         elif !height_raycast.is_colliding():
  187.             if current_walk_state == WalkState.PRONE:
  188.                 current_walk_state = WalkState.CROUCH
  189.                 _UpdateCollider()
  190.             elif Input.is_action_pressed("sprint"):
  191.                 current_sprint_cd = SPRINT_CD_MAX
  192.                 if current_walk_state != WalkState.SPRINT:
  193.                     current_walk_state = WalkState.SPRINT
  194.                     _UpdateCollider()
  195.             elif current_walk_state != WalkState.NORMAL:
  196.                 current_walk_state = WalkState.NORMAL
  197.                 _UpdateCollider()
  198.                
  199.     floor_angle = get_floor_angle()
  200.    
  201.     _UpdateEnergyLabel()
  202.  
  203.  
  204. func _physics_process(delta):
  205.     if WalkState.SLIDE == current_walk_state:
  206.         if current_slide_time > 0:
  207.             if floor_angle < SLOPE_SLIDE_THRESHOLD || velocity.y > 0:
  208.                 current_slide_time -= delta
  209.                 current_slide_time = clamp(current_slide_time, 0, SLIDE_TIME_MAX)
  210.            
  211.         else:
  212.             current_walk_state = WalkState.CROUCH
  213.             _UpdateCollider()
  214.    
  215.     if current_sprint_cd > 0:
  216.         current_sprint_cd -= delta
  217.  
  218.     #calc target speed based on current input
  219.     var target_speed : Vector3 = direction * current_max_speed
  220.  
  221.     var current_acc_rate : Vector3 = Vector3.ZERO
  222.     if input_dir:
  223.         current_acc_rate = Vector3(current_lerp_acc,
  224.                 0,
  225.                 current_lerp_acc)
  226.     else:
  227.         current_acc_rate = Vector3(current_lerp_dec,
  228.             0,
  229.             current_lerp_dec)
  230.    
  231.    
  232.     #lerp the target speed for smoother change
  233.     #if the movement is in the same direction make the target closer to the current velocity
  234.     #otherwise, since direction shift is required make the target closer to actual target
  235.     #if player is faster than top speed don't slow down on X and Z axis
  236.     if (target_speed.x != 0 &&
  237.         abs(velocity.x) >= abs(target_speed.x) &&
  238.         sign(velocity.x) == sign(target_speed.x)):
  239.            
  240.         target_speed.x = lerp(velocity.x, target_speed.x, 1-TARGET_LERP)
  241.     else:
  242.         target_speed.x = lerp(velocity.x, target_speed.x, TARGET_LERP)
  243.        
  244.     if (target_speed.z != 0 &&
  245.         abs(velocity.z) >= abs(target_speed.z) &&
  246.         sign(velocity.z) == sign(target_speed.z)):
  247.  
  248.         target_speed.z = lerp(velocity.z, target_speed.z, 1-TARGET_LERP)
  249.     else:
  250.         target_speed.z = lerp(velocity.z, target_speed.z, TARGET_LERP)
  251.    
  252.     #Handle jetpack
  253.     if Input.is_action_pressed("jump"):
  254.         current_jetpack_start_timer += delta
  255.         current_jetpack_start_timer = min(current_jetpack_start_timer, JETPACK_START_TIMER)
  256.     elif Input.is_action_just_released("jump"):
  257.         current_jetpack_start_timer = 0
  258.        
  259.     if current_walk_state != WalkState.JETPACK:
  260.         if current_energy_regen_cooldown >= ENERGY_REGEN_COOLDOWN:
  261.             current_energy += delta * ENERGY_REGEN_MULT
  262.             current_energy = min(current_energy, ENERGY_MAX)
  263.         else:
  264.             current_energy_regen_cooldown += delta
  265.        
  266.         if current_energy > ENERGY_DRAIN_JETPACK_START && (
  267.             current_jetpack_start_timer >= JETPACK_START_TIMER ||
  268.             (Input.is_action_just_pressed("jump") &&
  269.             abs(velocity.y) > JETPACK_VELOCITY_THRESHOLD)):
  270.             current_walk_state = WalkState.JETPACK
  271.             _UpdateCollider()
  272.             jetpack_stream.volume_db = linear_to_db(0.00)
  273.             jetpack_stream.play()
  274.             current_energy -= ENERGY_DRAIN_JETPACK_START
  275.  
  276.     if current_walk_state != WalkState.JETPACK:
  277.         if jetpack_stream.playing:
  278.             jetpack_stream.volume_db = linear_to_db(lerp(
  279.                 db_to_linear(jetpack_stream.volume_db),
  280.                 0.0,
  281.                 JETPACK_VOLUME_LERP_MULT * delta
  282.             ))
  283.             if linear_to_db(JETPACK_STREAM_STOP_THRESHOLD) >= jetpack_stream.volume_db:
  284.                 jetpack_stream.volume_db = linear_to_db(0)
  285.                 jetpack_stream.stop()
  286.        
  287.         # Handle Jump.
  288.         if Input.is_action_just_released("jump") and velocity.y > 0:
  289.             current_jump_cd = 0
  290.             velocity.y = velocity.y / 2.0
  291. #           current_gravity = gravity_falling
  292.         elif current_coyote_time > 0 && (
  293.             Input.is_action_just_pressed("jump") || current_jump_cd > 0):
  294.             current_jump_cd = JUMP_CD_MAX
  295.             current_coyote_time = 0
  296.             velocity.y = JUMP_VELOCITY
  297.             if Input.is_action_pressed("sprint"): current_walk_state = WalkState.SPRINT
  298.             else: current_walk_state = WalkState.NORMAL
  299.             _UpdateCollider()
  300.            
  301.         if abs(velocity.y) < JUMP_HANG_TIME_THRESHOLD && !is_on_floor():
  302.             #make the gravity weaker around apex of jump
  303.             current_gravity = gravity_hang_time
  304.            
  305.             #increase responsiveness
  306.             target_speed *= JUMP_HANG_TIME_SPEED_MULT
  307.             current_acc_rate *= JUMP_HANG_TIME_ACC_MULT
  308.         else:
  309.             #if falling make gravity stronger
  310.             if velocity.y < 0:
  311.                 current_gravity = gravity_falling
  312.             else:
  313.                 current_gravity = gravity_default
  314.     else:  
  315.         if jetpack_stream.volume_db < linear_to_db(1):
  316.             jetpack_stream.volume_db = linear_to_db(lerp(
  317.                 db_to_linear(jetpack_stream.volume_db),
  318.                 1.0,
  319.                 JETPACK_VOLUME_LERP_MULT * delta
  320.             ))
  321.             jetpack_stream.volume_db = min(linear_to_db(1),
  322.             jetpack_stream.volume_db)
  323.        
  324.         current_gravity = 0
  325.         current_energy -= delta * ENERGY_DRAIN_JETPACK_MULT
  326.         current_energy_regen_cooldown = 0
  327.        
  328.         var vertical_target = JETPACK_VERTICAL_VELOCITY_MAX
  329.         vertical_target = lerp(velocity.y, vertical_target, JETPACK_TARGER_LERP)
  330.         var vertical_difference : float = vertical_target - velocity.y
  331.  
  332.         #final force that will be applied to character
  333.         var jetpack_movement = vertical_difference * JETPACK_VERTICAL_FORCE
  334.        
  335.         if position.y <= current_jetpack_vertical + JETPACK_VERTICAL_DIFFERENCE_MAX:
  336.             velocity.y += jetpack_movement * delta
  337.             velocity.y = min(velocity.y, JETPACK_VERTICAL_VELOCITY_MAX)
  338.         else:
  339.             velocity.y = lerp(velocity.y, 0.0, 15 * delta)
  340.  
  341.  
  342.         if Input.is_action_just_released("jump") || current_energy <= 0:
  343.             current_jetpack_start_timer = 0
  344.             if Input.is_action_pressed("sprint"): current_walk_state = WalkState.SPRINT
  345.             else: current_walk_state = WalkState.NORMAL
  346.             _UpdateCollider()
  347.    
  348.     # Add the gravity.
  349.     if not is_on_floor():
  350.         current_coyote_time -= delta
  351.         if current_coyote_time < 0: current_coyote_time = 0
  352.         velocity.y -= current_gravity * delta
  353.         current_jetpack_vertical = min(position.y, current_jetpack_vertical)
  354.     else:
  355.         current_jetpack_vertical = position.y
  356.         current_coyote_time = COYOTE_TIME_MAX
  357.  
  358.    
  359.     #calculate dif between max and current speed
  360.     #ignore y axis
  361.     var speed_difference : Vector3 = target_speed - velocity
  362.     speed_difference.y = 0
  363.  
  364.     #final force that will be applied to character
  365.     var movement = speed_difference * current_acc_rate
  366.  
  367.     if is_on_floor() && floor_angle > SLOPE_SLIDE_THRESHOLD:
  368.         var plane = Plane(get_floor_normal())
  369.         movement = plane.project(movement)
  370.         current_slide_vector = plane.project(current_slide_vector)
  371.  
  372.     if WalkState.SLIDE == current_walk_state:
  373.         velocity = velocity + (movement) * delta * SLIDE_DAMPEN_RATE
  374.         velocity = velocity + current_slide_vector * delta * (current_slide_time) * (-(current_slide_vector.y) + .01)
  375.     else:
  376.         velocity = velocity + (movement) * delta
  377.  
  378.     if velocity.y < -FALL_SPEED_MAX:
  379.         velocity.y = -FALL_SPEED_MAX
  380.        
  381.     current_jump_cd -= delta
  382.     if current_jump_cd < 0: current_jump_cd = 0
  383.    
  384.     debug_label.text = "State: " + WalkState.keys()[current_walk_state] + "\n" + str(velocity.length()) + "\n" + (
  385.         "Vertical:" + str(velocity.y)) + "\nJetpack: " + str(current_energy) + (
  386.         "\nGravity: " + str(current_gravity)) + "\nVolume: " + str(jetpack_stream.volume_db)
  387.    
  388.     _UpdateCameraPosition(delta, inverse_lerp(0, abs(SPRINT_SPEED), velocity.length()))
  389.     move_and_slide()
  390.  
  391. func _UpdateCameraPosition(delta, speed_t):
  392.     var t = CAMERA_LERP * delta
  393.  
  394.     if WalkState.SLIDE == current_walk_state:
  395.         camera_3d.rotation.z = lerp(camera_3d.rotation.z, deg_to_rad(15.0), t)
  396.     else:
  397.         camera_3d.rotation.z = lerp(camera_3d.rotation.z, 0.0, t)
  398.        
  399.     if is_head_bob_active && WalkState.SLIDE != current_walk_state && is_on_floor() && direction != Vector3.ZERO:
  400.         head_bob_var += current_head_bob_frequency * delta
  401.         head_bob_pivot.position.y = lerp(
  402.             head_bob_pivot.position.y,
  403.             sin(head_bob_var) * current_head_bob_intensity / 2.0,
  404.             t)
  405.         head_bob_pivot.position.x = lerp(
  406.             head_bob_pivot.position.x,
  407.             cos(head_bob_var / 2.0) * current_head_bob_intensity,
  408.             t)
  409.     else:
  410.         head_bob_pivot.position.y = lerp(
  411.             head_bob_pivot.position.y,
  412.             0.0,
  413.             t)
  414.         head_bob_pivot.position.x = lerp(
  415.             head_bob_pivot.position.x,
  416.             0.0,
  417.             t)
  418.        
  419.     var tmp = lerp(CAMERA_FOV_NORMAL, CAMERA_FOV_MAX_SPEED, speed_t)
  420.     camera_3d.fov = lerp(camera_3d.fov, min(tmp, CAMERA_FOV_MAX_SPEED), t)
  421.     camera_pivot.position.y = lerp(camera_pivot.position.y, current_camera_height, t)
  422.  
  423. func _UpdateCollider():
  424.     match current_walk_state:
  425.         WalkState.NORMAL:
  426.             collider.shape.height = COLLIDER_HEIGHT_NORMAL
  427.             collider.position.y = COLLIDER_HEIGHT_NORMAL / 2.0
  428.             height_raycast.target_position.y = COLLIDER_HEIGHT_NORMAL
  429.             current_camera_height = CAMERA_HEIGHT_NORMAL
  430.             current_max_speed = WALK_SPEED
  431.             current_head_bob_frequency = HEAD_BOB_FREQUENCY_NORMAL
  432.             current_head_bob_intensity = HEAD_BOB_INTENSITY_NORMAL
  433.             current_lerp_acc = WALK_LERP_ACC
  434.             current_lerp_dec = WALK_LERP_DEC
  435.         WalkState.CROUCH:  
  436.             collider.shape.height = COLLIDER_HEIGHT_CROUCH
  437.             collider.position.y = COLLIDER_HEIGHT_CROUCH / 2.0
  438.             height_raycast.target_position.y = COLLIDER_HEIGHT_NORMAL
  439.             current_camera_height = CAMERA_HEIGHT_CROUCH
  440.             current_max_speed = CROUCH_SPEED
  441.             current_head_bob_frequency = HEAD_BOB_FREQUENCY_CROUCH
  442.             current_head_bob_intensity = HEAD_BOB_INTENSITY_CROUCH
  443.             current_lerp_acc = CROUCH_LERP_ACC
  444.             current_lerp_dec = CROUCH_LERP_DEC
  445.         WalkState.SLIDE:   
  446.             collider.shape.height = COLLIDER_HEIGHT_CROUCH
  447.             collider.position.y = COLLIDER_HEIGHT_CROUCH / 2.0
  448.             height_raycast.target_position.y = COLLIDER_HEIGHT_NORMAL
  449.             current_camera_height = CAMERA_HEIGHT_CROUCH
  450.             current_max_speed = WALK_SPEED
  451.             current_head_bob_frequency = HEAD_BOB_FREQUENCY_CROUCH
  452.             current_head_bob_intensity = HEAD_BOB_INTENSITY_CROUCH
  453.             current_lerp_acc = CROUCH_LERP_ACC
  454.             current_lerp_dec = CROUCH_LERP_DEC
  455.         WalkState.PRONE:   
  456.             collider.shape.height = COLLIDER_HEIGHT_PRONE
  457.             collider.position.y = COLLIDER_HEIGHT_PRONE / 2.0
  458.             height_raycast.target_position.y = COLLIDER_HEIGHT_CROUCH
  459.             current_camera_height = CAMERA_HEIGHT_PRONE
  460.             current_max_speed = PRONE_SPEED
  461.             current_head_bob_frequency = HEAD_BOB_FREQUENCY_PRONE
  462.             current_head_bob_intensity = HEAD_BOB_INTENSITY_PRONE
  463.             current_lerp_acc = PRONE_LERP_ACC
  464.             current_lerp_dec = PRONE_LERP_DEC
  465.         WalkState.SPRINT:  
  466.             collider.shape.height = COLLIDER_HEIGHT_NORMAL
  467.             collider.position.y = COLLIDER_HEIGHT_NORMAL / 2.0
  468.             height_raycast.target_position.y = COLLIDER_HEIGHT_NORMAL
  469.             current_camera_height = CAMERA_HEIGHT_NORMAL
  470.             current_max_speed = SPRINT_SPEED
  471.             current_head_bob_frequency = HEAD_BOB_FREQUENCY_SPRINT
  472.             current_head_bob_intensity = HEAD_BOB_INTENSITY_SPRINT
  473.             current_lerp_acc = SPRINT_LERP_ACC
  474.             current_lerp_dec = SPRINT_LERP_DEC
  475.         WalkState.JETPACK
  476.             collider.shape.height = COLLIDER_HEIGHT_NORMAL
  477.             collider.position.y = COLLIDER_HEIGHT_NORMAL / 2.0
  478.             height_raycast.target_position.y = COLLIDER_HEIGHT_NORMAL
  479.             current_camera_height = CAMERA_HEIGHT_NORMAL
  480.             current_max_speed = JETPACK_SPEED
  481.             current_head_bob_frequency = HEAD_BOB_FREQUENCY_PRONE
  482.             current_head_bob_intensity = HEAD_BOB_INTENSITY_PRONE
  483.             current_lerp_acc = JETPACK_LERP_ACC
  484.             current_lerp_dec = JETPACK_LERP_DEC
  485.  
  486. func _UpdateEnergyLabel():
  487.     energy_bar_label.text = str(floor(current_energy))
  488.     energy_bar_bar.value = current_energy
  489.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement