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. In previous versions of the engine, this was all handled by a single CharacterBehaviour script. While it’s not necessarily bad design in a small game where your character only does walking and jumping, here it became hard to read and maintain as new features kept being added. Having separated ability scripts also allows for a much easier extension of the system. It’ll also make it much easier for you to create your own abilities.

Standard Abilities

  • Character HorizontalMovement : This component handles basic left/right movement, friction, and ground hit detection. In its inspector you can define standard movement speed, walk speed, and what effects to use when the character hits the ground after a jump/fall.

  • Character Crouch : This component handles crouch and crawl behaviours. In its inspector you can determine the crouch speed, and whether or not the collider should resize when crouched (to crawl into tunnels for example). If it should, make sure you setup its new size.

  • Character Dash : This component allows your character to dash. From the inspector you can define the distance the dash should cover, how much force to apply, and the cooldown between the end of a dash and the start of the next one

  • Character Dive : This component allows your character to dive (by pressing the dash button + the down direction while in the air). In its inspector you can define how much the camera should shake on impact, and how fast the dive should be.

  • Character Dangling : Add this component to a character and it’ll adopt a dangling stance if facing a hole in the ground. The detection is done using a raycast, whose origin and length can be setup from the inspector.

  • Character Jump : This component handles jumps. In its inspector you can define the jump height, whether the jump is proportional to the press length or not, the minimum air time (how long a character should stay in the air before being able to go down if the player has released the jump button), jump restrictions, how many jumps the character can perform without touching the ground again, and how long collisions should be disabled when exiting 1-way platforms or moving platforms.

  • Character Run : This component allows your character to change speed (defined in its inspector) when pressing the run button

  • Character Jetpack : Add this component to a character and it’ll be able to activate a jetpack and fly through the level. From its inspector you can define the force to apply when jetpacking, the particle system to use, various fuel info, and optionnally what sound to play when the jetpack gets fully refueled

  • Character Fly : Allows your character to fly, either permanently (think Mario’s ghosts), or on command. You can define the Fly speed from the ability’s inspector. You’ll find an example of an always flying character in the RetroCopter demo scene, and one of a “fly on command” character in the MinimalFlight demo scene.

  • Character Glide : This ability allows your character to glide while falling. It’s heavily inspired by old school games such as Aladdin on Super Nes (still my superior version, fight me). From its inspector you can define the force that will be applied to the character when gliding (you’ll want to make it something like -0.1), and whether or not you can only glide if you don’t have any jumps left. There’s a separate input axis in the InputManager settings for this, but you can also plug it to the same button/axis as Jump if you want. The RetroCorgi demo character (among others) has this ability, along with an animation for it.

  • Character Look Up : This component allows your character to look up when pressing up while grounded. How much the camera will move in this situation is defined on the CameraController’s inspector.

  • Character Grip : Add this component to a character and it’ll be able to grip level elements that have the Grip component.

  • Character Wall Clinging : Add this component to your character and it’ll be able to cling to walls, slowing down its fall. From its inspector you can define the slow factor (close to 0 : super slow, 1 : normal fall) and the tolerance (to account for tiny holes in the wall

  • Character Walljump : This component allows your character to perform an extra jump while wall clinging only. Here you can determine the force to apply to that jump

  • Character Ladder : This component allows your character to climb ladders (objects with a Ladder component). From its inspector you can set the speed to apply to the character when it’s climbing a ladder.

  • Character Swim : Gives your character the ability to swim in Water. From its inspector you’ll be able to define how much force you want to apply when swimming (the “swim height”), and the duration of the accompanying animation. You can also bind effects for water entry/exit, as well as define the force on Water exit. The RetroCorgi is setup with proper animations for it if you want to take a look at it in action.

  • Character Push : This component will allow your character to push Pushable blocks. This is not mandatory, you’d be able to push objects without it, but this component will allow you to have a dedicated push animation when pushing, and override default push values. For the animation to work, you’ll need to add a “Pushable” component on your pushable blocks.

  • CharacterLedgeHang : This component allows your character to hang from ledges when connecting with them. Ledges are gameobjects with a Collider2D on them, and a Ledge component. On the Ledge component you’ll be able to specify from what direction that ledge can be grabbed, and define a Hang Offset and a Climb Offset, which are respectively the position the character should be at when hanging from the ledge and after climbing it. Tweaking this ability can take some time, as basically it’ll require you to have its inspector and your animation in sync. You can look at how the RetroCorgi works in that regard.

  • Character Pause : Allows this character (and the player controlling it) to press the pause button to pause the game.

  • Character SlopeOrientation : This component, added to a Character, allows you to have your model perpendicular to the slope it’s on. You can define its rotation speed, the min and max angles allowed, whether the weapon should rotate too, and whether or not the angle should reset in the air.

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

  • Character Switch Model : This component allows your character to have its model replaced at a press of a button. If you want to have it change its whole prefab instead, look for the CharacterSwitchManager class.

  • Character Handle Weapon : This component will allow your character to pickup and use weapons. What the weapon will do is defined in the Weapon classes. This just describes the behaviour of the ‘hand’ holding the weapon, not the weapon itself.

  • Character Handle Secondary Weapon : This component will allow your character to handle a secondary weapon. It acts exactly like the regular Character Handle Weapon component (actually, it extends it), but is bound to different inputs. Feel free to duplicate it to handle a third, fourth, and more weapons.

  • Character Follow Path : Probably more suited for an AI character than a Player character, this ability allows the Character to follow a path made of a set of nodes.

  • Character Inventory : This component is mandatory if you want your character to use an InventoryEngine’s inventory. It’ll make the link between both systems, and will allow your character to equip weapons and use items.

Ability overview

So what does an ability do ? If you’re interested in code, 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, CorgiController 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.CorgiEngine // you might want to use your own namespace here
{
	/// <summary>
	/// TODO_DESCRIPTION
	/// </summary>
	[AddComponentMenu("Corgi 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)
				// or if we're gripping
				|| (_movement.CurrentState == CharacterStates.MovementStates.Gripping) )
			{
				// 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);			
		}
	}
}