Attempting to build a basic auto rigger

hey, I’m attempting to build a basic auto rigger in pyhton in maya, following this tutorial https://www.youtube.com/watch?v=4rcDrbgD1zI

I’ll probably run into more problems ahead and I’ll probably also post them here haha, but so far…
here’s the first problem I can’t seem to figure out myself.

there’s the code I’ve got right now:

import maya.cmds as cmds

###window###

cmds.window(“Auto Rigger”)
cmds.rowColumnLayout(nc = 2)
cmds.button(l = “Create Locators”, w = 200, c = “createLocators()”)
cmds.button(l = “Delete Locators”, w = 200, c = “deleteLocators()”)
cmds.text(“Spine Count”, l = “Spine Count”)
spineCount = cmds.intField(minValue = 1, maxValue = 10, value = 4)
cmds.showWindow()

###functions###

#pelvis

def createLocators():
if cmds.objExists(“Loc_Master”):
cmds.error(“Loc_Master already exists”)
else:
cmds.group(em = 1, name = “Loc_Master”)

root = cmds.spaceLocator(n = "Loc_Root")
cmds.scale(0.5, 0.5, 0.5, root)
cmds.move(0, 1, 0, root)
cmds.parent(root, "Loc_Master")

def createSpine():
for i in range(0, cmds.intField(spineCount, query = True, value = True)):
spine = cmds.spaceLocator(n = “Loc_Spine_” + str(i))

def deleteLocators():
nodes = cmds.ls(“Loc_*”)
cmds.delete(nodes)


so… it gives me an error saying

"# Warning: Step must be less than range (maximum - minimum). # "

and nothing happens with the createSpine function

any help? :frowning:

The warning message is Maya reminding you about the ‘step’ setting of intFields. It defaults to a value of 1, and with that, your intField is valid. Kind of annoying, but a harmless warning in this case. If you specify the ‘step’ parameter, there is no warning.

Here’s the updated code:
(I used triple backticks before and after the code to keep the formatting)
```
<code_in_here>
```

###window###

cmds.window("Auto Rigger")
cmds.rowColumnLayout(nc = 2)
cmds.button(l = "Create Locators", w = 200, c = "createLocators()")
cmds.button(l = "Delete Locators", w = 200, c = "deleteLocators()")
cmds.text("Spine Count", l = "Spine Count")
spineCount = cmds.intField(minValue = 1, maxValue = 10, value = 4, step=1)  # added 'step' parameter
cmds.showWindow()

###functions###

#pelvis

def createLocators():
    if cmds.objExists("Loc_Master"):
        cmds.error("Loc_Master already exists")
    else:
        cmds.group(em = 1, name = "Loc_Master")    
        root = cmds.spaceLocator(n = "Loc_Root")
        cmds.scale(0.5, 0.5, 0.5, root)
        cmds.move(0, 1, 0, root)
        cmds.parent(root, "Loc_Master")

def createSpine():
    for i in range(0, cmds.intField(spineCount, query = True, value = True)):
        spine = cmds.spaceLocator(n = "Loc_Spine_" + str(i))

def deleteLocators():
    nodes = cmds.ls("Loc_*")
    cmds.delete(nodes)

If I run the window code and press the Create Locators button, it works. If I then run the createSpine() function, it works. createSpine() worked before I specified the ‘step’ parameter and after specifying it.

How exactly are you executing createSpine() when it doesn’t work? Any errors from createSpine()?

1 Like

If you’ll pardon a piece of old-timey advice: Leave the gui for last.

Even though you’re just getting started on the project, you’ve already got a couple of potential problems:

  1. The functions are tightly tied to the actual controls in the UI . This adds a layer of potential bugs that have to do with how you move data from the UI into the functions on top of the bugs you always have to consider in the functional code. It’s a lot easier to write and test isolated functions that work with programmatic input first and then add very simple code to just pass inputs from the GUI to the functions once you’re sure the functions already work. It’s better for your sanity.
  2. Eventually you’ll want to be able to automate the code – in an autorigger, for example, you might want to be able to script building different kinds of rigs or rigging different kinds of skeletons. If your functions include references to GUI elements you’ll have a lot of extea work to decouple them and put them back together in new ways.

Also. for future sanity, you want to avoid calling functions by their string names: You can use the form

    cmds.button("right",  c=my_function)
in place of

     cmds.button("dont", c='my_function()')

The big advantage of the former version over the latter is that you’ll get an immediate failure if my_function does note exist when the GUI is created. If you use the string version you can never be 100% sure where the version of my_function you execute comes from; it might fail only when the button is pushed or it might even be a different function than the one you’re expecting. This frequently leads to code that “works on your machine” because for you my_function is definited but does not work on somebody else’s machine.

For more on that, see https://theodox.github.io/2014/maya_callbacks_cheat_sheet

2 Likes

first of all thanks a lot :slight_smile: yea, I figured that error wasn’t a real problem but still knowing what caused it is great.
about the createSpine function… I think I was just confused as to how it should work.
I eventually eliminated that function and made the code in it to be a part of the createLocators function so eventually I achieved my goal of creating a certain amount of locators based of the number specified in the UI when I click on the “Create Locators” button.

In general, lots of smaller functions with well defined inputs and outputs is the key to staying sane :slight_smile: