class_name Move
extends Object
## Task that can be performed by an actor
## @remarks
## Think of a move as when someone says "cool moves" - these are actions,
## feats or stunts an actor can perform. For player-controlled actors, possible moves
## might be standing around, running, jumping, punching, falling over and so on.
## For AI-controlled actors, moves are usually atomic actions such as
## "run to position x" or "jump onto the platform".
##
## Each move can decide which other moves it can transition to. For example,
## crawling while jumping doesn't make much sense, but jumping while running does.
##
## Usually, moves have a class derived from this one to add more properties
## specific to the actor implementation (eg. platformer moves would reference a
## platformer actor). Overriding moves to use custom implementations can be done
## through the specific move repository classes.
##
## Moves have to be cancellable at any time and also need to be reusable.
# ----------------------------------------------------------------------------------------------- #
## Actor controller the move belongs to
var actor_controller : ActorController
## Actor physics component the move can use to control the actor
var actor_physics : ActorPhysics \
setget _set_actor_physics, _get_actor_physics
## Rigid body component the move can use to control the actor
var rigid_body : RigidBody \
setget _set_rigid_body, _get_rigid_body
# ----------------------------------------------------------------------------------------------- #
## Whether the lookup for the actor physics component has taken place already
## @remarks
## Used to avoid looking it up over and over in move-derived classes
var _actor_physics_queried : bool
## Whether the lookup for the actor physics component has taken place already
## @remarks
## Used to avoid looking it up over and over in move-derived classes
var _rigid_body_queried : bool
# ----------------------------------------------------------------------------------------------- #
## Initialzes the move when it is accessed by an actor controller for the first time
## @param new_actor_controller ActorController that is making use of the move
func _initialize(var new_actor_controller) -> void:
if actor_controller == null:
actor_controller = new_actor_controller
if has_method("_initialize_derived"):
_initialize_derived()
if has_method("_ready"):
_ready()
elif new_actor_controller != actor_controller:
printerr("ERROR: Move can only belong to one ActorController")
# ----------------------------------------------------------------------------------------------- #
## Gives derived classes a chance to do initialization before _ready() is called
func _initialize_derived() -> void:
pass # Replace with function body.
# ----------------------------------------------------------------------------------------------- #
## Called when the node enters the scene tree for the first time
func _ready() -> void:
pass # Replace with function body.
# ----------------------------------------------------------------------------------------------- #
## Called every visual frame to update the observed state of the world
## @param delta_seconds Elapsed time since the previous frame
func _process(delta_seconds : float) -> void:
pass
# ----------------------------------------------------------------------------------------------- #
## Called every physics frame to move objects and the state of the game
## @param delta_seconds Elapsed time since the previous frame
func _physics_process(delta_seconds : float) -> void:
pass
# ----------------------------------------------------------------------------------------------- #
## Called when the actor controller has started performing the move
## @param delta_seconds Elapsed time since the previous frame
func _move_started() -> void:
pass
# ----------------------------------------------------------------------------------------------- #
## Called when the actor controller has stopped performing the move
## @param delta_seconds Elapsed time since the previous frame
func _move_stopped() -> void:
pass
# ----------------------------------------------------------------------------------------------- #
## Whether the move has completed executing
## @remarks
## If a move can finish, this state needs to be reset when calling
## at the earliest and at the latest.
## It is okay to have this property always return false if the moves themselves
## take care of transitions to other moves.
##
## The property is usually only used for AI characters
## where moves are scheduled by a 'strategy' that uses them in a fashion similar to
## behavior tree nodes (though behavior tree nodes would be at a higher level, eg.
## a 'MoveTowardsPlayer' behavior tree node / strategy would use multiple 'run' and
## 'jump' moves to achieve its goal.
##
## When a move completes, the
## method is invoked. By default, this just sets the active move to null, but
## custom actor controllers can override this to notify a behavior tree or
## fall back to some kind of default move, for example.
func is_completed() -> bool:
return false
# ----------------------------------------------------------------------------------------------- #
## Retrieves the actor physics component when the property is read from
## @returns The actor physics component used by the actor, if any
func _get_actor_physics() -> ActorPhysics:
if not _actor_physics_queried:
if actor_controller == null:
printerr("ERROR: actor physics accessed before move was initialized")
return null
actor_physics = actor_controller.actor_physics
_actor_physics_queried = true
return actor_physics
# ----------------------------------------------------------------------------------------------- #
## Complains if the user tries to directly assign the actor physics component
## @param new_actor_physics_component New component that will not be assigned
func _set_actor_physics(new_actor_physics : ActorPhysics) -> void:
if new_actor_physics != actor_physics:
printerr("ERROR: The actor physics component cannot be assigned to")
# ----------------------------------------------------------------------------------------------- #
## Retrieves the rigid body node when the property is read from
## @returns The rigid body node used by the actor, if any
func _get_rigid_body() -> RigidBody:
if not _rigid_body_queried:
if actor_controller == null:
printerr("ERROR: actor physics accessed before move was initialized")
return null
rigid_body = actor_controller.rigid_body
_rigid_body_queried = true
return rigid_body
# ----------------------------------------------------------------------------------------------- #
## Complains if the user tries to directly assign the rigid body node
## @param new_rigid_body_node New node that will not be assigned
func _set_rigid_body(new_rigid_body : RigidBody) -> void:
if new_rigid_body != rigid_body:
printerr("ERROR: The rigid body node cannot be assigned to")