From 69ab471d228b0c7674f88287c84a2b2bd927d18e Mon Sep 17 00:00:00 2001 From: Emma Date: Sun, 5 Nov 2023 02:04:18 -0700 Subject: [PATCH] module exports --- bundle.js | 363 ++++++++++++++++++++++---------------------- geometry/polygon.ts | 5 + mod.ts | 16 +- 3 files changed, 204 insertions(+), 180 deletions(-) diff --git a/bundle.js b/bundle.js index f830bc4..39bae87 100644 --- a/bundle.js +++ b/bundle.js @@ -684,6 +684,184 @@ class OriginVector extends Vector { return new OriginVector(origin, v); } } +class SplineSegment { + points; + length; + constructor(points){ + this.points = points; + this.length = this.calculateApproxLength(100); + } + draw(color) { + const [a, b, c, d] = this.points; + doodler.drawBezier(a, b, c, d, { + strokeColor: color || "#ffffff50" + }); + } + getPointAtT(t) { + const [a, b, c, d] = this.points; + const res = a.copy(); + res.add(Vector.add(a.copy().mult(-3), b.copy().mult(3)).mult(t)); + res.add(Vector.add(Vector.add(a.copy().mult(3), b.copy().mult(-6)), c.copy().mult(3)).mult(Math.pow(t, 2))); + res.add(Vector.add(Vector.add(a.copy().mult(-1), b.copy().mult(3)), Vector.add(c.copy().mult(-3), d.copy())).mult(Math.pow(t, 3))); + return res; + } + getClosestPoint(v) { + const resolution = 1 / 25; + let closest = this.points[0]; + let closestDistance = this.points[0].dist(v); + let closestT = 0; + for(let i = 0; i < 25; i++){ + const point = this.getPointAtT(i * resolution); + const distance = v.dist(point); + if (distance < closestDistance) { + closest = point; + closestDistance = distance; + closestT = i * resolution; + } + } + return [ + closest, + closestDistance, + closestT + ]; + } + getPointsWithinRadius(v, r) { + const points = []; + const resolution = 1 / 25; + for(let i = 0; i < 25 + 1; i++){ + const point = this.getPointAtT(i * resolution); + const distance = v.dist(point); + if (distance < r) { + points.push([ + i * resolution, + this + ]); + } + } + return points; + } + tangent(t) { + const [a, b, c, d] = this.points; + const res = Vector.sub(b, a).mult(3 * Math.pow(1 - t, 2)); + res.add(Vector.add(Vector.sub(c, b).mult(6 * (1 - t) * t), Vector.sub(d, c).mult(3 * Math.pow(t, 2)))); + return res; + } + doesIntersectCircle(x, y, r) { + const v = new Vector(x, y); + const resolution = 1 / 25; + let distance = Infinity; + let t; + for(let i = 0; i < 25 - 1; i++){ + const a = this.getPointAtT(i * resolution); + const b = this.getPointAtT((i + 1) * resolution); + const ac = Vector.sub(v, a); + const ab = Vector.sub(b, a); + const d = Vector.add(Vector.vectorProjection(ac, ab), a); + const ad = Vector.sub(d, a); + const k = Math.abs(ab.x) > Math.abs(ab.y) ? ad.x / ab.x : ad.y / ab.y; + let dist; + if (k <= 0.0) { + dist = Vector.hypot2(v, a); + } else if (k >= 1.0) { + dist = Vector.hypot2(v, b); + } + dist = Vector.hypot2(v, d); + if (dist < distance) { + distance = dist; + t = i * resolution; + } + } + if (distance < r) return t; + return false; + } + intersectsCircle(circleCenter, radius) { + for(let i = 0; i < 100; i++){ + const t1 = i / 100; + const t2 = (i + 1) / 100; + const segmentStart = this.getPointAtT(t1); + const segmentEnd = this.getPointAtT(t2); + const segmentLength = Math.sqrt((segmentEnd.x - segmentStart.x) ** 2 + (segmentEnd.y - segmentStart.y) ** 2); + const resolution = Math.max(10, Math.ceil(100 * (segmentLength / radius))); + for(let j = 0; j <= resolution; j++){ + const t = j / resolution; + const point = this.getPointAtT(t); + const distance = Math.sqrt((point.x - circleCenter.x) ** 2 + (point.y - circleCenter.y) ** 2); + if (distance <= radius) { + return true; + } + } + } + return false; + } + calculateApproxLength(resolution = 25) { + const stepSize = 1 / resolution; + const points = []; + for(let i = 0; i <= resolution; i++){ + const current = stepSize * i; + points.push(this.getPointAtT(current)); + } + this.length = points.reduce((acc, cur)=>{ + const prev = acc.prev; + acc.prev = cur; + if (!prev) return acc; + acc.length += cur.dist(prev); + return acc; + }, { + prev: undefined, + length: 0 + }).length; + return this.length; + } + calculateEvenlySpacedPoints(spacing, resolution = 1) { + const points = []; + points.push(this.points[0]); + let prev = points[0]; + let distSinceLastEvenPoint = 0; + let t = 0; + const div = Math.ceil(this.length * resolution * 10); + while(t < 1){ + t += 1 / div; + const point = this.getPointAtT(t); + distSinceLastEvenPoint += prev.dist(point); + if (distSinceLastEvenPoint >= spacing) { + const overshoot = distSinceLastEvenPoint - spacing; + const evenPoint = Vector.add(point, Vector.sub(point, prev).normalize().mult(overshoot)); + distSinceLastEvenPoint = overshoot; + points.push(evenPoint); + prev = evenPoint; + } + prev = point; + } + return points; + } + _aabb; + get AABB() { + if (!this._aabb) { + this._aabb = this.recalculateAABB(); + } + return this._aabb; + } + recalculateAABB() { + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + for(let i = 0; i < 100; i++){ + const t = i / 100; + const point = this.getPointAtT(t); + minX = Math.min(minX, point.x); + minY = Math.min(minY, point.y); + maxX = Math.max(maxX, point.x); + maxY = Math.max(maxY, point.y); + } + return { + x: minX, + y: minY, + w: maxX - minX, + h: maxY - minY + }; + } +} class Doodler { ctx; _canvas; @@ -1292,6 +1470,10 @@ class Polygon { color }); } + doodler.dot(this.center, { + weight: 4, + color: "yellow" + }); } calcCenter() { if (!this.points.length) return new Vector(); @@ -1354,6 +1536,9 @@ class Polygon { poly.points.push(pt); } poly.center = poly.calcCenter(); + for (const p of poly.points){ + p.sub(poly.center); + } return poly; } getEdges() { @@ -1413,184 +1598,6 @@ function projectCircleOntoAxis(c, axis) { function overlap(proj1, proj2) { return proj1.min <= proj2.max && proj1.max >= proj2.min; } -class SplineSegment { - points; - length; - constructor(points){ - this.points = points; - this.length = this.calculateApproxLength(100); - } - draw(color) { - const [a, b, c, d] = this.points; - doodler.drawBezier(a, b, c, d, { - strokeColor: color || "#ffffff50" - }); - } - getPointAtT(t) { - const [a, b, c, d] = this.points; - const res = a.copy(); - res.add(Vector.add(a.copy().mult(-3), b.copy().mult(3)).mult(t)); - res.add(Vector.add(Vector.add(a.copy().mult(3), b.copy().mult(-6)), c.copy().mult(3)).mult(Math.pow(t, 2))); - res.add(Vector.add(Vector.add(a.copy().mult(-1), b.copy().mult(3)), Vector.add(c.copy().mult(-3), d.copy())).mult(Math.pow(t, 3))); - return res; - } - getClosestPoint(v) { - const resolution = 1 / 25; - let closest = this.points[0]; - let closestDistance = this.points[0].dist(v); - let closestT = 0; - for(let i = 0; i < 25; i++){ - const point = this.getPointAtT(i * resolution); - const distance = v.dist(point); - if (distance < closestDistance) { - closest = point; - closestDistance = distance; - closestT = i * resolution; - } - } - return [ - closest, - closestDistance, - closestT - ]; - } - getPointsWithinRadius(v, r) { - const points = []; - const resolution = 1 / 25; - for(let i = 0; i < 25 + 1; i++){ - const point = this.getPointAtT(i * resolution); - const distance = v.dist(point); - if (distance < r) { - points.push([ - i * resolution, - this - ]); - } - } - return points; - } - tangent(t) { - const [a, b, c, d] = this.points; - const res = Vector.sub(b, a).mult(3 * Math.pow(1 - t, 2)); - res.add(Vector.add(Vector.sub(c, b).mult(6 * (1 - t) * t), Vector.sub(d, c).mult(3 * Math.pow(t, 2)))); - return res; - } - doesIntersectCircle(x, y, r) { - const v = new Vector(x, y); - const resolution = 1 / 25; - let distance = Infinity; - let t; - for(let i = 0; i < 25 - 1; i++){ - const a = this.getPointAtT(i * resolution); - const b = this.getPointAtT((i + 1) * resolution); - const ac = Vector.sub(v, a); - const ab = Vector.sub(b, a); - const d = Vector.add(Vector.vectorProjection(ac, ab), a); - const ad = Vector.sub(d, a); - const k = Math.abs(ab.x) > Math.abs(ab.y) ? ad.x / ab.x : ad.y / ab.y; - let dist; - if (k <= 0.0) { - dist = Vector.hypot2(v, a); - } else if (k >= 1.0) { - dist = Vector.hypot2(v, b); - } - dist = Vector.hypot2(v, d); - if (dist < distance) { - distance = dist; - t = i * resolution; - } - } - if (distance < r) return t; - return false; - } - intersectsCircle(circleCenter, radius) { - for(let i = 0; i < 100; i++){ - const t1 = i / 100; - const t2 = (i + 1) / 100; - const segmentStart = this.getPointAtT(t1); - const segmentEnd = this.getPointAtT(t2); - const segmentLength = Math.sqrt((segmentEnd.x - segmentStart.x) ** 2 + (segmentEnd.y - segmentStart.y) ** 2); - const resolution = Math.max(10, Math.ceil(100 * (segmentLength / radius))); - for(let j = 0; j <= resolution; j++){ - const t = j / resolution; - const point = this.getPointAtT(t); - const distance = Math.sqrt((point.x - circleCenter.x) ** 2 + (point.y - circleCenter.y) ** 2); - if (distance <= radius) { - return true; - } - } - } - return false; - } - calculateApproxLength(resolution = 25) { - const stepSize = 1 / resolution; - const points = []; - for(let i = 0; i <= resolution; i++){ - const current = stepSize * i; - points.push(this.getPointAtT(current)); - } - this.length = points.reduce((acc, cur)=>{ - const prev = acc.prev; - acc.prev = cur; - if (!prev) return acc; - acc.length += cur.dist(prev); - return acc; - }, { - prev: undefined, - length: 0 - }).length; - return this.length; - } - calculateEvenlySpacedPoints(spacing, resolution = 1) { - const points = []; - points.push(this.points[0]); - let prev = points[0]; - let distSinceLastEvenPoint = 0; - let t = 0; - const div = Math.ceil(this.length * resolution * 10); - while(t < 1){ - t += 1 / div; - const point = this.getPointAtT(t); - distSinceLastEvenPoint += prev.dist(point); - if (distSinceLastEvenPoint >= spacing) { - const overshoot = distSinceLastEvenPoint - spacing; - const evenPoint = Vector.add(point, Vector.sub(point, prev).normalize().mult(overshoot)); - distSinceLastEvenPoint = overshoot; - points.push(evenPoint); - prev = evenPoint; - } - prev = point; - } - return points; - } - _aabb; - get AABB() { - if (!this._aabb) { - this._aabb = this.recalculateAABB(); - } - return this._aabb; - } - recalculateAABB() { - let minX = Infinity; - let minY = Infinity; - let maxX = -Infinity; - let maxY = -Infinity; - for(let i = 0; i < 100; i++){ - const t = i / 100; - const point = this.getPointAtT(t); - minX = Math.min(minX, point.x); - minY = Math.min(minY, point.y); - maxX = Math.max(maxX, point.x); - maxY = Math.max(maxY, point.y); - } - return { - x: minX, - y: minY, - w: maxX - minX, - h: maxY - minY - }; - } -} init({ fillScreen: true, bg: "#333", diff --git a/geometry/polygon.ts b/geometry/polygon.ts index a1c138f..14a1052 100644 --- a/geometry/polygon.ts +++ b/geometry/polygon.ts @@ -20,6 +20,8 @@ export class Polygon { color, }); } + + doodler.dot(this.center, { weight: 4, color: "yellow" }); } calcCenter() { @@ -103,6 +105,9 @@ export class Polygon { poly.points.push(pt); } poly.center = poly.calcCenter(); + for (const p of poly.points) { + p.sub(poly.center); + } return poly; } diff --git a/mod.ts b/mod.ts index 51444e0..d69e462 100644 --- a/mod.ts +++ b/mod.ts @@ -1,5 +1,17 @@ /// -export { init as initializeDoodler } from "./init.ts"; - +export { GIFAnimation } from "./animation/gif.ts"; +export { SpriteAnimation } from "./animation/sprite.ts"; +export { axisAlignedCollision, axisAlignedContains } from "./collision/aa.ts"; +export { circularCollision } from "./collision/circular.ts"; +export { + satCollisionAABBCircle, + satCollisionCircle, + satCollisionPolygon, + satCollisionSpline, +} from "./collision/sat.ts"; export { Vector } from "./geometry/vector.ts"; +export { Polygon } from "./geometry/polygon.ts"; +export { SplineSegment } from "./geometry/spline.ts"; + +export { init as initializeDoodler } from "./init.ts";