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

        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
        # 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)
            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')
                selection_ok = True
        pm.warning('[footfall.py] Select a curve and 2 keys')

    if selection_ok:

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)