Compare commits
4 Commits
61badb6404
...
ad14e4e51f
Author | SHA1 | Date | |
---|---|---|---|
ad14e4e51f | |||
10d67df9cc | |||
69c211c858 | |||
9a7c1d5ea8 |
|
@ -238,7 +238,21 @@ export class TransitionAnimationSegment extends AnimationSegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
override drawDebug(ctx: CanvasRenderingContext2D, progress: number) {
|
override drawDebug(ctx: CanvasRenderingContext2D, progress: number) {
|
||||||
// TODO display transition somehow?
|
// TODO better way to display transition?
|
||||||
|
if (progress < this.startTransitionProgress) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(this.startPosition.position.x, this.startPosition.position.y);
|
||||||
|
const transitionStart = this.actualAnimation.interpolateOffset(this.startTransitionProgress);
|
||||||
|
ctx.lineTo(transitionStart.x, transitionStart.y);
|
||||||
|
ctx.stroke();
|
||||||
|
} else if (progress > 1 - this.endTransitionProgress) {
|
||||||
|
ctx.beginPath();
|
||||||
|
const transitionEnd = this.actualAnimation.interpolateOffset(this.endTransitionProgress);
|
||||||
|
ctx.moveTo(transitionEnd.x, transitionEnd.y);
|
||||||
|
ctx.lineTo(this.endPosition.position.x, this.endPosition.position.y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
this.actualAnimation.drawDebug(ctx, progress);
|
this.actualAnimation.drawDebug(ctx, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,7 +594,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
});
|
});
|
||||||
|
|
||||||
case "swing":
|
case "swing":
|
||||||
return handlePairedMove(move.parameters.who, ({ id, startPos, around, withId }) => {
|
return handlePairedMove(move.parameters.who, ({ id, startPos, around, withId, withPos }) => {
|
||||||
// TODO swing can start from non-circle positions.
|
// TODO swing can start from non-circle positions.
|
||||||
// TODO swing end is only in notes / looking at next move.
|
// TODO swing end is only in notes / looking at next move.
|
||||||
|
|
||||||
|
@ -602,6 +602,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
// TODO more structured way to do this than enumerating next moves here?
|
// TODO more structured way to do this than enumerating next moves here?
|
||||||
// maybe instead of nextMove an optional endPosition for fixing up positions?
|
// maybe instead of nextMove an optional endPosition for fixing up positions?
|
||||||
// ... but then every move would have to handle that...
|
// ... but then every move would have to handle that...
|
||||||
|
const afterTake = startPos.longLines === LongLines.Near || withPos.longLines === LongLines.Near;
|
||||||
const toShortLines = nextMove.move === "down the hall" || nextMove.move === "up the hall";
|
const toShortLines = nextMove.move === "down the hall" || nextMove.move === "up the hall";
|
||||||
const endFacingAcross = (around === CircleSide.Left || around === CircleSide.Right) && !toShortLines;
|
const endFacingAcross = (around === CircleSide.Left || around === CircleSide.Right) && !toShortLines;
|
||||||
|
|
||||||
|
@ -609,7 +610,10 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
const startPosition: SemanticPosition = {
|
const startPosition: SemanticPosition = {
|
||||||
...startPos,
|
...startPos,
|
||||||
facing: around === CircleSide.Left || CircleSide.Right
|
facing: around === CircleSide.Left || CircleSide.Right
|
||||||
? (startWhich instanceof CirclePosition ? (startWhich.topBottomSide() === CircleSide.Bottom ? Facing.Up : Facing.Down)
|
? (startWhich instanceof CirclePosition
|
||||||
|
? afterTake
|
||||||
|
? startPos.longLines === LongLines.Near ? startWhich.facingOut() : startWhich.facingAcross()
|
||||||
|
: (startWhich.topBottomSide() === CircleSide.Bottom ? Facing.Up : Facing.Down)
|
||||||
: startWhich.facingSide())
|
: startWhich.facingSide())
|
||||||
: (startWhich.isLeft() ? Facing.Right : Facing.Left),
|
: (startWhich.isLeft() ? Facing.Right : Facing.Left),
|
||||||
};
|
};
|
||||||
|
@ -691,6 +695,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
around,
|
around,
|
||||||
endFacing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
endFacing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
||||||
swingRole,
|
swingRole,
|
||||||
|
afterTake,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -766,8 +771,9 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
|
|
||||||
return handleCirclePairedMove(move.parameters.who, ({ startPos }) => {
|
return handleCirclePairedMove(move.parameters.who, ({ startPos }) => {
|
||||||
const handTo = startPos.which.isOnLeftLookingAcross() ? HandTo.DancerRight : HandTo.DancerLeft;
|
const handTo = startPos.which.isOnLeftLookingAcross() ? HandTo.DancerRight : HandTo.DancerLeft;
|
||||||
const startingPos = {
|
const startingPos: SemanticPosition = {
|
||||||
...startPos,
|
...startPos,
|
||||||
|
facing: startPos.which.facingAcross(),
|
||||||
dancerDistance: DancerDistance.Compact,
|
dancerDistance: DancerDistance.Compact,
|
||||||
hands: new Map<Hand, HandConnection>([
|
hands: new Map<Hand, HandConnection>([
|
||||||
[Hand.Left, { hand: Hand.Left, to: handTo }],
|
[Hand.Left, { hand: Hand.Left, to: handTo }],
|
||||||
|
@ -874,35 +880,52 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
endPosition = withPos;
|
endPosition = withPos;
|
||||||
} else if (intoWave) {
|
} else if (intoWave) {
|
||||||
if (startPos.kind === PositionKind.ShortLines) {
|
if (startPos.kind === PositionKind.ShortLines) {
|
||||||
// Fix startPos if necessary. Needed because pass through always swaps but sometimes shouldn't.
|
if (around === CircleSide.Left || around === CircleSide.Right) {
|
||||||
if ((around === CircleSide.Left || around === CircleSide.Right) &&
|
// Fix startPos if necessary. Needed because pass through always swaps but sometimes shouldn't.
|
||||||
(startPos.facing === Facing.Up || startPos.facing === Facing.Down) &&
|
if ((startPos.facing === Facing.Up || startPos.facing === Facing.Down) &&
|
||||||
((byHandOrShoulder === Hand.Right)
|
((byHandOrShoulder === Hand.Right)
|
||||||
!== (startPos.facing === Facing.Up)
|
!== (startPos.facing === Facing.Up)
|
||||||
!== (startPos.which === ShortLinesPosition.FarLeft || startPos.which === ShortLinesPosition.MiddleRight))) {
|
!== (startPos.which === ShortLinesPosition.FarLeft || startPos.which === ShortLinesPosition.MiddleRight))) {
|
||||||
startingPos = {
|
startingPos = {
|
||||||
...startPos,
|
...startPos,
|
||||||
which: startPos.which.swapOnSide()
|
which: startPos.which.swapOnSide()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const endWhich = CirclePosition.fromSides(startingPos.which.leftRightSide(),
|
const endWhich = CirclePosition.fromSides(startingPos.which.leftRightSide(),
|
||||||
(startingPos.which === ShortLinesPosition.FarLeft || startingPos.which === ShortLinesPosition.MiddleRight)
|
(startingPos.which === ShortLinesPosition.FarLeft || startingPos.which === ShortLinesPosition.MiddleRight)
|
||||||
!== (byHandOrShoulder === Hand.Right)
|
!== (byHandOrShoulder === Hand.Right)
|
||||||
!== (intoWavePositions === 1)
|
!== (intoWavePositions === 1)
|
||||||
? CircleSide.Top
|
? CircleSide.Top
|
||||||
: CircleSide.Bottom);
|
: CircleSide.Bottom);
|
||||||
endPosition = {
|
endPosition = {
|
||||||
kind: PositionKind.Circle,
|
kind: PositionKind.Circle,
|
||||||
which: endWhich,
|
which: endWhich,
|
||||||
facing: (startingPos.facing === Facing.Up) === (intoWavePositions === 1)
|
facing: (startingPos.facing === Facing.Up) === (intoWavePositions === 1)
|
||||||
? endWhich.facingAcross()
|
? endWhich.facingAcross()
|
||||||
: endWhich.facingOut(),
|
: endWhich.facingOut(),
|
||||||
setOffset: startingPos.setOffset,
|
setOffset: startingPos.setOffset,
|
||||||
lineOffset: startingPos.lineOffset,
|
lineOffset: startingPos.lineOffset,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Allemande from short lines to line line in middle unsupported.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Allemande from circle to short lines is unsupported.");
|
if (around === "Center") {
|
||||||
|
const startCenter = startPos.longLines === LongLines.Center;
|
||||||
|
const endWhich = startPos.which.circleRight(intoWavePositions);
|
||||||
|
endPosition = {
|
||||||
|
kind: PositionKind.Circle,
|
||||||
|
which: endWhich,
|
||||||
|
facing: startPos.which.facingOut(),
|
||||||
|
longLines: startCenter ? undefined : LongLines.Center,
|
||||||
|
setOffset: startPos.setOffset,
|
||||||
|
lineOffset: startPos.lineOffset,
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("Allemande from circle to short lines is unsupported.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1446,7 +1469,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
|
||||||
{
|
{
|
||||||
beats: backwardBeats,
|
beats: backwardBeats,
|
||||||
endPosition: startPosition,
|
endPosition: startPosition,
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear },
|
movementPattern: { kind: SemanticAnimationKind.Linear, minRotation: 0 },
|
||||||
},
|
},
|
||||||
], startPosition);
|
], startPosition);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -345,6 +345,9 @@ export enum LongLines {
|
||||||
|
|
||||||
// Only a little offset (has walked almost all the way from the other side after a give and take).
|
// Only a little offset (has walked almost all the way from the other side after a give and take).
|
||||||
Near = "Near",
|
Near = "Near",
|
||||||
|
|
||||||
|
// Actually in center. May be slightly offset for wavy lines.
|
||||||
|
Center = "Center",
|
||||||
}
|
}
|
||||||
export type SemanticPosition = {
|
export type SemanticPosition = {
|
||||||
kind: PositionKind.Circle,
|
kind: PositionKind.Circle,
|
||||||
|
|
|
@ -88,6 +88,9 @@ export type SemanticAnimation = {
|
||||||
|
|
||||||
// Swings are asymmetric. This is usually but not always the dancer's role.
|
// Swings are asymmetric. This is usually but not always the dancer's role.
|
||||||
swingRole: common.DanceRole,
|
swingRole: common.DanceRole,
|
||||||
|
|
||||||
|
// After a take need to fixup the position.
|
||||||
|
afterTake: boolean,
|
||||||
} | {
|
} | {
|
||||||
kind: SemanticAnimationKind.TwirlSwap,
|
kind: SemanticAnimationKind.TwirlSwap,
|
||||||
|
|
||||||
|
@ -270,6 +273,8 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
|
||||||
throw "Invalid circle position: " + semantic.which;
|
throw "Invalid circle position: " + semantic.which;
|
||||||
}
|
}
|
||||||
switch(semantic.longLines) {
|
switch(semantic.longLines) {
|
||||||
|
case LongLines.Center:
|
||||||
|
position.x *= 0.1;
|
||||||
case LongLines.Forward:
|
case LongLines.Forward:
|
||||||
position.x *= 0.3;
|
position.x *= 0.3;
|
||||||
case LongLines.Near:
|
case LongLines.Near:
|
||||||
|
@ -585,6 +590,7 @@ function animateLowLevelMoveWithoutSlide(move: LowLevelMove): animation.Animatio
|
||||||
])
|
])
|
||||||
}),
|
}),
|
||||||
flags: {
|
flags: {
|
||||||
|
rotation: true,
|
||||||
hands: true,
|
hands: true,
|
||||||
handsDuring: circleHands,
|
handsDuring: circleHands,
|
||||||
},
|
},
|
||||||
|
@ -669,15 +675,26 @@ function animateLowLevelMoveWithoutSlide(move: LowLevelMove): animation.Animatio
|
||||||
|
|
||||||
const baseSwingStart = {
|
const baseSwingStart = {
|
||||||
...move.startPosition,
|
...move.startPosition,
|
||||||
dancerDistance,
|
dancerDistance: move.movementPattern.afterTake ? undefined : dancerDistance,
|
||||||
balance: undefined,
|
balance: undefined,
|
||||||
longLines: undefined,
|
longLines: undefined,
|
||||||
}
|
}
|
||||||
const swingStart = SemanticToSetPosition(move.startPosition.longLines === LongLines.Near ? {
|
const swingStartUnadjusted = SemanticToSetPosition(move.startPosition.longLines === LongLines.Near ? {
|
||||||
...baseSwingStart,
|
...baseSwingStart,
|
||||||
kind: PositionKind.Circle,
|
kind: PositionKind.Circle,
|
||||||
which: move.startPosition.which.swapUpAndDown(),
|
which: move.startPosition.which.swapUpAndDown(),
|
||||||
} : baseSwingStart);
|
} : baseSwingStart);
|
||||||
|
const swingStart = move.movementPattern.afterTake
|
||||||
|
? {
|
||||||
|
...swingStartUnadjusted, position: {
|
||||||
|
x: swingStartUnadjusted.position.x
|
||||||
|
+ ((move.startPosition.longLines === LongLines.Near) === (move.startPosition.which.isLeft())
|
||||||
|
? +0.5
|
||||||
|
: -0.5),
|
||||||
|
y: rotateSwingCenter.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: swingStartUnadjusted;
|
||||||
const beforeUnfold = SemanticToSetPosition({
|
const beforeUnfold = SemanticToSetPosition({
|
||||||
...move.endPosition,
|
...move.endPosition,
|
||||||
dancerDistance,
|
dancerDistance,
|
||||||
|
@ -696,15 +713,16 @@ function animateLowLevelMoveWithoutSlide(move: LowLevelMove): animation.Animatio
|
||||||
const turns = Math.ceil(Math.abs(move.movementPattern.minAmount / 360));
|
const turns = Math.ceil(Math.abs(move.movementPattern.minAmount / 360));
|
||||||
const swingMinRotation = (minTurns - turns) * (move.movementPattern.minAmount < 0 ? -360 : 360) + move.movementPattern.minAmount;
|
const swingMinRotation = (minTurns - turns) * (move.movementPattern.minAmount < 0 ? -360 : 360) + move.movementPattern.minAmount;
|
||||||
|
|
||||||
return [
|
const slideAmount = move.movementPattern.afterTake ? { x: 0, y: rotateSwingCenter.y - startSetPosition.position.y } : undefined;
|
||||||
new animation.TransitionAnimationSegment({
|
|
||||||
|
const swingAnimation = new animation.TransitionAnimationSegment({
|
||||||
actualAnimation: new animation.RotationAnimationSegment({
|
actualAnimation: new animation.RotationAnimationSegment({
|
||||||
beats: swingBeats,
|
beats: swingBeats,
|
||||||
startPosition: swingStart,
|
startPosition: slideAmount ? { ...swingStart, position: OffsetPlus(swingStart.position, OffsetTimes(slideAmount, -1)) } : swingStart,
|
||||||
endPosition: beforeUnfold,
|
endPosition: slideAmount ? { ...beforeUnfold, position: OffsetPlus(beforeUnfold.position, OffsetTimes(slideAmount, -1)) } : beforeUnfold,
|
||||||
rotation: swingMinRotation,
|
rotation: swingMinRotation,
|
||||||
around: {
|
around: {
|
||||||
center: rotateSwingCenter,
|
center: slideAmount ? OffsetPlus(rotateSwingCenter, OffsetTimes(slideAmount, -1)) : rotateSwingCenter,
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 1,
|
height: 1,
|
||||||
},
|
},
|
||||||
|
@ -722,7 +740,14 @@ function animateLowLevelMoveWithoutSlide(move: LowLevelMove): animation.Animatio
|
||||||
},
|
},
|
||||||
startTransitionBeats: 1,
|
startTransitionBeats: 1,
|
||||||
endTransitionBeats: 0,
|
endTransitionBeats: 0,
|
||||||
}),
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
slideAmount ? new animation.SlideAnimationSegment(
|
||||||
|
swingAnimation.beats,
|
||||||
|
[swingAnimation],
|
||||||
|
slideAmount,
|
||||||
|
) : swingAnimation,
|
||||||
new animation.LinearAnimationSegment({
|
new animation.LinearAnimationSegment({
|
||||||
beats: 1,
|
beats: 1,
|
||||||
startPosition: beforeUnfold,
|
startPosition: beforeUnfold,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user