Update framework

This commit is contained in:
2022-11-26 02:22:02 +01:00
parent 9a6ce1f832
commit ae057940af
508 changed files with 26011 additions and 14248 deletions

2
framework/physics/aabb.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
import { PhysicsObject } from './object';
export declare function AABB(obj1: PhysicsObject, obj2: PhysicsObject): boolean;

17
framework/physics/aabb.js Normal file
View File

@@ -0,0 +1,17 @@
export function AABB(obj1, obj2) {
if (checkOverlap(obj1.position.x, obj1.dimensions.x, obj2.position.x, obj2.dimensions.x)) {
return true;
}
else if (checkOverlap(obj1.position.y, obj1.dimensions.y, obj2.position.y, obj2.dimensions.y)) {
return true;
}
else if (checkOverlap(obj1.position.z, obj1.dimensions.z, obj2.position.z, obj2.dimensions.z)) {
return true;
}
return false;
}
function checkOverlap(x, w, yx, yw) {
if (x > yx || x < yx + yw || x + w > x || x + w < yx + yw) {
return true;
}
}

0
framework/physics/index.d.ts vendored Normal file
View File

View File

7
framework/physics/object.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
import { Vec3 } from './vec3';
export declare class PhysicsObject {
position: Vec3;
dimensions: Vec3;
velocity: Vec3;
affectedByGravity: boolean;
}

View File

@@ -0,0 +1,2 @@
export class PhysicsObject {
}

39
framework/physics/octree.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
import { PhysicsObject } from './object';
import { Vec3 } from './vec3';
export declare class Octree {
private dimensions;
private maxObjects;
private maxLevels;
root: OcTreeNode;
constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number);
insert(obj: PhysicsObject): void;
find(position: Vec3, dimensions: Vec3): PhysicsObject[];
}
export declare class OcTreeNode {
private position;
private dimensions;
private maxLevels;
private maxObjects;
private currentLevel;
objects: PhysicsObject[];
nodes: OcTreeNode[];
constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number, currentLevel?: number);
insert(obj: PhysicsObject): any;
find(x: number, y: number, z: number, xw: number, yh: number, zd: number): PhysicsObject[];
split(): void;
private distributeObjectsToNodes;
getIndex(x: number, y: number, z: number): Direction;
getIndeciesForRect(x: number, y: number, z: number, xw: number, yh: number, zd: number): Direction[];
}
declare enum Direction {
AboveUpperLeft = 0,
AboveUpperRight = 1,
AboveLowerRight = 2,
AboveLowerLeft = 3,
BelowUpperLeft = 4,
BelowUpperRight = 5,
BelowLowerRight = 6,
BelowLowerLeft = 7,
Here = 8
}
export {};

206
framework/physics/octree.js Normal file
View File

@@ -0,0 +1,206 @@
import { Vec3 } from './vec3';
export class Octree {
constructor(dimensions, maxObjects = 10, maxLevels = 10) {
this.dimensions = dimensions;
this.maxObjects = maxObjects;
this.maxLevels = maxLevels;
this.root = new OcTreeNode(new Vec3({
x: 0,
y: 0,
z: 0
}), this.dimensions, maxLevels, maxObjects, 0);
}
insert(obj) {
this.root.insert(obj);
}
find(position, dimensions) {
return this.root.find(position.x, position.y, position.z, dimensions.x, dimensions.y, dimensions.z);
}
}
export class OcTreeNode {
constructor(position, dimensions, maxLevels, maxObjects, currentLevel = 0) {
this.position = position;
this.dimensions = dimensions;
this.maxLevels = maxLevels;
this.maxObjects = maxObjects;
this.currentLevel = currentLevel;
this.objects = [];
this.nodes = [];
}
insert(obj) {
const index = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
if (index === Direction.Here) {
this.objects.push(obj);
}
else {
return this.nodes[index].insert(obj);
}
if (this.objects.length > this.maxObjects &&
this.currentLevel < this.maxLevels) {
this.split();
}
}
find(x, y, z, xw, yh, zd) {
if (this.nodes.length < 1) {
return this.objects;
}
const indecies = this.getIndeciesForRect(x, y, z, xw, yh, zd);
let results = [];
for (let i = 0; i < indecies.length - 1; i++) {
let res = this.nodes[indecies[i]].find(x, y, z, xw, yh, zd);
results.push([...res]);
}
return results;
}
split() {
const halfWidth = this.dimensions.x / 2;
const halfHeight = this.dimensions.y / 2;
const halfDepth = this.dimensions.z / 2;
this.nodes[Direction.AboveUpperLeft] = new OcTreeNode(new Vec3({
x: this.position.x,
y: this.position.y,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.AboveUpperRight] = new OcTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.AboveLowerRight] = new OcTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y + halfHeight,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.AboveLowerLeft] = new OcTreeNode(new Vec3({
x: this.position.x,
y: this.position.y + halfHeight,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.BelowUpperLeft] = new OcTreeNode(new Vec3({
x: this.position.x,
y: this.position.y,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.BelowUpperRight] = new OcTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.BelowLowerRight] = new OcTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y + halfHeight,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.nodes[Direction.BelowLowerLeft] = new OcTreeNode(new Vec3({
x: this.position.x,
y: this.position.y + halfHeight,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects, this.currentLevel++);
this.distributeObjectsToNodes();
}
distributeObjectsToNodes() {
if (this.nodes.length < 8) {
this.split();
return;
}
this.objects.forEach((obj) => {
const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
this.nodes[direction].insert(obj);
});
this.objects = [];
}
getIndex(x, y, z) {
if (this.nodes.length === 0) {
return Direction.Here;
}
const halfWidth = this.dimensions.x / 2;
const halfHeight = this.dimensions.y / 2;
const halfDepth = this.dimensions.z / 2;
const isBelow = z < this.position.z + halfDepth;
const isLeft = x < this.position.x + halfWidth;
const isUpper = y > this.position.y + halfHeight;
if (isBelow) {
if (isLeft) {
if (isUpper)
return Direction.AboveUpperLeft;
else
return Direction.AboveLowerLeft;
}
else {
if (isUpper)
return Direction.AboveUpperRight;
else
return Direction.AboveLowerRight;
}
}
else {
if (isLeft) {
if (isUpper)
return Direction.BelowUpperLeft;
else
return Direction.BelowLowerLeft;
}
else {
if (isUpper)
return Direction.BelowUpperRight;
else
return Direction.BelowLowerRight;
}
}
}
getIndeciesForRect(x, y, z, xw, yh, zd) {
if (!(x > this.position.x && x < this.position.x + this.dimensions.x) ||
!(y > this.position.y && y < this.position.y + this.dimensions.y) ||
!(z > this.position.z && z < this.position.z + this.dimensions.z)) {
return [];
}
let indecies = [];
indecies.push(this.getIndex(x, y, z));
indecies.push(this.getIndex(x + xw, y + yh, z + zd));
return indecies;
}
}
var Direction;
(function (Direction) {
Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft";
Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight";
Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight";
Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft";
Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft";
Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight";
Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight";
Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft";
Direction[Direction["Here"] = 8] = "Here";
})(Direction || (Direction = {}));

38
framework/physics/octtree.d.ts vendored Normal file
View File

@@ -0,0 +1,38 @@
import { PhysicsObject } from "./object";
import { Vec3 } from "./vec3";
export declare class Octtree {
private dimensions;
private maxObjects;
private maxLevels;
root: OctTreeNode;
constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number);
insert(obj: PhysicsObject): void;
find(position: Vec3, dimensions: Vec3): PhysicsObject[];
}
export declare class OctTreeNode {
private position;
private dimensions;
private maxLevels;
private maxObjects;
objects: PhysicsObject[];
nodes: OctTreeNode[];
constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number);
insert(obj: PhysicsObject): void;
find(position: Vec3, dimensions: Vec3): PhysicsObject[];
split(): void;
private distributeObjectsToNodes;
getIndex(x: number, y: number, z: number): Direction;
getIndeciesForRect(position: Vec3, dimensions: Vec3): Set<Direction>;
}
declare enum Direction {
AboveUpperLeft = 0,
AboveUpperRight = 1,
AboveLowerRight = 2,
AboveLowerLeft = 3,
BelowUpperLeft = 4,
BelowUpperRight = 5,
BelowLowerRight = 6,
BelowLowerLeft = 7,
Here = 8
}
export {};

View File

@@ -0,0 +1,193 @@
import { Vec3 } from "./vec3";
export class Octtree {
constructor(dimensions, maxObjects = 10, maxLevels = 10) {
this.dimensions = dimensions;
this.maxObjects = maxObjects;
this.maxLevels = maxLevels;
this.root = new OctTreeNode(new Vec3({
x: 0,
y: 0,
z: 0
}), this.dimensions, maxLevels, maxObjects);
}
insert(obj) {
this.root.insert(obj);
}
find(position, dimensions) {
return this.root.find(position, dimensions);
}
}
export class OctTreeNode {
constructor(position, dimensions, maxLevels, maxObjects) {
this.position = position;
this.dimensions = dimensions;
this.maxLevels = maxLevels;
this.maxObjects = maxObjects;
this.objects = [];
this.nodes = [];
}
insert(obj) {
this.objects.push(obj);
if (this.objects.length > this.maxObjects) {
this.split();
}
}
find(position, dimensions) {
if (!this.nodes.length) {
return this.objects;
}
const indecies = this.getIndeciesForRect(position, dimensions);
let results = [];
indecies.forEach((index) => {
let res = this.nodes[index].find(position, dimensions);
res.forEach((obj) => results.push(obj));
});
return results;
}
split() {
const halfWidth = this.dimensions.x / 2;
const halfHeight = this.dimensions.y / 2;
const halfDepth = this.dimensions.z / 2;
this.nodes[Direction.AboveUpperLeft] = new OctTreeNode(new Vec3({
x: this.position.x,
y: this.position.y,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.AboveUpperRight] = new OctTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.AboveLowerRight] = new OctTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y + halfHeight,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.AboveLowerLeft] = new OctTreeNode(new Vec3({
x: this.position.x,
y: this.position.y + halfHeight,
z: this.position.z + halfDepth
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.BelowUpperLeft] = new OctTreeNode(new Vec3({
x: this.position.x,
y: this.position.y,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.BelowUpperRight] = new OctTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.BelowLowerRight] = new OctTreeNode(new Vec3({
x: this.position.x + halfWidth,
y: this.position.y + halfHeight,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.nodes[Direction.BelowLowerLeft] = new OctTreeNode(new Vec3({
x: this.position.x,
y: this.position.y + halfHeight,
z: this.position.z
}), new Vec3({
x: halfWidth,
y: halfHeight,
z: halfDepth
}), this.maxLevels, this.maxObjects);
this.distributeObjectsToNodes();
}
distributeObjectsToNodes() {
if (this.nodes.length < 8) {
this.split();
return;
}
this.objects.forEach((obj) => {
const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
this.nodes[direction].insert(obj);
});
this.objects = [];
}
getIndex(x, y, z) {
if (this.nodes.length === 0) {
return Direction.Here;
}
const halfWidth = this.dimensions.x / 2;
const halfHeight = this.dimensions.y / 2;
const halfDepth = this.dimensions.z / 2;
const isBelow = (z < this.position.z + halfDepth);
const isLeft = (x < this.position.x + halfWidth);
const isUpper = (y > this.position.y + halfHeight);
if (isBelow) {
if (isLeft) {
if (isUpper)
return Direction.AboveUpperLeft;
else
return Direction.AboveLowerLeft;
}
else {
if (isUpper)
return Direction.AboveUpperRight;
else
return Direction.AboveLowerRight;
}
}
else {
if (isLeft) {
if (isUpper)
return Direction.BelowUpperLeft;
else
return Direction.BelowLowerLeft;
}
else {
if (isUpper)
return Direction.BelowUpperRight;
else
return Direction.BelowLowerRight;
}
}
}
getIndeciesForRect(position, dimensions) {
let indecies = new Set();
indecies.add(this.getIndex(position.x, position.y, position.z));
indecies.add(this.getIndex(position.x + dimensions.x, position.y + dimensions.y, position.z + dimensions.z));
return indecies;
}
}
var Direction;
(function (Direction) {
Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft";
Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight";
Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight";
Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft";
Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft";
Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight";
Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight";
Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft";
Direction[Direction["Here"] = 8] = "Here";
})(Direction || (Direction = {}));

0
framework/physics/quadtree.d.ts vendored Normal file
View File

View File

13
framework/physics/vec3.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
export declare class Vec3 {
x: number;
y: number;
z: number;
constructor(values?: {
x: number;
y: number;
z: number;
});
add(vector: Vec3): void;
multiply(vector: Vec3): void;
clone(): Vec3;
}

28
framework/physics/vec3.js Normal file
View File

@@ -0,0 +1,28 @@
export class Vec3 {
constructor(values = {
x: 0,
y: 0,
z: 0
}) {
this.x = values.x;
this.y = values.y;
this.z = values.z;
}
add(vector) {
this.x += vector.x;
this.y += vector.y;
this.z += vector.z;
}
multiply(vector) {
this.x *= vector.x;
this.y *= vector.y;
this.z *= vector.z;
}
clone() {
return new Vec3({
x: this.x,
y: this.y,
z: this.z
});
}
}

23
framework/physics/world.d.ts vendored Normal file
View File

@@ -0,0 +1,23 @@
import { Octree } from './octree';
import { EventBus } from '../event-bus';
import { PhysicsObject } from './object';
import { Vec3 } from './vec3';
export declare class World extends EventBus {
objects: PhysicsObject[];
gravity: Vec3;
dimensions: Vec3;
octreeOptions: OctreeOptions;
constructor(dimensions: Vec3, octreeOptions: OctreeOptions);
setGravity(grav: Vec3): void;
addObject(obj: PhysicsObject): void;
removeObject(obj: PhysicsObject): void;
step(dt: number): void;
checkCollisions(obj: PhysicsObject, octree: Octree): void;
}
interface OctreeOptions {
position: Vec3;
dimensions: Vec3;
maxObjects: number;
maxLevels: number;
}
export {};

View File

@@ -0,0 +1,54 @@
import { Octree } from './octree';
import { EventBus } from '../event-bus';
import { Vec3 } from './vec3';
import { AABB } from './aabb';
export class World extends EventBus {
constructor(dimensions, octreeOptions) {
super();
if (!octreeOptions) {
this.octreeOptions = {
position: new Vec3({ x: 0, y: 0, z: 0 }),
dimensions: new Vec3(this.dimensions),
maxLevels: 50,
maxObjects: 50
};
}
else {
this.octreeOptions = octreeOptions;
}
this.dimensions = dimensions;
this.objects = [];
}
setGravity(grav) {
this.gravity = grav;
}
addObject(obj) {
this.objects.push(obj);
}
removeObject(obj) {
this.objects = this.objects.filter((val) => val !== obj);
}
step(dt) {
const octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels);
this.objects.forEach((obj) => octree.insert(obj));
this.objects.forEach((obj) => {
let velocity = obj.velocity.clone();
velocity.multiply(new Vec3({ x: dt, y: dt, z: dt }));
let gravity = this.gravity.clone();
gravity.multiply(new Vec3({ x: dt, y: dt, z: dt }));
obj.position.add(velocity);
if (obj.affectedByGravity) {
obj.velocity.add(gravity);
}
this.checkCollisions(obj, octree);
});
}
checkCollisions(obj, octree) {
const potentialCandidates = octree.find(obj.position, obj.dimensions);
potentialCandidates.forEach((candidate) => {
if (AABB(obj, candidate)) {
this.emit('collision', [obj, candidate]);
}
});
}
}