class_name ActorController extends Node ## Controls an actor's movement in the game world ## @remarks ## Actors are players, enemies and items in the game world. Each actor can perform ## moves (see the Move class) which are either atomic tasks ("walk", "jump") combined ## into complex behaviors by AI or infinites task that respond to state changes, ## used by items and user-controller actors. # ----------------------------------------------------------------------------------------------- # ## Path at which the actor controller looks for the actor physics component ## @remarks ## The actor physics component is optional. It simulates actual physics without ## using a RigidBody, thus allowing for falling and jumping trajectories matching ## those of RigidBodies while avoiding issues standing on slopes and moving ## across steps and entire staircases. export(NodePath) var actor_physics_path : NodePath = "../ActorPhysics" ## Path at which the actor controller looks for the rigid body ## @remarks ## The rigid body9 node is optional. It can be used instead of the actor physics ## component if actual physics are needed (i.e. your actor is a cardboard box, etc.) export(NodePath) var rigid_body_path : NodePath = "../.." ## Debugging aid: name of the move currently executing export(String) var active_move_name : String \ setget _set_active_move_name, _get_active_move_name # ----------------------------------------------------------------------------------------------- # ## Move the actor is currently performing var move setget _set_move, _get_move # Cannot use static typing here, circular reference ## Actor physics component that can be used to handle the actor's movement ## @remarks ## If this is valid, it should be preferred over a RigidBody (though it's certainly ## not good if both are valid as they will interfere with each other) var actor_physics : ActorPhysics \ setget _set_actor_physics, _get_actor_physics ## Rigid body node through which the actor's movement can be handled ## @remarks ## This is a fallback of the ActorPhysics component is not used var rigid_body : RigidBody \ setget _set_rigid_body, _get_rigid_body ## 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 # ----------------------------------------------------------------------------------------------- # ## 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_searched : 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_searched : bool # ----------------------------------------------------------------------------------------------- # ## 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) -> void: if move != null: if move.has_method("_process"): move._process(delta_seconds) # ----------------------------------------------------------------------------------------------- # ## 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) -> void: if move != null: if move.has_method("_physics_process"): move._physics_process(delta_seconds) # ----------------------------------------------------------------------------------------------- # ## Retuns the name of the move the actor is currently performing ## @returns The name of the move being performed func _get_active_move_name() -> String: if move == null: active_move_name = "" else: active_move_name = move.get_class() # str(typeof(move)) #.get_type() return active_move_name # ----------------------------------------------------------------------------------------------- # ## Complains if the user tries to change the name of the executing move ## @param new_name New name that will not be assigned to the executing move func _set_active_move_name(new_name : String) -> void: if new_name != active_move_name: printerr("ERROR: The name of the executing move cannot be changed") # ----------------------------------------------------------------------------------------------- # ## Returns the moved currently being performed by the actor ## @returns The move the actor currently performs func _get_move(): return move # ----------------------------------------------------------------------------------------------- # ## Selects the move the actor is currently performing ## @param move Move the actor is currently perfoming func _set_move(new_move) -> void: # If this is the same move that's already running, do nothing if new_move == move: return # Notify the running move that it has been stopped if move != null: if move.has_method("_move_stopped"): move._move_stopped() move = new_move if new_move != null: if new_move.has_method("_initialize"): new_move._initialize(self) if new_move.has_method("_move_started"): new_move._move_started() # ----------------------------------------------------------------------------------------------- # ## 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_searched: actor_physics = get_node(actor_physics_path) as ActorPhysics _actor_physics_searched = true return actor_physics # ----------------------------------------------------------------------------------------------- # ## Complains if the user tries to directly assign the actor physics component ## @param new_actor_physics 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_searched: rigid_body = get_node(rigid_body_path) as RigidBody _rigid_body_searched = true return rigid_body # ----------------------------------------------------------------------------------------------- # ## Complains if the user tries to directly assign the rigid body node ## @param new_rigid_body 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") # ----------------------------------------------------------------------------------------------- # ## 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: var local_actor_physics = self.actor_physics if local_actor_physics != null: current_gravity = local_actor_physics.gravity_vector return current_gravity var local_rigid_body = self.rigid_body if local_rigid_body != null: var state : PhysicsDirectBodyState = ( PhysicsServer.body_get_direct_state(local_rigid_body.get_rid()) ) current_gravity = state.total_gravity return current_gravity printerr("ERROR: No ActorPhysics or RigidBody present, cannot look up current 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")