lusito / box2d.ts Goto Github PK
View Code? Open in Web Editor NEWThis project forked from flyover/box2d.ts
Full blown Box2D Ecosystem for the web, written in TypeScript
Home Page: https://lusito.github.io/box2d.ts
This project forked from flyover/box2d.ts
Full blown Box2D Ecosystem for the web, written in TypeScript
Home Page: https://lusito.github.io/box2d.ts
I can't find the source code for these examples: https://lusito.github.io/box2d.ts/testbed/#/Examples#Blob_Test
I only found examples from the parent project flyover/box2d.ts: https://github.com/flyover/box2d.ts/tree/master/testbed/tests
Currently, a lot of comments exist, which need to be cleaned up.
I was wondering, is this still actively being worked on? I might flip my game over that is using fly-over's version of Box2d. Any gotcha's with doing that?
Plz make little note in guide or jsdoc that Vec2 methods returns self (which usable for chaining) and not clone. I didn't notice it at first, which led to a bug in my code
Blocked by #13 in order to not make it harder than it already is to port upstream code and comments.
Currently, all comments are in a c++ style, which can't be harnessed by vscode and probably other editors.
All comments should be converted to be in jsdoc style. It's not part of this task to add missing jsdoc. Just convert the existing comments.
It might be necessary to adjust the updiff project a bit after this has been done. Not sure if the updiff project is going to be used much after #13 is done. So maybe it's not worth the effort. We'll have to see.
So there are a couple of things I'd like to address before a 1.0.0 release:
const b2Cos = Math.cos;
, use Math.cos
instead of b2Cos
.We should create separate issues for each of these in order to keep discussions clean. If an issue doesn't exist yet, create it and I will insert a link in this description.
@Lusito hi! How are you? I hope you are alive. There was no activity from you for six months.
I am making a simple Pong game. Sandbox: https://plnkr.co/edit/ievETHfAsuARZtzf?preview
I want to set a ball position to zero when it collides with holes:
I try to make it in the contact-listener.js
file:
let ballBody = null;
if (nameA === "leftPointTrigger" || nameB === "rightPointTrigger" ||
nameA === "rightPointTrigger" || nameB === "leftPointTrigger") {
if (nameA === "ball") {
ballBody = fixtureA.GetBody();
} else {
ballBody = fixtureB.GetBody();
}
ballBody.SetTransformXY(0, 0, 0);
}
But the error happens when the ball collides with holes at this line: ballBody.SetTransformXY(0, 0, 0);
in the contact-listener.js
file:
Flyover converted some of the bit-flags to boolean attributes. Not sure about this. Would be good to investigate:
Since it does make comparison between upstream source-code and this port a bit harder, I tend to revert that change unless it has some benefit.
This seems to be originating from the b2Timer
class and its usage of performance.now()
when @box2d/core
is executed from nodejs. A simple fix would be to synchronously require the performance module when running in node>=8.5
.
export const performance =
typeof globalThis.window !== "undefined"
? window.performance
: (require("perf_hooks") as typeof import("perf_hooks").performance;
However, this leads to Module "perf_hooks" not found
error when bundling with webpack, unless {externals: {perf_hooks: 'empty'}}
is set in the config.
I don't see a benefit of prefixing classes/methods/properties with b2
, other than making the API more idiomatic to the original C++ implementation. If a user wants to prefix, they can choose to use a default/namespace import instead of named imports.
This would result in a less verbose, cleaner looking API:
With prefixing:
const gravity = new b2Vec2(0, 0);
const world = b2World.Create(gravity);
// or default import
const gravity = new Box2D.b2Vec2(0, 0);
const world = Box2D.b2World.Create(gravity);
Without prefixing:
const gravity = new Vec2(0, 0);
const world = World.Create(gravity);
// or default import
const gravity = new Box2D.Vec2(0, 0);
const world = Box2D.World.Create(gravity);
Using camelCase for class methods and property names would make the code even more idiomatic to Typescript, but that can be its own discussion.
Box2D beginners with JavaScript skills think @box2d/core is a port of TypeScript when they read the description in jsDelivr. You must add the "JavaScript and TypeScript port of Box2D". Then you will have many more users of your Box2D port, because there are significantly more JavaScript programmers than TypeScript programmers.
Like it was made for Planck.js:
box2d-core 0.10.0
JavaScript
DrawSolidPolygon
gets wrong collider position: https://plnkr.co/edit/GU2srU06SAzySUg6
I try to set collider position in main.js
here:
const groundBody = world.CreateBody({ type: b2BodyType.b2_staticBody,
position: { x: groundPosition[0] / pixelsPerMeter,
y: groundPosition[1] / pixelsPerMeter}});
But I have wrong line positions in debug-drawer.js
:
DrawSolidPolygon(vertices, vertexCount, color) {
// console.log(vertices);
// console.log(color);
mat4.mul(this.projViewMatrix, this.projMatrix, this.viewMatrix);
gl.uniform3f(this.uColorLocation, color.r, color.g, color.b);
this.drawLine(vertices[0], vertices[1]);
this.drawLine(vertices[1], vertices[2]);
this.drawLine(vertices[2], vertices[3]);
this.drawLine(vertices[3], vertices[0]);
}
I ported this example to box2d-wasm v7.0.0 and it works fine: https://plnkr.co/edit/exqhktfXnvxwtBRq
This issue is similar to this one: Rotation problem with box2d-core and WebGL
box2d-core
has a method to draw vertices without translation and rotation: DrawSolidPolygon(vertices, vertexCount, color)
and separate method to set translations and rotations:
PushTransform(xf) {
this.translationX = xf.p.x;
this.translationY = xf.p.y;
this.angle = xf.q.s * 180 / Math.PI;
}
I created the lines object in the DebugDrawer
class:
constructor(stage, pixelsPerMeter) {
this.lines = new PIXI.Graphics();
stage.addChild(this.lines);
I draw lines but transforms applied on whole lines
object:
DrawSolidPolygon(vertices, vertexCount, color) {
const c = new PIXI.Color([color.r, color.g, color.b]).toHex();
this.lines.lineStyle(1, c, 1, 0.5, true);
this.lines.moveTo((vertices[0].x + this.translationX) * this.pixelsPerMeter,
(vertices[0].y + this.translationY) * this.pixelsPerMeter);
this.lines.lineTo((vertices[1].x + this.translationX) * this.pixelsPerMeter,
(vertices[1].y + this.translationY) * this.pixelsPerMeter);
this.lines.lineTo((vertices[2].x + this.translationX) * this.pixelsPerMeter,
(vertices[2].y + this.translationY) * this.pixelsPerMeter);
this.lines.lineTo((vertices[3].x + this.translationX) * this.pixelsPerMeter,
(vertices[3].y + this.translationY) * this.pixelsPerMeter);
this.lines.lineTo((vertices[0].x + this.translationX) * this.pixelsPerMeter,
(vertices[0].y + this.translationY) * this.pixelsPerMeter);
this.lines.angle = this.angle;
}
Solution:
This problem was solved in the Node.js 16. I have moved my example on the Glitch hosting: https://glitch.com/edit/#!/box2d-core-on-the-server-side-js
import { b2World } from "@box2d/core";
const world = b2World.Create({ x: 0, y: -9.8 });
const gravity = world.GetGravity();
console.log(`gravity = (${gravity.x}, ${gravity.y})`);
You can see an output result of the program if you press "LOGS" at the bottom:
I have add the required Node.js version to package.json
:
{
"name": "box2d-core-on-the-server-side-js",
"version": "1.0.0",
"description": "",
"type": "module",
"engines": {
"node": ">=16.0.0"
},
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server/app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@box2d/core": "^0.10.0"
}
Question:
I tried running box2d-core
on the server side using Node.js:
app.js
import { b2World } from "@box2d/core";
const world = b2World.Create({ x: 0, y: -9.8 });
console.log("ok");
Error:
`
E:_Projects\Physics\box2d-core\server-side-box2dcore-webgl-js>nodemon src/server/app.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter rs
[nodemon] watching path(s): .
[nodemon] watching extensions: js,mjs,json
[nodemon] starting node src/server/app.js
E:_Projects\node_modules@box2d\core\dist\common\b2_timer.js:27
this.m_start = performance.now();
^
ReferenceError: performance is not defined
at new b2Timer (E:_Projects\node_modules@box2d\core\dist\common\b2_timer.js:27:24)
at Object. (E:_Projects\node_modules@box2d\core\dist\collision\b2_time_of_impact.js:230:32)
at Module._compile (internal/modules/cjs/loader.js:1072:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
at Module.load (internal/modules/cjs/loader.js:937:32)
at Function.Module._load (internal/modules/cjs/loader.js:778:12)
at Module.require (internal/modules/cjs/loader.js:961:19)
at require (internal/modules/cjs/helpers.js:92:18)
at Object. (E:_Projects\node_modules@box2d\core\dist\index.js:46:14)
at Module._compile (internal/modules/cjs/loader.js:1072:14)
[nodemon] app crashed - waiting for file changes before starting...
`
Goal:
It would be nice to have tooling that supports build/release/publish workflows including good changelogs without requiring a steep learning curve, as that prevents people from contributing.
So there are multiple ways to go about this:
What would it take to integrate https://github.com/Birch-san/box2d-wasm/releases/tag/v4.0.0-liquidfun.0 i to the benchmarks?
JavaScript has a garbage collector.. we gotta live with it.
In the original code, temporary vectors and similar where created on the stack without problems.
If we use new objects everytime, we'll just push work for the garbage collector.
Flyover has 2 solutions for this:
The former is fine.
The latter, however, is a but ugly to work with and compare code. This also allows to access these static variables from other classes, which flyover does a lot with the b2Vec2 static attributes. This requires you to have a good eye on these to avoid accidental double use.
In order to make the code easier to compare to upstream, I used top-level constants instead in some places, but that approach isn't perfect either:
const temp = {
J1: new b2Vec2(),
J2: new b2Vec2(),
J3: new b2Vec2(),
r: new b2Vec2(),
e1: new b2Vec2(),
e2: new b2Vec2(),
Jd1: new b2Vec2(),
Jd2: new b2Vec2(),
d: new b2Vec2(),
u: new b2Vec2(),
dp1: new b2Vec2(),
dp2: new b2Vec2(),
dp3: new b2Vec2(),
d1: new b2Vec2(),
d2: new b2Vec2(),
dHat: new b2Vec2(),
};
When I'm talking about double use, I mean something like:
function doStuff(m: b2Vec2, n: b2Vec2, out: b2Vec2) {
const t = b2Vec2.s_t0.Set(0, 1);
// ...
out.x = m.x + n.x + t.x;
out.y = m.y + n.y + t.y;
return out;
}
function accidentalDoubleUse() {
const a = new b2Vec2(1, 2);
const b = new b2Vec2(2, 3);
const c = doStuff(a, b2Vec2.Add(a, b, b2Vec2.s_t0), b2Vec2.s_t1);
return c.y;
}
Both functions use b2Vec2.s_t0, causing loss of data.
The goal of this task would be to evaluate the best approach to encapsulate the temp variables, so they can't easily get used in two places at once.
Then when implementing these changes, ensure, that no public temporary variables get shared over multiple modules.
Title says it. Would like to try using https://allcontributors.org/
It would be nice to list this project in hacktoberfest WDYT ? (it requires adding the tag hacktoberfest
to the project)
See flyover#70
It would be nicer to have API Docs, since I'm confused on how this API works.
I think it would be a good idea to publish the packages to NPM before a v1.0.0 release. This would give some initial exposure to the beginnings of the Box2d ecosystem, and allow early adopters to test/report issues/give feedback on the API before things have solidified. Versioning everything under 0.x.x
and having a disclaimer in the readme should be enough forewarning.
From my fork, I published a few of the packages under the @plane2d
organization (due to not having access to @box2d
), purely to test the publish workflow. This involved manually running yarn publish
for each package, as the global find-replace of all @box2d
to @plane2d
broke yarn workspaces run build
for me.
Ideally, the entire publish workflow can be automated via GitHub actions and triggered on release.
@Lusito Do you own the @box2d
organization on NPM? What are your thoughts on releasing to NPM during the initial development phase?
The testbed is neat at all, but its only useful for proof of concepts. It also doesnt seem to be exposed anywhere. Which means anyone working on their own project will be unable to visualize their world unless they copypaste all their files into the testbed website.
What I'd prefer is a function to call that renders a world to canvas. (The original box2d.js has this, but that project is old and throws errors in modern environments. The dev also doesnt publish to npm despite having git updates)
I'd like something where I can run everything in a functional way in places that I control:
const initWorld = ()=>{ ... };
const tick = ()=>{
handleInputs();
world.step(time);
renderWorld({ world, canvas });
};
I'm looking through the code, but it seems impossible to figure out how to get this working. I know the functionality is there given that the testbed works. But I dont understand why its not easily available.
I dont particularly care how the api looks. bounds
, strokeColor
, and strokeSize
are good enough for me.
box2d.js has a class structure that probably works decently: https://github.com/kripken/box2d.js/#using-debug-draw
What is wrong with this JavaScript code: https://plnkr.co/edit/uCCFl4gDC4oOygxm
import { b2Draw } from "@box2d/core";
import { gl } from "./webgl-context.js";
// This class implements debug drawing callbacks that
// are invoked inside b2World::Step
export default class DebugDrawer extends b2Draw {
DrawSolidPolygon(vertices, vertexCount, color) {
// console.log(vertices);
// console.log(color);
}
PushTransform(xf) {}
PopTransform(xf) {}
DrawPolygon(vertices, vertexCount, color) {}
DrawCircle(center, radius, color) {}
DrawSolidCircle(center, radius, axis, color) {}
DrawSegment(p1, p2, color) {}
DrawTransform(xf) {}
DrawPoint(p, size, color) {}
}
In flyovers port, all *Def ports had one interface and one class defined.
In some cases, I was able to make this just an interface, making creation of objects even simpler by just passing an object rather than creating it and adjust its settings. b2FixtureDef is one of those.
There are however other places, where this has not been done yet. Partially, because in some of these cases, inheritance is part of the equation.
Evaluate what can be done to further improve this.
An added benefit might be that we could allow third-party joints if we only required an interface for the JointDef.
I installed a local server globally:
npm i -g http-server
I downloaded the repository, went to the documentation folder and started the local server:
http-server
Opened the browser and entered the address:
localhost:8080/index.html
There is a page with links: "Benchmarks", "Demos", "Documentation" and "GitHub". But when I try to click "Benchmarks", "Demos", "Documentation" I see these links:
and the message:
Hey, I didn't see a contact link, so I am adding a not-issue.
I am actively working on an IO game that I am building and I have two question I need answered.
Projects general premise is:
2D Spaceship combat simulation-lite with planets, gravity, ships etc etc.
Main physics needed: raycasts, impulse, newtonian physics, box collision.
I made a little video on how it renders on my computer here: https://files.nekland.fr/pro/test_bed_box2d.mov
I think it's "too fast" and looks like "something is wrong" which is bad promotion from my POV :) .
I can change this, would you accept the fix?
Please, implement b2Draw, SetDebugDraw, and DebugDraw like it was implemented in pybox2d
from Box2D import b2Draw
from OpenGL.GL import *
class DebugDrawer(b2Draw):
def __init__(self, program, worldScale):
super().__init__()
self.program = program
self.WORLD_SCALE = worldScale
def DrawSolidPolygon(self, vertexes, color):
print("Polygon. Begin")
print(vertexes[0][0] * 30, vertexes[0][1] * 30)
print(vertexes[1][0] * 30, vertexes[1][1] * 30)
print(vertexes[2][0] * 30, vertexes[2][1] * 30)
print(vertexes[3][0] * 30, vertexes[3][1] * 30)
print("Polygon. End")
self.debugDrawer = DebugDrawer(self.program, self.WORLD_SCALE)
self.world.renderer = self.debugDrawer
self.debugDrawer.flags = { 'drawShapes': True,
'drawJoints': True, 'drawAABBs': True, 'drawPairs': True }
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT)
glBindVertexArray(self.vao)
self.projViewMatrix = self.projMatrix * self.viewMatrix
if self.showColliders:
self.world.DrawDebugData()
I will try to fix this issue later. At the moment I have no ideas. Can someone fix: https://plnkr.co/edit/zTthXbGVITITERkL (another sandbox: https://playcode.io/1211513)
I've written a simple tool named updiff, which is located in the packages/updiff folder to help with comparing the current state of this project against upstream code of Erin Catto.
I've already ported a lot of the changes in recent upstream version, but during this effort, I improved the tool a lot and it seems I have missed some places.
This is quite stupid work, but it needs to be done: Compare code and port everything that has not been ported yet.
Here's the list of all modules to check:
I will update the checkboxes when they've been "upstreamed".
In flyovers port, almost all members have been made public. Probably due to TypeScript not having a "friend" concept as C++ does.
This should be avoided. Possible alternatives:
class A {
private x = 0;
}
const a = new A();
a["x"] = 10; // no error
This style should only be used as a last resort internally to imitate the "friend" concept of C++.
I usually only use this in tests, where I want to access/modify data, which is otherwise not allowed to be touched.
Update: After trying this a bit, it causes other issues. Like false detection of unused properties (property is only being written, not being read)
Update 2:
As said in the comments, I've written idtsc to get this working. The core project has been extended with this technique. The other projects might need adjustments as well.
Projects to adjust:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.