-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolved merge conflicts for package.json and yarn.lock
- Loading branch information
Showing
10 changed files
with
1,322 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,5 +85,10 @@ | |
}, | ||
"remote_execution": { | ||
"tabs": [] | ||
}, | ||
"physics_2d": { | ||
"tabs": [ | ||
"physics_2d" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(), | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
Oops, something went wrong.