Spaces:
Running on Zero
Running on Zero
File size: 2,429 Bytes
9a25493 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | """30 Hz target-point control and critically damped path smoothing."""
import math
FPS = 30
DEFAULT_PROMPTS = [
'A person walks forward.',
'A person runs forward.',
'A person walks forward in a crouched position.',
'A person jumps forward repeatedly.',
]
DEFAULT_SPEEDS = [0.8, 2.5, 0.45, 0.8]
def effective_slot(slot, shift):
slot = int(slot)
if slot not in range(4):
raise ValueError('Choose slot 1–4.')
return 1 if slot == 0 and shift else slot
class SpringPath:
def __init__(self, frequency=10.):
self.frequency = frequency
self.frame = 0
self.target = [0., 0.]
self.position = [0., 0.]
self.velocity = [0., 0.]
self.heading = 0.
def step(self, *, x, z, shift, slot, speeds):
selected = effective_slot(slot, shift)
dt = 1/FPS
previous = self.position.copy()
old_heading = self.heading
if self.frame:
norm = max(1., math.hypot(x, z))
self.target[0] += x/norm * speeds[selected] * dt
self.target[1] += z/norm * speeds[selected] * dt
decay = math.exp(-self.frequency*dt)
for axis in (0, 1):
offset = self.position[axis] - self.target[axis]
c = self.velocity[axis] + self.frequency*offset
self.position[axis] = self.target[axis] + (offset+c*dt)*decay
self.velocity[axis] = (self.velocity[axis]-self.frequency*c*dt)*decay
dx, dz = self.position[0]-previous[0], self.position[1]-previous[1]
if math.hypot(dx,dz) > 1e-5:
target_heading = math.atan2(dx,dz)
difference = (target_heading-self.heading+math.pi) % (2*math.pi)-math.pi
self.heading += max(-math.pi*dt, min(math.pi*dt, difference*(1-math.exp(-10*dt))))
c, s = math.cos(self.heading), math.sin(self.heading)
row = [self.heading-old_heading, c*dx-s*dz, s*dx+c*dz]
else:
row = [0., 0., 0.]
point = {'frame':self.frame, 'x':self.position[0], 'z':self.position[1],
'heading':self.heading, 'slot':selected, 'base_slot':int(slot),
'run':selected==1, 'target_x':self.target[0], 'target_z':self.target[1]}
self.frame += 1
return row, point
def target_point(self, slot):
return {'x':self.target[0], 'z':self.target[1], 'slot':slot}
|