Refactors options and adds a fillScreen mode
This commit is contained in:
parent
31596774df
commit
e70787260a
159
bundle.js
159
bundle.js
@ -684,54 +684,6 @@ class OriginVector extends Vector {
|
|||||||
return new OriginVector(origin, v);
|
return new OriginVector(origin, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function satCollisionSpline(p, spline) {
|
|
||||||
for(let i = 0; i < 100; i++){
|
|
||||||
const t1 = i / 100;
|
|
||||||
const t2 = (i + 1) / 100;
|
|
||||||
const segmentStart = spline.getPointAtT(t1);
|
|
||||||
const segmentEnd = spline.getPointAtT(t2);
|
|
||||||
if (segmentIntersectsPolygon(p, segmentStart, segmentEnd)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
function segmentIntersectsPolygon(p, start, end) {
|
|
||||||
const edges = p.getEdges();
|
|
||||||
for (const edge of edges){
|
|
||||||
const axis = edge.copy().normal().normalize();
|
|
||||||
const proj1 = projectPolygonOntoAxis(p, axis);
|
|
||||||
const proj2 = projectSegmentOntoAxis(start, end, axis);
|
|
||||||
if (!overlap(proj1, proj2)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
function projectPolygonOntoAxis(p, axis) {
|
|
||||||
let min = Infinity;
|
|
||||||
let max = -Infinity;
|
|
||||||
for (const point of p.points){
|
|
||||||
const dotProduct = point.copy().add(p.center).dot(axis);
|
|
||||||
min = Math.min(min, dotProduct);
|
|
||||||
max = Math.max(max, dotProduct);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
min,
|
|
||||||
max
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function projectSegmentOntoAxis(start, end, axis) {
|
|
||||||
const dotProductStart = start.dot(axis);
|
|
||||||
const dotProductEnd = end.dot(axis);
|
|
||||||
return {
|
|
||||||
min: Math.min(dotProductStart, dotProductEnd),
|
|
||||||
max: Math.max(dotProductStart, dotProductEnd)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function overlap(proj1, proj2) {
|
|
||||||
return proj1.min <= proj2.max && proj1.max >= proj2.min;
|
|
||||||
}
|
|
||||||
const easeInOut = (x)=>x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
|
const easeInOut = (x)=>x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
|
||||||
const map = (value, x1, y1, x2, y2)=>(value - x1) * (y2 - x2) / (y1 - x1) + x2;
|
const map = (value, x1, y1, x2, y2)=>(value - x1) * (y2 - x2) / (y1 - x1) + x2;
|
||||||
class Doodler {
|
class Doodler {
|
||||||
@ -749,15 +701,24 @@ class Doodler {
|
|||||||
draggables = [];
|
draggables = [];
|
||||||
clickables = [];
|
clickables = [];
|
||||||
dragTarget;
|
dragTarget;
|
||||||
constructor({ width, height, canvas, bg, framerate }, postInit){
|
constructor({ width, height, fillScreen, canvas, bg, framerate }, postInit){
|
||||||
if (!canvas) {
|
if (!canvas) {
|
||||||
canvas = document.createElement("canvas");
|
canvas = document.createElement("canvas");
|
||||||
document.body.append(canvas);
|
document.body.append(canvas);
|
||||||
}
|
}
|
||||||
this.bg = bg || "white";
|
this.bg = bg || "white";
|
||||||
this.framerate = framerate || 60;
|
this.framerate = framerate || 60;
|
||||||
canvas.width = width;
|
canvas.width = fillScreen ? document.body.clientWidth : width;
|
||||||
canvas.height = height;
|
canvas.height = fillScreen ? document.body.clientHeight : height;
|
||||||
|
if (fillScreen) {
|
||||||
|
const resizeObserver = new ResizeObserver((entries)=>{
|
||||||
|
for (const entry of entries){
|
||||||
|
this._canvas.width = entry.target.clientWidth;
|
||||||
|
this._canvas.height = entry.target.clientHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resizeObserver.observe(document.body);
|
||||||
|
}
|
||||||
this._canvas = canvas;
|
this._canvas = canvas;
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
if (!ctx) throw "Unable to initialize Doodler: Canvas context not found";
|
if (!ctx) throw "Unable to initialize Doodler: Canvas context not found";
|
||||||
@ -1308,6 +1269,54 @@ const init = (opt, zoomable, postInit)=>{
|
|||||||
window.doodler = zoomable ? new ZoomableDoodler(opt, postInit) : new Doodler(opt, postInit);
|
window.doodler = zoomable ? new ZoomableDoodler(opt, postInit) : new Doodler(opt, postInit);
|
||||||
window.doodler.init();
|
window.doodler.init();
|
||||||
};
|
};
|
||||||
|
function satCollisionSpline(p, spline) {
|
||||||
|
for(let i = 0; i < 100; i++){
|
||||||
|
const t1 = i / 100;
|
||||||
|
const t2 = (i + 1) / 100;
|
||||||
|
const segmentStart = spline.getPointAtT(t1);
|
||||||
|
const segmentEnd = spline.getPointAtT(t2);
|
||||||
|
if (segmentIntersectsPolygon(p, segmentStart, segmentEnd)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function segmentIntersectsPolygon(p, start, end) {
|
||||||
|
const edges = p.getEdges();
|
||||||
|
for (const edge of edges){
|
||||||
|
const axis = edge.copy().normal().normalize();
|
||||||
|
const proj1 = projectPolygonOntoAxis(p, axis);
|
||||||
|
const proj2 = projectSegmentOntoAxis(start, end, axis);
|
||||||
|
if (!overlap(proj1, proj2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function projectPolygonOntoAxis(p, axis) {
|
||||||
|
let min = Infinity;
|
||||||
|
let max = -Infinity;
|
||||||
|
for (const point of p.points){
|
||||||
|
const dotProduct = point.copy().add(p.center).dot(axis);
|
||||||
|
min = Math.min(min, dotProduct);
|
||||||
|
max = Math.max(max, dotProduct);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
min,
|
||||||
|
max
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function projectSegmentOntoAxis(start, end, axis) {
|
||||||
|
const dotProductStart = start.dot(axis);
|
||||||
|
const dotProductEnd = end.dot(axis);
|
||||||
|
return {
|
||||||
|
min: Math.min(dotProductStart, dotProductEnd),
|
||||||
|
max: Math.max(dotProductStart, dotProductEnd)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function overlap(proj1, proj2) {
|
||||||
|
return proj1.min <= proj2.max && proj1.max >= proj2.min;
|
||||||
|
}
|
||||||
class Polygon {
|
class Polygon {
|
||||||
points;
|
points;
|
||||||
center;
|
center;
|
||||||
@ -1580,9 +1589,8 @@ class SplineSegment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
init({
|
init({
|
||||||
width: 400,
|
fillScreen: true,
|
||||||
height: 400,
|
bg: "#333"
|
||||||
framerate: 90
|
|
||||||
}, true, (ctx)=>{
|
}, true, (ctx)=>{
|
||||||
ctx.imageSmoothingEnabled = false;
|
ctx.imageSmoothingEnabled = false;
|
||||||
});
|
});
|
||||||
@ -1590,7 +1598,48 @@ const img = new Image();
|
|||||||
img.src = "./pixel fire.gif";
|
img.src = "./pixel fire.gif";
|
||||||
const p = new Vector();
|
const p = new Vector();
|
||||||
const gif = new GIFAnimation("./fire-joypixels.gif", p, .5);
|
const gif = new GIFAnimation("./fire-joypixels.gif", p, .5);
|
||||||
|
const spline = new SplineSegment([
|
||||||
|
new Vector({
|
||||||
|
x: -25,
|
||||||
|
y: -25
|
||||||
|
}).mult(10).add(p),
|
||||||
|
new Vector({
|
||||||
|
x: 25,
|
||||||
|
y: -25
|
||||||
|
}).mult(10).add(p),
|
||||||
|
new Vector({
|
||||||
|
x: -25,
|
||||||
|
y: -25
|
||||||
|
}).mult(10).add(p),
|
||||||
|
new Vector({
|
||||||
|
x: -25,
|
||||||
|
y: 25
|
||||||
|
}).mult(10).add(p)
|
||||||
|
]);
|
||||||
|
const poly2 = Polygon.createPolygon(4);
|
||||||
|
poly2.center = p.copy().add(100, 100);
|
||||||
doodler.createLayer((c, i, t)=>{
|
doodler.createLayer((c, i, t)=>{
|
||||||
gif.draw(t);
|
gif.draw(t);
|
||||||
|
for(let i = 0; i < c.canvas.width; i += 50){
|
||||||
|
for(let j = 0; j < c.canvas.height; j += 50){
|
||||||
|
doodler.drawSquare(new Vector(i, j), 50, {
|
||||||
|
color: "#00000010"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poly2.circularHitbox;
|
||||||
|
const intersects = satCollisionSpline(poly2, spline);
|
||||||
|
const color = intersects ? "red" : "aqua";
|
||||||
|
spline.draw(color);
|
||||||
|
poly2.draw(color);
|
||||||
|
const [gamepad] = navigator.getGamepads();
|
||||||
|
if (gamepad) {
|
||||||
|
gamepad.axes[0];
|
||||||
|
gamepad.axes[1];
|
||||||
|
const rightX = gamepad.axes[2];
|
||||||
|
const rightY = gamepad.axes[3];
|
||||||
|
let mMulti = 10;
|
||||||
|
const mod = new Vector(Math.min(Math.max(rightX - 0.05, 0), rightX + 0.05), Math.min(Math.max(rightY - 0.05, 0), rightY + 0.05));
|
||||||
|
poly2.center.add(mod.mult(mMulti));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
requestAnimationFrame;
|
|
||||||
|
37
canvas.ts
37
canvas.ts
@ -6,7 +6,7 @@ import { postInit } from "./postInit.ts";
|
|||||||
import { ZoomableDoodler } from "./zoomableCanvas.ts";
|
import { ZoomableDoodler } from "./zoomableCanvas.ts";
|
||||||
|
|
||||||
export const init = (
|
export const init = (
|
||||||
opt: IDoodlerOptions,
|
opt: DoodlerOptions,
|
||||||
zoomable: boolean,
|
zoomable: boolean,
|
||||||
postInit?: postInit,
|
postInit?: postInit,
|
||||||
) => {
|
) => {
|
||||||
@ -19,13 +19,22 @@ export const init = (
|
|||||||
window.doodler.init();
|
window.doodler.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IDoodlerOptions {
|
type DoodlerOptionalOptions = {
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
canvas?: HTMLCanvasElement;
|
canvas?: HTMLCanvasElement;
|
||||||
bg?: string;
|
bg?: string;
|
||||||
framerate?: number;
|
framerate?: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
type DoodlerRequiredOptions = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
fillScreen?: false;
|
||||||
|
} | {
|
||||||
|
width?: 0;
|
||||||
|
height?: 0;
|
||||||
|
fillScreen: true;
|
||||||
|
};
|
||||||
|
export type DoodlerOptions = DoodlerOptionalOptions & DoodlerRequiredOptions;
|
||||||
|
|
||||||
type layer = (
|
type layer = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
@ -57,10 +66,11 @@ export class Doodler {
|
|||||||
constructor({
|
constructor({
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
fillScreen,
|
||||||
canvas,
|
canvas,
|
||||||
bg,
|
bg,
|
||||||
framerate,
|
framerate,
|
||||||
}: IDoodlerOptions, postInit?: postInit) {
|
}: DoodlerOptions, postInit?: postInit) {
|
||||||
if (!canvas) {
|
if (!canvas) {
|
||||||
canvas = document.createElement("canvas");
|
canvas = document.createElement("canvas");
|
||||||
document.body.append(canvas);
|
document.body.append(canvas);
|
||||||
@ -69,8 +79,19 @@ export class Doodler {
|
|||||||
this.bg = bg || "white";
|
this.bg = bg || "white";
|
||||||
this.framerate = framerate || 60;
|
this.framerate = framerate || 60;
|
||||||
|
|
||||||
canvas.width = width;
|
canvas.width = fillScreen ? document.body.clientWidth : width;
|
||||||
canvas.height = height;
|
canvas.height = fillScreen ? document.body.clientHeight : height;
|
||||||
|
|
||||||
|
if (fillScreen) {
|
||||||
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
this._canvas.width = entry.target.clientWidth;
|
||||||
|
this._canvas.height = entry.target.clientHeight;
|
||||||
|
// this.ctx = this.c
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resizeObserver.observe(document.body);
|
||||||
|
}
|
||||||
|
|
||||||
this._canvas = canvas;
|
this._canvas = canvas;
|
||||||
|
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
13
main.ts
13
main.ts
@ -14,8 +14,9 @@ import { SplineSegment } from "./geometry/spline.ts";
|
|||||||
|
|
||||||
initializeDoodler(
|
initializeDoodler(
|
||||||
{
|
{
|
||||||
width: 2400,
|
// width: 2400,
|
||||||
height: 1200,
|
fillScreen: true,
|
||||||
|
// height: 1200,
|
||||||
bg: "#333",
|
bg: "#333",
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@ -35,11 +36,6 @@ img.src = "./pixel fire.gif";
|
|||||||
const p = new Vector();
|
const p = new Vector();
|
||||||
const gif = new GIFAnimation("./fire-joypixels.gif", p, .5);
|
const gif = new GIFAnimation("./fire-joypixels.gif", p, .5);
|
||||||
|
|
||||||
doodler.createLayer((c, i, t) => {
|
|
||||||
gif.draw(t);
|
|
||||||
// c.drawImage(img, 0, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
const spline = new SplineSegment([
|
const spline = new SplineSegment([
|
||||||
new Vector({ x: -25, y: -25 }).mult(10).add(p),
|
new Vector({ x: -25, y: -25 }).mult(10).add(p),
|
||||||
new Vector({ x: 25, y: -25 }).mult(10).add(p),
|
new Vector({ x: 25, y: -25 }).mult(10).add(p),
|
||||||
@ -53,7 +49,8 @@ const poly2 = Polygon.createPolygon(4);
|
|||||||
poly2.center = p.copy().add(100, 100);
|
poly2.center = p.copy().add(100, 100);
|
||||||
// poly.center.add(p);
|
// poly.center.add(p);
|
||||||
|
|
||||||
doodler.createLayer((c) => {
|
doodler.createLayer((c, i, t) => {
|
||||||
|
gif.draw(t);
|
||||||
// c.translate(1200, 600);
|
// c.translate(1200, 600);
|
||||||
for (let i = 0; i < c.canvas.width; i += 50) {
|
for (let i = 0; i < c.canvas.width; i += 50) {
|
||||||
for (let j = 0; j < c.canvas.height; j += 50) {
|
for (let j = 0; j < c.canvas.height; j += 50) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Doodler, IDoodlerOptions } from "./canvas.ts";
|
import { Doodler, DoodlerOptions } from "./canvas.ts";
|
||||||
import { OriginVector, Point } from "./geometry/vector.ts";
|
import { OriginVector, Point } from "./geometry/vector.ts";
|
||||||
import { postInit } from "./postInit.ts";
|
import { postInit } from "./postInit.ts";
|
||||||
import { easeInOut } from "./timing/EaseInOut.ts";
|
import { easeInOut } from "./timing/EaseInOut.ts";
|
||||||
@ -29,7 +29,7 @@ export class ZoomableDoodler extends Doodler {
|
|||||||
|
|
||||||
maxScale = 4;
|
maxScale = 4;
|
||||||
|
|
||||||
constructor(options: IDoodlerOptions, postInit?: postInit) {
|
constructor(options: DoodlerOptions, postInit?: postInit) {
|
||||||
super(options, postInit);
|
super(options, postInit);
|
||||||
|
|
||||||
this._canvas.addEventListener("wheel", (e) => {
|
this._canvas.addEventListener("wheel", (e) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user