using System;
using UnityEngine;
using Framework.Input;
using Framework.Layers;
namespace Framework.Actors.Platformer {
/// Move that can be performed by the player
public class PlayerMove : PlatformerMove {
/// Called when the actor has started the move
public override void OnStarted() {
base.OnStarted();
SetPresenterState();
}
///
/// Switches the presenter to the animation state appropriate for this move
///
///
/// This is called when the move becomes active. It is typically used to trigger
/// the animation related to the move (or change exposed variables in Mecanim
/// to switch to the correct animation state).
///
protected virtual void SetPresenterState() {}
/// Injects the instance's dependencies
///
/// Input selector the instance uses to determine the active input source
///
///
/// This method is called automatically by the services framework. Any parameters
/// it requires will be filled out by looking up the respective services and creating
/// them as needed.
///
protected void Inject(IInputManager inputManager) {
this.inputManager = inputManager;
}
/// Called once when the movement is assigned to an actor
/// Actor the movement has been assigned to
protected override void Awake(ActorController actor) {
base.Awake(actor);
this.moveRepository = actor.GetComponent();
this.abilities = ActorController.Abilities;
}
/// Abilities the actor possesses
protected Abilities Abilities {
get { return this.abilities; }
}
/// Input manager from which the input state can be queried
protected IInputManager InputManager {
get { return this.inputManager; }
}
/// Adds a jump impulse to the actor
/// Apex height the actor should achieve from the jump
protected void GiveVerticalJumpImpulse(float apexHeight) {
Vector3 groundVelocity = ActorController.GroundChecker.GetMostRecentGroundVelocity();
float gravityStrength = Physics.gravity.magnitude;
if(Rigidbody != null) {
float jumpImpulse = PhysicsHelper.GetJumpOffImpulse(
gravityStrength, apexHeight, Time.fixedDeltaTime
);
float relativeImpulse = groundVelocity.y + jumpImpulse;
relativeImpulse -= Rigidbody.velocity.y;
Rigidbody.AddForce(
new Vector3(0.0f, relativeImpulse * Rigidbody.mass, 0.0f), ForceMode.Impulse
);
} else if(ActorPhysics != null) {
gravityStrength *= ActorPhysics.GravityScale;
float jumpImpulse = PhysicsHelper.GetJumpOffImpulse(
gravityStrength, apexHeight, Time.fixedDeltaTime
);
float relativeImpulse = groundVelocity.y + jumpImpulse;
relativeImpulse -= ActorPhysics.Velocity.y;
ActorPhysics.QueueImpulse(
new Vector3(0.0f, relativeImpulse * ActorPhysics.Mass, 0.0f)
);
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, cannot give jump impulse."
);
}
}
/// Sets the vertical velocity of the actor to zero
protected void ClearVerticalVelocity() {
if(Rigidbody != null) {
Vector3 velocity = Rigidbody.velocity;
velocity.y = 0.0f;
Rigidbody.velocity = velocity;
} else if(ActorPhysics != null) {
Vector3 velocity = ActorPhysics.Velocity;
velocity.y = 0.0f;
ActorPhysics.Velocity = velocity;
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, cannot clear vertical velocity."
);
}
}
/// Changes the character's velocity to the specified velocity
/// Velocity the character will assume
protected void ChangeVelocity(float targetVelocity) {
if(Rigidbody != null) {
float currentVelocity = Rigidbody.velocity.x;
float impulse = (targetVelocity - currentVelocity) * Rigidbody.mass;
Rigidbody.AddForce(new Vector3(impulse, 0.0f, 0.0f), ForceMode.Impulse);
} else if(ActorPhysics != null) {
float currentVelocity = ActorPhysics.Velocity.x;
float impulse = (targetVelocity - currentVelocity) * ActorPhysics.Mass;
ActorPhysics.QueueImpulse(new Vector3(impulse, 0.0f, 0.0f));
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, cannot set velocity."
);
}
}
/// Accelerates the character to the specified target velocity
/// Velocity the character should reach
/// Acceleration in units per second squared
protected void AccelerateToVelocity(float targetVelocity, float acceleration) {
float deltaTime = Time.fixedDeltaTime;
if(Rigidbody != null) {
float currentVelocity = Rigidbody.velocity.x;
// Get force that would be required to achieve target velocity instantly
// and limit it to the acceleration specified by the caller
float force = (targetVelocity - currentVelocity) / deltaTime;
force = Mathf.Clamp(force, -acceleration, acceleration);
force *= Rigidbody.mass;
Rigidbody.AddForce(new Vector3(force, 0.0f, 0.0f), ForceMode.Force);
} else if(ActorPhysics != null) {
float currentVelocity = ActorPhysics.Velocity.x;
// Get force that would be required to achieve target velocity instantly
// and limit it to the acceleration specified by the caller
float force = (targetVelocity - currentVelocity) / deltaTime;
force = Mathf.Clamp(force, -acceleration, acceleration);
force *= ActorPhysics.Mass;
ActorPhysics.QueueForce(new Vector3(force, 0.0f, 0.0f));
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, cannot accelerate."
);
}
}
/// Enables or disables gravity for the actor
/// True to enable gravity, false to disable it
protected void EnableGravity(bool active = true) {
if(Rigidbody != null) {
Rigidbody.useGravity = active;
} else if(ActorPhysics != null) {
ActorPhysics.IsAffectedByGravity = active;
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, cannot toggle gravity."
);
}
}
///
/// Uses the GroundChecker component to update the grounded state of the actor
///
protected bool RecheckGrounding() {
if(ActorPhysics != null) {
return
ActorController.GroundChecker.CheckIfGrounded(ActorPhysics) ||
ActorPhysics.UnreliableIsGrounded;
} else {
Collider collider = ActorController.GetComponent();
if(collider != null) {
int layerMask = LayerMaskHelper.GetLayerCollisionMaskFor(
ActorController.gameObject.layer
);
return ActorController.GroundChecker.CheckIfGrounded(collider, layerMask);
}
}
return false;
}
/// Checks whether the actor is standing on solid ground
protected bool IsGrounded {
get {
if(ActorPhysics != null) {
return
ActorController.GroundChecker.WasGroundedInMostRecentCheck ||
ActorPhysics.UnreliableIsGrounded;
} else {
return ActorController.GroundChecker.WasGroundedInMostRecentCheck;
}
}
}
/// Retrieves the current velocity of the actor
/// The actor's current velocity
protected Vector3 GetVelocity() {
if(Rigidbody != null) {
return Rigidbody.velocity;
} else if(ActorPhysics != null) {
return ActorPhysics.Velocity;
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, velocity retrieval impossible"
);
return Vector3.zero;
}
}
/// Retrieves the current vertical velocity of the actor
/// The actor's current vertical velocity
protected float GetVerticalVelocity() {
if(Rigidbody != null) {
return Rigidbody.velocity.y;
} else if(ActorPhysics != null) {
return ActorPhysics.Velocity.y;
} else {
Debug.LogError(
"No Rigidbody and no ActorPhysics component present, velocity check impossible"
);
return float.NaN;
}
}
/// Switches the actor controller to the ground move
/// Velocity the actor had when hitting the ground
protected void SwitchToGroundMove(float impactVelocity = 0.0f) {
Move groundMode;
if(this.moveRepository == null) {
groundMode = new GroundMove();
} else {
groundMode = this.moveRepository.GetGroundMove();
}
ActorController.ActiveMove = groundMode;
}
/// Switches the actor controller to the air move
/// Whether the character has jumped
protected void SwitchToAirMove(bool jumped) {
Move airMove;
if(this.moveRepository == null) {
airMove = new AirMove() { WasActivatedByJumping = jumped };
} else {
airMove = this.moveRepository.GetAirMove(jumped);
}
ActorController.ActiveMove = airMove;
}
/// Switches the actor controller to the dash move
protected void SwitchToDashMove() {
Move dashMove;
if(this.moveRepository == null) {
dashMove = new DashMove();
} else {
dashMove = this.moveRepository.GetDashMove();
}
ActorController.ActiveMove = dashMove;
}
/// Switches the actor controller to the squat move
protected void SwitchToSquatMove() {
Move squatMove;
if(this.moveRepository == null) {
squatMove = new SquatMove();
} else {
squatMove = this.moveRepository.GetSquatMove();
}
ActorController.ActiveMove = squatMove;
}
/// Switches the actor controller to the squat move
protected void SwitchToSlideMove() {
Move slideMove;
if(this.moveRepository == null) {
slideMove = new SlideMove();
} else {
slideMove = this.moveRepository.GetSlideMove();
}
ActorController.ActiveMove = slideMove;
}
/// Repository storing other moves to which this one can switch
private PlayerMoveRepository moveRepository;
/// Input manager from which inputs states will be queried
private IInputManager inputManager;
/// Defines the abilities of the platformer actor
private Abilities abilities;
}
} // namespace Framework.Actors.Platformer