First attempt at pass by / hey animation.
This commit is contained in:
parent
43ffd7d87a
commit
1c7f80e1c3
|
@ -1,5 +1,5 @@
|
|||
import { CoupleRole, DancerIdentity, Rotation, normalizeRotation } from "./danceCommon.js";
|
||||
import { DancerSetPosition, DancersSetPositions, Hand, OffsetEquals, OffsetMinus, OffsetPlus, OffsetTimes, offsetZero, setHeight } from "./rendererConstants.js";
|
||||
import { DancerSetPosition, DancersSetPositions, Hand, OffsetEquals, OffsetMinus, OffsetPlus, OffsetRotate, OffsetTimes, OffsetTranspose, offsetZero, setHeight } from "./rendererConstants.js";
|
||||
import { Offset, leftShoulder, rightShoulder, degreesToRadians, radiansToDegrees } from "./rendererConstants.js";
|
||||
|
||||
export enum AnimationKind {
|
||||
|
@ -325,9 +325,10 @@ export class RotationAnimationSegment extends AnimationSegment {
|
|||
case RotationAnimationFacing.CenterRelative:
|
||||
return degrees - this.startRotation + this.centerRelativeTo;
|
||||
case RotationAnimationFacing.Forward:
|
||||
return degrees + 180;
|
||||
case RotationAnimationFacing.Backward:
|
||||
return degrees;
|
||||
return (this.endRotation > this.startRotation === (this.facing === RotationAnimationFacing.Forward))
|
||||
? degrees + 180
|
||||
: degrees;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -361,6 +362,60 @@ export class RotationAnimationSegment extends AnimationSegment {
|
|||
}
|
||||
}
|
||||
|
||||
// For "PassBy" and related moves where stepping straight forward would walk into the
|
||||
// other dancer, so instead move in thin oval
|
||||
export class StepWideLinearAnimationSegment extends AnimationSegment {
|
||||
private readonly distanceAtMidpoint: number;
|
||||
private readonly sidewaysVector: Offset;
|
||||
private readonly progressCenter?: number;
|
||||
private readonly center?: Offset;
|
||||
|
||||
constructor({ beats, startPosition, endPosition, distanceAtMidpoint, center }: {
|
||||
beats: number;
|
||||
startPosition: DancerSetPosition;
|
||||
endPosition: DancerSetPosition;
|
||||
distanceAtMidpoint: number;
|
||||
center?: Offset;
|
||||
}) {
|
||||
super(beats, startPosition, endPosition);
|
||||
|
||||
this.distanceAtMidpoint = distanceAtMidpoint;
|
||||
|
||||
const vector = OffsetMinus(this.endPosition.position, this.startPosition.position);
|
||||
const norm = vector.x * vector.x + vector.y * vector.y;
|
||||
const distance = Math.sqrt(norm);
|
||||
const sideways = OffsetRotate(vector, Rotation.Left);
|
||||
const normalizedVector = OffsetTimes(sideways, 1/distance);
|
||||
this.sidewaysVector = normalizedVector;
|
||||
|
||||
// Center is the point where the dancer is closest to the other dancer.
|
||||
// If omitted, it's assumed the movement is symmetrical, so that happens halfway through the move.
|
||||
// Otherwise, find the point on the line between the start and end closest to the center.
|
||||
if (center) {
|
||||
this.center = center;
|
||||
this.progressCenter = ((center.x - this.startPosition.position.x) * vector.x
|
||||
+ (center.y - this.startPosition.position.y) * vector.y)
|
||||
/ norm;
|
||||
}
|
||||
}
|
||||
|
||||
interpolateOffset(progress: number): Offset {
|
||||
let sidewaysProgress = progress;
|
||||
if (this.progressCenter) {
|
||||
if (progress === this.progressCenter) {
|
||||
sidewaysProgress = 0.5;
|
||||
} else if (progress < this.progressCenter) {
|
||||
sidewaysProgress = progress / this.progressCenter / 2;
|
||||
} else /* progress => this.progressCenter */ {
|
||||
sidewaysProgress = ((progress - this.progressCenter) / (1 - this.progressCenter)) / 2 + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
return OffsetPlus(interpolateLinearOffset(progress, this.startPosition.position, this.endPosition.position),
|
||||
OffsetTimes(this.sidewaysVector, this.distanceAtMidpoint * Math.sin(sidewaysProgress * Math.PI)));
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
private readonly segments : Map<DancerIdentity, AnimationSegment[]>;
|
||||
public readonly progression : Offset;
|
||||
|
|
|
@ -691,8 +691,40 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
|
|||
endTransitionBeats: 1,
|
||||
})
|
||||
];
|
||||
// TODO Unsupported moves, just doing linear for now.
|
||||
case SemanticAnimationKind.PassBy:
|
||||
const passByCenter = CenterOf(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
||||
const wide = move.movementPattern.around === "Center";
|
||||
const width = wide ? dancerWidth : dancerWidth/2;
|
||||
const distanceAtMidpoint = move.movementPattern.side == Hand.Left ? +width : -width;
|
||||
// "Pull By" is just "Pass By" with hands.
|
||||
const passByHands = move.movementPattern.withHands
|
||||
? new Map<Hand, animation.HandAnimation>([
|
||||
[move.movementPattern.side, { kind: "Center" }],
|
||||
[move.movementPattern.side.opposite(), { kind: "None" }],
|
||||
])
|
||||
: new Map<Hand, animation.HandAnimation>([
|
||||
[Hand.Left, { kind: "None" }],
|
||||
[Hand.Right, { kind: "None" }],
|
||||
]);
|
||||
let endRotation = endSetPosition.rotation;
|
||||
const rotationAmount = endSetPosition.rotation - startSetPosition.rotation;
|
||||
if (rotationAmount !== 0) {
|
||||
if (rotationAmount >= 180 && move.movementPattern.side === Hand.Left) {
|
||||
endRotation -= 360;
|
||||
} else if (rotationAmount <= -180 && move.movementPattern.side === Hand.Right) {
|
||||
endRotation += 360;
|
||||
}
|
||||
}
|
||||
return [
|
||||
new animation.StepWideLinearAnimationSegment({
|
||||
beats: move.beats,
|
||||
startPosition: startSetPosition,
|
||||
endPosition: { ...endSetPosition, rotation: endRotation },
|
||||
distanceAtMidpoint,
|
||||
center: move.movementPattern.around === "Center" ? passByCenter : undefined, // TODO Better center?
|
||||
})
|
||||
];
|
||||
// TODO Unsupported moves, just doing linear for now.
|
||||
case SemanticAnimationKind.CourtesyTurn:
|
||||
case SemanticAnimationKind.RollAway:
|
||||
case SemanticAnimationKind.Promenade:
|
||||
|
|
Loading…
Reference in New Issue
Block a user