MMX Progress Report: 001

I wanted to share some quick images of where the game is at so far. Since I’ve mostly been focusing on the game-play/engine work, there aren’t a ton of visuals yet. Nothing is quite perfected yet, but I’ve got charged shooting, wall sliding, and dashing all implemented. There is a single level piece in there now, and a spawner for the first enemy, “Spiky” who is destructible. My former colleague and good friend Nick Reid is in charge of effects for the project and has done a stellar job so far with the dash after-images and weapon particle systems. Below you can see the Dash effect with Spiky chasing us in the background, the start of materials in Substance Designer, and the first bridge piece for our level. As game-play elements get more refined I’ll begin adding videos, and probably a few turnarounds of the characters as well.

mmx2webimage

megamaterialprogress

mmx_levelbuild_001

Scripting Your Rig: Creating a Three-Joint Chain, Part 1

In this series, we’re going to be scripting out the components for a character rig using Python. While the end result will be structured for a biped, we’re going to write these scripts in a generic way so that they can be used in various creatures. For this post, let’s take a look at a “Three-Joint Chain” setup which we could implement for an arm or a leg.

Creating The File

Before setting up a system like this, it’s generally a good idea to define some variables that you’ll reuse. I’m going to make this setup an for an arm and start my python file as such:

from maya import cmds, mel
import maya.api.OpenMaya as om


class Arm():
    """
    This will create an arm setup.
    """

    def __init__(self):

        self.PART = "Arm"
        self.JNTNAMES = ['Arm', 'Elbow', 'Wrist', 'Twist']
        self.xyz = [[3, 18, 0],[3, 14, -0.25],[3, 10, 0]]

It’s important to note a few things here. On the import, we’re going to be using the Maya Python API. This won’t be scary, I promise! We just need to grab some vectors for polevectors (get it?) and the API is much easier to work with for that particular task. We’re also defining a few variables up front to help with naming consistency later on. Our “xyz” variable is going to determine the default position for now.

Creating The Locators

Let’s setup some locators to use as a base point. You can honestly use anything you want (nulls, joints, primitives) and we’ll be enhancing this later on. For now, a simple spaceLocator will work.

def placers(self):
    """
    This will create locators for positioning.
    """

    # Create Locators
    self.FirstLoc = cmds.spaceLocator(n=self.JNTNAMES[0])
    cmds.xform(self.FirstLoc, ws=1, t=self.xyz[0])
    self.SecondLoc = cmds.spaceLocator(n=self.JNTNAMES[1])
    cmds.xform(self.SecondLoc, ws=1, t=self.xyz[1])
    self.ThirdLoc = cmds.spaceLocator(n=self.JNTNAMES[2])
    cmds.xform(self.ThirdLoc, ws=1, t=self.xyz[2])

Our function starts off crafting three locators on a single plane, something that will haunt your ikSolver later on if offset. Using those handy pre-defined variables, position and naming are taken care of for us. Given that this is an arm, and we need to keep that single plane, let’s scale down these massive locators and parent them together:

# Scale for ease of visibility
for segment in [self.FirstLoc, self.SecondLoc, self.ThirdLoc]:
    cmds.setAttr(segment[0] + ".localScaleX", .2)
    cmds.setAttr(segment[0] + ".localScaleY", .2)
    cmds.setAttr(segment[0] + ".localScaleZ", .2)

# Parent to maintain angle and move easier
cmds.parent(self.ThirdLoc, self.SecondLoc)
cmds.parent(self.SecondLoc, self.FirstLoc)

Now we have locators to properly move around… and that kinda sucks. We’re crafting bones, so it would be nice to visualize them! I want to explain that we could have used joints in the beginning instead of locators. I’m choosing locators because I want to keep my “types” separated. My setup uses locators, which are easy to find and remove by type, and the joints generated later on won’t get confusing. It’s a personal preference, so feel free to modify this to your own needs and preferences.

# Create pseudo-bones to make it easier to visualize
cmds.select(d=1)
tempA = cmds.joint(n="%s_Temp"%self.JNTNAMES[0])

tempC = cmds.joint(n="%s_Temp"%self.JNTNAMES[1])
tempD = cmds.joint(n="%s_Temp"%self.JNTNAMES[2])
cmds.setAttr(tempA + ".overrideEnabled", 1)
cmds.setAttr(tempA + ".overrideDisplayType", 1)

cmds.setAttr(tempC + ".overrideEnabled", 1)
cmds.setAttr(tempC + ".overrideDisplayType", 1)

cmds.parentConstraint(self.FirstLoc, tempA)
cmds.parentConstraint(self.SecondLoc, tempC)
cmds.parentConstraint(self.ThirdLoc, tempD)

cmds.parent(tempA, self.FirstLoc)

self.locatorList = [self.FirstLoc, self.SecondLoc, self.ThirdLoc]
self.locatorJointsList = [tempA, tempC, tempD]
cmds.select(d=1)
return self.locatorList, self.locatorJointsList

Let’s tear down this code. We’re creating some temporary joints, enabling overrides so they are just displayable, using contraints to put them into the correct location,  and parenting these temporary bones to our top Locator. We are making a list of the locators and joints as well, so we can return them for use later on. Nothing super fancy here, but now we’ve got out locator setup ready with pseudo-bones. If you put it all together, our final code should look like this:


from maya import cmds
import maya.api.OpenMaya as om

class Arm():
    """
    This will create an arm setup.
    """

    def __init__(self):

        self.PART = "Arm"
        self.JNTNAMES = ['Arm', 'Elbow', 'Wrist', 'Twist']
        self.xyz = [[3, 18, 0],[3, 14, -0.25],[3, 10, 0]]

    def placers(self):
        """
        This will create locators for positioning.
        """

        # Create Locators
        self.FirstLoc = cmds.spaceLocator(n=self.JNTNAMES[0])
        cmds.xform(self.FirstLoc, ws=1, t=self.xyz[0])
        self.SecondLoc = cmds.spaceLocator(n=self.JNTNAMES[1])
        cmds.xform(self.SecondLoc, ws=1, t=self.xyz[1])
        self.ThirdLoc = cmds.spaceLocator(n=self.JNTNAMES[2])
        cmds.xform(self.ThirdLoc, ws=1, t=self.xyz[2])

        # Scale for ease of visibility
        for segment in [self.FirstLoc, self.SecondLoc, self.ThirdLoc]:
            cmds.setAttr(segment[0] + ".localScaleX", .2)
            cmds.setAttr(segment[0] + ".localScaleY", .2)
            cmds.setAttr(segment[0] + ".localScaleZ", .2)

        # Parent to maintain angle and move easier
        cmds.parent(self.ThirdLoc, self.SecondLoc)
        cmds.parent(self.SecondLoc, self.FirstLoc)

        # Create pseudo-bones to make it easier to visualize
        cmds.select(d=1)
        tempA = cmds.joint(n="%s_Temp"%self.JNTNAMES[0])

        tempC = cmds.joint(n="%s_Temp"%self.JNTNAMES[1])
        tempD = cmds.joint(n="%s_Temp"%self.JNTNAMES[2])
        cmds.setAttr(tempA + ".overrideEnabled", 1)
        cmds.setAttr(tempA + ".overrideDisplayType", 1)

        cmds.setAttr(tempC + ".overrideEnabled", 1)
        cmds.setAttr(tempC + ".overrideDisplayType", 1)

        cmds.parentConstraint(self.FirstLoc, tempA)
        cmds.parentConstraint(self.SecondLoc, tempC)
        cmds.parentConstraint(self.ThirdLoc, tempD)

        cmds.parent(tempA, self.FirstLoc)

        self.locatorList = [self.FirstLoc, self.SecondLoc, self.ThirdLoc]
        self.locatorJointsList = [tempA, tempC, tempD]
        cmds.select(d=1)
        return self.locatorList, self.locatorJointsList

To run it, instantiate the class, then run the function like this:


myNewArm = Arm()

myNewArm.placers()

Now move around and resize that as needed, then we can pick up on creating the joints in the next post!

Embarking on an Unreal Journey

I’ve been working in Unity for over 3 years now, and a friend of mine has continually pestered me to switch to Unreal. Given that he worked for the company making Unreal, I assumed he had a natural bias and didn’t pay his advice much heed. After finally having some R&D time at work a few months ago I decided to check it out. I promptly apologized to my friend. I’ve made a few little games in Unity on the side, and my big dream project was to re-create the original Mega Man X on SNES as a fully rendered game. I started in Unity and made what I felt to be reasonable progress over the course of about 4 months. The issue lies in the finer details though. Wall sliding, after-images for dashing, and even simple things like the animation layering system felt frustrating to me as I trudged through APIs and Docs trying to piece all of the vector math together.

In steps Unreal. I’m by no means an expert here, but after watching some tutorials from their own docs, I was able to reconstruct my Unity game inside the Unreal engine… in a weekend. I’m now significantly further along; the speed and ease with which I can progress has re-ignited my passion for this project. I still work in Unity, I’ll still make cool projects in Unity, but this one lone project will be my Unreal baby. And you know what? I have a feeling it’s going to be epic!