Skip to content

Commit

Permalink
Resolved merge conflicts for package.json and yarn.lock
Browse files Browse the repository at this point in the history
  • Loading branch information
joeng03 committed Apr 14, 2023
2 parents 9c5e04a + ef08557 commit e682332
Show file tree
Hide file tree
Showing 10 changed files with 1,322 additions and 0 deletions.
5 changes: 5 additions & 0 deletions modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,10 @@
},
"remote_execution": {
"tabs": []
},
"physics_2d": {
"tabs": [
"physics_2d"
]
}
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
"@blueprintjs/core": "^4.6.1",
"@blueprintjs/icons": "^4.4.0",
"@blueprintjs/popover2": "^1.4.3",
"@box2d/core": "^0.10.0",
"@box2d/debug-draw": "^0.10.0",
"@jscad/modeling": "^2.9.5",
"@jscad/regl-renderer": "^2.6.1",
"@jscad/stl-serializer": "^2.1.13",
Expand Down
192 changes: 192 additions & 0 deletions src/bundles/physics_2d/PhysicsObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/* eslint-disable new-cap */
// We have to disable linting rules since Box2D functions do not
// follow the same guidelines as the rest of the codebase.

import {
type b2Body,
type b2Shape,
type b2Fixture,
b2BodyType,
b2CircleShape,
b2PolygonShape,
b2Vec2,
} from '@box2d/core';
import { type ReplResult } from '../../typings/type_helpers';

import { ACCURACY, type Force, type ForceWithPos } from './types';
import { type PhysicsWorld } from './PhysicsWorld';

export class PhysicsObject implements ReplResult {
private body: b2Body;
private shape: b2Shape;
private fixture: b2Fixture;
private forcesCentered: Force[] = [];
private forcesAtAPoint: ForceWithPos[] = [];

constructor(
position: b2Vec2,
rotation: number,
shape: b2Shape,
isStatic: boolean,
world: PhysicsWorld,
) {
this.body = world.createBody({
type: isStatic ? b2BodyType.b2_staticBody : b2BodyType.b2_dynamicBody,
position,
angle: rotation,
});
this.shape = shape;

this.fixture = this.body.CreateFixture({
shape: this.shape,
density: 1,
friction: 1,
});
}

public getFixture() {
return this.fixture;
}

public getMass() {
return this.body.GetMass();
}

public setDensity(density: number) {
this.fixture.SetDensity(density);
this.body.ResetMassData();
}

public setFriction(friction: number) {
this.fixture.SetFriction(friction);
}

public getPosition() {
return this.body.GetPosition();
}

public setPosition(pos: b2Vec2) {
this.body.SetTransformVec(pos, this.getRotation());
}

public getRotation() {
return this.body.GetAngle();
}

public setRotation(rot: number) {
this.body.SetAngle(rot);
}

public getVelocity() {
return this.body.GetLinearVelocity();
}

public setVelocity(velc: b2Vec2) {
this.body.SetLinearVelocity(velc);
}

public getAngularVelocity() {
return this.body.GetAngularVelocity();
}

public setAngularVelocity(velc: number) {
this.body.SetAngularVelocity(velc);
}

public addForceCentered(force: Force) {
this.forcesCentered.push(force);
}

public addForceAtAPoint(force: Force, pos: b2Vec2) {
this.forcesAtAPoint.push({
force,
pos,
});
}

private applyForcesToCenter(world_time: number) {
this.forcesCentered = this.forcesCentered.filter(
(force: Force) => force.start_time + force.duration > world_time,
);

const resForce = this.forcesCentered
.filter((force: Force) => force.start_time < world_time)
.reduce(
(res: b2Vec2, force: Force) => res.Add(force.direction.Scale(force.magnitude)),
new b2Vec2(),
);

this.body.ApplyForceToCenter(resForce);
}

private applyForcesAtAPoint(world_time: number) {
this.forcesAtAPoint = this.forcesAtAPoint.filter(
(forceWithPos: ForceWithPos) => forceWithPos.force.start_time + forceWithPos.force.duration > world_time,
);

this.forcesAtAPoint.forEach((forceWithPos) => {
const force = forceWithPos.force;
this.body.ApplyForce(
force.direction.Scale(force.magnitude),
forceWithPos.pos,
);
});
}

public applyForces(world_time: number) {
this.applyForcesToCenter(world_time);
this.applyForcesAtAPoint(world_time);
}

public isTouching(obj2: PhysicsObject) {
let ce = this.body.GetContactList();
while (ce !== null) {
if (ce.other === obj2.body && ce.contact.IsTouching()) {
return true;
}
ce = ce.next;
}
return false;
}

public toReplString = () => `
Mass: ${this.getMass()
.toFixed(ACCURACY)}
Position: [${this.getPosition().x.toFixed(
ACCURACY,
)},${this.getPosition().y.toFixed(ACCURACY)}]
Velocity: [${this.getVelocity().x.toFixed(
ACCURACY,
)},${this.getVelocity().y.toFixed(ACCURACY)}]
Rotation: ${this.getRotation()
.toFixed(ACCURACY)}
AngularVelocity: [${this.getAngularVelocity()
.toFixed(ACCURACY)}]`;

public scale_size(scale: number) {
if (this.shape instanceof b2CircleShape) {
this.shape.m_radius *= scale;
} else if (this.shape instanceof b2PolygonShape) {
let centroid: b2Vec2 = this.shape.m_centroid;
let arr: b2Vec2[] = [];
this.shape.m_vertices.forEach((vec) => {
arr.push(
new b2Vec2(
centroid.x + scale * (vec.x - centroid.x),
centroid.y + scale * (vec.y - centroid.y),
),
);
});
this.shape = new b2PolygonShape()
.Set(arr);
}
let f: b2Fixture = this.fixture;
this.body.DestroyFixture(this.fixture);
this.fixture = this.body.CreateFixture({
shape: this.shape,
density: f.GetDensity(),
friction: f.GetFriction(),
});
}
}
136 changes: 136 additions & 0 deletions src/bundles/physics_2d/PhysicsWorld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/* eslint-disable new-cap */
// We have to disable linting rules since Box2D functions do not
// follow the same guidelines as the rest of the codebase.

import {
type b2Body,
type b2Fixture,
type b2BodyDef,
b2BodyType,
b2PolygonShape,
type b2StepConfig,
b2Vec2,
b2World,
b2ContactListener,
type b2Contact,
} from '@box2d/core';
import { type PhysicsObject } from './PhysicsObject';
import { Timer } from './types';

export class PhysicsWorld {
private b2World: b2World;
private physicsObjects: PhysicsObject[];
private timer: Timer;
private touchingObjects: Map<b2Fixture, Map<b2Fixture, number>>;

private iterationsConfig: b2StepConfig = {
velocityIterations: 8,
positionIterations: 3,
};

constructor() {
this.b2World = b2World.Create(new b2Vec2());
this.physicsObjects = [];
this.timer = new Timer();
this.touchingObjects = new Map<b2Fixture, Map<b2Fixture, number>>();

const contactListener: b2ContactListener = new b2ContactListener();
contactListener.BeginContact = (contact: b2Contact) => {
let m = this.touchingObjects.get(contact.GetFixtureA());
if (m === undefined) {
let newMap = new Map<b2Fixture, number>();
newMap.set(contact.GetFixtureB(), this.timer.getTime());
this.touchingObjects.set(contact.GetFixtureA(), newMap);
} else {
m.set(contact.GetFixtureB(), this.timer.getTime());
}
};
contactListener.EndContact = (contact: b2Contact) => {
const contacts = this.touchingObjects.get(contact.GetFixtureA());
if (contacts) {
contacts.delete(contact.GetFixtureB());
}
};

this.b2World.SetContactListener(contactListener);
}

public setGravity(gravity: b2Vec2) {
this.b2World.SetGravity(gravity);
}

public addObject(obj: PhysicsObject) {
this.physicsObjects.push(obj);
return obj;
}

public createBody(bodyDef: b2BodyDef) {
return this.b2World.CreateBody(bodyDef);
}

public makeGround(height: number, friction: number) {
const groundBody: b2Body = this.createBody({
type: b2BodyType.b2_staticBody,
position: new b2Vec2(0, height - 10),
});
const groundShape: b2PolygonShape = new b2PolygonShape()
.SetAsBox(
10000,
10,
);

groundBody.CreateFixture({
shape: groundShape,
density: 1,
friction,
});
}

public update(dt: number) {
for (let obj of this.physicsObjects) {
obj.applyForces(this.timer.getTime());
}
this.b2World.Step(dt, this.iterationsConfig);
this.timer.step(dt);
}

public simulate(total_time: number) {
const dt = 0.01;
for (let i = 0; i < total_time; i += dt) {
this.update(dt);
}
}

public getB2World() {
return this.b2World;
}

public getWorldStatus(): String {
let world_status: String = `
World time: ${this.timer.toString()}
Objects:
`;
this.physicsObjects.forEach((obj) => {
console.log(obj.getMass());
world_status += `
------------------------
${obj.toReplString()}
------------------------
`;
});
return world_status;
}

public findImpact(obj1: PhysicsObject, obj2: PhysicsObject) {
let m = this.touchingObjects.get(obj1.getFixture());
if (m === undefined) {
return -1;
}
let time = m.get(obj2.getFixture());
if (time === undefined) {
return -1;
}
return time;
}
}
Loading

0 comments on commit e682332

Please sign in to comment.