splinecraft
12/15/2016 - 8:33 AM

## Calculate counter keys on feet for run/walk cycles

Calculate counter keys on feet for run/walk cycles

``````"""
Script for setting counter translate keys on the feet for walk/run cycles. Select the 2 keys on the curve(s)
of the foot Tz and run. It assumes you have a master curve with the speed for 1 second on the main control.
"""

import pymel.core as pm

class Footfall:
"""
Class data and methods for calculating the correct key values for foot counter animation

Attributes:
speed : global speed the master control is traveling at in maya units
backwards : if the walk/run is backwards
framerate : global framerate of the animation from settings
curves : list of selected curve names (so both feet can be done at once if desired
distance_per_frame : distance traveled per frame at the current speed
"""
def __init__(self, backwards=False):
self.speed = self.get_speed()
self.backwards = backwards
self.framerate = self.get_framerate()
self.curves = pm.keyframe(q=True, selected=True, name=True)
self.distance_per_frame = round(self.speed / self.framerate, 3)

def get_framerate(self):
"""
Checks the maya settings for the current framerate (assumes only 24 or 30 will be used)
:return: the framerate
"""
framerate = pm.currentUnit(q=True, time=True)

if framerate == 'ntsc':
return 30.0
elif framerate == 'film':
return 24.0

def get_speed(self):
"""
Looks at the main control TranslateZ curve and gets its speed to save needing a UI
:return: speed
"""
namespace = pm.selected()[0].namespace()
master_ctrl = '%sMain' % namespace  # Standard name for Relic rigs
return pm.keyframe(master_ctrl, q=True, at='translateZ', vc=True)[-1]

def get_counter_value(self, key_times, key_values):
"""
Calculates the value for the second key in the selection based on the speed and time planted
:param key_times: list of frames the keys happen at
:param key_values: list of values the keys hold currently
:return:
"""
# how long the foot is planted on the ground
foot_planted_frames = abs(key_times[1] - key_times[0])

if self.backwards:  # reverse for backwards walks
return key_values[0] + (self.distance_per_frame * foot_planted_frames)
else:
return key_values[0] - (self.distance_per_frame * foot_planted_frames)

def set_footfall_key(self):
"""
Go through the curves, get the value needed, and set the key values on the second key and set the
tangents to linear
:return: None
"""
for curve in self.curves:
key_times = pm.keyframe(curve, q=True, selected=True, timeChange=True)
key_values = pm.keyframe(curve, q=True, selected=True, valueChange=True)

counter_value = self.get_counter_value(key_times, key_values)

pm.keyframe(curve, edit=True, time=(key_times[1],), vc=counter_value)
pm.keyTangent(curve, edit=True, time=(key_times[0],), lock=False, ott='linear')
pm.keyTangent(curve, edit=True, time=(key_times[1],), lock=False, itt='linear')

def check_selection(backwards):
"""
Make sure the selection is ok before creating the class and running methods
:param backwards: if it's a backwards walk/run
:return: None
"""
curves = pm.keyframe(q=True, selected=True, name=True)
selection_ok = False

if len(curves) > 0:
for curve in curves:
if pm.keyframe(curve, q=True, selected=True, keyframeCount=True) != 2:
pm.warning('[footfall.py] Select only 2 keys per curve')
continue
else:
selection_ok = True
else:
pm.warning('[footfall.py] Select a curve and 2 keys')

if selection_ok:
do_footfall(backwards)

def do_footfall(backwards):
"""
Create the instance and run the script
:param backwards: if it's a backwards walk/run
:return: None
"""
ff = Footfall(backwards)
ff.set_footfall_key()

check_selection(backwards=False)``````