extends KinematicBody # Load Config File var player_data = {} var player_config = ConfigFile.new() var player_filepath = "res://config/player.ini" # Popup menus var Pause_Popup_tscn = preload("res://Pause_Popup.tscn") var Dead_Popup_tscn = preload("res://Dead_Popup.tscn") ###################-VARIABLES-#################### # Camera export(float) var mouse_sensitivity = 8.0 export(NodePath) var head_path = "Head" export(NodePath) var cam_path = "Head/Camera" export(float) var FOV = 80.0 var mouse_axis := Vector2() onready var head: Spatial = get_node(head_path) onready var cam: Camera = get_node(cam_path) # Move var velocity := Vector3() var direction := Vector3() var move_axis := Vector2() var snap := Vector3() # Connecting to ground var falling := Vector3() # Damage var max_fall := Vector3() # Total disatance falled down var fall_threshold_damage = 17 # distance down a player has to fall before taking damage # Walk and Sprint const FLOOR_MAX_ANGLE: float = deg2rad(46.0) export(float) var gravity = 20.0 export(int) var walk_speed = 10 export(int) var sprint_speed = 16 export(int) var acceleration = 8 export(int) var deacceleration = 10 export(float, 0.0, 1.0, 0.05) var air_control = 0.3 export(int) var jump_height = 12 var _speed: int var _is_sprinting_input := false var _is_jumping_input := false var sprint_enabled := true var hold_walk := false var stamina_delay = 0 # Grounded enum GROUNDED_STATE { GROUNDED, MIDAIR, TOUCHDOWN } var player_state = GROUNDED_STATE.GROUNDED # Player Stats Replaced by Globals. # var health = 100 # var stamina = 100 # var mana = 100 # var lifeforce = 100 # var xp = 0 # var dead = false var exhausted_delay = 30 var sprint_energy_consumption = 0.5 var stamina_regen_speed = 0.5 var mana_needed_to_heal = 30 var mana_heal_ammount = 10 var mana_regen_speed = 0.01 var player = "player" ################################################## # Called when the node enters the scene tree func _ready() -> void: if player_config.load(player_filepath) == OK: mana_needed_to_heal = player_config.get_value(player, "mana_needed_to_heal") mana_heal_ammount = player_config.get_value(player, "mana_heal_ammount") mana_regen_speed = player_config.get_value(player, "mana_regen_speed") fall_threshold_damage = player_config.get_value(player, "fall_threshold_damage") gravity = player_config.get_value(player, "gravity") walk_speed = player_config.get_value(player, "walk_speed") exhausted_delay = player_config.get_value(player, "exhausted_delay") stamina_regen_speed = player_config.get_value(player, "stamina_regen_speed") sprint_speed = player_config.get_value(player, "sprint_speed") sprint_energy_consumption = player_config.get_value(player, "sprint_energy_consumption") jump_height = player_config.get_value(player, "jump_height") else: print("Player Config File Not Found - Using defaults") # Remove this later, this is just a temp line until future code is avalable for each player to have its own stats Globals.dead = false Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) cam.fov = FOV # Called every frame. 'delta' is the elapsed time since the previous frame func _process(_delta: float) -> void: move_axis.x = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward") move_axis.y = Input.get_action_strength("move_right") - Input.get_action_strength("move_left") if Globals.dead: Globals.player_dead() if Globals.food_task: get_node("HUD/Control/LifeforceBar").value = Globals.lifeforce if Input.is_action_just_pressed("move_jump"): _is_jumping_input = true if Input.is_action_pressed("move_sprint"): _is_sprinting_input = true if Input.is_action_just_pressed("hold_move_forward"): if hold_walk == true: hold_walk = false else: hold_walk = true if Input.is_action_just_pressed("move_forward") || Input.is_action_just_pressed("move_backward"): hold_walk = false if hold_walk == true: move_axis.x = hold_walk # Recapture mouse when resuming if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE && !Globals.dead: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) # Called every physics tick. 'delta' is constant func _physics_process(delta: float) -> void: walk(delta) # Fall damage calculation match player_state: GROUNDED_STATE.GROUNDED: falling = Vector3.ZERO if not is_on_floor(): player_state = GROUNDED_STATE.MIDAIR GROUNDED_STATE.MIDAIR: falling += Vector3.DOWN * gravity * delta if velocity.y <= -fall_threshold_damage: max_fall = velocity if is_on_floor(): player_state = GROUNDED_STATE.TOUCHDOWN GROUNDED_STATE.TOUCHDOWN: if falling.length() >= fall_threshold_damage and max_fall.y <= -fall_threshold_damage: Globals.health -= round(-(max_fall.y + fall_threshold_damage)) Globals.stamina -= round(-(max_fall.y + fall_threshold_damage)) if round(-(max_fall.y + fall_threshold_damage)) > 5: Globals.health -= round(-(max_fall.y + fall_threshold_damage)*9) else: if round(-(max_fall.y + fall_threshold_damage)) > 10: Globals.health -= round(-(max_fall.y + fall_threshold_damage)*15) if Globals.health <= 0: Globals.lifeforce += Globals.health * 2 if Globals.lifeforce <= 0: Globals.health = 0 Globals.lifeforce = 0 Globals.dead = true else: Globals.health = 1 Globals.mana = 0 Globals.stamina = 0 stamina_delay = exhausted_delay sprint_enabled = false get_node("HUD/Control/LifeforceBar").value = Globals.lifeforce get_node("HUD/Control/ManaBar").value = Globals.mana get_node("Head/AnimationPlayer").play("FallDamage") get_node("HUD/Control/HealthBar").value = Globals.health max_fall = Vector3.ZERO player_state = GROUNDED_STATE.GROUNDED # Called when there is an input event func _input(event: InputEvent) -> void: if event is InputEventMouseMotion: mouse_axis = event.relative camera_rotation() # Heal button if Input.is_action_just_pressed("heal") && Globals.mana >= mana_needed_to_heal: if Globals.health != 100: Globals.mana -= mana_needed_to_heal if 100 < Globals.health + mana_heal_ammount: Globals.health = 100 elif Globals.health == 0: Globals.health = mana_heal_ammount else: Globals.health += mana_heal_ammount get_node("HUD/Control/HealthBar").value = Globals.health get_node("HUD/Control/ManaBar").value = Globals.mana func walk(delta: float) -> void: direction_input() if is_on_floor(): snap = -get_floor_normal() - get_floor_velocity() * delta # Workaround for sliding down after jump on slope if velocity.y < 0: velocity.y = 0 jump() else: # Workaround for 'vertical bump' when going off platform if snap != Vector3.ZERO && velocity.y != 0: velocity.y = 0 snap = Vector3.ZERO velocity.y -= gravity * delta sprint(delta) accelerate(delta) velocity = move_and_slide_with_snap(velocity, snap, Vector3.UP, true, 4, FLOOR_MAX_ANGLE) _is_jumping_input = false _is_sprinting_input = false func camera_rotation() -> void: if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED: return if mouse_axis.length() > 0: var horizontal: float = -mouse_axis.x * (Globals.mouse_sensitivity / 100) var vertical: float = -mouse_axis.y * (Globals.mouse_sensitivity / 100) mouse_axis = Vector2() rotate_y(deg2rad(horizontal)) head.rotate_x(deg2rad(vertical)) # Clamp mouse rotation var temp_rot: Vector3 = head.rotation_degrees temp_rot.x = clamp(temp_rot.x, -90, 90) head.rotation_degrees = temp_rot func direction_input() -> void: direction = Vector3() var aim: Basis = get_global_transform().basis if move_axis.x >= 0.5: direction -= aim.z if move_axis.x <= -0.5: direction += aim.z if move_axis.y <= -0.5: direction -= aim.x if move_axis.y >= 0.5: direction += aim.x direction.y = 0 direction = direction.normalized() func accelerate(delta: float) -> void: # Where would the player go var _temp_vel: Vector3 = velocity var _temp_accel: float var _target: Vector3 = direction * _speed _temp_vel.y = 0 if direction.dot(_temp_vel) > 0: _temp_accel = acceleration else: _temp_accel = deacceleration if not is_on_floor(): _temp_accel *= air_control # Interpolation _temp_vel = _temp_vel.linear_interpolate(_target, _temp_accel * delta) velocity.x = _temp_vel.x velocity.z = _temp_vel.z # Make too low values zero if direction.dot(velocity) == 0: var _vel_clamp := 0.01 if abs(velocity.x) < _vel_clamp: velocity.x = 0 if abs(velocity.z) < _vel_clamp: velocity.z = 0 func jump() -> void: if _is_jumping_input: velocity.y = jump_height snap = Vector3.ZERO func sprint(delta: float) -> void: if can_sprint(): if Globals.stamina >= 0 && stamina_delay <= 1: _speed = sprint_speed cam.set_fov(lerp(cam.fov, FOV * 1.25, delta * 8)) Globals.stamina -= sprint_energy_consumption if Globals.stamina <= 0: stamina_delay = exhausted_delay sprint_enabled = false cam.fov = FOV _speed = walk_speed return get_node("HUD/Control/StaminaBar").value = Globals.stamina else: _speed = walk_speed cam.set_fov(lerp(cam.fov, FOV, delta * 8)) if stamina_delay >= 0: stamina_delay -= 0.1 sprint_enabled = true elif Globals.stamina <= 100: if velocity.x == 0: Globals.stamina += stamina_regen_speed * 2 else: Globals.stamina += stamina_regen_speed elif Globals.stamina >= 100 && Globals.mana < 100: if velocity.x == 0: Globals.mana += mana_regen_speed * 2 else: Globals.mana += mana_regen_speed get_node("HUD/Control/ManaBar").value = Globals.mana get_node("HUD/Control/StaminaBar").value = Globals.stamina func can_sprint() -> bool: return (sprint_enabled and is_on_floor() and _is_sprinting_input and move_axis.x >= 0.5)