class_name PlatformerPlayerMove extends PlatformerMove ## Move that controls an actor based on user input # ----------------------------------------------------------------------------------------------- # ## Stores the moves that can be executed by player characters ## @remarks ## This allows for moves to be reused and specialized move repositories can be ## created to replace individual moves for an actor. var move_repository ## Whether the actor is currently standing on solid ground var is_grounded : bool = false \ setget _set_is_grounded, _get_is_grounded ## Gravity that is currently influencing the actor var current_gravity : Vector3 = Vector3(0.0, -9.80665, 0.0) \ setget _set_current_gravity, _get_current_gravity # ----------------------------------------------------------------------------------------------- # ## Applies an upwards impulse to the actor that makes it jump into the ir ## @param apex_height How high the actor should jump in meters ## @param delta_seconds Current physics frame rate. This is required to calculate ## a compensation factor because all physics are framerate dependent func give_vertical_jump_impulse(apex_height : float, delta_seconds : float) -> void: #var ground_velocity : Vector3 = Vector3(0.0, 0.0, 0.0) # TODO: Port ground V reporting var gravity_vector : Vector3 = self.current_gravity var jump_impulse : float = PhysicsHelper.get_jump_off_impulse( gravity_vector.length(), apex_height, delta_seconds ) var local_actor_physics = self.actor_physics if local_actor_physics != null: jump_impulse *= local_actor_physics.mass local_actor_physics.queue_impulse(gravity_vector.normalized() * -jump_impulse) return var local_rigid_body = self.rigid_body if local_rigid_body != null: jump_impulse *= local_rigid_body.mass local_rigid_body.add_central_force(gravity_vector.normalized() * -jump_impulse) return printerr("ERROR: No ActorPhysics or RigidBody present, cannot apply jump impulse") # ----------------------------------------------------------------------------------------------- # ## Sets the actor's vertical velocity relative to the gravity vector to zero func clear_vertical_velocity() -> void: var gravity_vector : Vector3 = _get_current_gravity() var local_actor_physics = self.actor_physics if local_actor_physics != null: local_actor_physics.velocity.y = 0.0 # TODO: Actually use the gravity vector! return var local_rigid_body = self.rigid_body if local_rigid_body != null: local_rigid_body.velocity.y = 0.0 # TODO: Actually use the gravity vector return printerr("ERROR: No ActorPhysics or RigidBody present, cannot reset vertical velocity") # ----------------------------------------------------------------------------------------------- # func get_horizontal_velocity() -> float: return 0.0 # TODO # ----------------------------------------------------------------------------------------------- # ## Adjusts the actor's horizontal velocity by applying an impulse to the actor ## @param target_x_velocity Horizontal velocity the actor should be set to func change_x_velocity(target_x_velocity : float) -> void: var local_actor_physics = self.actor_physics if local_actor_physics != null: var current_x_velocity : float = local_actor_physics.velocity.x var x_impulse : float = (target_x_velocity - current_x_velocity) * local_actor_physics.mass local_actor_physics.queue_impulse(Vector3(x_impulse, 0.0, 0.0)) return var local_rigid_body = self.rigid_body if local_rigid_body != null: var current_x_velocity : float = local_rigid_body.velocity.x var x_impulse : float = (target_x_velocity - current_x_velocity) * local_rigid_body.mass local_rigid_body.add_central_force(Vector3(x_impulse, 0.0, 0.0)) return printerr("ERROR: No ActorPhysics or RigidBody present, cannot change horizontal velocity") # ----------------------------------------------------------------------------------------------- # ## Accelerates the character to the specified target velocity ## @param target_velocity Desired velocity the character should reach ## @param acceleration Maximum acceleration applied in units per second squared ## @param delta_seconds Amount of time that has elapsed since the last physics frame func accelerate_to_velocity( target_velocity : float, acceleration : float, delta_seconds : float ) -> void: var local_actor_physics = self.actor_physics if local_actor_physics != null: var current_velocity : float = local_actor_physics.velocity.x # Get force that would be required to achieve target velocity instantly # and limit it to the maximum acceleration specified by the caller var force : float = (target_velocity - current_velocity) / delta_seconds force = clamp(force, -acceleration, acceleration) force *= local_actor_physics.mass local_actor_physics.queue_force(Vector3(force, 0.0, 0.0)) return var local_rigid_body = self.rigid_body if local_rigid_body != null: var current_velocity : float = local_rigid_body.velocity.x # Get force that would be required to achieve target velocity instantly # and limit it to the maximum acceleration specified by the caller var force : float = (target_velocity - current_velocity) / delta_seconds force = clamp(force, -acceleration, acceleration) force *= local_rigid_body.mass local_rigid_body.add_central_force(Vector3(force, 0.0, 0.0)) return printerr("ERROR: No ActorPhysics or RigidBody present, cannot accelerate") # ----------------------------------------------------------------------------------------------- # ## Enables or disables gravity for the actor ## @param enable True to enable gravity, false to disable func enable_gravity(var enable : bool) -> void: var local_actor_physics = self.actor_physics if local_actor_physics != null: local_actor_physics.is_affected_by_gravity = enable return var local_rigid_body = self.rigid_body if local_rigid_body != null: local_rigid_body.use_gravity = enable return printerr("ERROR: No ActorPhysics or RigidBody present, cannot toggle gravity") # ----------------------------------------------------------------------------------------------- # ## Rechecks whether the actor is currently standing on solid ground ## @returns True if the actor is standing on solid ground, false otherwise func recheck_grounding() -> bool: return false # TODO Implement explicit grounding check # ----------------------------------------------------------------------------------------------- # ## Complains if the user tries to changes the value of the is_grounded property ## @param new_grounded Grounded state that will not be applied to the is_grounded property func _set_is_grounded(new_grounded : bool) -> void: printerr("ERROR: is_grounded property cannot be written to") # ----------------------------------------------------------------------------------------------- # ## Looks up whether the actor is currently standing on solid ground ## @returns True if the actor is standing on solid ground, false otherwise func _get_is_grounded() -> bool: var local_actor_physics = self.actor_physics if local_actor_physics != null: return local_actor_physics.is_grounded var local_rigid_body = self.rigid_body if local_rigid_body != null: return false # TODO printerr("ERROR: No ActorPhysics or RigidBody present, cannot check groundedness") return false # TODO: Check grounded state from actor # ----------------------------------------------------------------------------------------------- # ## Retrieves the current velocity at which the actor is moving ## @returns A vector holding the actor's current velocity func get_velocity() -> Vector3: var local_actor_physics = self.actor_physics if local_actor_physics != null: return local_actor_physics.velocity var local_rigid_body = self.rigid_body if local_rigid_body != null: return local_rigid_body.velocity printerr("ERROR: No ActorPhysics or RigidBody present, cannot retrieve velocity") return Vector3(0.0, 0.0, 0.0) # ----------------------------------------------------------------------------------------------- # ## Retrieves the current vertical velocity of the actor ## @returns The actor's current vertical velocity func get_vertical_velocity() -> float: # TODO: Make this relative to the gravity vector var local_actor_physics = self.actor_physics if local_actor_physics != null: return local_actor_physics.velocity.y var local_rigid_body = self.rigid_body if local_rigid_body != null: return local_rigid_body.velocity.y printerr("ERROR: No ActorPhysics or RigidBody present, cannot retrieve velocity") return 0.0 # TODO: Generalize everything above here and put it into the Move class? # Or put it in a helper class? # ----------------------------------------------------------------------------------------------- # # ----------------------------------------------------------------------------------------------- # ## Switches the actor controller to the ground move ## @param impact_velocity Velocity the actor had when hitting the ground func switch_to_ground_move(impact_velocity : float) -> void: var ground_move : Move if move_repository == null: ground_move = load( "res://Framework/Platformer/Code/PlayerMoves/PlatformerPlayerGroundMove.gd" ).new() else: ground_move = move_repository.get_ground_move(impact_velocity) print("%s now executing ground move" % actor_controller.get_node("../..").name) actor_controller.move = ground_move # ----------------------------------------------------------------------------------------------- # ## Switches the actor controller to the air move ## @param jumped Whether the character has jumped (false: actor just fell) func switch_to_air_move(jumped : bool) -> void: var air_move : Move if move_repository == null: air_move = load( "res://Framework/Platformer/Code/PlayerMoves/PlatformerPlayerAirMove.gd" ).new() air_move.jumped = jumped else: air_move = move_repository.get_air_move(jumped) print("%s now executing air move" % actor_controller.get_node("../..").name) actor_controller.move = air_move # ----------------------------------------------------------------------------------------------- # ## Switches the actor controller to the dash move func switch_to_dash_move() -> void: var dash_move : Move if move_repository == null: dash_move = load( "res://Framework/Platformer/Code/PlayerMoves/PlatformerPlayerDashMove.gd" ).new() else: dash_move = move_repository.get_dash_move() actor_controller.move = dash_move # ----------------------------------------------------------------------------------------------- # ## Switches the actor controller to the squat move func switch_to_squat_move() -> void: var squat_move : Move if move_repository == null: squat_move = load( "res://Framework/Platformer/Code/PlayerMoves/PlatformerPlayerSquatMove.gd" ).new() else: squat_move = move_repository.get_squat_move() actor_controller.move = squat_move # ----------------------------------------------------------------------------------------------- # ## Switches the actor controller to the squat move func switch_to_slide_move() -> void: var slide_move = Move if move_repository == null: slide_move = load( "res://Framework/Platformer/Code/PlayerMoves/PlatformerPlayerSlideMove.gd" ).new() else: slide_move = move_repository.get_slide_move() actor_controller.move = slide_move # ----------------------------------------------------------------------------------------------- # ## Looks up the current direction and strength of gravity influencing the actor ## @returns A vector pointing downwards (in terms of gravity) with the strength of gravity func _get_current_gravity() -> Vector3: if actor_controller != null: current_gravity = actor_controller.current_gravity return current_gravity printerr("ERROR: Move has not been bound to an actor controller yet, cannot check gravity") current_gravity = Vector3(0.0, -9.80665, 0.0) # Default average earth gravity return current_gravity # ----------------------------------------------------------------------------------------------- # ## Complains if the user tries to directly assign the current gravity vector ## @param new_gravity New gravity vector that will not be assigned func _set_current_gravity(new_gravity : Vector3) -> void: if new_gravity != current_gravity: printerr("ERROR: The current gravity vector cannot be assigned to")