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
// This code was bundled using `deno bundle` and it's not recommended to edit it manually
const axisAlignedCollision = (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;
const axisAlignedContains = (aa1, aa2)=>{
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 = {
TWO_PI: Math.PI * 2
@ -293,6 +293,89 @@ class OriginVector extends Vector {
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 map = (value, x1, y1, x2, y2)=>(value - x1) * (y2 - x2) / (y1 - x1) + x2;
class Doodler {
@ -879,10 +962,6 @@ class Polygon {
doodler.line(p1.copy().add(this.center), p2.copy().add(this.center), {
color
});
const { x, y, w, h } = this.aaHitbox();
doodler.drawRect(new Vector(x, y), w, h, {
color: "lime"
});
}
}
calcCenter() {
@ -894,7 +973,7 @@ class Polygon {
center.div(this.points.length);
return center;
}
circularHitbox() {
get circularHitbox() {
let greatestDistance = 0;
for (const p of this.points){
greatestDistance = Math.max(p.copy().add(this.center).dist(this.center), greatestDistance);
@ -904,7 +983,7 @@ class Polygon {
radius: greatestDistance
};
}
aaHitbox() {
get aaHitbox() {
let smallestX, biggestX, smallestY, biggestY;
smallestX = smallestY = Infinity;
biggestX = biggestY = -Infinity;
@ -953,12 +1032,12 @@ document.body.append(img);
const p = new Vector(500, 500);
const poly = new Polygon([
{
x: -50,
x: -25,
y: -25
},
{
x: 25,
y: -50
y: -25
},
{
x: 25,
@ -970,7 +1049,7 @@ const poly = new Polygon([
}
]);
const poly2 = Polygon.createPolygon(5, 75);
poly2.center = p.copy();
poly2.center = p.copy().add(100, 100);
poly.center.add(p);
doodler.createLayer((c)=>{
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);
poly2.draw(color);
const [gamepad] = navigator.getGamepads();
if (gamepad) {
const leftX = gamepad.axes[0];
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 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));
}
});

View File

@ -14,3 +14,13 @@ export const axisAlignedCollision = (
aa1.y < aa2.y + aa2.h &&
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), {
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;
}
circularHitbox(): CircleLike {
get circularHitbox(): CircleLike {
let greatestDistance = 0;
for (const p of this.points) {
greatestDistance = Math.max(
@ -50,7 +48,7 @@ export class Polygon {
};
}
aaHitbox(): axisAlignedBoundingBox {
get aaHitbox(): axisAlignedBoundingBox {
let smallestX, biggestX, smallestY, biggestY;
smallestX =
smallestY =

38
main.ts
View File

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