import { Broadphase,NaiveBroadphase } from "./broadphases/index.js"
import { NarrowPhase,SATNarrowphase } from "./narrowphase/index.js"
import { Vector2 } from "../math/index.js"
import { Body2D } from "./bodies/index.js"
import { Settings } from './settings.js';
import { CollisionManifold } from './narrowphase/index.js';
import { Intergrator2DPlugin } from "../intergrator/index.js"
import { Manager } from "../ecs/index.js";
export class Physics2DPlugin {
/**
* @param {Physics2DPluginOptions} options
*/
constructor(options = {}) {
this.gravity = options.gravity || new Vector2()
this.enableGravity = options.enableGravity || true
this.broadphase = new Broadphase2DPlugin(options.broadphase)
this.narrowphase = new Narrowphase2DPlugin(options.narrowphase)
this.intergrator = new Intergrator2DPlugin(options.intergratorOpt)
}
/**
* @param {Manager} manager
*/
register(manager) {
if (this.enableGravity) {
manager.setResource("gravity",this.gravity)
manager.registerSystem(applyGravity)
}
manager.registerPlugin(this.intergrator)
manager.registerSystem(updateBodies)
manager.registerPlugin(this.broadphase)
manager.registerPlugin(this.narrowphase)
manager.registerSystem(collisionResponse)
}
}
export class Broadphase2DPlugin {
/**
*
* @param {Broadphase} broadphase
*/
constructor(broadphase = new NaiveBroadphase()) {
this.broadphase = broadphase
}
/**
* @param {Manager} manager
*/
register(manager) {
manager.setResource("collisionPairs",[])
manager.setResource("broadphase",this.broadphase)
manager.registerSystem(naivebroadphaseUpdate)
}
}
export class Narrowphase2DPlugin {
/**
*
* @param {NarrowPhase} narrowphase
*/
constructor(narrowphase = new SATNarrowphase()) {
this.narrowphase = narrowphase
}
/**
* @param {Manager} manager
*/
register(manager) {
manager.setResource("contacts",[])
manager.setResource("narrowphase",this.narrowphase)
if (this.narrowphase instanceof SATNarrowphase) {
manager.registerSystem(satNarrowphaseUpdate)
}
}
}
/**
* @param {Manager} manager
*/
export function naivebroadphaseUpdate(manager) {
const [entities,bounds] = manager.query("entity","bound").raw()
const broadphase = manager.getResource("broadphase")
broadphase.update(entities,bounds)
const pairs = manager.getResource("collisionPairs")
pairs.length = 0
broadphase.getCollisionPairs(pairs)
}
/**
* @param {Manager} manager
*/
export function satNarrowphaseUpdate(manager) {
const narrowphase = manager.getResource("narrowphase")
const pairs = manager.getResource("collisionPairs")
const contacts = manager.getResource("contacts")
contacts.length = 0
narrowphase.getCollisionPairs(manager,pairs,contacts)
}
/**
* @param {Manager} manager
*/
export function applyGravity(manager) {
const gravity = manager.getResource("gravity")
const [bodies,movables] = manager.query("body","movable").raw()
for (let i = 0; i < bodies.length; i++) {
for (let j = 0; j < bodies[i].length; j++) {
if (bodies[i][j].inv_mass) {
Vector2.add(
movables[i][j].acceleration,
gravity,
movables[i][j].acceleration
)
}
}
}
}
/**
* @param {Manager} manager
*/
export function updateBodies(manager) {
const [transform,bounds,bodies] = manager.query("transform","bound","body").raw()
for (let i = 0; i < bodies.length; i++) {
for (let j = 0; j < bodies[i].length; j++) {
Body2D.update(
bodies[i][j],
transform[i][j].position,
transform[i][j].orientation,
transform[i][j].scale,
bounds[i][j]
)
}
}
}
/**
* @param {Manager} manager
*/
export function collisionResponse(manager) {
const inv_dt = 1 / manager.getResource("delta")
const contacts = manager.getResource("contacts")
for (let i = 0; i < contacts.length; i++) {
const manifold = contacts[i]
const [transformA,movableA,bodyA] = manager.get(manifold.entityA,"transform","movable","body")
const [transformB,movableB,bodyB] = manager.get(manifold.entityB,"transform","movable","body")
if (Settings.warmStarting)
CollisionManifold.warmstart(
manifold,
movableA,
movableB,
bodyA,
bodyB
)
CollisionManifold.prepare(
manifold,
bodyA,
bodyB,
movableA,
movableB,
transformA.position,
transformB.position,
inv_dt
)
}
for (let i = 0; i < Settings.velocitySolverIterations; i++) {
for (let j = 0; j < contacts.length; j++) {
const manifold = contacts[j]
const [movableA,bodyA] = manager.get(manifold.entityA,"movable","body")
const [movableB,bodyB] = manager.get(manifold.entityB,"movable","body")
CollisionManifold.solve(
manifold,
movableA,
movableB,
bodyA,
bodyB
)
}
} /***/
}
/**
* @typedef Physics2DPluginOptions
* @property {boolean} [enableGravity=true]
* @property {Vector2} [gravity]
* @property {Broadphase} [broadphase]
* @property {NarrowPhase} [narrowphase]
* @property {import("../intergrator/index.js").IntergratorPluginOptions} [intergratorOpt]
*/