gamedev


Dev Log: November 2019

Decided since it’s the 11th month of the year to write a dev log about the progress of my current games and projects.

MerFight: A Show, UVs, and More

MerFight has been making steady progress. I’m trying to update builds regularly on itch.io and GameJolt. In late October, I took the game to a local indie game showcase presented by Bit Bridge in Pittsburgh. I think it went well. Players seemed to enjoy the game and understand the input system relatively quickly. There were a lot of “Wait, how did I do that?” questions, which is understandable. Demoing at any shows can be difficult, especially a fighting game, and even more so if the show is not fighting-game-centric. Regardless, people seemed to enjoy it. Here are some things I learned for the next update:

Making Marketing Materials Is Hard

For the show, I wanted to make a brochure for the game to go over the different features of the game and whatnot. Unfortunately, I decided very soon before the show to do this. So it didn’t quite come out as I would have liked it. Even worse, I forgot to include a link to the game’s itch.io page for downloading. Fortunately, I only got 25 printed from Staples; amusingly, the person who gave me my order even seemed interested in the game, which at the time, really caught me off guard.

The “front” of my MerFight brochure.
The “back” of my MerFight brochure.

Additionally, I made a poster to put on the monitor displaying the game. I was able to get it working with some “duct-tapery,” but it did not look very clean. Regardless, the lesson is to start marketing materials much earlier and test things out beforehand.

The poster I created to adhere to my monitor.

Pushback!

The only real crash in my game occurred when someone tried to use the online mode. I didn’t bother connecting to the Internet, so the game just threw an error. So I was happy I didn’t come from the show with a huge list of blocker bugs to fix — though I’m sure there will still be a ton. That being said, I did notice one major gameplay flaw, that being that most of MerFight’s attacks don’t have enough pushback. I watched one match where the player just light and heavy kicked to win. Even when blocked, the distance between the players was so small, that the winning player easily was able to just walk up and continue spamming these attacks. I also think lack of pushback is a complaint for Battle High 2 A+, so this will be something I will be addressing in the next MerFight build.

New Characters

I started working on new characters for MerFight. There’s Octonia, an octupus-inspired wrestler, and Naeco, a clawed fighter dealing with barnacles. (And yes, I know Naeco is just ocean backwards. It was either that or Aes.)

I may change her outfit in the future. I’m not in love with it.
The deep sea calls for a deep V.

I’m at a crossroads now that I’ve made these two. Should I continue modeling the rest of the game’s cast or should I move onto animating them? I have this bad tendency to do one task — create a character — then move onto the next part — animate and implement the character. When it comes time to repeat the original task for a new character though, I forget a ton that I learned, even if I document, it’s not as fresh and sometimes I miss nuance in said documentation.

For example, I’ve greatly improved the texture maps for the characters. For comparison, Strike textures include:

  • Body, Arms, Legs, and Head
  • Eyes
  • Upper Teeth
  • Lower teeth
  • Tongue
  • Eyelashes
  • Nails
  • Hair
  • Fins
  • Clothing

Meanwhile, Octonia only has

  • Body, Arms, Legs, Head, and Nails
  • Eyelashes
  • Teeth, Eyes, and Tongue
  • Clothing
  • Tentacles and Hair

Essentially, I almost cut the number of meshes and textures in half. Had I moved onto animating her and not creating Naeco, I wouldn’t have found a way to simplify it further. I found a way to put the eyelashes onto the new texture, which is nice because I know longer have to deal with a sub-material setup in 3ds max or Unity. They aren’t hard to setup, but can be annoying.

The composite UV for Naeco.

By default, Character Creator 3 characters have their arms, legs, head, body, nails, and eyelashes all split into submeshes, which require one texture and material for each. This isn’t the most efficient, so I now have a way to combine my meshes and materials and require fewer meshes. In the UV above, there are some large gaps, but this is where Naeco had mesh removed to prevent intersections with his clothing. The current UV setup is done so that it can work with any character from CC3 regardless of how much of the original mesh is intact.

I’ll be writing more on this process in the next couple of days, probably posting here, with some additional info on my Patreon.

Next Steps

So what’s next for Merfight? Well, again, I’m unsure if I should model the remaining 5 characters or begin implementing Octonia and Naeco. I’m leaning towards more modeling, especially because, in reality, I’m going to have to remodel or at least make fixes to the remaining characters, so I could, in theory, do a first pass on the rest of the characters. Additionally, I may find some more ways to improve my pipeline and process.

Regardless, I’d love to get one new playable character before 2020, but if I decide to model the remaining characters, this may become rather difficult.

Other Prototypes

In addition to creating characters for MerFight, I’ve been working on some prototypes.

Cylinder Fighter

The idea behind this prototype is that a lot of fighting games seem to focus on getting your opponent in the corner. Though I know there are some 2D fighting games without corners, I wanted to make one that definitely doesn’t have any. Plus, I think the circular concept could create an interesting perspective or, for example, have projectiles that travel the entire circle or something instead of just disappearing off screen. I also want the surface to not be flat either. This is probably about 5% done, but close to have an early build for people to test, see if the online works, etc. I’m not sure of the theming yet, but this is still something I’m interested in pursuing.

2D -> 3D Fighter

A few months ago, I wrote a tutorial on creating a 3D fighting game camera using Cinemachine. This began because I was experimenting with a game that used both a 2D and 3D camera and switched between them. In my head, I feel it could be interesting to have a game that plays like a 3D fighter and then a 2D fighter. This is even barely in development though, and probably something I won’t touch for some time.

Despite having prototypes in the works, MerFight is my main focus as I’d like to finish it before 2022 (hopefully earlier). Just, as a solo dev, this stuff takes a long time. Fortunately, having shown off MerFight in October, definitely did help with my motivation.


Tutorial: Setting up a 3D Fighting Game Camera Using Cinemachine in Unity3D

This is a simple tutorial exploring the use of a Cinemachine camera in Unity3D for a 3D fighting games such as Virtua Fighter or Tekken.  This is by no means the only solution to achieve this; this tutorial just explores methods that I’ve had some success with when prototyping.

Why use a Cinemachine camera? One nice advantage to a Cinemachine camera is that you can blend into other camera views quickly and easily, so, for example, if you have a unique camera animation for a throw or super move intro, you can easily blend to this animation and back to the main camera using Cinemachine by just simply switching the priority of the virtual camera.

This being said, my Cinemachine camera has the following goals:

  • Track the two characters in the environment
  • Rotate as the two characters move around the scene in any direction.
  • Move in and out as the characters get closer and farther apart.

My scene initially looks like this.  I have two characters, a pink fighter and a teal fighter, which will be tracked by my Cinemachine camera setup.

Initial scene setup

Tracking the Characters

To track the characters, I first create a Cinemachine Target Group Camera (Cinemachine -> Create Target Group Camera).  This creates my Cinemachine Virtual Camera as well as a Cinemachine Target Group.

The Cinemachine Target Group allows me to track multiple transforms.  The following is the Cinemachine Target Group Component setup:

The Cinemachine Target Group Setup

I want the position mode to be Group Center and the Rotation Mode to be Manual.  A script will be applied that’ll rotate this later. I use Late Update for the Update Method.

I set both fighter transforms in the target list with the same weight.  I set the radius to about 1.7. Originally, I was experimenting with the Framing Transposer, where this value is very important; however, for now, just making sure this radius is the same for both transforms is the most important.

The Cinemachine Virtual Camera is setup as follows:

Cinemachine Virtual Camera Setup

The camera is setup to follow and look at the target group.  For the body of the virtual camera, I’m using a Transposer. Again, I originally tried a Framing Transposer, however, I found it was really jittery when rotating the camera.  I later read that the Framing Transposer is better for 2D camera usage than 3D, rotated camera use, so I went back to the basic Transposer.

Anyway, the values are pretty similar to the default values, except I lowered the damping to 0.5 per axis and set the Follow Offset to [0, 2, -4.3333333].  This makes it so the camera is 2 units up and -4.33333333 units away from the center of the target group during runtime.

For the Aim, I use “Same as Follow Target” meaning it’ll use the same rotation as the target group’s transform.

Using this initial setup, the camera should appear like this:

The camera setup just following the center of the targets.

Right now, the camera does a pretty decent job tracking the center of the two characters; however, it doesn’t move back to fit them in view when the pink fighter gets a certain distance away and the camera doesn’t rotate as the pink fighter walks around their opponent.

The next section of this tutorial will go over setting up the camera so it both rotates and moves to track the fighters better.

Rotating and Aligning the Camera

To achieve this, instead of fighting with built-in Cinemachine tools, I decided to write a script.  The MonoBehaviour, Align3DCam, is attached to the Target Group GameObject and appears as follows:

Cinemachine Target Group with Align 3D Cam

TA and TB are the two transforms that will be tracked.  In this case, our fighters.

We then reference the virtual camera itself.  Its Transposer Component will be referenced as well, but this reference will be set during Awake.

Framing Normal is the normal vector.  This is set on Awake based on the follow offset of the virtual camera’s Transposer value.

Distance shows the distance between the two tracked transforms; it is serialized in the inspector for debugging purposes.

Transposer Linear Slope and Transposer Linear Offset are two values that represent a simple linear equation (y = mx + b) where x is the distance between the two tracked transforms and y is the distance along the Framing Normal that the virtual camera will be offset.

The framing helpers are used to help create the slope and offset as well as set the minimum allowed distance so that the camera doesn’t move in too closely when the fighters are standing next to one another.

Now, the following is the script used for Align3DCam:

using Cinemachine;
using UnityEngine;

public class Align3DCam : MonoBehaviour
{
    [Tooltip("The transforms the camera attempts to align to.")]
    public Transform tA, tB;

    [Tooltip("The cinemachine camera that will be updated.")]
    public Cinemachine.CinemachineVirtualCamera virtualCamera;

    /// <summary>
    /// The Transposer component of the cinemachine camera.
    /// </summary>
    private Cinemachine.CinemachineTransposer tranposer;

    /// <summary>
    /// Boolean that is set based on whether or not a virtual camera is supplied.
    /// </summary>
    private bool hasVirtualCamera;

    [SerializeField(), Tooltip("The starting normal of the cinemachine transposer.")]
    private Vector3 framingNormal;

    [SerializeField(), Tooltip("The current distance between the two tracked transforms.")]
    float distance;

    [Tooltip("Slope Value (m) of the linear equation used to determine how far the camera should be based on the distance of the tracked transforms.")]
    public float transposerLinearSlope;

    [Tooltip("Offset Value (b) of the linear equation used to determine how far the camera should be based on the distance of the tracked transforms.")]
    public float transposerLinearOffset;

    [Header("Framing helpers")]
    [Tooltip("The minimum distance allowed between the two transforms before the camera stops moving in and out.")]
    public float minDistance;

    [Tooltip("The minimum distance the camera will be from the tracked transforms.")]
    public float minCamDist;

    [Tooltip("A secondary distance between the two transforms used for reference.")]
    public float secondaryDistance;

    [Tooltip("A secondary distance the camera should be at when the tracked transforms are at the secondary distance.")]
    public float secondaryCamDistance;

    /// <summary>
    /// Function to help determine the
    /// </summary>
    [ContextMenu("Calculate Slope")]
    void CalculateSlopes()
    {
        if (virtualCamera == null)
            return;
        tranposer = virtualCamera.GetCinemachineComponent<CinemachineTransposer>();
        if (transposer == null)
            return;

        // If the application is playing, we don't update the minimum values.
        if (!Application.isPlaying)
        {
            // We get the distance between the transforms currently
            minDistance = Vector3.Distance(tA.position, tB.position);
            distance = minDistance;

            // We get the magnitude of the follow offset vector.
            minCamDist = tranposer.m_FollowOffset.magnitude;
        }

        // We calculate the slope ((y2-y1)/(x2-x1))
        transposerLinearSlope = (secondaryCamDistance - minCamDist) / (secondaryDistance - minDistance);

        // We calculate the offset b = y - mx;
        transposerLinearOffset = minCamDist - (transposerLinearSlope * minDistance);
    }

    private void Awake()
    {
        // Determines if a virtual camera is present and active.
        hasVirtualCamera = virtualCamera != null;
        if (hasVirtualCamera)
        {
            transposer = virtualCamera.GetCinemachineComponent<CinemachineTransposer>();

            if (transposer == null)
            {
                hasVirtualCamera = false;
            }
            else
            {
                // Sets the framing normal by the transposer's initial offset.
                framingNormal = tranposer.m_FollowOffset;
                framingNormal.Normalize();
            }
        }
    }

    // Update is called once per frame
    void LateUpdate()
    {
        // Gets the distance between the two tracked transforms.
        Vector3 diff = tA.position - tB.position;
        distance = diff.magnitude;

        // The Y is removed and the vector is normalized.
        diff.y = 0f;
        diff.Normalize();

        // Adjusts the follow offset of the transposer based on the distance between the two tracked transforms, using a minimum value.
        if (hasVirtualCamera)
        {
            tranposer.m_FollowOffset = framingNormal * (Mathf.Max(minDistance, distance) *
                transposerLinearSlope + transposerLinearOffset);
        }

        // If the two transforms are at the same position, we don't do any updating.
        if (Mathf.Approximately(0f, diff.sqrMagnitude))
            return;

        // We create a quaternion that looks in the initial direction and rotate it 90 degrees
        Quaternion q = Quaternion.LookRotation(diff, Vector3.up) * Quaternion.Euler(0, 90, 0);

        // We create a second one that is rotated 180 degrees.
        Quaternion qA = q * Quaternion.Euler(0, 180, 0);

        // We determine the angle between the current rotation and the two previously created rotations.
        float angle = Quaternion.Angle(q, transform.rotation);
        float angleA = Quaternion.Angle(qA, transform.rotation);

        // The transform's rotation is set to whichever one is closer to the current rotation.
        if (angle < angleA)
            transform.rotation = q;
        else
            transform.rotation = qA;
    }
}

The script is rather lengthy, so I’ll summarize it a bit.  It’s essentially doing two things. Offsetting the camera based on the linear equation values and rotating the camera based on the vector between the two tracked transforms.

The slope values are calculated in the CalculateSlope method, which has a ContextMenu attribute, meaning it can be accessed through the right-click menu of the Align3DCam Component.

The Calculate Slope Context Menu Method

What this does is it takes the current distance of the fighters and the magnitude of the cinemachine camera follow offset position to set the minimum distance and minimum camera distance.  The secondary values are then used to calculate Transposer Linear Slope and Transposer Linear Offset.

Now, to get good secondary values, you’ll have to manually adjust them until you have something you like.  If you use Calculate Slope while the game is playing, the minimum values will not be adjusted, so you can test different secondary values out, and then copy the Component and paste its values when you are no longer running.  I could have probably written a more advanced algorithm that uses a bounding box, but for now, I found this got the job done pretty quickly.

When it comes to rotation, the method works by taking the vector between the two transforms, which is found by subtracting the position of TB from TA.  The y value of this vector is then set to 0 and the vector is normalized.  

A quaternion is then created using Quaternion.LookAt, which takes the normalized diff Vector and Vector3.Up to create a rotation that is essentially look in the direction of this vector.  This quaternion is then multiplied by a 90 degree rotation, thus creating a rotation that will look at both characters; however, this assumes that the TA will always be on the left and TB will be on the right.  If they switch sides, such as one fighter jumping over the other, the camera will rotate and snap quickly like this:

How the camera will look if we only care about one Vector

We certainly don’t want that, so we create another quaternion, which is the first quaternion we created and rotate it 180 degrees on the Y axis, essentially, the same rotation looking in the opposite direction.  We then get the angle between both of these quaternions and the camera’s current rotation. Whichever angle is lower, that is the rotation we use. So now, when jumping over the opponent, the camera will no longer pop to keep the pink player on the left side:

The camera no longer forcing the pink player to the left side.

So, once applied with proper values, the cinemachine virtual camera and target group should work as follows:

The Final Result of the 3D Fighter Cinemachine Camera Setup

As the pink player moves around the teal player, the camera rotates.  The camera moves back as the pink player gets farther away and the camera doesn’t snap sharply when jumping over the opponent.  All of the initial goals have been achieved.

Overall, this is a very simple setup, but it’s a good place for setting up a 3D camera for a fighting game using Cinemachine, especially for early prototypes.  Future features that would probably need to be added are collision with objects in the world if scenes are more complex or using a bounding box to frame fighters in more properly, but again, this is a simple approach to get something off the ground.

If you have questions feel free to comment here or send me a tweet to @mattrified. Additionally, a sample can be found on my Patreon.


Maxscript: Constrain to Biped 3.0 1

I made a video showcasing the latest version of my biped constraining maxscript:

Music by Rainbow Kitten: https://soundcloud.com/dr-sunshine

This point of this script is to constraint humanoid rigs such as those created by CC3 to the 3ds max biped.

Changes from version 2.0:

  • A wizard was created for picking bones. You select a bone, it populates the larger list and then displays the children.
  • You no longer have to create fingertip, toe, and head helpers. When running the script, these are created automatically.
  • There is a button to rotate the arms and knees and ankles slightly. This needs to be done so the biped is aligned correctly; otherwise, the knees could end up facing the wrong way.
  • The helper rig still needs to be created, but it can be deleted once you are finished.

The current plan is to sell the script for a nominal fee through Gumroad or provide the rigging service through Fiverr, so stayed tuned for more on that. If you would like to inquire about it sooner, just comment here or email support@mattrifiedgames.com


Jam Week 2019: Golem Jox 3

Golem Jox 3 (GJ3) is a prototype demo I developed during Schell Game’s Jam Week. Here’s quick preview:

Essentially, once a year the studio “closes” and allows its employees to work on whatever they want – within reason. Usually I work on something fighting game related by myself. Last year, for example, I worked on developing something that utilized my own rollback netcode solution in Unity. This year I decided to experiment with what I was calling a “Single Player Fighter” or “Fighting Game RPG.” Someone suggested a fighting adventure game; someone else, a turn-based fighter. I’m still not 100% sure what to call it, or if it’s even that unique as apparently there are a few games that have attempted similar approaches.
The game flow is rather simple.

  1. Player explores rather simple environments
  2. Player encounters an enemy
  3. Short dialog introduction
  4. The player’s turn begins where they attack the enemy, trying to perform the most damage in an allotted amount of time
  5. The enemy takes their turn
  6. Repeat 4 to 5 until someone wins
  7. If the player wins, return to 1; otherwise, end the game

Questions

So many, many questions…

I find one of the primary goals behind prototypes is to answer questions. Here are some of the questions I was trying to answer a lot of questions with GJ3’s prototype:

How should the player explore the environment?

I decided to just have the player explore the environment like they would if they were in a 2D fighting game.  I feel if I – especially within the 4 day jam period – tried to implement a top-down RPG exploration map or 4-way movement system, I wouldn’t have gotten to answer a lot of the other questions I was trying to answer. This also allows players to practice various moves, and I can “teach” how to perform different attacks in the environment.

I know it’s not the “right” input for that attack style…

Do character move sets evolve overtime? If so, how?

The Golem Jox theme sort of comes in for this. Golem Jox is a silly IP that I used for Jam Weeks in the past in which players control a “golem” or just an entity made of random things. You start off as “Juhnk,” a golem made of white cubes. As you progress, you swap and equip different “limbs.” Some of the limbs are more powerful than what you previously had, either granting new moves, having more attack power, or granting other changes such as increased max health. I sort of “force” limb switching by locking off sections without wearing different limbs. Most people during playthroughs didn’t switch back after going through a “door” and then realized the new limb or move set was better.

For this prototype the idea was:

  • Your base or body, torso and head, determined things like your walk speed, jump weight, max health, etc. Unfortunately, I didn’t get very far with these.
  • Left arm was for weak or light punch
  • Right arm was for strong or heavy punch
  • Left leg was for weak or light kick
  • Right leg was for strong or heavy kick

Players were then supposed to have a forward and/or back special move for each non-torso limb and a super attack, but this sadly didn’t happen due to time. In the prototype, they got unique limbs and some had unique special moves, but supers were never implemented.

How do you prevent players from sticking to one set?

Sadly this question is still unanswered. What I wanted to do is that the player does not level up based on how many matches they win, but by how often they use a limb. So, for example, if I’m level 1, and I use my left arm 5 times in one fight, and it levels up to level 2, then I level up to level 2 as well. However, if the same limb is level 4 and maxed out, then I will no longer gain EXP for using it. As a player, I’d have to make the choice, “Do I keep using a limb I’m really good with or do I equip a newer, maybe weaker one, so I can continue to level up overall.”

Again, unfortunately, due to time, I didn’t get this far, but is probably the first question I would try to answer next if I were to continue to polish this prototype.

I think the other, final question, that I’m not 100% sure is answered, is will a player enjoy this gameplay loop.  That’s difficult to tell without more work, but based on the playtest I had, I think, with a lot of polish to the combat itself, I think they could.

Learning New Tools:  Playables

Not my playable graph, but a sample one provided by Unity.

Learning is an important part of Jam Week.  Besides learning the answers to prototyping questions, I often decide to try something new.  This Jam Week in particular, I decided to work with Unity’s Playable System. One challenge with this game is that characters would need to be able to choose from a wide variety of animations; however, having all of these animations loaded at runtime would probably not be very efficient.

Take remedy this, I utilized the Playable System.  Unlike a Unity’s runtime animator controller, you can dynamic build a Playable System at runtime.  So, for example, if a character is equipped with a cubic right leg, I can utilize an animation, let’s call it, “cubic right kick.”  If I then equip a spherical right leg though, I can replace it with “spherical right kick.” All I have to do is rebuild the playable graph and apply it.  There is still a lot of finesse needed, such as how to make the animations blend cleanly, but the playable’s system ability to load animations dynamically definitely make them seem like a great.  The system also has some strict rules such as you MUST destroy a playable graph once you’re done with it.

Next Steps

Getting something playable — not pun intended — felt nice, but there is still a lot that can be done.

Getting as far as I did felt like a minor victory.

This is just a prototype, but also something I’d like to continue at a future time in some capacity.  I think the following are things I would like to answer in the future:

  • Should there be guard functionality?  If so, what does that look like?
  • Can this work with an original IP that does NOT involve swapping limbs?  
    • Would swapping “styles” like in Final Fantasy Tactics work better?
    • How many moves does a character need to make them feel “complete?”
  • Can you have multiple characters on a team?  
    • If you have multiple enemies on a team, can you change position and try to line up a “shot”?

And this is just a few questions.  Overall, there is a lot that would need to be done to make this a full game; however, I think Jam Week gave me a good head start to understand the idea a lot better.  For now though, I’m most likely going to continue with MerFight and give this a break for a few weeks before returning to it with fresh eyes. I’d like to eventually release this prototype to the public to try, but I think it needs a bit more polish before that.


Unity3D Tool – HairKit

Hair.  It’s probably one of the most difficult things for me to 3D model.  Whether I’m trying to go for more chunky, anime look for my hair or planar hair, it’s a challenge.  To try and remedy this, I created a tool a few months ago — maybe even over a year — that I called HairKit.  This post is about this tool, a brief overview, and where it is now.

HairKit Components

The following diagram demonstrates how the different components of HairKit come together.

Hair Kit Main is the main component that creates the Unity3D mesh.  This is made up of a set of Hair Kit Lines which require a Hair Kit Shape and a set of Hair Kit Line Points.  Finally, there is an optional component, HairKit Smoothed Line Helper, which can create a set of Hair Kit Line Points with smooth interpolation and spacing.

HairKit Main

The HairKitMain component is pretty straightforward.  When adding it to an object, it’ll automatically add a MeshFilter and a MeshRenderer component to the GameObject.  It will also create a new mesh named <GameObject’s Name> mesh.  Before lines can be rendered, a HairKitShape and HairKitLine needs to be set up.

HairKitShape

HairKitShape defines the shape that will be used when making lines.  It uses the children of this GameObject to define the shape. The Gradient is used by the gizmo system to draw the shape.  The UV Percentages, which will be used for the UV layout of the different meshes are based on the distance between points. You can automate this based on the by having Automate UV Percentages checked; if you uncheck it, it’ll force the UV Percentage array to the correct number but you can set the values as you wish.

You can rename the children of this game object more cleanly by pressing the Renamed Children Button.

You can also create an enclosed, circular shape by Pressing “Create Shape.”  The resulting shape will have the number of points specified by Count, minus one, and a radius of that specified.  You cannot set count lower than 3. So, to create a line, use 3 points, a triangle 4, etc.

The previous image showcases some examples of shapes created by different HairKitShape configurations.

HairKitLine

One you have a satisfactory shape, it’s time to start creating the line.

HairKitLine is a pretty full component.  For the quickest approach, assign a HairKitShape and then press “Add Child.” This will create a HairKintLinePoint.

Each point can then add a child or a sibling, which will be added to the line itself.

Locking a point allows the parent to be moved around without disrupting the position of the point.

The following .gif demonstrates adding a set of points:

Once you have a line you are happy with, you can add it to the Hair Kit Main see the shape itself.

HairKitLine has the most fields to edit, but for now, this covers the basics of the HairKit system.  The HairKitLineSmoother

Saving the Mesh

Once you are happy with the mesh, you can save out the mesh using the context menu of the Hair Kit Main component.

You can either Clone and Save the mesh or Skin the mesh.

Clone and Save will create a new GameObject except this game object will not have a HairKitMain component and the Mesh Filter will now refer to a newly created asset.

Skin is a bit more difficult.  The bones have to be set up in a specific way, cascading child-by-child for this to work properly.

Either way, the mesh should be saved out because the update methods used by the HairKit components are not the most efficient and should not be included in a final game.

Was It Useful?

In the end, I essentially recreated 3D Max’s loft tool; I realize now that this tool should probably be renamed LoftKitTool, but the original intent was for hair.  Recently, however, I discovered I can use it for creating trails in my current game rather quickly. The following are some .gif of it being used.

Anyway, I wanted to share about this as I may release this one day as a Unity Package or maybe even in the Unity Asset store.  Anything you’d like to see in the tool, if you would pay for said tool or how much, or any comments will be greatly appreciated.


Character Creator 3: Head Separation with Morph Preservation in 3DS Max

For my current work, I use Reallusion’s Character Creator 3 for my humanoid characters. They offer a lot of customization, are rigged and skinned, and come with a variety of morphs for facial expressions and lip syncing. One issue, however, is that because I am using these characters in a game engine — in this case Unity3D — the morphs are a bit problematic.

Morphs or Blendshapes are composed of vertex data describing translation of vertices between different blendshapes. You can then interpolate between these shapes to get a variety of small changes in the model.

The entire body mesh uses the morph but most targets just affect the face.

For Character Creator 3 models though, because the head and body are part of the same mesh, the morph data has a lot of empty space for all of the vertices from the neck down that do not move. This post goes over the process I use to

  • Separate the head mesh from the body mesh
  • Reapply morph targets to the head mesh
  • Reskin the separated head and body meshes

Note, these methods utilize 3DS Max; however, they can probably also be done in Blender or Maya using tools that those programs utilize.

Separating the Head and Body

The first part of this process includes separating the head and the body. By default, CC3 characters’ head and body are setup between different sub meshes; unfortunately, you can’t simply just use the head submesh and separated that as some morphs affect vertices in the torso’s submesh.

The first thing I do is copy the original mesh. These processes can cause some issues, so always make sure to have a version of the original mesh just in case something goes awry and you have to start over.

Selecting the Right “Loop”

In the duplicated mesh, I ADD an edit poly modifier. I want the original skinning and morph modifiers to remain. I’ll explain why later. Then, I try to select an edge loop that I’m sure is not affected by any of the morphs. In fact, if you character is clothed selecting an edge loop that is hidden or obscured by clothing would probably be a good idea.

Some morphs affect the neck slightly, so separating the head from the body at the base of the jaw could cause issues.

The goal of this is to eliminate as many unused vertices as possible, not all of them.

This edge loop is hidden by most of the shirt, which is hidden for demoing purposes.

Once the edge loop is selected, press “Split” in the edit poly panel. This will make the torso and the head separate elements. I then select the head elements as well as the eyelashes as they are considered separated elements but are also affected by the head’s morphs — and “Detach” the element from the body as a new mesh.

The body (red wireframe) and body (blue wireframe) separated.

The head and body have now been separated. In fact, the morphs on the removed head still work; however, the skin modifier data is no longer valid. This is because the number of vertices has been altered.

Hair-raising problems

Preserving the Morphs

Despite the morphs still working, they essentially contain the old morph data, the unused vertices we are trying to eliminate.

I wrote a maxscript to preserve this data. It can be downloaded here. To use the script, select the head mesh and then run the maxscript.

What this script does is essentially recreate every morph target but only for the head. Once this script is finishing executing, there will be a new, duplicated head mesh with only the morph modifier on it.

The new head mesh with no skinning

Reapplying Skinning Data with Skin Wrap

So now that the body and head mesh with new morphs have been created, we need to reapply the skinning data. For the first step, I right-click the body mesh and convert it to an edit poly. So, before starting the next step, we should have two meshes. The head mesh with just morph modifier and the body with no additional modifiers.

Anyway, select the body mesh and add a Skin Wrap modifier. This modifier essentially uses vertex positioning to recreate skinning from one mesh to another. In this case we are essentially copying the data from the original mesh to the new mesh. The following are the settings I use to accomplish this:

Skin Wrap Setup

Once the settings are defined, select the original CC3 mesh to copy over its skinning data to this new mesh. Once copied over, you can create a new skin modifier by pressing “button”. This will disable the Skin Wrap modifier and automatically add a skin modifier.

Repeat this process for the head, making sure that the morph modifier is beneath Skin Wrap modifier.

Once done, the head and body should now be separated, the morphs only applied to the head, and both skinned properly and identically to the original CC3 mesh.

Conclusion

In conclusion, these steps should help separate CC3 character heads and bodies while preserving morph targets and skinning data. This is a rather short process, but I hope one day CC3’s exports options include a way to separate meshes on export so this process is already taken care of. In the meantime, hopefully this will be useful for someone working with CC3 and importing their characters into a game engine. Again, here is the link for the Morph Preserve maxscript used during this process.


Maxscript: Constrain to Biped 2.0 11

Two years ago, I wrote a post about a maxscript I had written that constrains a humanoid rig to the 3D Studio Max’s biped. Recently, I’ve been working on a fighitng game prototype. I’m using animations from an asset package for this, and though the animations are very nice, there are sometimes things missing or I wish I could make certain tweaks. I said to myself, “I wish there was a way to record these animations so I could edit them more easily.”

I know you can import a .fbx file, the format of the aforementioned animations, into 3DS Max, but every frame is keyed and making edits is rather difficult. I could try and use animation layers, but if I want to apply the animation to a different character, this can’t really be done either.

So, remembering the script I wrote awhile ago, I figured I would try and make a version, so I could record animations. At the same time, one issue with the previous script was that when using it, it forced the original rig to rotate so it would fit the biped. This would cause this strange “bulging” in various areas that some users, including myself, didn’t care for.

Before rigging [left] / After rigging [right]

Most of this is due to the fact that not all rigs are not perfectly aligned like the biped so when going from a rig’s t-pose to the biped’s, the rotation done to conform the rig to the biped results in some rotations that otherwise, the original rig wouldn’t utilize.

The New Script

Version 2.0

This new version has a few changes compared to the original:

  • The bone selection area has been separated into two columns for easier organization
  • The addition of a lot of new features and buttons
    • Quick Midpoint – creates a new midpoint between selected objects
    • Quick Connector – creates a new bone that connects two selected objects
    • Foot Angle Adjustment in Degrees: An angle, measured in degrees, used to more correctly size the created biped’s foot
    • Turn Figure Mode Off: A toggle button that turns figure mode on and off
    • Alignment Tools and Animation Recording, both of which will be explained later

How to Use

Preparing the Rig

So, like the original version, you start off by preparing the rig. You have to add make sure that all bones (besides the infamous bone #7) are assigned properly. This can be done using tools such as quick child.

Determining Foot Angle

One new value that should be assigned is Foot Angle Adjustment in Degrees. This value is used to determine how big to make the biped’s foot and when aligning the biped’s foot to the original rig’s, how much to rotate it back so it matches the original rig’s foot angle.

One way to determine this value is to go into rotation mode and the view coordinate system and select the original rig’s foot bone.

Here, my rotation values are -12.979, -0.169, and 172.337. The biped’s foot will always be rotated positively on its z axis, so for this rig, I would use 12.979 for this value. This can be a little trial and error unfortunately, but as long as this value isn’t changed after building the biped, the toes should stay aligned properly.

Building the Biped

Once all of the bones are assigned and the rig is validated, the biped can be built. You’ll notice that when doing so a “FAUX_RIG” is created as well as the creation of a bunch of dummy objects. These dummy objects are used to align the biped to your rig.

New biped and “faux rig”
Small spheres are also added to the top of the biped’s fingers to help indicate the “top” of the fingers better.

Aligning the Faux Rig

This, unfortunately, is probably the longest part of this new process. Using the Biped Alignment section, you set the index of the bone you want to edit. Then you click one of the rotate buttons. When time this button is clicked, it’ll realign the associated bone with the newly aligned faux dummy.

How a misaligned biped MAY appear depending on the rig.

Fortunately, every time you do a rotation, it is recorded so you can save it out and reload it at a later time or for new rigs that are similarly oriented.

You can also check the alignment by clicking Align Bone or Align All. Also thighs, calves, upper arms, and fore arms do not need to be aligned since aligning the biped’s hands and feet will automatically align these better.

Another note is that you should stay in figure mode when aligning the first spine bone, the clavicles, neck, head, toes, and fingers. This is because, while in figure mode, these items are all oriented AND positioned. Once out of figure mode, they will not be moveable.

Additional Alignment Notes

If you are doing this from scratch, you should note that the clavicles are rather difficult to rotate while in figure mode. They translate to the proper position but will not align properly, but once out of figure mode, they will. Additionally, because of this, I suggest putting a slight bend in both the original rig’s elbow if possible. Even if the clavicles are off a bit, if the hands can reach the original rig’s, they and the fingers will line up properly. This is also useful to do at the knees so after positioning the hands and feet, the rig’s knees and elbows can be positions correctly. If they are too straight, these sometimes will rotate incorrectly.

Aligned rig with slightly bent knees and elbows

Finishing the Rig

Once the rig is aligned properly and figure mode is exited, you can either create constraints, which will add orientation constraints and positions constraints to the original rig so they follow the biped OR record the character’s animation to the biped.

The Key Frame button will do just that, recording the pose of the original rig to the given frame. However, you can also record the entire animation. You can set an interval. An interval of 1 means it will records every frame. An interval of 2 means it will record every other frame, 3 every third, etc.

This process, unfortunately, is rather slow. A 100 frame animation can take almost 10 minutes if every frame is captured, but once finished, the biped’s new animation can be saved to a .bip file and applied or edited.

Final Notes and Areas of Improvement

This script, though usable, could probably use some improvements.

  • Sometimes the script will crash like if you, for example, try to rotate a faux transform without building it first; thus, requiring the user to close the window and rerun the script. Having more error-catching would probably be useful.
  • I think there is a memory leak somewhere; after using the script many times or opening and closing it several times, 3ds may sometimes crash when starting a new project.
  • The alignment process takes awhile in general; I wish there was an easier way to automate this. Fortunately, I’ve created a file for Character Creator 3 rigs that should align the rig properly and quickly after being loaded.
  • Recording animation can be slow.
  • Adding rig automation would be nice so the nubs don’t need to be added manually
  • Foot sizing and placement can still be rather troublesome

Updates

March 31, 2019 – Version 2.0.1

  • Added new button to quickly create nubs for the head, fingers, and feet, since these are usually missing.

Download

You can download the script here for free. If you use my script, credit would be nice but not necessary. Additionally, I would love to see what people do with it. Enjoy!


Fighting Games Ideas: Some Ridiculous, Others Not, & Some That Hopefully Never Happen

Fighting games appear to be at a unique crossroad, being pulled in various directions, between their grassroots origins, esports, popular IPs, and more.

I think one of the most important things a genre can do in an attempt to grow is innovate.  Even small tweaks — hopefully in the right direction but not always — can help direct and guide games in the genre to succeed and exceed predecessors.

So, inspired by @goodFGideas on Twitter, here are some ideas — some could be interesting, others purposefully awful.

Also, apology in advance if some of these have already been done; either stated by @goodFGideas already or in an existing game.

Business Models

There isn’t a lot of variation when it comes to fighting games’ business models.  Usually the game is sold at one price; extra characters are then released several months after launch with some cosmetic DLC sprinkled throughout.  There’s also special or deluxe editions that already include the aforementioned character DLC released at launch.  The other variation is free to play, where players get one or two characters to play — that sometimes change on a weekly or monthly basis — and buy the characters they want.

Lately, it seems the post-launch character releases sometimes make games feel incomplete, irritating some players such as the case with BlazBlue Cross Tag Battle’s DLC character packs.  I sort of understand the logic behind the developer’s choice.  If you launch the game at the full $69.99 price, it may appear too high and scare some more fiscally responsible players away.  This can also make supporting the game post launch with server support, balance updates, and patches more difficult.  Doing DLC character packs allow some players to buy at the lower price, and if they decide they don’t like the game, move on.  Some will enjoy the game and continue to support it by buying the DLC; others will wait until the game and/or DLC is cheaper and buy it all at once.

Anyway, here are some business models future fighting games could try (or not):

Buy Characters?  Why Not Buy Modes Too!

I think Dead or Alive 5 already did this to a degree; allowing players to buy the story mode for an additional cost in the Final Round edition of the game, but why stop at story mode?  Are you a casual who only wants to play story mode and arcade mode while you wait for a 100+ hour rpg to come out?  Then just buy Story Mode and Arcade mode, just $5 each!  Are you a pro that doesn’t care about narrative at all and just want to grind, lab, and play online?  Then just get those!  Similar to ordering a’la carte at a restaurant, you buy just the modes you want instead of a large meal with a side you’ll probably forget at the table anyway despite getting a to go bag.

Regardless, this idea focuses on the compartmentalization of fighting games.  Devs release the game at a relatively low price and see what modes are selling, need expansion, etc.  Is nobody playing the single-player content?  Then don’t make more of it!  A similar logic could be applied to cosmetic character DLC.  Why make more costumes for character X if they are the least used character?  The biggest risk is the game may appear unfinished, so upon release, a good number of these modes would need to be playable.  Not, “Oh, 6 months from now, you can buy Story Mode.”  It should probably be a day one release that’ll be expanded upon if successful.

Training Mode by the Hour?!

For professional players, training mode is probably one of the most important modes in a fighter outside of versus and online play.  And training modes have definitely evolved from earlier fighting games.  You can record inputs to be played back or program an AI to react in a variety of ways.  Though most training mode features were probably used by the developers to help debug key game features, there is still a considerable amount of UI work involved in getting these features usable to players.

Now, athletes train in gyms and on fields every day.  The use of that equipment and those facilities isn’t free, so why should training mode?!  So, similar to Tekken Revolution’s quarter system, why not use a similar system for Training Mode?  If a game could make even $0.25 for every hour players are in training mode, can you imagine the revenue?!  Heck, even just having ads pop-up could probably create decent revenue steam.

Now, will players be annoyed by this?  Yes.  Don’t do this.  This is a horrible idea that I hope a company, no matter how hungry for profit, never does.  Though I liked Tekken Revolution’s quarter system to a degree  — free to play with quarters you kept by winning or gained back every hour — doing this for training mode would probably cause lasting damage to any IP that tries it, except Street Fighter or Tekken; these two brands could maybe survive the backlash from hourly training mode fees.

Player Cards & Paid Modifications

Player cards are pretty common in fighters.  They show your gamertag, wins, losses, achievement-based banners, and more.  My idea:  Let players modify them more freely.  If you don’t wanna show how many losses you have, don’t.  Want to keep your number of wins a secret?!  Remove it.  Want multiple labels?!  Go right ahead!  Obviously, there’d be a limit.  I imagine you’d have to fit items on the card similar to Resident Evil 4’s inventory system.

So the business model portion?  Well, most banners and labels are earned through playing the game — beat arcade mode with this character on hard, win 100 ranked matches, etc.  Why not just let people buy these?  They don’t need to be expensive.  If you like a label, just buy it.  “But they didn’t EARN it,” you may decry.  Who cares? (Obviously the person asking, but I digress.)  A player earning a banner by doing something like beating arcade mode on Expert is good for them, but getting a dollar because the player didn’t want to do is good for the developer (but could also speak to a poorly designed arcade mode or AI.)

Also it could create an interesting headgame during online matches.  “Wait, they have the banner for doing all of that character’s challenge combos?!  They must be really good with them!” Are they, or did they buy that label?  Well, you’ll quickly learn once they drop a combo or two, but you were a little nervous, right?  No?  Fine.

Furthermore, wanna clear the number of losses you have?  You can pay to have your criminal record expunged — or at least a Google search tells me that — why not you loss record?  Or even your win record!

You may ask, couldn’t this create an atmosphere of distrust?  Well, I mean, so does rage quitting, a common practice players do to preserve win streaks, even despite punishments companies implement.  And I’m pretty sure there are people who can easily figure out to mod their records somehow.

This idea is probably also very bad.  I am curious to how many players actually even care about their player card or how many would pay to expunge their losses or to get a special, difficult-to-earn-badge.  Does it cheapen said labels because some players didn’t really earn it?  Yes, but at the same time, when you earn one for real, knowing you earned it and saved money in doing so, that’s a good feeling too.  Overall, I think that’s what the idea is referring to; more concepts that you can either earn through play or just buy.  I believe Injustice 2 allowed this with Brainiac.  You could either buy him immediately — useful to tournament organizers for sure — or save a few bucks — at the cost of a few hours — and earn him by completing Story Mode.

Single Player Content

Single player content is a surprisingly contentious topic in fighting game.  To the main design of a fighting game, single player content isn’t really important.  If the actual gameplay of a fighter is boring or uninspired, having good story, arcade, or campaigns modes really aren’t going to save it.

SPC seems to really excel as expanding the brand of the game and its lore, letting players know why should they invest in this world or these characters.  Also, it can be the vehicle to crossover into merchandising, expanding the brand into other media — comics, movies, shows, etc. (Or do the opposite, get more people interested in an existing brand.)

Stop Copying NetherRealm Studios

I’ll admit, I really liked Mortal Kombat 9’s story mode.  It did a great job at exploring the rather complex (or convoluted) lore of the Mortal Kombat series and allowed players to try multiple characters, acting almost like mini introductions to the cast — or kast?  Sorry.

Though I feel after that game’s success EVERY AAA fighting game has copied that formula — do a fight, watch a cutscene, do a fight, repeat.  I can’t imagine how expensive these modes are.  With all of their animation, narrative design and writing, voice acting, and various one-off systems needed to implement just to — and I could be wrong about this — have a majority of players ignore or ridicule it.

One issue is often these fights usually aren’t anything special or unique from the basic play experience.  Maybe you’ll face someone like Peter the Cop from Street Fighter V or an unplayable boss, but they are just small snippets of unique play.  Also, cutscenes seems to get longer and longer, highlighting an already problematic flow style.  At least Guilty Gear Xrd just did away with the flow problem and made a movie with no fights.

Anyway, the “idea” is just to try something new with this.  Shorter cutscenes, more tutorialized or unique challenges, just something that’ll separate it from NRS’s current story mode implementations.  Something that’ll make players go “Hey, playing this story mode was a lot more beneficial to me than just watching it on YouTube.”

Invisible (or Hard to See) Tutorials

“Tutorial” feels like a dirty word in game development.  It feels like a lot of developers and designers — myself included — seem to dread creating them, especially if they are leaning towards being very text heavy or requiring a lot of unique features that are only for the tutorial.  A lot of this stems from the feeling that players often ignore or rush through them, missing key points and then quitting out of frustration because they ignored said points.  I think the best tutorials are once considered to be invisible; however, implementing these ideas in fighting games seems rather difficult since the progression can’t be neatly laid out like in Half Life 2.

Tekken 7’s Story Mode is an example of a single player content that tries to replace a tutorial — though I think doesn’t do a great job of it, particularly due to the limited character set, easy input mode, and other factors.  Regardless, I think, if a developer isn’t going to take the time to do an in-depth tutorial, some level of single player content to teach various aspects of the game is important.  Challenges such as blocking a series of attacks or fighting opponents that only take damage from juggles I think can help a player learn, but also explore different aspects of the game without feeling like they are necessarily doing a tutorial.

Online Ideas

I feel one thing that hasn’t changed a ton over the course of fighting games has been online mode.  You have ranked, casual, and lobbies to play with friends.  Besides things like Factions in Mortal Kombat X, I’m unsure what innovation is really being brought to online play.

Mentorship

Now this idea probably already doable to a degree, but the problem it’s trying to solve is that new players often jump right online and just get demolished by more experienced players.  Those players pretty much have two options then:  try to learn and improve or just leave and move on to a different game.

What if, instead of immediately jumping online, players could learn from a mentor of sorts.  Apparently online training modes already exists, but this service would more or less allow more experience players — probably determined by rank or experience — to train and mentor newer players through private one on one online training.

This probably already exists through more experienced players Patreons — donate X per month and I’ll play with you for an hour a week or something — but what is the game could facilitate this more?  You can then rank which mentors were helpful or unhelpful, etc., and said mentors are rewarded.

Again, probably not a necessary idea as the community and players could facilitate this instead of the game; however, I think by putting it out there, it could help newer players realize that the fighters take time to learn and sometimes they just need help from some more experienced in the genre to succeed.  Also, it could be a nice alternative to videos, which don’t always work for individuals who learn more kinesthetically.  I mean, most people don’t learn martial arts through videos or books, they learn through classes with a skilled teacher, and I think fighting games taking a similar approach could be helpful in growing a lasting playerbase.  This idea also fails if the player refuses to believe they need help of any kind as finding a learning from a mentor is usually an admittance that one needs help — which shouldn’t and isn’t something to be ashamed of, yet it often is believed to be one.

Nemeses

When online, sometimes you lose, you lose bad, and you want that over seasoned rematch.  Most games do keep track of your last couple of opponents.  So you could probably find that gamertag, invite to a match, and have your revenge match, but what if the game did more?

Inspired by the Nemesis System of Shadow of Mordor / War, what if fighters had a similar system?  Every time you lose a match, you have the option to make that opponent a nemesis.  Then, in the future, you can rechallenge that player.  It probably wouldn’t go toward your in-game ranking, but you could have built-in rewards to create an incentive to challenge nemeses but also for said nemeses to accept rematches.  Though not a huge or new concept, it’s a small tweak that could make online play more interesting and motivate players in a different way, giving them a reason to come back in the future.

Asymmetrical Effects

Some fighters have special status effects such as turning a character invisible or poisoning an opponent.  I think it would be interesting that, when playing online, the effects were visually asymmetrical.  If I turn invisible, I can still see my character locally — probably with some fancy effect so I can tell the effect is still active — but on the opponent’s side, my character is completely invisible.  In the case of poisoning, the entire screen gets a slight purple hue, not only to indicate that the negative effect is active but to give an additional layer of difficult by affect the game’s visual.  This is a short idea, but I feel something small like this could make online play more interesting.

Answer “Why?”

I feel the biggest issue with fighting game online modes today is that they don’t really have strong incentives to keep playing or can feel like a grind.  They don’t give a great sense of progress nor do they really offer a reason to keep coming back.

You get the trophies, now what?  They are usually one-and-done.  You get top rank — and if you do, you’re probably already a pro player and it doesn’t matter because you’re preparing for some tournament — but in that case, tournaments already provide the why.

But what drives average or below average players to keep coming back?  They may enjoy playing the game itself but just aren’t that great, losing online becomes tedious, and they may not have the time or resources dedicated to improving quickly.  Should they quit playing?  Developers never really want the answer to that to be “yes.”

So developers need to contemplate, besides the frustration brought on from losing, what are they getting out of it?  A lose streak and loss record already is a harsh punishment to some — something else I’ll applaud Tekken Revolution for doing away with.  If said player does feel like they are making some progress on their play and eventually will break through and end the losing streak, nothing really needs to be done; however, there will always be players that when faced with even minor frustration, feelings of regression with no accomplishment, will probably quit and move onto something else.  This is a reality some games need to face; developers can’t please everyone, but the more they can prevent players leaving and quitting, the better.

Overall, I guess the idea is give players a reason to play online, regardless of the outcome.  Sure, the subjective nature of the game being fun is there — if you can make players enjoy losing as much as winning, you’ve made great progress, but I feel like even a minor reward for losing, can help.

Some games have made efforts towards this, awarding small amounts of EXP or in game currency just for playing.  Some games offer daily challenges:  throw an opponent five times during a ranked match, win 3 matches with X character — though personally I don’t like these because they force you to change your play style to complete said challenges, ultimately serving as a distraction.  And developers can’t do what some mobile or single player games do — allow players to buy in-game currency so they can overcome the next challenge more easily.  Maybe this isn’t really a problem, but just a reality of competitive games.  You have your core players that will utilize online play the most, and more casual players who will consume single player content and move on as they make little to no progress online.

I guess this isn’t so much an idea — and it’s not really unique to fighting games.  This is more or less just expressing the opinion that online play currently can feel like a pointless grind, that some players need a better reason to come back to online mode, a “Why?”  I think the game design lens of visible progress has some good questions for this; I feel showing players their progress could help answer this too, but of course, the counter question, do players even care about their progress if said progress isn’t just win accumulation?

Conclusion

In conclusion, here is a list of ideas that I could have probably tweeted instead of writing this:

  • Allow players to buy what modes they want to play
  • Charge a nominal fee per hour of Training Mode usage
  • Allow players to buy any badge for their player card as well as the ability to expunge their loss record
  • Stop copying NetherRealm Studios Story Modes
  • Make more single player content fights unique and/or act as invisible tutorials
  • Create an online mentorship program to allow more skilled players train less skilled ones
  • A nemesis system that allows players to quickly have revenge matches and rewards both players for victory and participation
  • Asymmetrical networking effects between players.
  • Give players a reason to play online through visible progress and/or minimal reward/punishment.

Oh and one more I didn’t feel like writing about at length — use machine learning to prevent infinites and improve balance.  I didn’t write at length on this, because I feel like machine learning is a buzzword I don’t know a ton about.  Regardless, I am curious if someone could create an AI that could take a game’s data, analyze it, and point out a lot of the initial flaws.  It probably wouldn’t find all of them, and worse, it could result in a sterile experience so it could end up being a horrible, expensive idea.

Again, some ideas are maybe okay and could extend to other genres; some ideas are awful, and I would secretly love to watch attempts at subduing the PR nightmare manifested by someone trying them.

Overall, I think the genre is in an interesting period.  I think things are exciting and great, but I also feel they could be improved and evolve, and I hope we continue to see developers attempt to evolve the genre through even the slightest changes in the future.


It’s 2018!

It’s officially 2018!  With a new year comes new hopes and dreams and ambitions — 5% of which will probably get accomplished or worked towards.  Despite this, I think it’s still important to establish these goals.  Anyway, this post will go over how 2017’s game development went and things I’d like to shoot for in this new calendar year.

Battle High 2 A+

I started 2017 by showing Battle High 2 A+ at MagFest.  It was an exciting trip, although a little stressful.  I really enjoyed showing the game off to potential new players; in fact, I did again at the Pittsburgh Retro Gaming Convention in March followed by a small tournament at ReplayFX in the summer.

Besides showing the game off, I also wanted to try and get a new character in the game; however, I got distracted by TrueSync, which I’ve mentioned in previous posts and will discuss later in this one.  The big issue is that adding new character isn’t cheap, especially this one as all of the sprites aren’t finished.  I could try and release the character as paid DLC to make up for some of the cost; however, that involves extra work — integration, VO, new music, etc.  I’m not going to say that the new character won’t come in 2018; however, it’s definitely lower on my list of priorities.

In 2017, however, Stream Greenlight was replaced by Steam Direct, allowing indies to publish their game onto Steam for a small fee, so I spent a small part of November and December releasing the game on Steam, so though I didn’t get a new character into the game, I did get it released on a new platform to hopefully expose the game to more players.

I’m not sure what my goals for Battle High 2 A+ will be in 2018.  I’d love to get the new character done, update the 3D backgrounds, or get netplay working; however, these are all currently low priority to me.  I’m super grateful for the fans of the game, and I know I could do a lot more to make the community grow; however, I want to move onto new ideas, a lot of why the TrueSync stuff was such a distraction though a very good one.  I’m not going to say the game is dead and that I’m never going to work on it, but I’m not going to promise tons of new content or changes either.  I think the most I will do is work to make sure all versions — itch.io, Game Jolt, Steam, and Xbox One and all consistent and up to date.

Project MerFight

Project MerFight was a rough part of 2017.  For awhile, I wanted to work on a tactics RPG with fighting game elements.  I learned a lot about art, pathfinding, and more; however, as I worked on the project, I just felt overwhelmed, that it was too big for me to take on by myself, that I was focusing on areas that just don’t really interest me that much.

With that, I made the difficult decisions, despite months of work, to put the game on hold indefinitely.  I think what this helped me realize is that I should really only focus on games and aspects of them I’m really passionate about, until I’m able to — if ever — build a team to help me in these others areas.  As much as I enjoyed Namco X Capcom, which was serving as a lot of my inspiration, there were features I just wasn’t excited to implement or felt overwhelmed trying to.

Though it feels like a failure, I think what I learned will ultimately help me and future ideas improve.  This if, of course, if the information is well documented, something I also want to improve in 2018.

TrueSync

In a previous post, I mentioned TrueSync, a online rollback framework for Unity3D by Exit Games, the company behind Photon.  Although not perfect — it’s still in beta — I think it has great potential to democratize deterministic online gameplay for a lot of developers that, like myself, find it rather difficult to approach or are unsure where to start.

I spent a lot of time working and experimenting with it.  I made a prototype fighting game using it called ProtoFighter; however, I also want to learn and improve my art and animation skills instead of a majority of my assets being from the asset store.  I’d really love to get my own fighting game framework fleshed out so that I can create new games using TrueSync more quickly.  This will take some time; for example, I refactored a lot of ProtoFighter so I could make it more extensible with other types of games, and there is still a lot of refactoring work to do.

2018 Goals

So 2017 doesn’t sound too exciting.  I focused on showing off Battle High 2 A+ and learning TrueSync and chose to “pause” a game idea; however, I did a lot of other things too, but they are all small prototypes, difficult to organize in any meaningful way.  Battle High, Project Merfight, and TrueSync are probably the most important when it came to my independent game development.

Anyway, here are some goals I’d like to aim for (not necessarily hit) for 2018:

  • Develop my fighting game framework and create a prototype with TrueSync
  • Show off a new game, prototype, or Battle High at another show, maybe one not based in Pittsburgh
  • Submit a new game idea (not a finished game) to Xbox One for the ID@Xbox program
  • Better self-care — sleep & exercise more, eat healthier, etc. (really, these are life goals but a new year always reminds me that I should be doing them as I get older)
  • Better my visual art skills — shaders, Substance, animation, etc.
  • Write more posts and/or tutorials as well as try dev streams.
  • Submit a talk to a conference — and do it NOT on the last day for submissions

This isn’t the most exciting list, and I know I won’t hit all of these.  Every new year, however, reminds me to step back and really observe and update and pivot on what I’m focusing on.  Since one of my goals is to write more posts here, hopefully I’ll write about my progress soon!


ProtoFighter Dev Blog 01 4

So for the past couple of months I’ve been working on a new fighting game prototype.  After discovering TrueSync by Exit Games, I’ve been trying very hard to create a new fighting game with it.  Again, one of my biggest regrets with Battle High is that I was never able to implement multiplayer before its release.  I definitely feel that TrueSync could definitely help me achieve that!  Anyway, I decided to write a little bit about the game and what I’m trying to do with it.

ProtoFighter

I chose this name because what I made was a prototype, and I wanted to make this clear.  I decided to use only assets from the Unity3D Asset Store, which TrueSync already is.  This includes my characters, audio, and more!  Here is a short list of some of the assets I am using:

Goals

I had several goals while making this prototype.

Learn TrueSync With a Focus on a Fighting Game

My first goal was to learn TrueSync and make a game using it.  I think I accomplished this.  In fact, it’s not my first TrueSync experiment.  Diamonds Not Donuts, a small game I released on itch.io for free, is!  That being said, for ProtoFighter, I wanted to focus more on fighting games and various issues concerning them.  ProtoFighter has a lot of gameplay functionality that most fighters do — blocking, jumping, attacking, special moves, supers, rounds, etc.  Obviously it’s missing a lot to be a complete fighting game package — single player modes, balance is a MESS, more characters, etc.  Again, for a pre-pre-pre alpha, I think I achieved my goal, but of course, when it comes to TrueSync, there are still a ton of questions I have and hope to continue to answer them as I expand upon this prototype.

Make a Fighter That Is Slightly More Accessible Than Most

Though not TrueSync related, I’ve always wanted to try and make a fighting game that was a bit more accessible to the average player.  Maybe not as extreme as Fantasy Strike, but something that I could still explain relatively easily.

In ProtoFighter, though I sadly haven’t released a tutorial yet, I tried to do this.  Essentially, instead of performing quarter circle attacks, I simplify this to forward or back plus an attack.  Now, a lot of people would immediately say this oversimplification could cause issues such as instant dragon punches or anti-airs, so to solve this I did two things.  Firstly, all initial moves such as forward+punch have rather long start-up and are reserved for moves like overheads or projectiles.  Then, every special move has a “secondary” special that branches from it.  For example, forward+punch may begin an overhead but then pressing up before the attack activates, a secondary attack, probably an anti-air attack, would be performed.  The hope is that performing the initial move and then the secondary move will require just enough time and frames that the anti-air move won’t be so instantaneous.  Maybe this won’t help, but the idea it’s simple to actually perform an attack, but requires some dexterity and memorization to cancel one move into another properly.

A secondary idea I then had is to still allow players to perform attacks using quarter-circles; however, these players would be rewarded with a slight meter bonus, so you don’t have to perform moves properly to compete or play, but players who can are rewarded slightly for taking the time and effort to perform more complex inputs.  I can’t really tell if this input system will be good or not until someone tests it, which is why I released the prototype.

Create a Framework

My third goal was to begin creating a framework so that I can create future titles, TrueSync or not, more quickly.  A lot of games I work on are usually fighting game influenced, so I wanted to construct a framework so that creating future titles, whether 2D or 3D, would be easier in the future.  Though not perfect, I definitely tried to abstract more of my classes and functionality and believe I could quickly go from this 2.5D fighting game to a 3D game rather quickly with few changes.

TrueSync Tips

So, for this fighting game, I learned a good amount about TrueSync.  TrueSync attempts to be deterministic, allowing a local player’s inputs to be immediately respected, passed over the network, and compared to the game’s state and rolled back if there are inconsistencies found and resimulated.

The issue though is that Unity3D wasn’t built to be deterministic.  Its use of floats and random system for example can cause various issues.  It’s animation system also isn’t deterministic so trying to perfectly simulate results across two machines can be rather problematic.  Anyway, here are some tips I found were helpful for completing my prototype.

Note, these tips were written for Unity3D version 2017.1.1f1 and TrueSync version 1.1.0B.

Don’t “Press” Inputs

TrueSync uses a unique method to capture and send input, it’s called OnSyncedInput.  Here’s an example of how it works.

public class MyTSClass : TrueSyncBehaviour
{
    public override void OnSyncedInput()
    {
        TrueSyncInput.SetBool(0, Input.GetKeyDown(KeyCode.Space));
    }
}

So in the above, TrueSyncInput is used to pass inputs over the network.  The first argument is a byte, used as a key.  I’m just using 0 for now, but if you use multiple,  you should probably assign them to a constant.  Then, I’m using Input.GetKeyDown to send a bool if space is down or not.  One issue with this method is that it is performed similarly to OnFixedUpdate so calls such as “Input.GetKeyDown” don’t work consistently as when OnSyncedInput is called, Input.GetKeyDown is sometimes missed.  To resolve this for button inputs, here’s what I did:

public class MyTSClass : TrueSyncBehaviour
{
    bool hasPressed = false;

    public override void OnSyncedInput()
    {
        bool singlePress = false;
        if (Input.GetKey(KeyCode.Space))
        {
            if (!hasPressed)
            {
                hasPressed = true;
                singlePress = true;
            }
        }
        else if (hasPressed)
        {
            hasPressed = false;
        }

        TrueSyncInput.SetBool(0, singlePress);
    }
}

This change uses a bool that is set to true when OnSyncedInput is executed if the space bar is currently down. The toggle is then reset once the spacebar is no longer being held down.  The bool that is actually pased in TrueSyncInput.SetBool is only set if the keyboard is down AND hasPressed was false before being set to true.  This way, the first entry of TrueSyncInput will be true for only one execution of OnSyncedInput.  This should prevent any issues with OnSyncedInput missing an input as the average button press usually occurs for a few frames.  I don’t use this method exactly in ProtoFighter, but the idea is similar.  Instead of doing separate Booleans for each input type — up, down, left, right, etc. — I use an integer and bitmasking to change it during OnSyncedInput.

Treat TrueSync Like A Separate Engine

This sounds silly as Unity3D is a game engine; however, to make TrueSync’s determinism work properly, you have to use a lot of unique structs and classes that it introduces.  There’s FP, or FixedPoint, for float values for example and TSVector for Vector3’s.  Also, TrueSync has its own Transform class (TSTransform) that does not have all the functionality — at least now — that Unity3D’s Transform class has.  You can’t use children the same way and certain methods such as those that convert transform information from world to local space are missing.  Overall, you can’t just take a finished game and integrate TrueSync into it quickly.

One trick I had to do, for example, was figure out a way to align character hit spheres to certain joints.  In a normal setting, I could just use the following:

Animator anim = GetComponent<Animator>();
Transform t = anim.GetBoneTransform(HumanBodyBones.Chest);
Vector3 chestPos = t.position;

However, one problem is that this creates a Vector3 and even though I can convert the position to TrueSync’s Vector3 equivalent, a TSVector, they may be different values between the multiple players due to floating point precision errors.

To resolve this, I built a tool to cycle through my animations and store important point information as a TSVector  in a ScriptableObject.  I don’t save the position though; instead, I save the vector from the center to this point.  So, to get where the chest would be in my animation, it would be something like the following:

TSVector localChestVector = GetChestPosition(frame);
TSVector worldChestVector = tsTransform.position + tsTransform.rotation * localChestVector;

So, in the above, I’ve gotten a local vector for my chest position and then used the position of my player and rotation to define the world position for my chest now.  You’ll also notice that I’ve used a frame.  This is because a lot of fighting game interpret things as frames, and I believe interpreting your deterministic game in TrueSync is a lot easier to understand through the concept of frames than through time.  Even though my 3D animation is made up of curves, I store different bone information in these TSVectors so they can be referred to later regardless of the rotation or position of my character.  I also do a similar technique for moving a character by their root animation without actually having the Animator drive it.

No Animators — At Least How You Think

As of right now, TrueSync doesn’t have an Animator class.  For fighting games, this can be an issue since animations and the accuracy of said animations is so important.  To handle this, I did the following:

  • Stored all of my animator data in a separate data structure, mostly just my transition parameters and conditions
  • Muted ALL of my animation transitions
  • Disabled the Animator Component
  • Use Animator.Update(float)

So, even though the animator is disabled, Animator.Update(float) still allows the Animator to be updated.  Even though you do have to use a float instead of an FP, the amount I update is determined by the frame I’m supposed to be on, so my update function looks like this.

FP syncedFrame;
FP localFrame;
Animator anim;

private void Update()
{
    anim.Update(((TrueSyncManager.DeltaTime) * syncedFrame - localFrame).AsFloat());
    localFrame = syncedFrame;
}

So, here I have syncedFrame which is the frame of my animation that is set during OnSyncedUpdate.  Then I substract the syncedFrame to the localFrame and convert it to a float value.  I then set the localFrame to the syncedFrame.  I used FP instead of integers in case I want to play the game in slow motion.  This still needs some tweaking, however, but it gets the general idea across.

Overall, using Animator.Update(float) is great because it allows me to still get a lot of the functionality of Animators

  • Transition blending
  • IK
  • Mirroring
  • Humanoid rigs

But with more control.  This is one reason all transitions in the Animator are muted actually.  Because I don’t want transitions to happen automatically and switch states suddenly if there is rollback.  Doing it more manually allows me to switch state when I need to.

Just one small part of my AnimatorController; the red arrows show that my transitions are muted.

Anyway, the future of ProtoFighter is uncertain.  I will most certainly not release this as a full game, but instead a fighting game demo.  I know in this current 2D version I’d like to do the following:

  • Add rooms and lobbies instead of the “Ranked Match” system it uses now
  • Add stage select
  • Add an interactive tutorial
  • Balance and clean up the existing characters, Protolightning and Protaqua
  • Start looking into AI and single player modes

Overall, the goal with this game is to eventually get a framework to a place where I can experiment with a variety of gameplay styles and making something myself later down the road, hopefully sooner rather than later.  Maybe I can even use this to integrate TrueSync into Battle High 2 A+ — though I make zero promises.

ProtoFighter is available on itch.io & Game Jolt for free!  If you download the game and play them, I’d love to hear your feedback — but make sure you try the multiplayer as that’s the main area I’m trying to focus on.  Also, if you have any questions on TrueSync, I’d love to try and help as I think it’s a great asset and can help give online functionality to a lot of new indie game content — fighting games and other — in the future.