UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

94 lines (82 loc) 3.91 kB
import {position_canvas_to_curve} from "./position_canvas_to_curve.js"; import {Keyframe} from "../Keyframe.js"; import {assert} from "../../../../core/assert.js"; import {animation_curve_subdivide} from "../animation_curve_subdivide.js"; import {animation_curve_nearest_point} from "../animation_curve_nearest_point.js"; import Vector2 from "../../../../core/geom/Vector2.js"; import {position_curve_to_canvas} from "./position_curve_to_canvas.js"; /** * Check if new keyframe is in valid bounds * @param {CanvasView} graph * @param {AABB2} frame * @param {Vector2} margin * @param {AnimationCurve} curve * @param {AABB2} validEditableBounds * @param {Vector2} newCanvasPosition * @param {Keyframe} newKeyframeContainer * @returns {boolean} */ export function isInjectedKeyframeInBounds(graph, frame, margin, curve, validEditableBounds, newCanvasPosition, newKeyframeContainer) { const curvePosition = position_canvas_to_curve(graph.size, frame, margin, newCanvasPosition.x, newCanvasPosition.y); const curveTimePos = curvePosition.x; //New keyframe is within the curve range const isWithinCurveTimeBounds = curveTimePos > curve.keys[0].time && curveTimePos < curve.keys[curve.length - 1].time if (isWithinCurveTimeBounds) { const timeSplicePosition = detectClosestCurveTimePoint(curve, graph, frame, margin, curvePosition, newCanvasPosition); if (timeSplicePosition !== Infinity) { acquireInjectedKeyframePosition(curve, timeSplicePosition, newKeyframeContainer); return true; } } else if (validEditableBounds.containsPoint(curvePosition.x, curvePosition.y)) { //New keyframe is within the bounds limit newKeyframeContainer.time = curvePosition.x; newKeyframeContainer.value = curvePosition.y; return true; } return false; } /** * * @param {AnimationCurve} curve * @param {CanvasView} graph * @param {AABB2} frame * @param {Vector2} margin * @param {Vector2} curvePosition * @param {Vector2} mousePosition * @returns {number} */ export function detectClosestCurveTimePoint(curve, graph, frame, margin, curvePosition, mousePosition) { const distTolerance = 10; const nearestTimePoint = animation_curve_nearest_point(curve, curvePosition.x, curvePosition.y) const foundCurvePoint = new Vector2(nearestTimePoint, curve.evaluate(nearestTimePoint)); const canvasPositionOfFoundCurvePoint = position_curve_to_canvas(graph.size, frame, margin, foundCurvePoint.x, foundCurvePoint.y) let closestPoint = Infinity; if (mousePosition.distanceTo(canvasPositionOfFoundCurvePoint) <= distTolerance) { closestPoint = nearestTimePoint; } return closestPoint; } /** * * @param {AnimationCurve} curve * @param {number} timeSplicePosition * @param {Keyframe} newKeyframeContainer */ function acquireInjectedKeyframePosition(curve, timeSplicePosition, newKeyframeContainer) { const prevKeyframeRef = new Keyframe(); const nextKeyframeRef = new Keyframe(); curve.keys.forEach((kf) => { if (kf.time <= timeSplicePosition && kf.time >= prevKeyframeRef.time) { prevKeyframeRef.copy(kf); } if (kf.time >= timeSplicePosition && nextKeyframeRef.time === 0) { nextKeyframeRef.copy(kf); } }); assert.notEqual(nextKeyframeRef.time, 0, "Invalid next keyframe value"); assert.notEqual(prevKeyframeRef.time, nextKeyframeRef.time, "Invalid keyframes value") const segmentTimeDiff = nextKeyframeRef.time - prevKeyframeRef.time; const segmentTimeTravel = timeSplicePosition - prevKeyframeRef.time; const segmentTimeSplitRatio = segmentTimeTravel / segmentTimeDiff; animation_curve_subdivide(newKeyframeContainer, prevKeyframeRef, nextKeyframeRef, segmentTimeSplitRatio); }