This page goes over the various Character Abilities included in the asset, and how to create your own.

General Information

The Character Abilities are the scripts that will enable your character to perform actions. Whether it’s jumping, running, or pressing a button, that’s where it happens. Having these separated ability scripts will allow for the best possible architecture. It’ll also make it much easier for you to create your own abilities.

Standard Abilities

  • Character Button Activation : This component allows your character to interact with button powered objects (dialogue zones, switches…). Nothing special to setup here.

  • CharacterConeOfVision : Projects a cone of vision around the character, that can be used to detect targets, or purely for decorative purposes.

  • CharacterCrouch : Allows for the resizing of the controller (and dedicated animations) when the crouch button is pressed

  • CharacterDash2D/3D : This ability allows the character to dash in the specified direction. You can decide on a Dash Mode, specify a curve animation to use to move the character, the dash’s duration, the distance it should cover, and more.

  • CharacterFallDownHoles2D : A 2D only ability, it will make your character fall down “holes”, defined by the hole layer mask you’ll have specified in the TopDownController2D’s inspector.

  • CharacterHandleWeapon : Lets your character equip and use a weapon, whether it’s from an inventory or not.

  • CharacterHandleSecondaryWeapon : Same thing, but with one more weapon.

  • CharacterInventory : Lets your character bind itself to inventories, to be able to equip weapons and more.

  • CharacterJump2D/3D : Will make your character jump when you press the jump button. Note that the 3D version will actually move your character’s controller, while the 2D version will keep it in place, an animation being responsible for the jump illusion. Note that in both cases, your character won’t be considered grounded anymore while jumping.

  • CharacterMovement : Basic, ground based movement. You’ll be able to specify the walk speed, the idle threshold, acceleration and deceleration, footstep particles, and more from its inspector.

  • CharacterOrientation2D/3D : Will rotate or flip your character to have it face the movement’s direction, the weapon’s direction, or both.

  • CharacterPathfinder3D : A 3D only ability, will let your character find a path on a navmesh. That navmesh will need to be present in the scene before it can be used though.

  • CharacterPause : Allows the character with this ability (and the player controlling it) to use the pause button to pause the game

  • CharacterRun : Lets your character run at the specified speed when pressing the run button

  • CharacterTimeControl : Lets your character change the current timescale to the one specified in the inspector when pressing the Time Control button, for the duration of your choice, lerping it or not.

Ability overview

So what does an ability do ? If you’re interested in how the code works, the easiest way to find out is to look at the CharacterAbility.cs class, from which all abilities inherit. It has a few methods, let’s go over the main ones quickly :

  • Initialization : as the name implies, that’s where the base class will get parts of the Character or Scene that’ll be regularly useful in children abilities. Stuff like the camera, TopDownController component, input manager, etc. A child ability will typically use this to grab additional components or initialize variables (number of jumps, etc).
  • Animation methods : InitializeAnimatorParameters and UpdateAnimator : use the first one to register animation parameters, and the second to update them. This is done in two steps to avoid checking for the existence of each parameter every frame, which would end up causing performance issues.
  • HandleInput : overridden by each ability to check for the state of relevant buttons and axis. If a certain button is pressed/released, this method will call other methods in the ability.
  • Early/Process/Late Process ability : these methods are called by the state machine at each update.
  • Reset : this method will be called when the character dies. Useful to reset counters etc.
  • Play/Stop Sfx : methods used to trigger the abilities sounds. By default each ability comes with 3 sounds (defined per ability in their inspector) : one when it starts, one while it’s used, and one when it stops. You can of course only use one or none of these. If you create your own ability, you’ll need to call these methods to trigger the sounds.

The State Machine

The Character component is responsible for triggering the various abilities. It does so using state machines. A StateMachine is a design pattern that will basically store a current state and the previous one (if you’re curious for more, look at the code or API documentation). By default a Character uses two state machines :

  • MovementState : accessed via the _movement property from any Ability, it represents the current action the Character is performing.
  • ConditionState : accessed via the _condition property from any Ability, it stores the current status of the Character (normal, dead, paused, etc).

The way it works is that at the start of a Scene, the Character will initialize all Abilities, then every frame, call their EarlyProcess, Process and LateProcess methods, and eventually reset them on Death. Other State Machine implementations would usually only call the current state’s ability on Update. This one doesn’t, for a number of reasons, but mostly to make it easy to extend the system, without having to rewrite everything or modify existing classes. This means that each ability is responsible for handling its own input, preventing the entry into its methods (by testing if the current state allows it - you can’t walk while not grounded for example). Most abilities included in the engine don’t use EarlyProcess or LateProcess, but it’s still a possibility if you need it.

Create your own ability

The easiest way to create your own ability is to extend CharacterAbility, the same way all abilities in the engine right now do. Override methods (make sure you call the base one at the start then) when needed. To test your new ability, you just have to add it to an existing Character, and it’ll be automatically added to the state machine, and processed like the others. One thing to keep in mind is the interaction with the other abilities. You may want to extend other abilities to prevent or authorize certain state changes. Additionnally, your Ability may require new states. You can declare these in CharacterStates.cs (anywhere in the MovementStates or CharacterConditions enums, the order doesn’t matter).

For inspiration you can have a look at the current Character Abilities, as they are exactly what you’re trying to create, and are good examples of what you can achieve. Here’s a good basis I used to create them, as I found out these methods were the ones I used to override the most. Make sure you replace all the TODOs with your stuff :

using UnityEngine;
using System.Collections;
using MoreMountains.Tools;

namespace MoreMountains.TopDownEngine // you might want to use your own namespace here
{
	/// <summary>
	/// TODO_DESCRIPTION
	/// </summary>
	[AddComponentMenu("TopDown Engine/Character/Abilities/TODO_REPLACE_WITH_ABILITY_NAME")]
	public class TODO_NEW_ABILITY_NAME : CharacterAbility
	{
		/// This method is only used to display a helpbox text
		/// at the beginning of the ability's inspector
		public override string HelpBoxText() { return "TODO_HELPBOX_TEXT."; }

		[Header("TODO_HEADER")]
		/// declare your parameters here
		public float randomParameter = 4f;
		public bool randomBool;

		/// <summary>
		/// Here you should initialize our parameters
		/// </summary>
		protected override void Initialization()
		{
			base.Initialization();
			randomBool = false;
		}

		/// <summary>
		/// Every frame, we check if we're crouched and if we still should be
		/// </summary>
		public override void ProcessAbility()
		{
			base.ProcessAbility();
		}

		/// <summary>
		/// Called at the start of the ability's cycle, this is where you'll check for input
		/// </summary>
		protected override void HandleInput()
		{			
			// here as an example we check if we're pressing down
			// on our main stick/direction pad/keyboard
			if (_inputManager.PrimaryMovement.y < -_inputManager.Threshold.y) 				
			{
				DoSomething ();
			}
		}

		/// <summary>
		/// If we're pressing down, we check for a few conditions to see if we can perform our action
		/// </summary>
		protected virtual void DoSomething()
		{
			// if the ability is not permitted
			if ( !AbilityPermitted
				// or if we're not in our normal stance
				|| (_condition.CurrentState != CharacterStates.CharacterConditions.Normal)
				// or if we're grounded
				|| (!_controller.State.IsGrounded))
			{
				// we do nothing and exit
				return;
			}

			// if we're still here, we display a text log in the console
			MMDebug.DebugLogTime("We're doing something yay!");
		}

		/// <summary>
		/// Adds required animator parameters to the animator parameters list if they exist
		/// </summary>
		protected override void InitializeAnimatorParameters()
		{
			RegisterAnimatorParameter ("TODO_ANIMATOR_PARAMETER_NAME", AnimatorControllerParameterType.Bool);
		}

		/// <summary>
		/// At the end of the ability's cycle,
		/// we send our current crouching and crawling states to the animator
		/// </summary>
		public override void UpdateAnimator()
		{
			MMAnimator.UpdateAnimatorBool(_animator,"TODO_ANIMATOR_PARAMETER_NAME",(_movement.CurrentState == CharacterStates.MovementStates.Crouching), _character._animatorParameters);			
		}
	}
}