using System;
using UnityEngine;
using Framework.Services;
using Framework.State;
namespace Framework.Actors {
/// Controls an animated character in a scene
public class ActorController : ScriptComponent {
#if UNITY_EDITOR
/// Name of the current move the actor is running (for debugging)
public string ActiveMoveName;
#endif // UNITY_EDITOR
/// Presenter driving the Mecanim animation state machine
public ActorPresenter Presenter {
get {
if(this.presenter == null) {
this.presenter = gameObject.GetComponentInChildren();
}
#if UNITY_EDITOR
if((this.presenter == null) && !this.warnedAboutMissingPresenter) {
Debug.LogWarning(
"Actor controller on '" + gameObject.name + "' could not locate a presenter. " +
"The actor's animation state will not be updated."
);
this.warnedAboutMissingPresenter = true;
}
#endif
return this.presenter;
}
}
/// Helper used to check whether the actor is grounded or airborne
///
/// This is component is created lazily - if your actor doesn't need ground
///
public GroundChecker GroundChecker {
get {
if(this.groundChecker == null) {
this.groundChecker = new GroundChecker();
}
return this.groundChecker;
}
}
/// Actor physics provider, if present
public ActorPhysics ActorPhysics {
get {
if(!this.checkedForActorPhysics) {
this.actorPhysics = GetComponent();
this.checkedForActorPhysics = true;
}
return this.actorPhysics;
}
}
/// Rigid body physics component, if present
public Rigidbody Rigidbody {
get {
if(!this.checkedForRigidBody) {
this.rigidBody = GetComponent();
this.checkedForRigidBody = true;
}
return this.rigidBody;
}
}
/// Move that is currently being executed by the actor controller
///
/// 'Moves' are micro-actions that can be performed by actors, such as jumping,
/// falling or sitting down. See the class for a more thorough
/// description. If no move is active, the actor will remain passive.
///
public Move ActiveMove {
get { return this.activeMove; }
set {
if(this.activeMove != null) {
this.activeMove.OnEnded();
}
this.activeMove = value;
#if UNITY_EDITOR
if(this.activeMove == null) {
this.ActiveMoveName = null;
} else {
this.ActiveMoveName = this.activeMove.GetType().Name;
}
#endif
if(value != null) {
value.Initialize(this); // Does nothing if already initialized
value.OnStarted();
}
}
}
/// Called when the component gets added to a gameObject
///
/// Unity calls this method right after all components have been constructed.
/// This is the place to look up other components and GameObjects, but no calls
/// should be made to them yet (because the Awake() order is undefined and
/// the other component might not have set up its dependencies yet).
///
protected override void Awake() {
base.Awake();
// If the control framework is used (lets players 'possess' actors to decide
// which actor should respond to input), sign up for it.
this.controllable = GetComponent();
if(this.controllable == null) {
OnControlTaken(0);
} else {
this.onControlTakenDelegate = new Action(OnControlTaken);
this.onControlReleasedDelegate = new Action(OnControlReleased);
this.controllable.ControlTaken += this.onControlTakenDelegate;
this.controllable.ControlReleased += this.onControlReleasedDelegate;
}
}
/// Called once per physics frame to update the positions of game object
protected virtual void FixedUpdate() {
if(this.activeMove != null) {
this.activeMove.FixedUpdate();
if(this.activeMove.IsCompleted) {
OnMoveCompleted();
}
}
}
/// Called once per visual frame
protected virtual void Update() {
if(this.activeMove != null) {
this.activeMove.Update();
if(this.activeMove.IsCompleted) {
OnMoveCompleted();
}
}
}
/// Called when the currently active move has completed
protected virtual void OnMoveCompleted() {
ActiveMove = null; // Using property setter to ensure OnEnded() call.
}
/// Called when a player assumes control of the actor
/// Index of the player that has assumed control
protected virtual void OnControlTaken(int playerIndex) {}
/// Called when a player releases control of the actor
/// Index of the player that has released control
protected virtual void OnControlReleased(int playerIndex) {}
/// Helper used to check whether the actor is grounded or airborne
private GroundChecker groundChecker;
/// Presenter driving the Mecanim animation state machine
private ActorPresenter presenter;
/// Rigid body physics component, if present
private Rigidbody rigidBody;
/// Whether the presence of a Rigidbody component has been checked
private bool checkedForRigidBody;
/// Actor physics provider, if present
private ActorPhysics actorPhysics;
/// Whether the presence of an ActorPhysics component has been checked
private bool checkedForActorPhysics;
/// Move the actor is currently executing
private Move activeMove;
/// Tracks, if present, whether the player is controlling this actor
private IControllable controllable;
/// Delegate for the OnControlTaken() method
private Action onControlTakenDelegate;
/// Delegate for the OnControlReleased() method
private Action onControlReleasedDelegate;
#if UNITY_EDITOR
/// Whether the missing presenter warning has been displayed
private bool warnedAboutMissingPresenter;
#endif
}
} // namespace Framework.Actors