I am an animator who is a beginner at coding...I appreciate your help!
I am writing a Python script to automatically duplicate controller objects in Maya. It creates controllers for each bone in the character's hand.
It worked fine as a single long function, but I want to have a Main Function, "handCtrls()", call functions within it for the various tasks. I also need to pass variables to the sub-functions, because I am iterating on the variable "i".
I get an error on the line which calls the function "nullGrouper(side, boney, i, ctrl)", and the error says that "global variable 'ctrl' is undefined". But it is defined in the "ctrlDup" function, and I used "return ctrl", which I though would send that variable back to 'handCtrls()'.
here is the code:
import maya.cmds as c
def ctrlDup(side, boney, i, ctrlOrig):
#Select and duplicate the original Control, and place it at the appropiate boney
c.select(ctrlOrig)
ctrl = c.duplicate(ctrlOrig, n=side + boney + str(i) + '_CTRL')
print(ctrl)
print('ctrlDup passed')
return ctrl
def nullGrouper(side, boney, i, ctrl):
#Create null group at same position as Control
print(ctrl)
print(ctrl[0])
nullGrp = c.group(n=side + boney + str(i) + '_GRP', empty=1, world=1)
print(nullGrp)
c.parentConstraint(ctrl, nullGrp, n='nullGrp_parentConstr_temp')
c.delete('nullGrp_parentConstr_temp')
print('nullGrouper passed')
return ctrl, nullGrp
def handCtrls():
#First select the Controller to be duplicated
sel = c.ls(sl=1)
ctrlOrig = sel[0]
#List sides
sideList = ['L_', 'R_']
#List bones of part
boneyList = ['thumb', 'index', 'middle', 'ring', 'pinky']
#Now, iterate across finger joints, up to 3, group controls, and parent them
for side in sideList:
for boney in boneyList:
for i in range(1, 4, 1):
#Check if boney is thumb, and joint number is 3
if (boney!='thumb') or (i!=3):
ctrlDup(side, boney, i, ctrlOrig)
nullGrouper(side, boney, i, ctrl)
else:
pass
print("It's done.")
handCtrls()
There are several 'print' commands just to check if the variable is getting passed. Thank you!
It is because you are not storing the return
...
ctrl = ctrlDup(side, boney, i, ctrlOrig)
nullGrouper(side, boney, i, ctrl)
Related
I’m starting as a programmer and currently working on a project but got stuck + have a bit of a brain fart(sorry).
I need to write a tool that will:
1 - set character rig by selecting character in the scene and set script to remember selection.
2 - evaluate whether selected character rig has a namespace or not (depending on that the next step takes different root)
if there is a namespace:
3 - find control in the character rig [namespace] + [side L\R] + [Ctrl]
4 - select target loc and snap one to another then bake animation
if there is no namespace:
3 - find control in the character rig [side L\R] + [Ctrl]
4 - select target loc and snap one to another then bake animation
I wrote parts of the script but don’t know how to put it together because I don’t know how to word this condition in the script.
Can anyone help me to put my brain back in order?
CH = pm.ls(sl=True, fl=True)
for c in CH:
if pm.referenceQuery(c, isNodeReferenced=True):
nameSpace = c.split(':')[0] + ':'
nameS.append(nameSpace)
name = nameSpace + 'L' + '_Weapon_ctrl'
print name
else:
name = 'L' + '_Weapon_ctrl'
print name
def bakeToObj():
Target = pm.ls(sl=True, fl=True)[0]
pm.cutKey(Weapon)
par = pm.parentConstraint([Target] + [Weapon], mo=False)
startTime = pm.playbackOptions(query=True, minTime=True)
endTime = pm.playbackOptions(query=True, maxTime=True)
pm.bakeResults(Weapon, simulation=True, t=(startTime, endTime))
pm.showHidden(above=True)
pm.delete(par)
return bakeToObj
I recommend to continue where you started. The list ist a very good start. Now you can create a script with all functions you need for the list of tasks and one function to call them all, e.g.:
def getSelectedCharacterRig():
sel = pm.ls(sl=True, fl=True)
return sel
def getCtrlName(rig):
....
return ctrlName
def findCtrl(ctrlName):
...
return ctrl
def selectTargetLoc(ctrl):
...
def bake(someObject):
return bakedObject
def doIt():
selection = getSelectedCharacterRig()
ctrlName = getCtrlName(selection)
...
This way you can see what you need an how to do it. And you will see if a function is not needed at all.
I'm attempting to create a game similar to battleship, and I'm having trouble figuring out how I would initialize the board by having each cell begin with an 'O' and displaying it to the user. A requirement for the function player_board() is that it's supposed to take in a grid representing the player's game board as an argument and output it to the user's screen. This is a portion of my code that I'm struggling with. I'm also not sure why it keeps printing out an extra 'O' at the end. Any help or feedback would be appreciated!
import random
sizeof_grid = 9
chance = 10
def mines():
grid = [{("M" if random.randint(0, chance) == 0 else " ") for i in
range(sizeof_grid)} for i in range(sizeof_grid)]
return grid
def initialize_board():
start_board=[["O" for i in range(sizeof_grid)] for i in range(sizeof_grid)]
return start_board
def players_board():
for r in initialize_board():
for c in r:
print (c, end="")
print()
return c
print(players_board())
You get the extra "O: because of the last line of code. You call the function with print(players_board) and in the function itself you return c (which has the value of one "O"). This means you print out the return value of the function which is "O".
You can execute the function with players_board() and remove the print().
Also you can remove the return c at the bottom of the function.
I am using Squish 6.3 Qt. The application i am testing contains a QLabel whose content changes dynamically.
Is it possible to wait for the label to be set to a particular value?
I can't use waitForObject as the object always exists and only its text value keeps changing.
This example is from Example - Testing or waiting for an expected property value:
def main():
# Register squish_dir/examples/qt/addressbook
# for this example code:
startApplication("addressbook")
# This will fail, unless you create a new
# address book and add a single entry to it,
# but it demonstrates how to use this
# function:
if not waitForPropertyValue("{type='QTableWidget' visible='1'}", "rowCount", 1, 20000):
test.fail("Property did not have the expected value")
else:
test.passes("Property had the expected value")
def waitForPropertyValue(objectName, propertyName, expectedValue, timeoutInMilliseconds):
"""Waits for property value of an already existing object"""
condition = "findObject(objectName)." + propertyName + " == expectedValue";
return waitFor(condition, timeoutInMilliseconds));
Adding TimeoutMilliseconds did not work, so I added time.sleep(Seconds) and this worked for me better.
From frog.ca answer, the correct condition implementation is:
condition = "findObject('{}').".format(objectName) + propertyName + "==" + str(expectedValue);
I have created the following function that allows the user to change the shape of the Python turtle to an image he/she selects from a file dialog file dialog that pops up when a specific button is pressed:
def TurtleShape(iop = None):
# "iop" is supposed to be an image path
try:
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
originalButton.config(state = NORMAL)
resetturtle.config(state = NORMAL)
rotateButton.config(state = NORMAL)
global klob
# The following "if-else" statement uses the "iop" argument's value as the value for "klob" if `iop` is NOT `None`
if iop != None:
klob = iop
print("lmcv")
else:
klob = filedialog.askopenfilename()
print("klobby")
global im
im = Image.open(klob)
pictures.append(im)
edited.clear()
print(im)
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except:
pass
The above function is also supposed to use the iop argument's value as the turtle's image if it is not None.
Now, consider this situation; you draw a bunch of things, set the turtle to an image, and just when you are about to stamp the image, you accidentally press the button that resets the turtle to its normal shape (yes, that button exists in my program). Oh no! How would you get it back without going through all the steps to open and edit it again? Well, that is where my undoHandler function (shown below) comes in. It just essentially undoes the last function called using many stacks, which I created as deques. It is pretty straightforward if you are proficient in Python:
def undoHandler():
if len(function) > 0 and draw.drawing == True:
undoHandler.handling = True
if not hasattr(undoHandler, "counter"):
undoHandler.counter = 0
undoHandler.counter += 1
# clear the canvas
Clear()
# Pop a point object from function deque
function.pop()
penup()
goto(-200, 100)
pendown()
try:
# Execute everything up to point before last function called
for i in function:
# Set canvas and turtle to previous state
tsd = i.recieveshape()
shape(tsd)
mndf = i.recieveheading()
setheading(mndf)
hk = i.getletterheight()
global letter_height
letter_height = hk
rk = i.getletterwidth()
global letter_width
letter_width = rk
milk = i.getspacewidth()
global space_width
space_width = milk
hw = i.getwidth()
width(hw)
op = i.getcolor()
try:
color(op)
except:
for g in colors:
cp = g.getcolor2()
colormode(255)
color(cp)
# Get function wrapped in Point object and execute it
j = i.getfunction()
j()
# Following is the code block where the issue occurs. Basically, if the function being run is equal to `TurtleShape`, then do the following...
if j.__name__ == "TurtleShape":
# `hfl` is a deque that holds all of the `pictures` deque's contents as it is cleared when the turtle is set to its default state
pictures.extend(hfl)
lmcv = pictures.pop()
pictures.append(lmcv)
try:
# Resize image to previous size if user changes it. Otherwise, skip this.
bun = picwidth.pop()
picwidth.append(bun)
mun = picheight.pop()
picheight.append(mun)
clob = lmcv.resize((int(bun), int(mun)), Image.ANTIALIAS)
except:
clob = lmcv
clob.save(klob + str(undoHandler.counter) + ".gif")
# Use the `clob.save` output from above as source image in `TurtleShape` function (this is where issue occurs)
TurtleShape(klob + str(undoHandler.counter) + ".gif")
print("Undone!")
else:
pass
except:
pass
Basically what happens here is that it takes the function (wrapped in a Point object) from a queue through which the main functions go through as they are called. The functions then get appended to the function deque, after which, when undoHandler is called by the user, the screen gets cleared, and latest value is popped from the function deque so that all the other actions except the last one will be executed again. This issue I am facing occurs specifically in the if j.__name__ == "TurtleShape": code block. Basically, for some reason, when the user chooses to undo the resetting of the turtle to its original shape, it works as it should until the TurtleShape function is executed by the undoHandler. For some reason, when the undoHandler executes the TurtleShape function, even when I give a valid argument for the iop attribute of the TurtleShape function (as you can see in the if j.__name__ == "TurtleShape": code block), the else statement is executed first (i.e. the file dialog comes up instead of continuing from the if statement). Only if the user clicks cancel in that dialog will the turtle get set to the previous image.
What is wrong in my code that is leading to this occurrence, and how would I stop this from happening? I have tried changing the klob attribute in the function where the output is saved in the undoHandler function to, for example, "SaveImage", but still no luck. I have also tried to add an if-elif statement in the TurtleShape when it is supposed to choose between iop or a file dialog as the value for klob, but still the issue occurs. Apparently, it executes the elif statement even when it is not necessarily true. Therefore, any help is very much appreciated in remedying this issue! :)
It's happening here:
j = i.getfunction()
j()
If the function you've just gotten is the TurtleShape() function, then you're calling it once with its default arguments (i.e., iop = None). Then you go into your big if j.__name__ == "TurtleShape": statement and call it again inside the if block.
Move that j() call into the else: block of your big if j.__name__ == "TurtleShape": statement, and your problem should go away.
Does that brief explanation make enough sense for you to understand why the problem is happening? Or do you need me to explain a bit more in-depth how calling j() is calling TurtleShape with the parameter iop = None?
I've tried to simplify the issue with my program through the code below. I can get it to work but am curious as to why it won't work using the method below.
The print values show the first index, yet the function calls the last index.
list1 = ["Title_0", "Title_1"]
for i, string in enumerate(list1):
if i == 0:
print str(i) + ", " + string # Prints: 0, Title_0
btn_monty = Button(the_window, text='Monty Python', command = lambda:the_window.title(string))
#### This also doesn't work ####
# btn_monty = Button(the_window, text='Monty Python', command = lambda:the_window.title(list1[i]))
The issue is that the string within the lambda is closed on the variable string, not the value of string . That means that the value for variable string is not evaluated until the button is actually called, and when it gets called it uses the latest value of string which would be same for both buttons.
You can instead try using default arguments to pass string . Example -
list1 = ["Title_0", "Title_1"]
for i, strng in enumerate(list1):
print str(i) + ", " + strng # Prints: 0, Title_0
btn_monty = Button(the_window, text='Monty Python', command = lambda new_title=strng:the_window.title(new_title))
I also changed the variable to strng so that it does not conflict with the string module (would be good to avoid any kind of issues in future if you decide to import that module). Also, you should make sure you place the buttons using grid or pack, etc.