changes hitbox getters to get properties, adds aaContains

This commit is contained in:
Emmaline Autumn 2023-11-03 05:12:19 -06:00
parent 601bc51233
commit 62b13e49e7
4 changed files with 135 additions and 28 deletions

109
bundle.js
View File

@ -2,8 +2,8 @@
// deno-lint-ignore-file // deno-lint-ignore-file
// This code was bundled using `deno bundle` and it's not recommended to edit it manually // This code was bundled using `deno bundle` and it's not recommended to edit it manually
const axisAlignedCollision = (aa1, aa2)=>{ const axisAlignedContains = (aa1, aa2)=>{
return aa1.x < aa2.x + aa2.w && aa1.x + aa1.w > aa2.x && aa1.y < aa2.y + aa2.h && aa1.y + aa1.h > aa2.y; return aa1.x < aa2.x && aa1.y < aa2.y && aa1.x + aa1.w > aa2.x + aa2.w && aa1.y + aa1.h > aa2.y + aa2.h;
}; };
const Constants = { const Constants = {
TWO_PI: Math.PI * 2 TWO_PI: Math.PI * 2
@ -293,6 +293,89 @@ class OriginVector extends Vector {
return new OriginVector(origin, v); return new OriginVector(origin, v);
} }
} }
const satCollision = (s1, s2)=>{
const shape1 = s1.points.map((p)=>new Vector(p).add(s1.center));
const shape2 = s2.points.map((p)=>new Vector(p).add(s2.center));
if (shape1.length < 2 || shape2.length < 2) {
throw "Insufficient shape data in satCollision";
}
new Vector(s1.center).sub(s2.center);
for(let i = 0; i < shape1.length; i++){
const axis = shape1[i].normal(shape1.at(i - 1));
let [p1min, p1minDot] = Vector.vectorProjectionAndDot(shape1[0], axis);
let [p1max, p1maxDot] = [
p1min,
p1minDot
];
for (const point of shape1){
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
p1min = dot < p1minDot ? projected : p1min;
p1minDot = Math.min(dot, p1minDot);
p1max = dot > p1maxDot ? projected : p1max;
p1maxDot = Math.max(dot, p1maxDot);
}
let [p2min, p2minDot] = Vector.vectorProjectionAndDot(shape2[0], axis);
let [p2max, p2maxDot] = [
p2min,
p2minDot
];
for (const point of shape2){
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
p2min = dot < p2minDot ? projected : p2min;
p2minDot = Math.min(dot, p2minDot);
p2max = dot > p2maxDot ? projected : p2max;
p2maxDot = Math.max(dot, p2maxDot);
}
if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) {
return false;
}
[
axis,
p1max,
p1min,
p2max,
p2min
];
}
for(let i = 0; i < shape2.length; i++){
const axis = shape2[i].normal(shape2.at(i - 1));
let [p1min, p1minDot] = Vector.vectorProjectionAndDot(shape2[0], axis);
let [p1max, p1maxDot] = [
p1min,
p1minDot
];
for (const point of shape2){
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
p1min = dot < p1minDot ? projected : p1min;
p1minDot = Math.min(dot, p1minDot);
p1max = dot > p1maxDot ? projected : p1max;
p1maxDot = Math.max(dot, p1maxDot);
}
let [p2min, p2minDot] = Vector.vectorProjectionAndDot(shape1[0], axis);
let [p2max, p2maxDot] = [
p2min,
p2minDot
];
for (const point of shape1){
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
p2min = dot < p2minDot ? projected : p2min;
p2minDot = Math.min(dot, p2minDot);
p2max = dot > p2maxDot ? projected : p2max;
p2maxDot = Math.max(dot, p2maxDot);
}
if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) {
return false;
}
[
axis,
p1max,
p1min,
p2max,
p2min
];
}
return true;
};
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 {
@ -879,10 +962,6 @@ class Polygon {
doodler.line(p1.copy().add(this.center), p2.copy().add(this.center), { doodler.line(p1.copy().add(this.center), p2.copy().add(this.center), {
color color
}); });
const { x, y, w, h } = this.aaHitbox();
doodler.drawRect(new Vector(x, y), w, h, {
color: "lime"
});
} }
} }
calcCenter() { calcCenter() {
@ -894,7 +973,7 @@ class Polygon {
center.div(this.points.length); center.div(this.points.length);
return center; return center;
} }
circularHitbox() { get circularHitbox() {
let greatestDistance = 0; let greatestDistance = 0;
for (const p of this.points){ for (const p of this.points){
greatestDistance = Math.max(p.copy().add(this.center).dist(this.center), greatestDistance); greatestDistance = Math.max(p.copy().add(this.center).dist(this.center), greatestDistance);
@ -904,7 +983,7 @@ class Polygon {
radius: greatestDistance radius: greatestDistance
}; };
} }
aaHitbox() { get aaHitbox() {
let smallestX, biggestX, smallestY, biggestY; let smallestX, biggestX, smallestY, biggestY;
smallestX = smallestY = Infinity; smallestX = smallestY = Infinity;
biggestX = biggestY = -Infinity; biggestX = biggestY = -Infinity;
@ -953,12 +1032,12 @@ document.body.append(img);
const p = new Vector(500, 500); const p = new Vector(500, 500);
const poly = new Polygon([ const poly = new Polygon([
{ {
x: -50, x: -25,
y: -25 y: -25
}, },
{ {
x: 25, x: 25,
y: -50 y: -25
}, },
{ {
x: 25, x: 25,
@ -970,7 +1049,7 @@ const poly = new Polygon([
} }
]); ]);
const poly2 = Polygon.createPolygon(5, 75); const poly2 = Polygon.createPolygon(5, 75);
poly2.center = p.copy(); poly2.center = p.copy().add(100, 100);
poly.center.add(p); poly.center.add(p);
doodler.createLayer((c)=>{ doodler.createLayer((c)=>{
for(let i = 0; i < c.canvas.width; i += 50){ for(let i = 0; i < c.canvas.width; i += 50){
@ -980,16 +1059,20 @@ doodler.createLayer((c)=>{
}); });
} }
} }
const color = axisAlignedCollision(poly.aaHitbox(), poly2.aaHitbox()) ? "red" : "black"; const color = satCollision(poly, poly2) ? "red" : "aqua";
poly.draw(color); poly.draw(color);
poly2.draw(color); poly2.draw(color);
const [gamepad] = navigator.getGamepads(); const [gamepad] = navigator.getGamepads();
if (gamepad) { if (gamepad) {
const leftX = gamepad.axes[0]; const leftX = gamepad.axes[0];
const leftY = gamepad.axes[1]; const leftY = gamepad.axes[1];
poly.center.add(new Vector(Math.min(Math.max(leftX - 0.05, 0), leftX + 0.05), Math.min(Math.max(leftY - 0.05, 0), leftY + 0.05)).mult(10));
const rightX = gamepad.axes[2]; const rightX = gamepad.axes[2];
const rightY = gamepad.axes[3]; const rightY = gamepad.axes[3];
if (axisAlignedContains(poly2.aaHitbox, poly.aaHitbox)) {
poly.center.add(new Vector(Math.min(Math.max(rightX - 0.05, 0), rightX + 0.05), Math.min(Math.max(rightY - 0.05, 0), rightY + 0.05)).mult(10));
poly2.center.add(new Vector(Math.min(Math.max(leftX - 0.05, 0), leftX + 0.05), Math.min(Math.max(leftY - 0.05, 0), leftY + 0.05)).mult(10));
}
poly.center.add(new Vector(Math.min(Math.max(leftX - 0.05, 0), leftX + 0.05), Math.min(Math.max(leftY - 0.05, 0), leftY + 0.05)).mult(10));
poly2.center.add(new Vector(Math.min(Math.max(rightX - 0.05, 0), rightX + 0.05), Math.min(Math.max(rightY - 0.05, 0), rightY + 0.05)).mult(10)); poly2.center.add(new Vector(Math.min(Math.max(rightX - 0.05, 0), rightX + 0.05), Math.min(Math.max(rightY - 0.05, 0), rightY + 0.05)).mult(10));
} }
}); });

View File

@ -14,3 +14,13 @@ export const axisAlignedCollision = (
aa1.y < aa2.y + aa2.h && aa1.y < aa2.y + aa2.h &&
aa1.y + aa1.h > aa2.y; aa1.y + aa1.h > aa2.y;
}; };
export const axisAlignedContains = (
aa1: axisAlignedBoundingBox,
aa2: axisAlignedBoundingBox,
) => {
return aa1.x < aa2.x &&
aa1.y < aa2.y &&
aa1.x + aa1.w > aa2.x + aa2.w &&
aa1.y + aa1.h > aa2.y + aa2.h;
};

View File

@ -19,8 +19,6 @@ export class Polygon {
doodler.line(p1.copy().add(this.center), p2.copy().add(this.center), { doodler.line(p1.copy().add(this.center), p2.copy().add(this.center), {
color, color,
}); });
const { x, y, w, h } = this.aaHitbox();
doodler.drawRect(new Vector(x, y), w, h, { color: "lime" });
} }
} }
@ -35,7 +33,7 @@ export class Polygon {
return center; return center;
} }
circularHitbox(): CircleLike { get circularHitbox(): CircleLike {
let greatestDistance = 0; let greatestDistance = 0;
for (const p of this.points) { for (const p of this.points) {
greatestDistance = Math.max( greatestDistance = Math.max(
@ -50,7 +48,7 @@ export class Polygon {
}; };
} }
aaHitbox(): axisAlignedBoundingBox { get aaHitbox(): axisAlignedBoundingBox {
let smallestX, biggestX, smallestY, biggestY; let smallestX, biggestX, smallestY, biggestY;
smallestX = smallestX =
smallestY = smallestY =

38
main.ts
View File

@ -1,6 +1,6 @@
/// <reference types="./global.d.ts" /> /// <reference types="./global.d.ts" />
import { axisAlignedCollision } from "./collision/aa.ts"; import { axisAlignedCollision, axisAlignedContains } from "./collision/aa.ts";
import { circularCollision } from "./collision/circular.ts"; import { circularCollision } from "./collision/circular.ts";
import { satCollision } from "./collision/sat.ts"; import { satCollision } from "./collision/sat.ts";
import { Polygon } from "./geometry/polygon.ts"; import { Polygon } from "./geometry/polygon.ts";
@ -32,15 +32,15 @@ document.body.append(img);
const p = new Vector(500, 500); const p = new Vector(500, 500);
const poly = new Polygon([ const poly = new Polygon([
{ x: -50, y: -25 }, { x: -25, y: -25 },
{ x: 25, y: -50 }, { x: 25, y: -25 },
{ x: 25, y: 25 }, { x: 25, y: 25 },
{ x: -25, y: 25 }, { x: -25, y: 25 },
]); ]);
// poly.center = p.copy(); // poly.center = p.copy();
const poly2 = Polygon.createPolygon(5, 75); const poly2 = Polygon.createPolygon(5, 75);
poly2.center = p.copy(); poly2.center = p.copy().add(100, 100);
poly.center.add(p); poly.center.add(p);
@ -50,12 +50,12 @@ doodler.createLayer((c) => {
doodler.drawSquare(new Vector(i, j), 50, { color: "#00000010" }); doodler.drawSquare(new Vector(i, j), 50, { color: "#00000010" });
} }
} }
const color = axisAlignedCollision( const color = satCollision(
poly.aaHitbox(), poly,
poly2.aaHitbox(), poly2,
) )
? "red" ? "red"
: "black"; : "aqua";
// console.log(satCollision( // console.log(satCollision(
// )); // ));
@ -70,21 +70,37 @@ doodler.createLayer((c) => {
if (gamepad) { if (gamepad) {
const leftX = gamepad.axes[0]; const leftX = gamepad.axes[0];
const leftY = gamepad.axes[1]; const leftY = gamepad.axes[1];
const rightX = gamepad.axes[2];
const rightY = gamepad.axes[3];
if (axisAlignedContains(poly2.aaHitbox, poly.aaHitbox)) {
poly.center.add(
new Vector(
Math.min(Math.max(rightX - deadzone, 0), rightX + deadzone),
Math.min(Math.max(rightY - deadzone, 0), rightY + deadzone),
).mult(10),
);
poly2.center.add(
new Vector(
Math.min(Math.max(leftX - deadzone, 0), leftX + deadzone),
Math.min(Math.max(leftY - deadzone, 0), leftY + deadzone),
).mult(10),
);
}
poly.center.add( poly.center.add(
new Vector( new Vector(
Math.min(Math.max(leftX - deadzone, 0), leftX + deadzone), Math.min(Math.max(leftX - deadzone, 0), leftX + deadzone),
Math.min(Math.max(leftY - deadzone, 0), leftY + deadzone), Math.min(Math.max(leftY - deadzone, 0), leftY + deadzone),
).mult(10), ).mult(10),
); );
const rightX = gamepad.axes[2];
const rightY = gamepad.axes[3];
poly2.center.add( poly2.center.add(
new Vector( new Vector(
Math.min(Math.max(rightX - deadzone, 0), rightX + deadzone), Math.min(Math.max(rightX - deadzone, 0), rightX + deadzone),
Math.min(Math.max(rightY - deadzone, 0), rightY + deadzone), Math.min(Math.max(rightY - deadzone, 0), rightY + deadzone),
).mult(10), ).mult(10),
); );
// (doodler as ZoomableDoodler).moveOrigin({ x: -rigthX * 5, y: -rigthY * 5 }); // (doodler as ZoomableDoodler).moveOrigin({ x: -rigthX * 5, y: -rigthY * 5 });
// if (gamepad.buttons[7].value) { // if (gamepad.buttons[7].value) {