Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Games Demystified: Dissidia Final Fantasy
August 4, 2021
View All     Post     RSS
August 4, 2021
Press Releases
August 4, 2021
Games Press
If you enjoy reading this site, you might also want to check out these UBM Tech sites:

# Games Demystified: Dissidia Final Fantasy

[Design]

November 5, 2009 Page 4 of 4

Since the rail and its mechanics are the focus here though we're going to switch gears and put our algorithmic hats on.

This example contains just 2 scripts. One script allows for camera control and the other controls the character showcasing our basic rail-grinding algorithm.

Here's what that script looks like:

var currentNode : Transform;
var thisDirection : boolean;

private var thisController : CharacterController;
private var moveDirection : Vector3;
private var nextNode : Transform;

function Update()
{
if ( Input.GetButtonDown( "Jump" ) )
switchDirection();

if ( Vector3.Distance( transform.position, nextNode.position ) < Vector3.Distance( transform.position, currentNode.position ) )
{
currentNode = nextNode;

if ( thisDirection )
{
if ( nextNode.childCount > 0 )
nextNode = currentNode.GetChild( 0 );
else
{
nextNode = currentNode.parent;
thisDirection = false;
}
}
else
{
if ( nextNode.parent.childCount == 1 )
nextNode = currentNode.parent;
else
{
nextNode = currentNode.GetChild( 0 );
thisDirection = true;
}
}
}

transform.LookAt( nextNode );
moveDirection = nextNode.position - transform.position;
thisController.Move( moveDirection * 10 * Time.deltaTime );
}

function Start()
{
thisController = gameObject.GetComponent( CharacterController );
nextNode = currentNode.GetChild( 0 );
}

function switchDirection()
{
if ( thisDirection )
thisDirection = false;
else
thisDirection = true;
}

The opening lines of this script set up the editor exposed variables currentNode and thisDirection. The currentNode variable represents the transform of the current node or bone our character is standing upon.

Depending on the direction the character is facing we set thisDirection to true to traverse the spline path from parent to child node or false to travel from child to parent node. With these variables exposed you could place the character at any point on the rail and set its initial spline traversal position and direction correctly. It should be noted that you could just as easily append some code to the script to dynamically set these parameters.

The next few lines set up the private variables for this script. The thisController variable represents the Character Controller component of the character. This is what we use to actually move and orient the character.

The moveDirection variable is a Vector3 and represents the actual motion of the character through 3D space. Finally, the nextNode variable is the next transform transform thisController aims for.

The Update() callback of this script contains all juicy bits. The first part of Update() allows us to press the spacebar to switch directions on the rail. Afterward we have a conditional which resets our currentNode and nextNodes if the transform of our characterController scene object is closer to the next node in the chain of bones than to its current target.

Depending on thisDirection the chracter either travels from parent to child node or vice versa. The way the bones were chained together allows us to simply traverse only relying on Unity's parenting system instead of by an indexing or naming routine.

As was stated above, if thisDirection is true then the character travels from parent node to child node. There is a conditional within the thisDirection true/false conditional which checks the childCount of the nextNode.

If the childCount is greater than 0 it means that there's another node in the chain, otherwise it means we've reached the end of the rail. In our example here we simply turn the character around and begin traversing the rail in the opposite direction when it reaches the end.

When thisDirection is false the character travels from child to parent along the chain of nodes. The conditional within checks to make sure that the parent has only one child. If the parent node has more than one child then we've reached the top node on the chain because its parent is the Arc root, which contains two children, the Arc mesh and the chain of nodes/bones.

The final portion of Update() contains code which orients and moves the characterController. First, transform.LookAt( nextNode ) rotates the chracterController. Next up, we calculate the moveDirection as a Vector3 difference between characterController's position and nextNode's position. Finally, we actually move the characterController scene object at a rate of moveDirection * 10 * Time.deltaTime.

The only other functions within this script are the Start() callback and the switchDirection() function. The Start() callback initializes thisController and nextNode. The switchDirection() function is merely a flag toggle function for the direction our character traverses the rail.

To wrap up, I think it's safe to say that Dissidia Final Fantasy is a real feat of game design, art direction, and programming prowess. The combat remains fluid throughout even with the addition of mechanics like rail grinding, which at first glance appear tangent to the core gameplay.

As it turns out this was a fantastic addition, which opened the game up to all new methods of combat. Until next time, happy level-grinding!

You can check out a Unity Web Demo for this article by clicking here.

Page 4 of 4

### Related Jobs

Ramen VR — San Leandro, California, United States
[08.04.21]

Junior Content Designer (Remote)
Mountaintop Studios — San Francisco, California, United States
[08.03.21]