diff --git a/example/8-Ball.js b/example/8-Ball.js deleted file mode 100644 index 6b47f10e..00000000 --- a/example/8-Ball.js +++ /dev/null @@ -1,157 +0,0 @@ -const { Vec2, World, Circle, Settings, Polygon, Testbed } = planck; - -let SPI4 = Math.sin(Math.PI / 4), SPI3 = Math.sin(Math.PI / 3); - -let COLORED = true; -let BLACK = {fill: 'black', stroke: 'white'}; -let WHITE = {fill: 'white', stroke: 'black'}; -let COLORS = [ - {fill: '#ffdd00', stroke: '#000000'}, - {fill: '#ffdd00', stroke: '#ffffff'}, - {fill: '#ff3300', stroke: '#000000'}, - {fill: '#ff3300', stroke: '#ffffff'}, - {fill: '#662200', stroke: '#000000'}, - {fill: '#662200', stroke: '#ffffff'}, - {fill: '#ff8800', stroke: '#000000'}, - {fill: '#ff8800', stroke: '#ffffff'}, - {fill: '#00bb11', stroke: '#000000'}, - {fill: '#00bb11', stroke: '#ffffff'}, - {fill: '#9900ff', stroke: '#000000'}, - {fill: '#9900ff', stroke: '#ffffff'}, - {fill: '#0077ff', stroke: '#000000'}, - {fill: '#0077ff', stroke: '#ffffff'} -]; - -let width = 8.00, height = 4.00; - -let BALL_R = 0.12; -let POCKET_R = 0.2; - -Settings.velocityThreshold = 0; - -let world = new World(); - -const testbed = Testbed.mount(); -testbed.x = 0; -testbed.y = 0; -testbed.width = width * 1.2; -testbed.height = height * 1.2; -testbed.mouseForce = -20; -testbed.start(world); - -let railH = [ - new Vec2(POCKET_R, height * .5), - new Vec2(POCKET_R, height * .5 + POCKET_R), - new Vec2(width * .5 - POCKET_R / SPI4 + POCKET_R, height * .5 + POCKET_R), - new Vec2(width * .5 - POCKET_R / SPI4, height * .5) -]; - -let railV = [ - new Vec2(width * .5, -(height * .5 - POCKET_R / SPI4)), - new Vec2(width * .5 + POCKET_R, -(height * .5 - POCKET_R / SPI4 + POCKET_R)), - new Vec2(width * .5 + POCKET_R, height * .5 - POCKET_R / SPI4 + POCKET_R), - new Vec2(width * .5, height * .5 - POCKET_R / SPI4) -]; - -let railFixDef = { - friction: 0.1, - restitution: 0.9, - userData: 'rail' -}; -let pocketFixDef = { - userData: 'pocket' -}; -let ballFixDef = { - friction: 0.1, - restitution: 0.99, - density: 1, - userData: 'ball' -}; -let ballBodyDef = { - linearDamping: 1.5, - angularDamping: 1 -}; - -function mirror(vertices, x, y) { - return vertices.map(v => new Vec2(x * v.x, y * v.y)); -} - -world.createBody().createFixture(new Polygon(railV), railFixDef); -world.createBody().createFixture(new Polygon(mirror(railV, -1, +1)), railFixDef); - -world.createBody().createFixture(new Polygon(railH), railFixDef); -world.createBody().createFixture(new Polygon(mirror(railH, -1, +1)), railFixDef); -world.createBody().createFixture(new Polygon(mirror(railH, +1, -1)), railFixDef); -world.createBody().createFixture(new Polygon(mirror(railH, -1, -1)), railFixDef); - -world.createBody().createFixture(new Circle(new Vec2(0, -height * .5 - POCKET_R * 1.5), POCKET_R), pocketFixDef); -world.createBody().createFixture(new Circle(new Vec2(0, +height * .5 + POCKET_R * 1.5), POCKET_R), pocketFixDef); - -world.createBody().createFixture(new Circle(new Vec2(+width * .5 + POCKET_R * .7, +height * .5 + POCKET_R * .7), POCKET_R), pocketFixDef); -world.createBody().createFixture(new Circle(new Vec2(-width * .5 - POCKET_R * .7, +height * .5 + POCKET_R * .7), POCKET_R), pocketFixDef); - -world.createBody().createFixture(new Circle(new Vec2(+width * .5 + POCKET_R * .7, -height * .5 - POCKET_R * .7), POCKET_R), pocketFixDef); -world.createBody().createFixture(new Circle(new Vec2(-width * .5 - POCKET_R * .7, -height * .5 - POCKET_R * .7), POCKET_R), pocketFixDef); - -let balls = rack(BALL_R, width / 4, 0); - -balls.push({x: -width / 4, y: 0}); - -if (COLORED) { - shuffleArray(COLORS); - for (let i = 0; i < COLORS.length; i++) { - balls[i].style = COLORS[i]; - } - balls[14].style = balls[4].style; - balls[4].style = BLACK; - balls[balls.length - 1].style = WHITE; -} - -for (let i = 0; i < balls.length; i++) { - let ball = world.createDynamicBody(ballBodyDef); - ball.setBullet(true); - ball.setPosition(balls[i]); - ball.createFixture(new Circle(BALL_R), ballFixDef); - ball.style = balls[i].style; -} - -world.on('post-solve', function(contact) { - let fA = contact.getFixtureA(), bA = fA.getBody(); - let fB = contact.getFixtureB(), bB = fB.getBody(); - - let pocket = fA.getUserData() === pocketFixDef.userData && bA || fB.getUserData() === pocketFixDef.userData && bB; - let ball = fA.getUserData() === ballFixDef.userData && bA || fB.getUserData() === ballFixDef.userData && bB; - - // do not change world immediately - setTimeout(function() { - if (ball && pocket) { - world.destroyBody(ball); - } - }, 1); -}); - -function rack(r, cx, cy) { - let n = 5; - let balls = []; - let d = r * 2, l = SPI3 * d; - for (let i = 0; i < n; i++) { - for (let j = 0; j <= i; j++) { - balls.push({ - x: cx + i * l /*- (n - 1) * 0.5 * l*/ + Math.random() * r * 0.02, - y: cy + (j - i * 0.5 ) * d + Math.random() * r * 0.02, - }); - } - } - return balls; -} - -function shuffleArray(array) { - // http://stackoverflow.com/a/12646864/483728 - for (let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i + 1)); - let temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - return array; -} diff --git a/example/8-Ball.ts b/example/8-Ball.ts new file mode 100644 index 00000000..7808599b --- /dev/null +++ b/example/8-Ball.ts @@ -0,0 +1,159 @@ +import planck from "../src/main"; + +const { World, Circle, Settings, Polygon , Testbed} = planck + +const SPI4 = Math.sin(Math.PI / 4), SPI3 = Math.sin(Math.PI / 3); + +const COLORED = true; +const BLACK = {fill: 'black', stroke: 'white'}; +const WHITE = {fill: 'white', stroke: 'black'}; +const COLORS = [ + {fill: '#ffdd00', stroke: '#000000'}, + {fill: '#ffdd00', stroke: '#ffffff'}, + {fill: '#ff3300', stroke: '#000000'}, + {fill: '#ff3300', stroke: '#ffffff'}, + {fill: '#662200', stroke: '#000000'}, + {fill: '#662200', stroke: '#ffffff'}, + {fill: '#ff8800', stroke: '#000000'}, + {fill: '#ff8800', stroke: '#ffffff'}, + {fill: '#00bb11', stroke: '#000000'}, + {fill: '#00bb11', stroke: '#ffffff'}, + {fill: '#9900ff', stroke: '#000000'}, + {fill: '#9900ff', stroke: '#ffffff'}, + {fill: '#0077ff', stroke: '#000000'}, + {fill: '#0077ff', stroke: '#ffffff'} +]; + +const width = 8.00, height = 4.00; + +const BALL_R = 0.12; +const POCKET_R = 0.2; + +Settings.velocityThreshold = 0; + +const world = new World(); + +const testbed = Testbed.mount(); +testbed.x = 0; +testbed.y = 0; +testbed.width = width * 1.2; +testbed.height = height * 1.2; +testbed.mouseForce = -20; +testbed.start(world); + +const railH = [ + new planck.Vec2(POCKET_R, height * .5), + new planck.Vec2(POCKET_R, height * .5 + POCKET_R), + new planck.Vec2(width * .5 - POCKET_R / SPI4 + POCKET_R, height * .5 + POCKET_R), + new planck.Vec2(width * .5 - POCKET_R / SPI4, height * .5) +]; + +const railV = [ + new planck.Vec2(width * .5, -(height * .5 - POCKET_R / SPI4)), + new planck.Vec2(width * .5 + POCKET_R, -(height * .5 - POCKET_R / SPI4 + POCKET_R)), + new planck.Vec2(width * .5 + POCKET_R, height * .5 - POCKET_R / SPI4 + POCKET_R), + new planck.Vec2(width * .5, height * .5 - POCKET_R / SPI4) +]; + +const railFixDef = { + friction: 0.1, + restitution: 0.9, + userData: 'rail' +}; +const pocketFixDef = { + userData: 'pocket' +}; +const ballFixDef = { + friction: 0.1, + restitution: 0.99, + density: 1, + userData: 'ball' +}; +const ballBodyDef = { + linearDamping: 1.5, + angularDamping: 1 +}; + +function mirror(vertices:planck.Vec2[], x:number, y:number) { + return vertices.map((v:planck.Vec2) => new planck.Vec2(x * v.x, y * v.y)); +} + +world.createBody().createFixture(new Polygon(railV), railFixDef); +world.createBody().createFixture(new Polygon(mirror(railV, -1, +1)), railFixDef); + +world.createBody().createFixture(new Polygon(railH), railFixDef); +world.createBody().createFixture(new Polygon(mirror(railH, -1, +1)), railFixDef); +world.createBody().createFixture(new Polygon(mirror(railH, +1, -1)), railFixDef); +world.createBody().createFixture(new Polygon(mirror(railH, -1, -1)), railFixDef); + +world.createBody().createFixture(new Circle(new planck.Vec2(0, -height * .5 - POCKET_R * 1.5), POCKET_R), pocketFixDef); +world.createBody().createFixture(new Circle(new planck.Vec2(0, +height * .5 + POCKET_R * 1.5), POCKET_R), pocketFixDef); + +world.createBody().createFixture(new Circle(new planck.Vec2(+width * .5 + POCKET_R * .7, +height * .5 + POCKET_R * .7), POCKET_R), pocketFixDef); +world.createBody().createFixture(new Circle(new planck.Vec2(-width * .5 - POCKET_R * .7, +height * .5 + POCKET_R * .7), POCKET_R), pocketFixDef); + +world.createBody().createFixture(new Circle(new planck.Vec2(+width * .5 + POCKET_R * .7, -height * .5 - POCKET_R * .7), POCKET_R), pocketFixDef); +world.createBody().createFixture(new Circle(new planck.Vec2(-width * .5 - POCKET_R * .7, -height * .5 - POCKET_R * .7), POCKET_R), pocketFixDef); + +const balls = rack(BALL_R, width / 4, 0); + +balls.push({x: -width / 4, y: 0}); + +if (COLORED) { + shuffleArray(COLORS); + for (let i = 0; i < COLORS.length; i++) { + balls[i].style = COLORS[i]; + } + balls[14].style = balls[4].style; + balls[4].style = BLACK; + balls[balls.length - 1].style = WHITE; +} + +for (let i = 0; i < balls.length; i++) { + const ball = world.createDynamicBody(ballBodyDef); + ball.setBullet(true) + ball.setPosition(balls[i]); + ball.createFixture(new Circle(BALL_R), ballFixDef); + ball.style = balls[i].style; +} + +world.on('post-solve', function(contact) { + const fA = contact.getFixtureA(), bA = fA.getBody(); + const fB = contact.getFixtureB(), bB = fB.getBody(); + + const pocket = fA.getUserData() === pocketFixDef.userData && bA || fB.getUserData() === pocketFixDef.userData && bB; + const ball = fA.getUserData() === ballFixDef.userData && bA || fB.getUserData() === ballFixDef.userData && bB; + + // do not change world immediately + setTimeout(function() { + if (ball && pocket) { + world.destroyBody(ball); + } + }, 1); +}); + +function rack(r, cx, cy) { + const n = 5; + const balls = []; + const d = r * 2, l = SPI3 * d; + for (let i = 0; i < n; i++) { + for (let j = 0; j <= i; j++) { + balls.push({ + x: cx + i * l /*- (n - 1) * 0.5 * l*/ + Math.random() * r * 0.02, + y: cy + (j - i * 0.5 ) * d + Math.random() * r * 0.02, + }); + } + } + return balls; +} + +function shuffleArray(array) { + // http://stackoverflow.com/a/12646864/483728 + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + const temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + return array; +} \ No newline at end of file diff --git a/example/AddPair.js b/example/AddPair.ts similarity index 87% rename from example/AddPair.js rename to example/AddPair.ts index 94497d63..ab47f1bc 100644 --- a/example/AddPair.js +++ b/example/AddPair.ts @@ -20,10 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; -const { Vec2, World, Circle, Box, Math, Testbed } = planck; +const { Vec2, World, Circle, Box, Testbed } = planck; -let world = new World(new Vec2(0, 0)); +const world = new World(new Vec2(0, 0)); const testbed = Testbed.mount(); testbed.y = 0; @@ -31,17 +32,17 @@ testbed.hz = 60; testbed.speed = 1; testbed.start(world); -let circle = new Circle(0.1); +const circle = new Circle(0.1); for (let i = 0; i < 50; ++i) { - let b = world.createBody({ + const b = world.createBody({ type : 'dynamic', position : new Vec2(Math.random() * -6, Math.random() * 2 - 1), }); b.createFixture(circle, 0.01); } -let box = world.createBody({ +const box = world.createBody({ type : 'dynamic', position : new Vec2(-40.0, 0.0), bullet : true diff --git a/example/ApplyForce.js b/example/ApplyForce.ts similarity index 61% rename from example/ApplyForce.js rename to example/ApplyForce.ts index f7a84eb3..6efa087b 100644 --- a/example/ApplyForce.js +++ b/example/ApplyForce.ts @@ -21,58 +21,60 @@ * SOFTWARE. */ -const { Vec2, Transform, Polygon, Box, FrictionJoint, World, Edge, Testbed } = planck; +import planck from "../src/main"; -let world = new World(); +const { Transform, Polygon, Box, FrictionJoint, World, Edge, Testbed } = planck; + +const world = new World(); const testbed = Testbed.mount(); testbed.y = -20; testbed.start(world); -let ground = world.createBody(new Vec2(0.0, 20.0)); +const ground = world.createBody(new planck.Vec2(0.0, 20.0)); -let wallFD = { +const wallFD = { density: 0.0, restitution: 0.4, }; // Left vertical -ground.createFixture(new Edge(new Vec2(-20.0, -20.0), new Vec2(-20.0, 20.0)), wallFD); +ground.createFixture(new Edge(new planck.Vec2(-20.0, -20.0), new planck.Vec2(-20.0, 20.0)), wallFD); // Right vertical -ground.createFixture(new Edge(new Vec2(20.0, -20.0), new Vec2(20.0, 20.0)), wallFD); +ground.createFixture(new Edge(new planck.Vec2(20.0, -20.0), new planck.Vec2(20.0, 20.0)), wallFD); // Top horizontal -ground.createFixture(new Edge(new Vec2(-20.0, 20.0), new Vec2(20.0, 20.0)), wallFD); +ground.createFixture(new Edge(new planck.Vec2(-20.0, 20.0), new planck.Vec2(20.0, 20.0)), wallFD); // Bottom horizontal -ground.createFixture(new Edge(new Vec2(-20.0, -20.0), new Vec2(20.0, -20.0)), wallFD); +ground.createFixture(new Edge(new planck.Vec2(-20.0, -20.0), new planck.Vec2(20.0, -20.0)), wallFD); const xf1 = new Transform(); xf1.q.set(0.3524 * Math.PI); xf1.p.set(xf1.q.getXAxis()); -let poly1 = new Polygon([ - new Vec2(-1.0, 0.0), - new Vec2(1.0, 0.0), - new Vec2(0.0, 0.5) -].map(v => Transform.mul(xf1, v))); +const poly1 = new Polygon([ + new planck.Vec2(-1.0, 0.0), + new planck.Vec2(1.0, 0.0), + new planck.Vec2(0.0, 0.5) +].map((v:planck.Vec2) => Transform.mul(xf1, v))); const xf2 = new Transform(); xf2.q.set(-0.3524 * Math.PI); -xf2.p.set(Vec2.neg(xf2.q.getXAxis())); +xf2.p.set(planck.Vec2.neg(xf2.q.getXAxis())); -let poly2 = new Polygon([ - new Vec2(-1.0, 0.0), - new Vec2(1.0, 0.0), - new Vec2(0.0, 0.5) -].map(v => Transform.mul(xf2, v))); +const poly2 = new Polygon([ + new planck.Vec2(-1.0, 0.0), + new planck.Vec2(1.0, 0.0), + new planck.Vec2(0.0, 0.5) +].map((v:planck.Vec2) => Transform.mul(xf2, v))); -let jet = world.createBody({ +const jet = world.createBody({ type : 'dynamic', angularDamping : 2.0, linearDamping : 0.5, - position : new Vec2(0.0, 2.0), + position : new planck.Vec2(0.0, 2.0), angle : Math.PI, allowSleep : false }); @@ -80,28 +82,28 @@ let jet = world.createBody({ jet.createFixture(poly1, 2.0); jet.createFixture(poly2, 2.0); -let boxFD = { +const boxFD = { density: 1.0, friction: 0.3, }; for (let i = 0; i < 10; ++i) { - let box = world.createDynamicBody(new Vec2(0.0, 5.0 + 1.54 * i)); + const box = world.createDynamicBody(new planck.Vec2(0.0, 5.0 + 1.54 * i)); box.createFixture(new Box(0.5, 0.5), boxFD); - let gravity = 10.0; - let I = box.getInertia(); - let mass = box.getMass(); + const gravity = 10.0; + const I = box.getInertia(); + const mass = box.getMass(); // For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m) - let radius = Math.sqrt(2.0 * I / mass); + const radius = Math.sqrt(2.0 * I / mass); world.createJoint(new FrictionJoint({ collideConnected : true, maxForce : mass * gravity, maxTorque : mass * radius * gravity - }, ground, box)); + }, ground, box,box.getPosition())); } testbed.step = function() { @@ -113,8 +115,8 @@ testbed.step = function() { } if (testbed.activeKeys.up) { - let f = jet.getWorldVector(new Vec2(0.0, -1.0)); - let p = jet.getWorldPoint(new Vec2(0.0, 2.0)); + const f = jet.getWorldVector(new planck.Vec2(0.0, -1.0)); + const p = jet.getWorldPoint(new planck.Vec2(0.0, 2.0)); jet.applyLinearImpulse(f, p, true); } }; diff --git a/example/Asteroid.js b/example/Asteroid.ts similarity index 54% rename from example/Asteroid.js rename to example/Asteroid.ts index 92e3bea3..3239ff12 100644 --- a/example/Asteroid.js +++ b/example/Asteroid.ts @@ -1,28 +1,30 @@ +import planck from "../src/main"; + const { World, Vec2, Circle, Polygon, Testbed } = planck; -let SHIP = 2; -let BULLET = 4; -let ASTEROID = 4; +const SHIP = 2; +const BULLET = 4; +const ASTEROID = 4; -let SPACE_WIDTH = 16; -let SPACE_HEIGHT = 9; +const SPACE_WIDTH = 16; +const SPACE_HEIGHT = 9; -let SHIP_SIZE = 0.30; -let FIRE_RELOAD_TIME = 100; -let BULLET_LIFE_TIME = 2000; +const SHIP_SIZE = 0.3; +const FIRE_RELOAD_TIME = 100; +const BULLET_LIFE_TIME = 2000; -let asteroidRadius = 0.9; -let asteroidSpeed = 2; -let asteroidLevels = 4; +const asteroidRadius = 0.9; +const asteroidSpeed = 2; +const asteroidLevels = 4; -let level; -let lives; -let gameover; +let level: number; +let lives: number; +let gameover: boolean; let allowCrashTime = 0; let allowFireTime = 0; -let world = new World(); +const world = new World(); const testbed = Testbed.mount(); testbed.width = SPACE_WIDTH; @@ -30,43 +32,40 @@ testbed.height = SPACE_HEIGHT; testbed.y = 0; testbed.start(world); -let asteroidBodies = []; -let bulletBodies = []; +const asteroidBodies = []; +const bulletBodies = []; let shipBody; -testbed.keydown = function(code, char) { +testbed.keydown = function () { if (testbed.activeKeys.fire) { gameover && start(); } }; // Todo: check if several bullets hit the same asteroid in the same time step -world.on('pre-solve', function(contact) { - let fixtureA = contact.getFixtureA(); - let fixtureB = contact.getFixtureB(); +world.on("pre-solve", function (contact) { + const fixtureA = contact.getFixtureA(); + const fixtureB = contact.getFixtureB(); - let bodyA = contact.getFixtureA().getBody(); - let bodyB = contact.getFixtureB().getBody(); + const bodyA = contact.getFixtureA().getBody(); + const bodyB = contact.getFixtureB().getBody(); - let aship = bodyA === shipBody; - let bship = bodyB === shipBody; - let abullet = fixtureA.getFilterCategoryBits() & BULLET; - let bbullet = fixtureB.getFilterCategoryBits() & BULLET; + const aship = bodyA === shipBody; + const bship = bodyB === shipBody; + const abullet = fixtureA.getFilterCategoryBits() & BULLET; + const bbullet = fixtureB.getFilterCategoryBits() & BULLET; if ((aship || bship) && allowCrashTime < globalTime) { // Ship collided with something - let ship = aship ? bodyA : bodyB; - let asteroid = !aship ? bodyA : bodyB; - setTimeout(function () { - crash(ship, asteroid); + crash(); }, 1); } if (abullet || bbullet) { // Bullet collided with something - let bullet = abullet ? bodyA : bodyB; - let asteroid = !abullet ? bodyA : bodyB; + const bullet = abullet ? bodyA : bodyB; + const asteroid = !abullet ? bodyA : bodyB; setTimeout(function () { hit(bullet, asteroid); @@ -79,7 +78,7 @@ function start() { level = 1; lives = 3; uiStatus(); - setupShip(true); + setupShip(); addAsteroids(); uiStart(); } @@ -91,32 +90,34 @@ function end() { function setupShip() { shipBody = world.createBody({ - type : 'dynamic', - angularDamping : 2.0, - linearDamping : 0.5, - position : new Vec2(), + type: "dynamic", + angularDamping: 2.0, + linearDamping: 0.5, + position: new Vec2(), }); - shipBody.createFixture(new Polygon([ - new Vec2(-0.15, -0.15), - new Vec2(0, -0.1), - new Vec2(0.15, -0.15), - new Vec2(0, 0.2) - ]), { - density : 1000, - filterCategoryBits : SHIP, - filterMaskBits : ASTEROID - }); + shipBody.createFixture( + new Polygon([ + new Vec2(-0.15, -0.15), + new Vec2(0, -0.1), + new Vec2(0.15, -0.15), + new Vec2(0, 0.2), + ]), + { + density: 1000, + filterCategoryBits: SHIP, + filterMaskBits: ASTEROID, + } + ); allowCrashTime = globalTime + 2000; } let globalTime = 0; -testbed.step = function(dt) { +testbed.step = function (dt) { globalTime += dt; if (shipBody) { - // Set velocities if (testbed.activeKeys.left && !testbed.activeKeys.right) { shipBody.applyAngularImpulse(0.1, true); @@ -133,7 +134,6 @@ testbed.step = function(dt) { // Fire if (testbed.activeKeys.fire && globalTime > allowFireTime) { - const magnitude = 2; const angle = shipBody.Getangle + Math.PI / 2; @@ -142,11 +142,11 @@ testbed.step = function(dt) { // mass : 0.05, position: shipBody.getWorldPoint(new Vec2(0, SHIP_SIZE)), linearVelocity: shipBody.getWorldVector(new Vec2(0, magnitude)), - bullet: true + bullet: true, }); bulletBody.createFixture(new Circle(0.05), { filterCategoryBits: BULLET, - filterMaskBits: ASTEROID + filterMaskBits: ASTEROID, }); bulletBodies.push(bulletBody); @@ -154,7 +154,11 @@ testbed.step = function(dt) { allowFireTime = globalTime + FIRE_RELOAD_TIME; // Remember when we should delete this bullet - bulletBody.dieTime = globalTime + BULLET_LIFE_TIME; + // bulletBody.die = globalTime + BULLET_LIFE_TIME; + bulletBody.setUserData({ + ...((bulletBody.getUserData() as any) || {}), + die: globalTime + BULLET_LIFE_TIME, + }); } wrap(shipBody); @@ -174,11 +178,10 @@ testbed.step = function(dt) { } for (let i = 0; i !== asteroidBodies.length; i++) { - let asteroidBody = asteroidBodies[i]; + const asteroidBody = asteroidBodies[i]; wrap(asteroidBody); } - -} +}; // Adds some asteroids to the scene. function addAsteroids() { @@ -189,59 +192,73 @@ function addAsteroids() { } for (let i = 0; i < level; i++) { - let shipPosition = shipBody.getPosition(); + const shipPosition = shipBody.getPosition(); let x = shipPosition.x; let y = shipPosition.y; // Aviod the ship! - while (Math.abs(x - shipPosition.x) < asteroidRadius * 2 - && Math.abs(y - shipPosition.y) < asteroidRadius * 2) { + while ( + Math.abs(x - shipPosition.x) < asteroidRadius * 2 && + Math.abs(y - shipPosition.y) < asteroidRadius * 2 + ) { x = rand(SPACE_WIDTH); y = rand(SPACE_HEIGHT); } - let vx = rand(asteroidSpeed); - let vy = rand(asteroidSpeed); - let va = rand(asteroidSpeed); + const vx = rand(asteroidSpeed); + const vy = rand(asteroidSpeed); + const va = rand(asteroidSpeed); // Create asteroid body const asteroidBody = makeAsteroidBody(x, y, vx, vy, va, 0); - asteroidBody.level = 1; + // asteroidBody.level = 1; + asteroidBody.setUserData({ + ...((asteroidBody.getUserData() as any) || {}), + level: 1, + }); } } -function asteroidLevelRadius(level) { - return asteroidRadius * (asteroidLevels - level) / asteroidLevels; +function asteroidLevelRadius(level: number) { + return (asteroidRadius * (asteroidLevels - level)) / asteroidLevels; } -function makeAsteroidBody(x, y, vx, vy, va, level) { - let asteroidBody = world.createKinematicBody({ +function makeAsteroidBody( + x: number, + y: number, + vx: number, + vy: number, + va: number, + level: number +) { + const asteroidBody = world.createKinematicBody({ // mass : 10, - position : new Vec2(x, y), - linearVelocity : new Vec2(vx, vy), - angularVelocity : va + position: new Vec2(x, y), + linearVelocity: new Vec2(vx, vy), + angularVelocity: va, }); asteroidBodies.push(asteroidBody); - let radius = asteroidLevelRadius(level); + const radius = asteroidLevelRadius(level); - let n = 8, path = []; + const n = 8, + path = []; for (let i = 0; i < n; i++) { - let a = i * 2 * Math.PI / n; + const a = (i * 2 * Math.PI) / n; const x = radius * (Math.sin(a) + rand(0.3)); const y = radius * (Math.cos(a) + rand(0.3)); path.push(new Vec2(x, y)); } asteroidBody.createFixture(new Polygon(path), { - filterCategoryBits : ASTEROID, - filterMaskBits : BULLET | SHIP + filterCategoryBits: ASTEROID, + filterMaskBits: BULLET | SHIP, }); return asteroidBody; } -function crash(ship, asteroid) { +function crash() { if (!shipBody) return; lives--; @@ -255,17 +272,16 @@ function crash(ship, asteroid) { end(); return; } - setTimeout(function() { + setTimeout(function () { // Add ship again setupShip(); }, 1000); } -function hit(asteroidBody, bulletBody) { - let aidx = asteroidBodies.indexOf(asteroidBody); - let bidx = bulletBodies.indexOf(bulletBody); +function hit(asteroidBody: planck.Body, bulletBody: planck.Body) { + const aidx = asteroidBodies.indexOf(asteroidBody); + const bidx = bulletBodies.indexOf(bulletBody); if (aidx != -1 && bidx != -1) { - // Remove asteroid world.destroyBody(asteroidBody); asteroidBodies.splice(aidx, 1); @@ -287,39 +303,46 @@ function hit(asteroidBody, bulletBody) { } } -function splitAsteroid(parent) { - if (parent.level < 4) { - let angleDisturb = Math.PI / 2 * Math.random(); +function splitAsteroid(parent: planck.Body) { + const parentLevel: number = (parent.getUserData() as any).level; + if (parentLevel < 4) { + const angleDisturb = (Math.PI / 2) * Math.random(); for (let i = 0; i < 4; i++) { - let angle = Math.PI / 2 * i + angleDisturb; - - let r = asteroidLevelRadius(0) - asteroidLevelRadius(parent.level); - let sp = parent.getWorldPoint(new Vec2(r * Math.cos(angle), r * Math.sin(angle))); - - let vx = rand(asteroidSpeed); - let vy = rand(asteroidSpeed); - let va = rand(asteroidSpeed); - - let child = makeAsteroidBody(sp.x, sp.y, vx, vy, va, parent.level); - child.level = parent.level + 1; + const angle = (Math.PI / 2) * i + angleDisturb; + + const r = asteroidLevelRadius(0) - asteroidLevelRadius(parentLevel); + const sp = parent.getWorldPoint( + new Vec2(r * Math.cos(angle), r * Math.sin(angle)) + ); + + const vx = rand(asteroidSpeed); + const vy = rand(asteroidSpeed); + const va = rand(asteroidSpeed); + + const child = makeAsteroidBody(sp.x, sp.y, vx, vy, va, parentLevel); + // child.level = parent.level + 1; + child.setUserData({ + ...((child.getUserData() as any) || {}), + level: parentLevel + 1, + }); child.setAngle(rand() * Math.PI); } } } // If the body is out of space bounds, wrap it to the other side -function wrap(body) { - let p = body.getPosition(); +function wrap(body: planck.Body) { + const p = body.getPosition(); p.x = wrapNumber(p.x, -SPACE_WIDTH / 2, SPACE_WIDTH / 2); p.y = wrapNumber(p.y, -SPACE_HEIGHT / 2, SPACE_HEIGHT / 2); body.setPosition(p); } function wrapNumber(num, min, max) { - if (typeof min === 'undefined') { - max = 1, min = 0; - } else if (typeof max === 'undefined') { - max = min, min = 0; + if (typeof min === "undefined") { + (max = 1), (min = 0); + } else if (typeof max === "undefined") { + (max = min), (min = 0); } if (max > min) { num = (num - min) % (max - min); @@ -331,23 +354,23 @@ function wrapNumber(num, min, max) { } // Returns a random number between -0.5 and 0.5 -function rand(value) { +function rand(value?: number) { return (Math.random() - 0.5) * (value || 1); } function uiStart() { - console.log('Game started'); + console.log("Game started"); } function uiEnd() { - console.log('Game over'); - testbed.status('Game Over!'); + console.log("Game over"); + testbed.status("Game Over!"); } function uiStatus() { - console.log('Level: ' + level + ' Lives: ' + lives); - testbed.status('Level', level); - testbed.status('Lives', lives); + console.log("Level: " + level + " Lives: " + lives); + testbed.status("Level", level); + testbed.status("Lives", lives); } start(); diff --git a/example/BasicSliderCrank.js b/example/BasicSliderCrank.ts similarity index 78% rename from example/BasicSliderCrank.js rename to example/BasicSliderCrank.ts index b3738dda..d5e0f7fc 100644 --- a/example/BasicSliderCrank.js +++ b/example/BasicSliderCrank.ts @@ -22,32 +22,41 @@ */ // A basic slider crank created for GDC tutorial: Understanding Constraints +import planck from "../src/main"; const { Vec2, World, Box, RevoluteJoint, PrismaticJoint, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.y = -15; testbed.start(world); -let ground = world.createBody(new Vec2(0.0, 17.0)); +const ground = world.createBody(new Vec2(0.0, 17.0)); // Define crank. -let crank = world.createDynamicBody(new Vec2(-8.0, 20.0)); +const crank = world.createDynamicBody(new Vec2(-8.0, 20.0)); crank.createFixture(new Box(4.0, 1.0), 2.0); world.createJoint(new RevoluteJoint({}, ground, crank, new Vec2(-12.0, 20.0))); // Define connecting rod -let rod = world.createDynamicBody(new Vec2(4.0, 20.0)); +const rod = world.createDynamicBody(new Vec2(4.0, 20.0)); rod.createFixture(new Box(8.0, 1.0), 2.0); world.createJoint(new RevoluteJoint({}, crank, rod, new Vec2(-4.0, 20.0))); // Define piston -let piston = world.createDynamicBody({ - fixedRotation : true, - position : new Vec2(12.0, 20.0) +const piston = world.createDynamicBody({ + fixedRotation: true, + position: new Vec2(12.0, 20.0), }); piston.createFixture(new Box(3.0, 3.0), 2.0); world.createJoint(new RevoluteJoint({}, rod, piston, new Vec2(12.0, 20.0))); -world.createJoint(new PrismaticJoint({}, ground, piston, new Vec2(12.0, 17.0), new Vec2(1.0, 0.0))); +world.createJoint( + new PrismaticJoint( + {}, + ground, + piston, + new Vec2(12.0, 17.0), + new Vec2(1.0, 0.0) + ) +); diff --git a/example/BodyTypes.js b/example/BodyTypes.ts similarity index 59% rename from example/BodyTypes.js rename to example/BodyTypes.ts index 027cd22b..4f121efb 100644 --- a/example/BodyTypes.js +++ b/example/BodyTypes.ts @@ -20,71 +20,83 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; -const { Vec2, World, Edge, Box, RevoluteJoint, PrismaticJoint, Testbed } = planck; +const { Vec2, World, Edge, Box, RevoluteJoint, PrismaticJoint, Testbed } = + planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); -testbed.info('Z: Dynamic, X: Static, C: Kinematic'); +testbed.info("Z: Dynamic, X: Static, C: Kinematic"); testbed.start(world); -let SPEED = 3.0; +const SPEED = 3.0; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0))); // Define attachment -let attachment = world.createDynamicBody(new Vec2(0.0, 3.0)); +const attachment = world.createDynamicBody(new Vec2(0.0, 3.0)); attachment.createFixture(new Box(0.5, 2.0), 2.0); // Define platform -let platform = world.createDynamicBody(new Vec2(-4.0, 5.0)); - -platform.createFixture( - new Box(0.5, 4.0, new Vec2(4.0, 0.0), 0.5 * Math.PI), - { friction : 0.6, density : 2.0 } +const platform = world.createDynamicBody(new Vec2(-4.0, 5.0)); + +platform.createFixture(new Box(0.5, 4.0, new Vec2(4.0, 0.0), 0.5 * Math.PI), { + friction: 0.6, + density: 2.0, +}); + +world.createJoint( + new RevoluteJoint( + { + maxMotorTorque: 50.0, + enableMotor: true, + }, + attachment, + platform, + new Vec2(0.0, 5.0) + ) ); -world.createJoint(new RevoluteJoint({ - maxMotorTorque : 50.0, - enableMotor : true -}, attachment, platform, new Vec2(0.0, 5.0))); - -world.createJoint(new PrismaticJoint({ - maxMotorForce : 1000.0, - enableMotor : true, - lowerTranslation : -10.0, - upperTranslation : 10.0, - enableLimit : true -}, ground, platform, new Vec2(0.0, 5.0), new Vec2(1.0, 0.0))); +world.createJoint( + new PrismaticJoint( + { + maxMotorForce: 1000.0, + enableMotor: true, + lowerTranslation: -10.0, + upperTranslation: 10.0, + enableLimit: true, + }, + ground, + platform, + new Vec2(0.0, 5.0), + new Vec2(1.0, 0.0) + ) +); // Create a payload -let payload = world.createDynamicBody(new Vec2(0.0, 8.0)); -payload.createFixture( - new Box(0.75, 0.75), - { friction : 0.6, density : 2.0 } -); +const payload = world.createDynamicBody(new Vec2(0.0, 8.0)); +payload.createFixture(new Box(0.75, 0.75), { friction: 0.6, density: 2.0 }); -testbed.keydown = function(code, char) { - if (char === 'Z') { +testbed.keydown = function (code, char) { + if (char === "Z") { platform.setDynamic(); - - } else if (char === 'X') { + } else if (char === "X") { platform.setStatic(); - - } else if (char === 'C') { + } else if (char === "C") { platform.setKinematic(); platform.setLinearVelocity(new Vec2(-SPEED, 0.0)); platform.setAngularVelocity(0.0); } }; -testbed.step = function() { +testbed.step = function () { // Drive the kinematic body. if (platform.isKinematic()) { - let p = platform.getTransform().p; - let v = platform.getLinearVelocity(); + const p = platform.getTransform().p; + const v = platform.getLinearVelocity(); if ((p.x < -10.0 && v.x < 0.0) || (p.x > 10.0 && v.x > 0.0)) { v.x = -v.x; diff --git a/example/Boxes.js b/example/Boxes.ts similarity index 64% rename from example/Boxes.js rename to example/Boxes.ts index 00d1e500..e92fd0a4 100644 --- a/example/Boxes.js +++ b/example/Boxes.ts @@ -1,23 +1,25 @@ +import planck from "../src/main"; + const { Vec2, World, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let bar = world.createBody(); +const bar = world.createBody(); bar.createFixture(new Edge(new Vec2(-20, 5), new Vec2(20, 5))); bar.setAngle(0.2); for (let i = -2; i <= 2; i++) { for (let j = -2; j <= 2; j++) { - let box = world.createBody().setDynamic(); + const box = world.createBody().setDynamic(); box.createFixture(new Box(0.5, 0.5)); box.setPosition(new Vec2(i * 1, -j * 1 + 20)); box.setMassData({ - mass : 1, - center : new Vec2(), - I : 1 + mass: 1, + center: new Vec2(), + I: 1, }); } } diff --git a/example/Breakable.js b/example/Breakable.ts similarity index 69% rename from example/Breakable.js rename to example/Breakable.ts index 29a30e60..67c6655d 100644 --- a/example/Breakable.js +++ b/example/Breakable.ts @@ -22,40 +22,41 @@ */ // This is used to test sensor shapes. +import planck from "../src/main"; const { World, Vec2, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let breakVelocity; -let breakAngularVelocity; +let breakVelocity: planck.Vec2; +let breakAngularVelocity: number; let broke = false; // Ground body -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); // Breakable dynamic body -let body1 = world.createDynamicBody(new Vec2(0.0, 40.0), 0.25 * Math.PI); +const body1 = world.createDynamicBody(new Vec2(0.0, 40.0), 0.25 * Math.PI); -let shape1 = new Box(0.5, 0.5, new Vec2(-0.5, 0.0), 0.0); -let piece1 = body1.createFixture(shape1, 1.0); +const shape1 = new Box(0.5, 0.5, new Vec2(-0.5, 0.0), 0.0); +const piece1 = body1.createFixture(shape1, 1.0); -let shape2 = new Box(0.5, 0.5, new Vec2(0.5, 0.0), 0.0); +const shape2 = new Box(0.5, 0.5, new Vec2(0.5, 0.0), 0.0); let piece2 = body1.createFixture(shape2, 1.0); -world.on('post-solve', function (contact, impulse) { +world.on("post-solve", function (contact, impulse) { if (broke) { // The body already broke. return; } // Should the body break? - let count = contact.getManifold().pointCount; + const count = contact.getManifold().pointCount; let maxImpulse = 0.0; for (let i = 0; i < count; ++i) { @@ -63,7 +64,7 @@ world.on('post-solve', function (contact, impulse) { } if (maxImpulse > 40.0) { - setTimeout(function() { + setTimeout(function () { Break(); broke = true; }); @@ -72,21 +73,27 @@ world.on('post-solve', function (contact, impulse) { function Break() { // Create two bodies from one. - let center = body1.getWorldCenter(); + const center = body1.getWorldCenter(); body1.destroyFixture(piece2); - let body2 = world.createDynamicBody(body1.getPosition(), body1.getAngle()); + const body2 = world.createDynamicBody(body1.getPosition(), body1.getAngle()); piece2 = body2.createFixture(shape2, 1.0); // Compute consistent velocities for new bodies based on // cached velocity. - let center1 = body1.getWorldCenter(); - let center2 = body2.getWorldCenter(); - - let velocity1 = Vec2.add(breakVelocity, Vec2.cross(breakAngularVelocity, Vec2.sub(center1, center))); - let velocity2 = Vec2.add(breakVelocity, Vec2.cross(breakAngularVelocity, Vec2.sub(center2, center))); + const center1 = body1.getWorldCenter(); + const center2 = body2.getWorldCenter(); + + const velocity1 = Vec2.add( + breakVelocity, + Vec2.cross(breakAngularVelocity, Vec2.sub(center1, center)) + ); + const velocity2 = Vec2.add( + breakVelocity, + Vec2.cross(breakAngularVelocity, Vec2.sub(center2, center)) + ); body1.setAngularVelocity(breakAngularVelocity); body1.setLinearVelocity(velocity1); @@ -95,7 +102,7 @@ function Break() { body2.setLinearVelocity(velocity2); } -testbed.step = function() { +testbed.step = function () { // Cache velocities to improve movement on breakage. if (!broke) { breakVelocity = body1.getLinearVelocity(); diff --git a/example/Breakout.js b/example/Breakout.ts similarity index 59% rename from example/Breakout.js rename to example/Breakout.ts index 19b7464f..07ee4b7c 100644 --- a/example/Breakout.js +++ b/example/Breakout.ts @@ -1,17 +1,19 @@ +import planck from "../src/main"; + const { World, Vec2, Circle, Box, Edge, Polygon, Testbed } = planck; -let WIDTH = 20; -let HEIGHT = 26; +const WIDTH = 20; +const HEIGHT = 26; const testbed = Testbed.mount(); testbed.width = WIDTH; testbed.height = HEIGHT * 1.12; testbed.y = 0; -testbed.keydown = function() { +testbed.keydown = function () { if (testbed.activeKeys.fire) { - if(state.state == 'gameover') { + if (state.state == "gameover") { state.initGame(); - } else if (state.state == 'ready') { + } else if (state.state == "ready") { state.startGame(); } } @@ -23,31 +25,29 @@ const state = new State(); testbed.start(physics.world); function State() { - let state = this; + const state = this; - state.state = ''; + state.state = ""; let _score = 0; let _combo = 1; let _time = 0; let _createRowTime = 0; let _fullPaddleTime = 0; - let _balls = []; - let _bricks = []; - let _drops = []; + const _balls = []; + const _bricks = []; + const _drops = []; function updateStatus() { - if (state.state == 'gameover') { - testbed.status('Gameover!'); - testbed.status('Score', _score); - - } else if (state.state == 'ready') { - testbed.status('Ready!'); - testbed.status('Score', _score); - + if (state.state == "gameover") { + testbed.status("Gameover!"); + testbed.status("Score", _score); + } else if (state.state == "ready") { + testbed.status("Ready!"); + testbed.status("Score", _score); } else { - testbed.status(''); - testbed.status('Score', _score); + testbed.status(""); + testbed.status("Score", _score); } } @@ -91,11 +91,11 @@ function State() { } function createDrop(brick) { - let random = Math.random(); + const random = Math.random(); if (random < 0.06) { - addDrop({i: brick.i, j: brick.j, type: '+', speed : dropSpeed()}); + addDrop({ i: brick.i, j: brick.j, type: "+", speed: dropSpeed() }); } else if (random < 0.1) { - addDrop({i: brick.i, j: brick.j, type: '-', speed : dropSpeed()}); + addDrop({ i: brick.i, j: brick.j, type: "-", speed: dropSpeed() }); } } @@ -108,24 +108,25 @@ function State() { _createRowTime = _time + createRowTime(); let gameover = false; - _bricks.forEach(function(brick) { + _bricks.forEach(function (brick) { brick.j++; physics.updateBrick(brick); - gameover = gameover | brick >= 10; + gameover = gameover || brick >= 10; }); for (let i = 0; i < 7; i++) { if (Math.random() < 0.1) { continue; } - let one = _score + 1, four = Math.max(0, _score * 1.1 - 60); + const one = _score + 1, + four = Math.max(0, _score * 1.1 - 60); if (Math.random() < one / (four + one)) { - addBrick({type: 'normal', i: i, j: 0}); + addBrick({ type: "normal", i: i, j: 0 }); } else { - addBrick({type: 'small', i: i - 0.25, j: -0.25}); - addBrick({type: 'small', i: i + 0.25, j: -0.25}); - addBrick({type: 'small', i: i - 0.25, j: +0.25}); - addBrick({type: 'small', i: i + 0.25, j: +0.25}); + addBrick({ type: "small", i: i - 0.25, j: -0.25 }); + addBrick({ type: "small", i: i + 0.25, j: -0.25 }); + addBrick({ type: "small", i: i - 0.25, j: +0.25 }); + addBrick({ type: "small", i: i + 0.25, j: +0.25 }); } } @@ -134,21 +135,20 @@ function State() { } } - testbed.step = function(dt) { + testbed.step = function (dt) { _time += dt = Math.min(dt, 50); - if (state.state !== 'playing' && state.state !== 'ready') { + if (state.state !== "playing" && state.state !== "ready") { return; } if (testbed.activeKeys.left && !testbed.activeKeys.right) { - physics.movePaddle(-paddleSpeed() * dt / 1000); - + physics.movePaddle((-paddleSpeed() * dt) / 1000); } else if (!testbed.activeKeys.left && testbed.activeKeys.right) { - physics.movePaddle(+paddleSpeed() * dt / 1000); + physics.movePaddle((+paddleSpeed() * dt) / 1000); } - if (state.state !== 'playing') { + if (state.state !== "playing") { return; } @@ -165,7 +165,7 @@ function State() { physics.tick(dt); }; - state.hitBrick = function(brick) { + state.hitBrick = function (brick) { if (!removeFromArray(_bricks, brick)) return; physics.removeBrick(brick); @@ -176,11 +176,11 @@ function State() { createDrop(brick); }; - state.hitBall = function() { + state.hitBall = function () { // _combo = 1; }; - state.missBall = function(ball) { + state.missBall = function (ball) { if (!removeFromArray(_balls, ball)) return; physics.removeBall(ball); @@ -189,38 +189,38 @@ function State() { } }; - state.catchDrop = function(drop) { + state.catchDrop = function (drop) { if (!removeFromArray(_drops, drop)) return; physics.removeDrop(drop); - if (drop.type == '+') { + if (drop.type == "+") { addBall({}); - } else if (drop.type == '-') { + } else if (drop.type == "-") { _fullPaddleTime = _time + resetPaddleTime(); miniPaddle(); } }; - state.missDrop = function(drop) { + state.missDrop = function (drop) { if (!removeFromArray(_drops, drop)) return; physics.removeDrop(drop); }; function endGame() { - state.state = 'gameover'; + state.state = "gameover"; updateStatus(); physics.endGame(); } - state.startGame = function() { + state.startGame = function () { state.initGame(); physics.startGame(); - state.state = 'playing'; + state.state = "playing"; }; - state.initGame = function() { - if (state.state == 'ready') return; - state.state = 'ready'; + state.initGame = function () { + if (state.state == "ready") return; + state.state = "ready"; _score = 0; _combo = 1; _createRowTime = 0; @@ -235,30 +235,36 @@ function State() { } function Physics() { - - let world = this.world = new World(); + const world = (this.world = new World()); - let bottomWall, paddle, balls = [], bricks = [], drops = []; + let bottomWall, paddle; + const balls = [], + bricks = [], + drops = []; - let BALL = 1, WALL = 2, BRICK = 4, DROP = 8, PADDLE = 16; + const BALL = 1, + WALL = 2, + BRICK = 4, + DROP = 8, + PADDLE = 16; - let ballFix = { + const ballFix = { friction: 0.0, restitution: 1.0, filterCategoryBits: BALL, - filterMaskBits: PADDLE | WALL | BRICK + filterMaskBits: PADDLE | WALL | BRICK, }; - let paddleFix = {filterCategoryBits: PADDLE, filterMaskBits: BALL | DROP}; - let wallFix = {filterCategoryBits: WALL, filterMaskBits: BALL | DROP}; - let brickFix = {filterCategoryBits: BRICK, filterMaskBits: BALL}; - let dropFix = {filterCategoryBits: DROP, filterMaskBits: PADDLE | WALL}; + const paddleFix = { filterCategoryBits: PADDLE, filterMaskBits: BALL | DROP }; + const wallFix = { filterCategoryBits: WALL, filterMaskBits: BALL | DROP }; + const brickFix = { filterCategoryBits: BRICK, filterMaskBits: BALL }; + const dropFix = { filterCategoryBits: DROP, filterMaskBits: PADDLE | WALL }; - let ballShape = new Circle(0.5); - let normalBrickShape = new Box(1.9 / 2, 1.9 / 2); - let smallBrickShape = new Box(0.9 / 2, 0.9 / 2); + const ballShape = new Circle(0.5); + const normalBrickShape = new Box(1.9 / 2, 1.9 / 2); + const smallBrickShape = new Box(0.9 / 2, 0.9 / 2); - let fullPaddleShape = new Polygon([ + const fullPaddleShape = new Polygon([ new Vec2(1.7, -0.2), new Vec2(1.8, -0.1), new Vec2(1.8, 0.1), @@ -270,11 +276,11 @@ function Physics() { new Vec2(-1.7, 0.2), new Vec2(-1.8, 0.1), new Vec2(-1.8, -0.1), - new Vec2(-1.7, -0.2) + new Vec2(-1.7, -0.2), ]); fullPaddleShape.paddleWidth = 3.6; - let miniPaddleShape = new Polygon([ + const miniPaddleShape = new Polygon([ new Vec2(1.2, -0.1), new Vec2(1.2, 0.1), new Vec2(0.9, 0.4), @@ -282,34 +288,32 @@ function Physics() { new Vec2(-0.2, 0.6), new Vec2(-0.9, 0.4), new Vec2(-1.2, 0.1), - new Vec2(-1.2, -0.1) + new Vec2(-1.2, -0.1), ]); miniPaddleShape.paddleWidth = 2.4; - world.on('pre-solve', function(contact) { - let fA = contact.getFixtureA(), bA = fA.getBody(); - let fB = contact.getFixtureB(), bB = fB.getBody(); + world.on("pre-solve", function (contact) { + const fA = contact.getFixtureA(), + bA = fA.getBody(); + const fB = contact.getFixtureB(), + bB = fB.getBody(); - let ball = bA.isBall && bA || bB.isBall && bB; - let brick = bA.isBrick && bA || bB.isBrick && bB; - let bottom = bA.isBottom && bA || bB.isBottom && bB; - let paddle = bA.isPaddle && bA || bB.isPaddle && bB; - let drop = bA.isDrop && bA || bB.isDrop && bB; + const ball = (bA.isBall && bA) || (bB.isBall && bB); + const brick = (bA.isBrick && bA) || (bB.isBrick && bB); + const bottom = (bA.isBottom && bA) || (bB.isBottom && bB); + const paddle = (bA.isPaddle && bA) || (bB.isPaddle && bB); + const drop = (bA.isDrop && bA) || (bB.isDrop && bB); // do not change world immediately - setTimeout(function() { + setTimeout(function () { if (ball && brick) { state.hitBrick(brick.getUserData()); - } else if (ball && bottom) { state.missBall(ball.getUserData()); - } else if (ball && paddle) { state.hitBall(ball.getUserData()); - } else if (drop && paddle) { state.catchDrop(drop.getUserData()); - } else if (drop && bottom) { state.missDrop(drop.getUserData()); } @@ -317,24 +321,31 @@ function Physics() { }); function createWorld() { - - world.createBody(new Vec2(+9, -0.5)) + world + .createBody(new Vec2(+9, -0.5)) .createFixture(new Edge(new Vec2(0, -12.5), new Vec2(0, +11.5)), wallFix); - world.createBody(new Vec2(-9, -0.5)) + world + .createBody(new Vec2(-9, -0.5)) .createFixture(new Edge(new Vec2(0, -12.5), new Vec2(0, +11.5)), wallFix); - world.createBody(new Vec2(0, +12)) + world + .createBody(new Vec2(0, +12)) .createFixture(new Edge(new Vec2(-8, 0), new Vec2(+8, 0)), wallFix); - world.createBody(new Vec2(9, 12)) + world + .createBody(new Vec2(9, 12)) .createFixture(new Edge(new Vec2(-1, 0), new Vec2(0, -1)), wallFix); - world.createBody(new Vec2(-9, 12)) + world + .createBody(new Vec2(-9, 12)) .createFixture(new Edge(new Vec2(1, 0), new Vec2(0, -1)), wallFix); bottomWall = world.createBody(new Vec2(0, -13)); - bottomWall.createFixture(new Edge(new Vec2(-9, 0), new Vec2(+9, 0)), wallFix); + bottomWall.createFixture( + new Edge(new Vec2(-9, 0), new Vec2(+9, 0)), + wallFix + ); bottomWall.isBottom = true; } @@ -347,7 +358,7 @@ function Physics() { } paddle = world.createKinematicBody({ - position: new Vec2(0, -10.5) + position: new Vec2(0, -10.5), }); paddle.paddleWidth = shape.paddleWidth; paddle.createFixture(shape, paddleFix); @@ -358,10 +369,10 @@ function Physics() { } function createBall(pos) { - let body = world.createDynamicBody({ + const body = world.createDynamicBody({ bullet: true, angle: Math.random() * Math.PI * 2, - position: pos + position: pos, }); body.createFixture(ballShape, ballFix); body.isBall = true; @@ -370,7 +381,7 @@ function Physics() { } function createBrick(shape, pos) { - let body = world.createBody(pos); + const body = world.createBody(pos); body.createFixture(shape, brickFix); body.isBrick = true; bricks.push(body); @@ -378,11 +389,11 @@ function Physics() { } function createDrop(type) { - let body = world.createDynamicBody(); - if (type == '+') { + const body = world.createDynamicBody(); + if (type == "+") { body.createFixture(new Box(0.08, 0.32), dropFix); body.createFixture(new Box(0.32, 0.08), dropFix); - } else if (type == '-') { + } else if (type == "-") { body.createFixture(new Box(0.3, 0.1), dropFix); } else { body.createFixture(new Circle(0.3), dropFix); @@ -392,44 +403,44 @@ function Physics() { return body; } - this.removeDrop = function(drop) { + this.removeDrop = function (drop) { if (!removeFromArray(drops, drop.body)) return; world.destroyBody(drop.body); }; - this.removeBrick = function(brick) { + this.removeBrick = function (brick) { if (!removeFromArray(bricks, brick.body)) return; world.destroyBody(brick.body); }; - this.removeBall = function(ball) { + this.removeBall = function (ball) { if (!removeFromArray(balls, ball.body)) return; world.destroyBody(ball.body); }; - this.updateBrick = function(brick) { + this.updateBrick = function (brick) { brick.body.setPosition(new Vec2((brick.i - 3) * 2, 9 - brick.j * 2)); }; - this.addBrick = function(brick) { - let shape = brick.type == 'small' ? smallBrickShape : normalBrickShape; - let pos = new Vec2((brick.i - 3) * 2, 9 - brick.j * 2); - let body = brick.body = createBrick(shape, pos); + this.addBrick = function (brick) { + const shape = brick.type == "small" ? smallBrickShape : normalBrickShape; + const pos = new Vec2((brick.i - 3) * 2, 9 - brick.j * 2); + const body = (brick.body = createBrick(shape, pos)); body.setUserData(brick); }; - this.addDrop = function(drop) { - let body = drop.body = createDrop(drop.type); + this.addDrop = function (drop) { + const body = (drop.body = createDrop(drop.type)); body.setUserData(drop); body.setPosition(new Vec2((drop.i - 3) * 2, 9 - drop.j * 2)); body.setLinearVelocity(new Vec2(0, drop.speed)); }; - this.addBall = function(ball) { - let body = ball.body = createBall(); + this.addBall = function (ball) { + const body = (ball.body = createBall()); body.setUserData(ball); - let oldball = balls[0]; + const oldball = balls[0]; if (oldball) { body.setPosition(oldball.getPosition()); body.setLinearVelocity(Vec2.neg(oldball.getLinearVelocity())); @@ -438,45 +449,47 @@ function Physics() { } }; - this.miniPaddle = function() { + this.miniPaddle = function () { createPaddle(miniPaddleShape); }; - this.fullPaddle = function() { + this.fullPaddle = function () { createPaddle(fullPaddleShape); }; - this.movePaddle = function(dir) { + this.movePaddle = function (dir) { let p = paddle.getPosition(); p = new Vec2(dir, 0).add(p); - p.x = Math.min(9 - paddle.paddleWidth / 2, Math.max(-(9 - paddle.paddleWidth / 2), p.x)); + p.x = Math.min( + 9 - paddle.paddleWidth / 2, + Math.max(-(9 - paddle.paddleWidth / 2), p.x) + ); paddle.setPosition(p); }; - this.tick = function(t) { - }; + this.tick = function (t) {}; - this.endGame = function() { + this.endGame = function () { world.destroyBody(paddle); }; - this.startGame = function() { - let ball = balls[0]; - let a = Math.PI * Math.random() * 0.4 - 0.2; - let speed = ball.getUserData().speed; + this.startGame = function () { + const ball = balls[0]; + const a = Math.PI * Math.random() * 0.4 - 0.2; + const speed = ball.getUserData().speed; ball.setLinearVelocity(new Vec2(speed * Math.sin(a), speed * Math.cos(a))); }; - this.initGame = function() { - balls.forEach(function(body) { + this.initGame = function () { + balls.forEach(function (body) { world.destroyBody(body); }); - bricks.forEach(function(body) { + bricks.forEach(function (body) { world.destroyBody(body); }); - drops.forEach(function(body) { + drops.forEach(function (body) { world.destroyBody(body); }); createPaddle(fullPaddleShape); @@ -488,7 +501,7 @@ function Physics() { state.initGame(); function removeFromArray(array, item) { - let i = array.indexOf(item); + const i = array.indexOf(item); if (i == -1) { return false; } else { diff --git a/example/Bridge.js b/example/Bridge.ts similarity index 73% rename from example/Bridge.js rename to example/Bridge.ts index 6fd9e49e..6b2bd707 100644 --- a/example/Bridge.js +++ b/example/Bridge.ts @@ -2,26 +2,28 @@ * MIT License * Copyright (c) 2019 Erin Catto */ +import planck from "../src/main"; -const { Vec2, World, Edge, Box, Polygon, Circle, RevoluteJoint, Testbed } = planck; +const { Vec2, World, Edge, Box, Polygon, Circle, RevoluteJoint, Testbed } = + planck; -let world = new World(new Vec2(0, -4)); +const world = new World(new Vec2(0, -4)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 30; +const COUNT = 30; -let middle; +let middle: planck.Body; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let bridgeRect = new Box(0.5, 0.125); +const bridgeRect = new Box(0.5, 0.125); -let bridgeFD = { +const bridgeFD = { density: 20.0, - friction: 0.2 + friction: 0.2, }; let prevBody = ground; @@ -44,11 +46,15 @@ world.createJoint(new RevoluteJoint({}, prevBody, ground, anchor)); for (let i = 0; i < 2; ++i) { const body = world.createDynamicBody(new Vec2(-8.0 + 8.0 * i, 12.0)); - let vertices = [new Vec2(-0.5, 0.0), new Vec2(0.5, 0.0), new Vec2(0.0, 1.5)]; + const vertices = [ + new Vec2(-0.5, 0.0), + new Vec2(0.5, 0.0), + new Vec2(0.0, 1.5), + ]; body.createFixture(new Polygon(vertices), 1.0); } -let shape = new Circle(0.5); +const shape = new Circle(0.5); for (let i = 0; i < 3; ++i) { const body = world.createDynamicBody(new Vec2(-6.0 + 6.0 * i, 10.0)); body.createFixture(shape, 1.0); diff --git a/example/BulletTest.js b/example/BulletTest.ts similarity index 91% rename from example/BulletTest.js rename to example/BulletTest.ts index dcd7b547..da014c93 100644 --- a/example/BulletTest.js +++ b/example/BulletTest.ts @@ -20,26 +20,27 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { World, Vec2, Edge, Box, stats, Testbed } = planck; -let world = new World(new Vec2(0, -10)); - +const world = new World(new Vec2(0, -10)); + const testbed = Testbed.mount(); testbed.start(world); -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-10.0, 0.0), new Vec2(10.0, 0.0)), 0.0); ground.createFixture(new Box(0.2, 1.0, new Vec2(0.5, 1.0), 0.0), 0.0); -let body = world.createDynamicBody(new Vec2(0.0, 4.0)); +const body = world.createDynamicBody(new Vec2(0.0, 4.0)); body.createFixture(new Box(2.0, 0.1), 1.0); // x = Math.random(-1.0, 1.0); let x = 0.20352793; -let bullet = world.createBody({ - type: 'dynamic', +const bullet = world.createBody({ + type: "dynamic", position: new Vec2(x, 10.0), bullet: true, }); @@ -69,7 +70,7 @@ function Launch() { } let stepCount = 0; -testbed.step = function() { +testbed.step = function () { testbed.status(stats); // if (stats.gjkCalls > 0) { diff --git a/example/Cantilever.js b/example/Cantilever.ts similarity index 72% rename from example/Cantilever.js rename to example/Cantilever.ts index c7fef0f8..6b803133 100644 --- a/example/Cantilever.js +++ b/example/Cantilever.ts @@ -28,14 +28,14 @@ const { World, Vec2, Edge, Box, WeldJoint, Polygon, Circle, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 8; +const COUNT = 8; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); { let prevBody = ground; @@ -52,14 +52,21 @@ ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); { let prevBody = ground; for (let i = 0; i < 3; ++i) { - let body = world.createDynamicBody(new Vec2(-14.0 + 2.0 * i, 15.0)); + const body = world.createDynamicBody(new Vec2(-14.0 + 2.0 * i, 15.0)); body.createFixture(new Box(1.0, 0.125), 20.0); - let anchor = new Vec2(-15.0 + 2.0 * i, 15.0); - world.createJoint(new WeldJoint({ - frequencyHz: 5.0, - dampingRatio: 0.7, - }, prevBody, body, anchor)); + const anchor = new Vec2(-15.0 + 2.0 * i, 15.0); + world.createJoint( + new WeldJoint( + { + frequencyHz: 5.0, + dampingRatio: 0.7, + }, + prevBody, + body, + anchor + ) + ); prevBody = body; } @@ -67,11 +74,11 @@ ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); { let prevBody = ground; for (let i = 0; i < COUNT; ++i) { - let body = world.createDynamicBody(new Vec2(-4.5 + 1.0 * i, 5.0)); + const body = world.createDynamicBody(new Vec2(-4.5 + 1.0 * i, 5.0)); body.createFixture(new Box(0.5, 0.125), 20.0); if (i > 0) { - let anchor = new Vec2(-5.0 + 1.0 * i, 5.0); + const anchor = new Vec2(-5.0 + 1.0 * i, 5.0); world.createJoint(new WeldJoint({}, prevBody, body, anchor)); } @@ -81,15 +88,22 @@ ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); { let prevBody = ground; for (let i = 0; i < COUNT; ++i) { - let body = world.createDynamicBody(new Vec2(5.5 + 1.0 * i, 10.0)); + const body = world.createDynamicBody(new Vec2(5.5 + 1.0 * i, 10.0)); body.createFixture(new Box(0.5, 0.125), 20.0); if (i > 0) { - let anchor = new Vec2(5.0 + 1.0 * i, 10.0); - world.createJoint(new WeldJoint({ - frequencyHz: 8.0, - dampingRatio: 0.7, - }, prevBody, body, anchor)); + const anchor = new Vec2(5.0 + 1.0 * i, 10.0); + world.createJoint( + new WeldJoint( + { + frequencyHz: 8.0, + dampingRatio: 0.7, + }, + prevBody, + body, + anchor + ) + ); } prevBody = body; @@ -97,17 +111,17 @@ ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); } { for (let i = 0; i < 2; ++i) { - let vertices = []; + const vertices = []; vertices[0] = new Vec2(-0.5, 0.0); vertices[1] = new Vec2(0.5, 0.0); vertices[2] = new Vec2(0.0, 1.5); - let body = world.createDynamicBody(new Vec2(-8.0 + 8.0 * i, 12.0)); + const body = world.createDynamicBody(new Vec2(-8.0 + 8.0 * i, 12.0)); body.createFixture(new Polygon(vertices), 1.0); } for (let i = 0; i < 2; ++i) { - let body = world.createDynamicBody(new Vec2(-6.0 + 6.0 * i, 10.0)); + const body = world.createDynamicBody(new Vec2(-6.0 + 6.0 * i, 10.0)); body.createFixture(new Circle(0.5), 1.0); } -} \ No newline at end of file +} diff --git a/example/Car.js b/example/Car.js deleted file mode 100644 index f0865ef1..00000000 --- a/example/Car.js +++ /dev/null @@ -1,209 +0,0 @@ -/* - * MIT License - * Copyright (c) 2019 Erin Catto - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -// This is a fun demo that shows off the wheel joint - -const { World, Vec2, Edge, Box, Circle, Polygon, RevoluteJoint, WheelJoint, Testbed } = planck; - -const testbed = Testbed.mount(); - -let world = new World({ - gravity : new Vec2(0, -10) -}); - -testbed.speed = 1.3; -testbed.hz = 50; -testbed.info('←/→: Accelerate car, ↑/↓: Change spring frequency'); -testbed.start(world); - -// wheel spring settings -let HZ = 4.0; -let ZETA = 0.7; -let SPEED = 50.0; - -let ground = world.createBody(); - -let groundFD = { - density : 0.0, - friction : 0.6 -}; - -ground.createFixture(new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0)), groundFD); - -let hs = [ 0.25, 1.0, 4.0, 0.0, 0.0, -1.0, -2.0, -2.0, -1.25, 0.0 ]; - -let x = 20.0, y1 = 0.0, dx = 5.0; - -for (let i = 0; i < 10; ++i) { - let y2 = hs[i]; - ground.createFixture(new Edge(new Vec2(x, y1), new Vec2(x + dx, y2)), groundFD); - y1 = y2; - x += dx; -} - -for (let i = 0; i < 10; ++i) { - let y2 = hs[i]; - ground.createFixture(new Edge(new Vec2(x, y1), new Vec2(x + dx, y2)), groundFD); - y1 = y2; - x += dx; -} - -ground.createFixture(new Edge(new Vec2(x, 0.0), new Vec2(x + 40.0, 0.0)), groundFD); - -x += 80.0; -ground.createFixture(new Edge(new Vec2(x, 0.0), new Vec2(x + 40.0, 0.0)), groundFD); - -x += 40.0; -ground.createFixture(new Edge(new Vec2(x, 0.0), new Vec2(x + 10.0, 5.0)), groundFD); - -x += 20.0; -ground.createFixture(new Edge(new Vec2(x, 0.0), new Vec2(x + 40.0, 0.0)), groundFD); - -x += 40.0; -ground.createFixture(new Edge(new Vec2(x, 0.0), new Vec2(x, 20.0)), groundFD); - -// Teeter -let teeter = world.createDynamicBody(new Vec2(140.0, 1.0)); -teeter.createFixture(new Box(10.0, 0.25), 1.0); -world.createJoint(new RevoluteJoint({ - lowerAngle : -8.0 * Math.PI / 180.0, - upperAngle : 8.0 * Math.PI / 180.0, - enableLimit : true -}, ground, teeter, teeter.getPosition())); - -teeter.applyAngularImpulse(100.0, true); - -// Bridge -let bridgeFD = { - density : 1.0, - friction : 0.6 -}; - -let prevBody = ground; -let i; -for (i = 0; i < 20; ++i) { - let bridgeBlock = world.createDynamicBody(new Vec2(161.0 + 2.0 * i, -0.125)); - bridgeBlock.createFixture(new Box(1.0, 0.125), bridgeFD); - - world.createJoint(new RevoluteJoint({}, prevBody, bridgeBlock, new Vec2(160.0 + 2.0 * i, -0.125))); - - prevBody = bridgeBlock; -} - -world.createJoint(new RevoluteJoint({}, prevBody, ground, new Vec2(160.0 + 2.0 * i, -0.125))); - -// Boxes -let box = new Box(0.5, 0.5); - -world.createDynamicBody(new Vec2(230.0, 0.5)) - .createFixture(box, 0.5); - -world.createDynamicBody(new Vec2(230.0, 1.5)) - .createFixture(box, 0.5); - -world.createDynamicBody(new Vec2(230.0, 2.5)) - .createFixture(box, 0.5); - -world.createDynamicBody(new Vec2(230.0, 3.5)) - .createFixture(box, 0.5); - -world.createDynamicBody(new Vec2(230.0, 4.5)) - .createFixture(box, 0.5); - -// Car -let car = world.createDynamicBody(new Vec2(0.0, 1.0)); -car.createFixture(new Polygon([ - new Vec2(-1.5, -0.5), - new Vec2(1.5, -0.5), - new Vec2(1.5, 0.0), - new Vec2(0.0, 0.9), - new Vec2(-1.15, 0.9), - new Vec2(-1.5, 0.2) -]), 1.0); - -let wheelFD = { - density : 1.0, - friction : 0.9 -}; - -let wheelBack = world.createDynamicBody(new Vec2(-1.0, 0.35)); -wheelBack.createFixture(new Circle(0.4), wheelFD); - -let wheelFront = world.createDynamicBody(new Vec2(1.0, 0.4)); -wheelFront.createFixture(new Circle(0.4), wheelFD); - -let springBack = world.createJoint(new WheelJoint({ - motorSpeed : 0.0, - maxMotorTorque : 20.0, - enableMotor : true, - frequencyHz : HZ, - dampingRatio : ZETA -}, car, wheelBack, wheelBack.getPosition(), new Vec2(0.0, 1.0))); - -let springFront = world.createJoint(new WheelJoint({ - motorSpeed : 0.0, - maxMotorTorque : 10.0, - enableMotor : false, - frequencyHz : HZ, - dampingRatio : ZETA -}, car, wheelFront, wheelFront.getPosition(), new Vec2(0.0, 1.0))); - -testbed.keydown = function() { - if (testbed.activeKeys.down) { - HZ = Math.max(0.0, HZ - 1.0); - springBack.setSpringFrequencyHz(HZ); - springFront.setSpringFrequencyHz(HZ); - - } else if (testbed.activeKeys.up) { - HZ += 1.0; - springBack.setSpringFrequencyHz(HZ); - springFront.setSpringFrequencyHz(HZ); - } -}; - -testbed.step = function() { - if (testbed.activeKeys.right && testbed.activeKeys.left) { - springBack.setMotorSpeed(0); - springBack.enableMotor(true); - - } else if (testbed.activeKeys.right) { - springBack.setMotorSpeed(-SPEED); - springBack.enableMotor(true); - - } else if (testbed.activeKeys.left) { - springBack.setMotorSpeed(+SPEED); - springBack.enableMotor(true); - - } else { - springBack.setMotorSpeed(0); - springBack.enableMotor(false); - } - - let cp = car.getPosition(); - if (cp.x > testbed.x + 10) { - testbed.x = cp.x - 10; - - } else if (cp.x < testbed.x - 10) { - testbed.x = cp.x + 10; - } -}; diff --git a/example/Car.ts b/example/Car.ts new file mode 100644 index 00000000..f8ebba24 --- /dev/null +++ b/example/Car.ts @@ -0,0 +1,271 @@ +/* + * MIT License + * Copyright (c) 2019 Erin Catto + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// This is a fun demo that shows off the wheel joint + +import planck from "../src/main"; + +const { + World, + Vec2, + Edge, + Box, + Circle, + Polygon, + RevoluteJoint, + WheelJoint, + Testbed, +} = planck; + +const testbed = Testbed.mount(); + +const world = new World({ + gravity: new Vec2(0, -10), +}); + +testbed.speed = 1.3; +testbed.hz = 50; +testbed.info("←/→: Accelerate car, ↑/↓: Change spring frequency"); +testbed.start(world); + +// wheel spring settings +let HZ = 4.0; +const ZETA = 0.7; +const SPEED = 50.0; + +const ground = world.createBody(); + +const groundFD = { + density: 0.0, + friction: 0.6, +}; + +ground.createFixture( + new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0)), + groundFD +); + +const hs = [0.25, 1.0, 4.0, 0.0, 0.0, -1.0, -2.0, -2.0, -1.25, 0.0]; + +let x = 20.0, + y1 = 0.0; +const dx = 5.0; + +for (let i = 0; i < 10; ++i) { + const y2 = hs[i]; + ground.createFixture( + new Edge(new Vec2(x, y1), new Vec2(x + dx, y2)), + groundFD + ); + y1 = y2; + x += dx; +} + +for (let i = 0; i < 10; ++i) { + const y2 = hs[i]; + ground.createFixture( + new Edge(new Vec2(x, y1), new Vec2(x + dx, y2)), + groundFD + ); + y1 = y2; + x += dx; +} + +ground.createFixture( + new Edge(new Vec2(x, 0.0), new Vec2(x + 40.0, 0.0)), + groundFD +); + +x += 80.0; +ground.createFixture( + new Edge(new Vec2(x, 0.0), new Vec2(x + 40.0, 0.0)), + groundFD +); + +x += 40.0; +ground.createFixture( + new Edge(new Vec2(x, 0.0), new Vec2(x + 10.0, 5.0)), + groundFD +); + +x += 20.0; +ground.createFixture( + new Edge(new Vec2(x, 0.0), new Vec2(x + 40.0, 0.0)), + groundFD +); + +x += 40.0; +ground.createFixture(new Edge(new Vec2(x, 0.0), new Vec2(x, 20.0)), groundFD); + +// Teeter +const teeter = world.createDynamicBody(new Vec2(140.0, 1.0)); +teeter.createFixture(new Box(10.0, 0.25), 1.0); +world.createJoint( + new RevoluteJoint( + { + lowerAngle: (-8.0 * Math.PI) / 180.0, + upperAngle: (8.0 * Math.PI) / 180.0, + enableLimit: true, + }, + ground, + teeter, + teeter.getPosition() + ) +); + +teeter.applyAngularImpulse(100.0, true); + +// Bridge +const bridgeFD = { + density: 1.0, + friction: 0.6, +}; + +let prevBody = ground; +let i: number; +for (i = 0; i < 20; ++i) { + const bridgeBlock = world.createDynamicBody( + new Vec2(161.0 + 2.0 * i, -0.125) + ); + bridgeBlock.createFixture(new Box(1.0, 0.125), bridgeFD); + + world.createJoint( + new RevoluteJoint( + {}, + prevBody, + bridgeBlock, + new Vec2(160.0 + 2.0 * i, -0.125) + ) + ); + + prevBody = bridgeBlock; +} + +world.createJoint( + new RevoluteJoint({}, prevBody, ground, new Vec2(160.0 + 2.0 * i, -0.125)) +); + +// Boxes +const box = new Box(0.5, 0.5); + +world.createDynamicBody(new Vec2(230.0, 0.5)).createFixture(box, 0.5); + +world.createDynamicBody(new Vec2(230.0, 1.5)).createFixture(box, 0.5); + +world.createDynamicBody(new Vec2(230.0, 2.5)).createFixture(box, 0.5); + +world.createDynamicBody(new Vec2(230.0, 3.5)).createFixture(box, 0.5); + +world.createDynamicBody(new Vec2(230.0, 4.5)).createFixture(box, 0.5); + +// Car +const car = world.createDynamicBody(new Vec2(0.0, 1.0)); +car.createFixture( + new Polygon([ + new Vec2(-1.5, -0.5), + new Vec2(1.5, -0.5), + new Vec2(1.5, 0.0), + new Vec2(0.0, 0.9), + new Vec2(-1.15, 0.9), + new Vec2(-1.5, 0.2), + ]), + 1.0 +); + +const wheelFD = { + density: 1.0, + friction: 0.9, +}; + +const wheelBack = world.createDynamicBody(new Vec2(-1.0, 0.35)); +wheelBack.createFixture(new Circle(0.4), wheelFD); + +const wheelFront = world.createDynamicBody(new Vec2(1.0, 0.4)); +wheelFront.createFixture(new Circle(0.4), wheelFD); + +const springBack = world.createJoint( + new WheelJoint( + { + motorSpeed: 0.0, + maxMotorTorque: 20.0, + enableMotor: true, + frequencyHz: HZ, + dampingRatio: ZETA, + }, + car, + wheelBack, + wheelBack.getPosition(), + new Vec2(0.0, 1.0) + ) +); + +const springFront = world.createJoint( + new WheelJoint( + { + motorSpeed: 0.0, + maxMotorTorque: 10.0, + enableMotor: false, + frequencyHz: HZ, + dampingRatio: ZETA, + }, + car, + wheelFront, + wheelFront.getPosition(), + new Vec2(0.0, 1.0) + ) +); + +testbed.keydown = function () { + if (testbed.activeKeys.down) { + HZ = Math.max(0.0, HZ - 1.0); + springBack.setSpringFrequencyHz(HZ); + springFront.setSpringFrequencyHz(HZ); + } else if (testbed.activeKeys.up) { + HZ += 1.0; + springBack.setSpringFrequencyHz(HZ); + springFront.setSpringFrequencyHz(HZ); + } +}; + +testbed.step = function () { + if (testbed.activeKeys.right && testbed.activeKeys.left) { + springBack.setMotorSpeed(0); + springBack.enableMotor(true); + } else if (testbed.activeKeys.right) { + springBack.setMotorSpeed(-SPEED); + springBack.enableMotor(true); + } else if (testbed.activeKeys.left) { + springBack.setMotorSpeed(+SPEED); + springBack.enableMotor(true); + } else { + springBack.setMotorSpeed(0); + springBack.enableMotor(false); + } + + const cp = car.getPosition(); + if (cp.x > testbed.x + 10) { + testbed.x = cp.x - 10; + } else if (cp.x < testbed.x - 10) { + testbed.x = cp.x + 10; + } +}; diff --git a/example/Chain.js b/example/Chain.ts similarity index 78% rename from example/Chain.js rename to example/Chain.ts index e8e47ebb..249a4129 100644 --- a/example/Chain.js +++ b/example/Chain.ts @@ -20,32 +20,40 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { World, Vec2, Edge, Box, RevoluteJoint, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let shape = new Box(0.6, 0.125); +const shape = new Box(0.6, 0.125); -let y = 25.0; +const y = 25.0; let prevBody = ground; for (let i = 0; i < 30; ++i) { - let body = world.createDynamicBody(new Vec2(0.5 + i, y)); + const body = world.createDynamicBody(new Vec2(0.5 + i, y)); body.createFixture(shape, { density: 20.0, friction: 0.2, }); - let anchor = new Vec2(i, y); - world.createJoint(new RevoluteJoint({ - collideConnected: false, - }, prevBody, body, anchor)); + const anchor = new Vec2(i, y); + world.createJoint( + new RevoluteJoint( + { + collideConnected: false, + }, + prevBody, + body, + anchor + ) + ); prevBody = body; } diff --git a/example/CharacterCollision.js b/example/CharacterCollision.ts similarity index 64% rename from example/CharacterCollision.js rename to example/CharacterCollision.ts index b2278881..f93f376d 100644 --- a/example/CharacterCollision.js +++ b/example/CharacterCollision.ts @@ -24,10 +24,11 @@ // This is a test of typical character collision scenarios. This does not // show how you should implement a character in your application. // Instead this is used to test smooth collision on edge chains. +import planck from "../src/main"; const { World, Vec2, Edge, Chain, Box, Polygon, Circle, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.info(` @@ -38,87 +39,102 @@ testbed.info(` testbed.start(world); // Ground body -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0)), 0.0); // Collinear edges with no adjacency information. // This shows the problematic case where a box shape can hit // an internal vertex. -let edge = world.createBody(); +const edge = world.createBody(); edge.createFixture(new Edge(new Vec2(-8.0, 1.0), new Vec2(-6.0, 1.0)), 0.0); edge.createFixture(new Edge(new Vec2(-6.0, 1.0), new Vec2(-4.0, 1.0)), 0.0); edge.createFixture(new Edge(new Vec2(-4.0, 1.0), new Vec2(-2.0, 1.0)), 0.0); // Chain shape -let chain = world.createBody(new Vec2(), 0.25 * Math.PI); -chain.createFixture(new Chain([ - new Vec2(5.0, 7.0), - new Vec2(6.0, 8.0), - new Vec2(7.0, 8.0), - new Vec2(8.0, 7.0) -]), 0.0); +const chain = world.createBody(new Vec2(), 0.25 * Math.PI); +chain.createFixture( + new Chain([ + new Vec2(5.0, 7.0), + new Vec2(6.0, 8.0), + new Vec2(7.0, 8.0), + new Vec2(8.0, 7.0), + ]), + 0.0 +); // Square tiles. This shows that adjacency shapes may // have non-smooth collision. There is no solution // to this problem. -let tiles = world.createBody(); +const tiles = world.createBody(); tiles.createFixture(new Box(1.0, 1.0, new Vec2(4.0, 3.0), 0.0), 0.0); tiles.createFixture(new Box(1.0, 1.0, new Vec2(6.0, 3.0), 0.0), 0.0); tiles.createFixture(new Box(1.0, 1.0, new Vec2(8.0, 3.0), 0.0), 0.0); // Square made from an edge loop. Collision should be smooth. -let square = world.createBody(); -square.createFixture(new Chain([ - new Vec2(-1.0, 3.0), - new Vec2(1.0, 3.0), - new Vec2(1.0, 5.0), - new Vec2(-1.0, 5.0) -], true), 0.0); +const square = world.createBody(); +square.createFixture( + new Chain( + [ + new Vec2(-1.0, 3.0), + new Vec2(1.0, 3.0), + new Vec2(1.0, 5.0), + new Vec2(-1.0, 5.0), + ], + true + ), + 0.0 +); // Edge loop. Collision should be smooth. -let loop = world.createBody(new Vec2(-10.0, 4.0)); -loop.createFixture(new Chain([ - new Vec2(0.0, 0.0), - new Vec2(6.0, 0.0), - new Vec2(6.0, 2.0), - new Vec2(4.0, 1.0), - new Vec2(2.0, 2.0), - new Vec2(0.0, 2.0), - new Vec2(-2.0, 2.0), - new Vec2(-4.0, 3.0), - new Vec2(-6.0, 2.0), - new Vec2(-6.0, 0.0) -], true), 0.0); +const loop = world.createBody(new Vec2(-10.0, 4.0)); +loop.createFixture( + new Chain( + [ + new Vec2(0.0, 0.0), + new Vec2(6.0, 0.0), + new Vec2(6.0, 2.0), + new Vec2(4.0, 1.0), + new Vec2(2.0, 2.0), + new Vec2(0.0, 2.0), + new Vec2(-2.0, 2.0), + new Vec2(-4.0, 3.0), + new Vec2(-6.0, 2.0), + new Vec2(-6.0, 0.0), + ], + true + ), + 0.0 +); // Square character 1 -let char1 = world.createBody({ - position : new Vec2(-3.0, 8.0), - type : 'dynamic', - fixedRotation : true, - allowSleep : false +const char1 = world.createBody({ + position: new Vec2(-3.0, 8.0), + type: "dynamic", + fixedRotation: true, + allowSleep: false, }); char1.createFixture(new Box(0.5, 0.5), 20.0); // Square character 2 -let char2 = world.createBody({ - position : new Vec2(-5.0, 5.0), - type : 'dynamic', - fixedRotation : true, - allowSleep : false +const char2 = world.createBody({ + position: new Vec2(-5.0, 5.0), + type: "dynamic", + fixedRotation: true, + allowSleep: false, }); char2.createFixture(new Box(0.25, 0.25), 20.0); // Hexagon character -let hex = world.createBody({ - position : new Vec2(-5.0, 8.0), - type : 'dynamic', - fixedRotation : true, - allowSleep : false +const hex = world.createBody({ + position: new Vec2(-5.0, 8.0), + type: "dynamic", + fixedRotation: true, + allowSleep: false, }); let angle = 0.0; -let delta = Math.PI / 3.0; -let vertices = []; +const delta = Math.PI / 3.0; +const vertices = []; for (let i = 0; i < 6; ++i) { vertices[i] = new Vec2(0.5 * Math.cos(angle), 0.5 * Math.sin(angle)); angle += delta; @@ -127,27 +143,27 @@ for (let i = 0; i < 6; ++i) { hex.createFixture(new Polygon(vertices), 20.0); // Circle character -let circle = world.createBody({ - position : new Vec2(3.0, 5.0), - type : 'dynamic', - fixedRotation : true, - allowSleep : false +const circle = world.createBody({ + position: new Vec2(3.0, 5.0), + type: "dynamic", + fixedRotation: true, + allowSleep: false, }); circle.createFixture(new Circle(0.5), 20.0); // Circle character -let character = world.createBody({ - position : new Vec2(-7.0, 6.0), - type : 'dynamic', - allowSleep : false +const character = world.createBody({ + position: new Vec2(-7.0, 6.0), + type: "dynamic", + allowSleep: false, }); character.createFixture(new Circle(0.25), { - density : 20.0, - friction : 1.0 + density: 20.0, + friction: 1.0, }); -testbed.step = function() { - let v = character.getLinearVelocity(); +testbed.step = function () { + const v = character.getLinearVelocity(); v.x = -5.0; character.setLinearVelocity(v); }; diff --git a/example/CollisionFiltering.js b/example/CollisionFiltering.ts similarity index 64% rename from example/CollisionFiltering.js rename to example/CollisionFiltering.ts index 12170bd8..5ff0dca9 100644 --- a/example/CollisionFiltering.js +++ b/example/CollisionFiltering.ts @@ -27,28 +27,32 @@ // The 3 small ones always collide. // The 3 large ones never collide. // The boxes don't collide with triangles (except if both are small). +import planck from "../src/main"; -const { World, Vec2, Edge, Polygon, Box, Circle, PrismaticJoint, Testbed } = planck; +const { World, Vec2, Edge, Polygon, Box, Circle, PrismaticJoint, Testbed } = + planck; -let SMALL_GROUP = 1; -let LARGE_GROUP = -1; +const SMALL_GROUP = 1; +const LARGE_GROUP = -1; -let TRIANGLE_CATEGORY = 0x0002; -let BOX_Category = 0x0004; -let CIRCLE_CATEGORY = 0x0008; +const TRIANGLE_CATEGORY = 0x0002; +const BOX_Category = 0x0004; +const CIRCLE_CATEGORY = 0x0008; -let TRIANGLE_MASK = 0xFFFF; -let BOX_MASK = 0xFFFF ^ TRIANGLE_CATEGORY; -let CIRCLE_MAX = 0xFFFF; +const TRIANGLE_MASK = 0xffff; +const BOX_MASK = 0xffff ^ TRIANGLE_CATEGORY; +const CIRCLE_MAX = 0xffff; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); // Ground body -let ground = world.createBody(); -ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), {friction : 0.3}); +const ground = world.createBody(); +ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), { + friction: 0.3, +}); // Small triangle const smallTriangle = { @@ -58,15 +62,14 @@ const smallTriangle = { filterGroupIndex: SMALL_GROUP, }; -let body1 = world.createBody({ - type : 'dynamic', - position : new Vec2(-5.0, 2.0) +const body1 = world.createBody({ + type: "dynamic", + position: new Vec2(-5.0, 2.0), }); -body1.createFixture(new Polygon([ - new Vec2(-1.0, 0.0), - new Vec2(1.0, 0.0), - new Vec2(0.0, 2.0) -]), smallTriangle); +body1.createFixture( + new Polygon([new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 2.0)]), + smallTriangle +); // Large triangle (recycle definitions) const largeTriangle = { @@ -76,71 +79,77 @@ const largeTriangle = { filterGroupIndex: LARGE_GROUP, }; -let body2 = world.createBody({ - type : 'dynamic', - position : new Vec2(-5.0, 6.0), - fixedRotation : true // look at me! +const body2 = world.createBody({ + type: "dynamic", + position: new Vec2(-5.0, 6.0), + fixedRotation: true, // look at me! }); -body2.createFixture(new Polygon([ - new Vec2(-2.0, 0.0), - new Vec2(2.0, 0.0), - new Vec2(0.0, 4.0) -]), largeTriangle); +body2.createFixture( + new Polygon([new Vec2(-2.0, 0.0), new Vec2(2.0, 0.0), new Vec2(0.0, 4.0)]), + largeTriangle +); -let body = world.createDynamicBody(new Vec2(-5.0, 10.0)); +const body = world.createDynamicBody(new Vec2(-5.0, 10.0)); body.createFixture(new Box(0.5, 1.0), 1.0); -world.createJoint(new PrismaticJoint({ - enableLimit : true, - localAnchorA : new Vec2(0.0, 4.0), - localAnchorB : new Vec2(), - localAxisA : new Vec2(0.0, 1.0), - lowerTranslation : -1.0, - upperTranslation : 1.0 -}, body2, body)); +world.createJoint( + /// NEED TO FIX + new PrismaticJoint( + { + enableLimit: true, + localAnchorA: new Vec2(0.0, 4.0), + localAnchorB: new Vec2(), + localAxisA: new Vec2(0.0, 1.0), + lowerTranslation: -1.0, + upperTranslation: 1.0, + }, + body2, + body + ) +); // Small box const smallBox = { - density : 1.0, - restitution : 0.1, + density: 1.0, + restitution: 0.1, filterCategoryBits: BOX_Category, filterMaskBits: BOX_MASK, filterGroupIndex: SMALL_GROUP, }; -let body3 = world.createDynamicBody(new Vec2(0.0, 2.0)); +const body3 = world.createDynamicBody(new Vec2(0.0, 2.0)); body3.createFixture(new Box(1.0, 0.5), smallBox); // Large box (recycle definitions) const largeBox = { - density : 1.0, - restitution : 0.1, + density: 1.0, + restitution: 0.1, filterCategoryBits: BOX_Category, filterMaskBits: BOX_MASK, filterGroupIndex: LARGE_GROUP, }; -let body4 = world.createDynamicBody(new Vec2(0.0, 6.0)); +const body4 = world.createDynamicBody(new Vec2(0.0, 6.0)); body4.createFixture(new Box(2.0, 1.0), largeBox); // Small circle const smallCircle = { - density : 1.0, + density: 1.0, filterCategoryBits: CIRCLE_CATEGORY, filterMaskBits: CIRCLE_MAX, filterGroupIndex: SMALL_GROUP, }; -let body5 = world.createDynamicBody(new Vec2(5.0, 2.0)); +const body5 = world.createDynamicBody(new Vec2(5.0, 2.0)); body5.createFixture(new Circle(1.0), smallCircle); // Large circle const largeCircle = { - density : 1.0, + density: 1.0, filterCategoryBits: CIRCLE_CATEGORY, filterMaskBits: CIRCLE_MAX, filterGroupIndex: LARGE_GROUP, }; -let body6 = world.createDynamicBody(new Vec2(5.0, 6.0)); +const body6 = world.createDynamicBody(new Vec2(5.0, 6.0)); body6.createFixture(new Circle(2.0), largeCircle); diff --git a/example/CollisionProcessing.js b/example/CollisionProcessing.ts similarity index 63% rename from example/CollisionProcessing.js rename to example/CollisionProcessing.ts index 2be2ed1a..b7acfd31 100644 --- a/example/CollisionProcessing.js +++ b/example/CollisionProcessing.ts @@ -21,61 +21,85 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Edge, Polygon, Box, Circle, Math, Testbed } = planck; // This test shows collision processing and tests // deferred body destruction. -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); // Ground body -world.createBody().createFixture(new Edge(new Vec2(-50.0, 0.0), new Vec2(50.0, 0.0))); +world + .createBody() + .createFixture(new Edge(new Vec2(-50.0, 0.0), new Vec2(50.0, 0.0))); -let xLo = -5.0, xHi = 5.0; -let yLo = 2.0, yHi = 35.0; +const xLo = -5.0, + xHi = 5.0; +const yLo = 2.0, + yHi = 35.0; // Small triangle -let body1 = world.createDynamicBody(new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi))); -body1.createFixture(new Polygon([new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 2.0)]), 1.0); +const body1 = world.createDynamicBody( + new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi)) +); +body1.createFixture( + new Polygon([new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 2.0)]), + 1.0 +); // Large triangle (recycle definitions) -let body2 = world.createDynamicBody(new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi))); -body2.createFixture(new Polygon([new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 2.0)]), 1.0); +const body2 = world.createDynamicBody( + new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi)) +); +body2.createFixture( + new Polygon([new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 2.0)]), + 1.0 +); // Small box -let body3 = world.createDynamicBody(new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi))); +const body3 = world.createDynamicBody( + new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi)) +); body3.createFixture(new Box(1.0, 0.5), 1.0); // Large box (recycle definitions) -let body4 = world.createDynamicBody(new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi))); +const body4 = world.createDynamicBody( + new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi)) +); body4.createFixture(new Box(2.0, 1.0), 1.0); // Small circle -let body5 = world.createDynamicBody(new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi))); +const body5 = world.createDynamicBody( + new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi)) +); body5.createFixture(new Circle(1.0), 1.0); // Large circle -let body6 = world.createDynamicBody(new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi))); +const body6 = world.createDynamicBody( + new Vec2(Math.random(xLo, xHi), Math.random(yLo, yHi)) +); body6.createFixture(new Circle(2.0), 1.0); -let points = []; +const points: any[] = []; -world.on('pre-solve', function(contact, oldManifold) { - let manifold = contact.getManifold(); +world.on("pre-solve", function (contact, oldManifold) { + const manifold = contact.getManifold(); if (manifold.pointCount == 0) { return; } - let fixtureA = contact.getFixtureA(); - let fixtureB = contact.getFixtureB(); + const fixtureA = contact.getFixtureA(); + const fixtureB = contact.getFixtureB(); - let worldManifold = contact.getWorldManifold(); + const worldManifold = contact.getWorldManifold(null); for (let i = 0; i < manifold.pointCount; ++i) { - let cp = {}; + const cp: any = {}; cp.fixtureA = fixtureA; cp.fixtureB = fixtureB; cp.position = worldManifold.points[i]; @@ -88,25 +112,24 @@ world.on('pre-solve', function(contact, oldManifold) { } }); -let bomb = null; -let MAX_NUKE = 6; - -testbed.step = function() { +const bomb = null; +const MAX_NUKE = 6; +testbed.step = function () { // We are going to destroy some bodies according to contact // points. We must buffer the bodies that should be destroyed // because they may belong to multiple contact points. - let nuke = []; + const nuke = []; // Traverse the contact results. Destroy bodies that // are touching heavier bodies. for (let i = 0; i < points.length && nuke.length < MAX_NUKE; ++i) { - let point = points[i]; + const point = points[i]; - let body1 = point.fixtureA.getBody(); - let body2 = point.fixtureB.getBody(); - let mass1 = body1.getMass(); - let mass2 = body2.getMass(); + const body1 = point.fixtureA.getBody(); + const body2 = point.fixtureB.getBody(); + const mass1 = body1.getMass(); + const mass2 = body2.getMass(); if (mass1 > 0.0 && mass2 > 0.0) { if (mass2 > mass1) { @@ -118,7 +141,7 @@ testbed.step = function() { } for (let i = 0; i < nuke.length; i++) { - let b = nuke[i]; + const b = nuke[i]; if (b != bomb) { world.destroyBody(b); } diff --git a/example/CompoundShapes.js b/example/CompoundShapes.ts similarity index 58% rename from example/CompoundShapes.js rename to example/CompoundShapes.ts index 8ac42b6b..cf2908ef 100644 --- a/example/CompoundShapes.js +++ b/example/CompoundShapes.ts @@ -22,34 +22,39 @@ */ // TODO_ERIN test joints on compounds. -const { World, Vec2, Transform, Math, Edge, Circle, Polygon, Box, Testbed } = planck; +import planck from "../src/main"; -let world = new World(new Vec2(0, -10)); +const { World, Vec2, Transform, Math, Edge, Circle, Polygon, Box, Testbed } = + planck; + +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -world.createBody(new Vec2(0.0, 0.0)).createFixture(new Edge(new Vec2(50.0, 0.0), new Vec2(-50.0, 0.0)), 0.0); +world + .createBody(new Vec2(0.0, 0.0)) + .createFixture(new Edge(new Vec2(50.0, 0.0), new Vec2(-50.0, 0.0)), 0.0); -let circle1 = new Circle(new Vec2(-0.5, 0.5), 0.5); -let circle2 = new Circle(new Vec2(0.5, 0.5), 0.5); +const circle1 = new Circle(new Vec2(-0.5, 0.5), 0.5); +const circle2 = new Circle(new Vec2(0.5, 0.5), 0.5); for (let i = 0; i < 10; ++i) { - let body = world.createDynamicBody({ - position : new Vec2(Math.random(-0.1, 0.1) + 5.0, 1.05 + 2.5 * i), - angle : Math.random(-Math.PI, Math.PI) + const body = world.createDynamicBody({ + position: new Vec2(Math.random(-0.1, 0.1) + 5.0, 1.05 + 2.5 * i), + angle: Math.random(-Math.PI, Math.PI), }); body.createFixture(circle1, 2.0); body.createFixture(circle2, 0.0); } -let polygon1 = new Box(0.25, 0.5); -let polygon2 = new Box(0.25, 0.5, new Vec2(0.0, -0.5), 0.5 * Math.PI); +const polygon1 = new Box(0.25, 0.5); +const polygon2 = new Box(0.25, 0.5, new Vec2(0.0, -0.5), 0.5 * Math.PI); for (let i = 0; i < 10; ++i) { - let body = world.createDynamicBody({ - position : new Vec2(Math.random(-0.1, 0.1) - 5.0, 1.05 + 2.5 * i), - angle : Math.random(-Math.PI, Math.PI) + const body = world.createDynamicBody({ + position: new Vec2(Math.random(-0.1, 0.1) - 5.0, 1.05 + 2.5 * i), + angle: Math.random(-Math.PI, Math.PI), }); body.createFixture(polygon1, 2.0); body.createFixture(polygon2, 2.0); @@ -59,36 +64,36 @@ const xf1 = new Transform(); xf1.q.set(0.3524 * Math.PI); xf1.p.set(xf1.q.getXAxis()); -let triangle1 = new Polygon([ - new Vec2(-1.0, 0.0), - new Vec2(1.0, 0.0), - new Vec2(0.0, 0.5) -].map(v => Transform.mul(xf1, v))); +const triangle1 = new Polygon( + [new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 0.5)].map( + (v: planck.Vec2) => Transform.mul(xf1, v) + ) +); const xf2 = new Transform(); xf2.q.set(-0.3524 * Math.PI); xf2.p.set(Vec2.neg(xf2.q.getXAxis())); -let triangle2 = new Polygon([ - new Vec2(-1.0, 0.0), - new Vec2(1.0, 0.0), - new Vec2(0.0, 0.5) -].map(v => Transform.mul(xf2, v))); +const triangle2 = new Polygon( + [new Vec2(-1.0, 0.0), new Vec2(1.0, 0.0), new Vec2(0.0, 0.5)].map( + (v: planck.Vec2) => Transform.mul(xf2, v) + ) +); for (let i = 0; i < 10; ++i) { - let body = world.createDynamicBody({ - position : new Vec2(Math.random(-0.1, 0.1), 2.05 + 2.5 * i), - angle : 0.0 + const body = world.createDynamicBody({ + position: new Vec2(Math.random(-0.1, 0.1), 2.05 + 2.5 * i), + angle: 0.0, }); body.createFixture(triangle1, 2.0); body.createFixture(triangle2, 2.0); } -let bottom = new Box(1.5, 0.15); -let left = new Box(0.15, 2.7, new Vec2(-1.45, 2.35), 0.2); -let right = new Box(0.15, 2.7, new Vec2(1.45, 2.35), -0.2); +const bottom = new Box(1.5, 0.15); +const left = new Box(0.15, 2.7, new Vec2(-1.45, 2.35), 0.2); +const right = new Box(0.15, 2.7, new Vec2(1.45, 2.35), -0.2); -let container = world.createBody(new Vec2(0.0, 2.0)); +const container = world.createBody(new Vec2(0.0, 2.0)); container.createFixture(bottom, 4.0); container.createFixture(left, 4.0); container.createFixture(right, 4.0); diff --git a/example/Confined.js b/example/Confined.ts similarity index 77% rename from example/Confined.js rename to example/Confined.ts index 97959d39..3d0a478a 100644 --- a/example/Confined.js +++ b/example/Confined.ts @@ -20,17 +20,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { World, Vec2, Edge, Circle, Testbed } = planck; -let world = new World(); +const world = new World(); const testbed = Testbed.mount(); testbed.start(world); -let e_columnCount = 0; -let e_rowCount = 0; -let ground = world.createBody(); +const e_columnCount = 0; +const e_rowCount = 0; +const ground = world.createBody(); // Floor ground.createFixture(new Edge(new Vec2(-10, 0), new Vec2(10, 0)), 0); @@ -44,38 +45,41 @@ ground.createFixture(new Edge(new Vec2(10, 0), new Vec2(10, 20)), 0); // Roof ground.createFixture(new Edge(new Vec2(-10, 20), new Vec2(10, 20)), 0); -let radius = 0.5; -let shape = new Circle(radius); +const radius = 0.5; +const shape = new Circle(radius); -let fd = { - density : 1.0, - friction : 0.1 +const fd = { + density: 1.0, + friction: 0.1, }; for (let j = 0; j < e_columnCount; ++j) { for (let i = 0; i < e_rowCount; ++i) { - let body = world.createDynamicBody(new Vec2(-10 + (2.1 * j + 1 + 0.01 * i) * radius, (2 * i + 1) * radius)); + const body = world.createDynamicBody( + new Vec2(-10 + (2.1 * j + 1 + 0.01 * i) * radius, (2 * i + 1) * radius) + ); body.createFixture(shape, fd); } } function CreateCircle() { - let body = world.createDynamicBody(new Vec2(Math.random() * 10 - 5, Math.random() * 10 + 5)); + const body = world.createDynamicBody( + new Vec2(Math.random() * 10 - 5, Math.random() * 10 + 5) + ); // bd.allowSleep = false; body.createFixture(new Circle(Math.random() * 2.5 + 0.5), { - density : 1.0, - friction : 0.0 + density: 1.0, + friction: 0.0, }); } -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { if (testbed.activeKeys.fire) { CreateCircle(); } }; -let stepCount = 0; -testbed.step = function() { +testbed.step = function () { let sleeping = true; for (let b = world.getBodyList(); b; b = b.getNext()) { if (b.isDynamic() && b.isAwake()) { @@ -92,12 +96,12 @@ testbed.step = function() { CreateCircle(); } - // for (let b = world.getBodyList(); b; b = b.getNext()) { + // for (const b = world.getBodyList(); b; b = b.getNext()) { // if (!b.isDynamic()) { // continue; // } // - // let p = b.getPosition(); + // const p = b.getPosition(); // if (p.x <= -10.0 || 10.0 <= p.x || p.y <= 0.0 || 20.0 <= p.y) { // // why? // p.x += 0.0; diff --git a/example/ContinuousTest.js b/example/ContinuousTest.ts similarity index 89% rename from example/ContinuousTest.js rename to example/ContinuousTest.ts index d2e9b2f0..46c1df29 100644 --- a/example/ContinuousTest.js +++ b/example/ContinuousTest.ts @@ -20,18 +20,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { Vec2, Math, World, stats, Circle, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let bullet; -let angularVelocity; +let bullet: planck.Body; +let angularVelocity: number; -let ground = world.createBody(new Vec2(0.0, 0.0)); +const ground = world.createBody(new Vec2(0.0, 0.0)); ground.createFixture(new Edge(new Vec2(-10.0, 0.0), new Vec2(10.0, 0.0)), 0.0); ground.createFixture(new Box(0.2, 1.0, new Vec2(0.5, 1.0), 0.0), 0.0); @@ -45,15 +46,12 @@ if (true) { // angularVelocity = 46.661274; bullet.setLinearVelocity(new Vec2(0.0, -100.0)); bullet.setAngularVelocity(angularVelocity); - } else { - let shape = new Circle(0.5); + const shape = new Circle(0.5); - world - .createDynamicBody(new Vec2(0.0, 2.0)) - .createFixture(shape, 1.0); + world.createDynamicBody(new Vec2(0.0, 2.0)).createFixture(shape, 1.0); - let body = world.createDynamicBody({ + const body = world.createDynamicBody({ bullet: true, position: new Vec2(0.0, 2.0), }); @@ -82,7 +80,7 @@ function launch() { launch(); let stepCount = 0; -testbed.step = function() { +testbed.step = function () { testbed.status(stats); if (stats.gjkCalls > 0) { diff --git a/example/ConvexHull.js b/example/ConvexHull.ts similarity index 79% rename from example/ConvexHull.js rename to example/ConvexHull.ts index 58a94066..656f40e8 100644 --- a/example/ConvexHull.js +++ b/example/ConvexHull.ts @@ -21,58 +21,56 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Polygon, Testbed } = planck; -let world = new World(); +const world = new World(); const testbed = Testbed.mount(); testbed.x = 0; testbed.y = 0; testbed.start(world); -testbed.info('X: Generate a new random convex hull, Z: Auto-generate'); +testbed.info("X: Generate a new random convex hull, Z: Auto-generate"); -let COUNT = 8; +const COUNT = 8; let auto = false; -let points = []; +const points = []; -let shape; +let shape: planck.PolygonShape; generate(); function generate() { - - let lowerBound = new Vec2(-8.0, -8.0); - let upperBound = new Vec2(8.0, 8.0); - points.length = 0; for (let i = 0; i < COUNT; ++i) { - let x = 10.0 * Math.random() - 5; - let y = 10.0 * Math.random() - 5; + const x = 10.0 * Math.random() - 5; + const y = 10.0 * Math.random() - 5; // Clamp onto a square to help create collinearities. // This will stress the convex hull algorithm. - let v = Vec2.clamp(new Vec2(x, y), lowerBound, upperBound); + const v = Vec2.clamp(new Vec2(x, y), x + y); points.push(v); } shape = new Polygon(points); } -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case 'Z': - auto = !auto; - break; + case "Z": + auto = !auto; + break; - case 'X': - generate(); - break; + case "X": + generate(); + break; } }; -testbed.step = function() { +testbed.step = function () { testbed.drawPolygon(shape.m_vertices, testbed.color(0.9, 0.9, 0.9)); for (let i = 0; i < points.length; ++i) { diff --git a/example/ConveyorBelt.js b/example/ConveyorBelt.ts similarity index 83% rename from example/ConveyorBelt.js rename to example/ConveyorBelt.ts index 0bcae0bd..37dec773 100644 --- a/example/ConveyorBelt.js +++ b/example/ConveyorBelt.ts @@ -21,21 +21,23 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { Vec2, World, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); // Ground -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0)), 0.0); // Platform -let platform = world +const platform = world .createBody(new Vec2(-5.0, 5.0)) - .createFixture(new Box(10.0, 0.5), {friction : 0.8}); + .createFixture(new Box(10.0, 0.5), { friction: 0.8 }); // Boxes for (let i = 0; i < 5; ++i) { @@ -44,9 +46,9 @@ for (let i = 0; i < 5; ++i) { .createFixture(new Box(0.5, 0.5), 20.0); } -world.on('pre-solve', function(contact, oldManifold) { - let fixtureA = contact.getFixtureA(); - let fixtureB = contact.getFixtureB(); +world.on("pre-solve", function (contact) { + const fixtureA = contact.getFixtureA(); + const fixtureB = contact.getFixtureB(); if (fixtureA == platform) { contact.setTangentSpeed(5.0); diff --git a/example/Debug.ts b/example/Debug.ts index 692bb366..5b9762d4 100644 --- a/example/Debug.ts +++ b/example/Debug.ts @@ -1,3 +1,5 @@ +import planck from "../src/main"; + const { Testbed, World, Vec2, Box } = planck; const testbed = Testbed.mount(); @@ -8,4 +10,6 @@ testbed.x = 0; testbed.y = 0; testbed.start(world); -testbed.info('This is a template, update the code and implement something here!'); \ No newline at end of file +testbed.info( + "This is a template, update the code and implement something here!" +); diff --git a/example/DistanceTest.js b/example/DistanceTest.ts similarity index 59% rename from example/DistanceTest.js rename to example/DistanceTest.ts index 1a59a5f9..63f91b91 100644 --- a/example/DistanceTest.js +++ b/example/DistanceTest.ts @@ -21,82 +21,84 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Transform, Box, Distance, Testbed } = planck; -let DistanceInput = Distance.Input; -let DistanceOutput = Distance.Output; -let SimplexCache = Distance.Cache; +const DistanceInput = Distance.Input; +const DistanceOutput = Distance.Output; +const SimplexCache = Distance.Cache; -let world = new World(); +const world = new World(); const testbed = Testbed.mount(); -testbed.start(world); +testbed.start(world); -let transformA = new Transform(new Vec2(0.0, -0.2)); +const transformA = new Transform(new Vec2(0.0, -0.2)); -let polygonA = new Box(10.0, 0.2); +const polygonA = new Box(10.0, 0.2); -let positionB = new Vec2(12.017401, 0.13678508); +const positionB = new Vec2(12.017401, 0.13678508); let angleB = -0.0109265; -let transformB = new Transform(positionB, angleB); +const transformB = new Transform(positionB, angleB); -let polygonB = new Box(2.0, 0.1); +const polygonB = new Box(2.0, 0.1); -let bodyA = world.createBody(); -let fixA = bodyA.createFixture(polygonA); +const bodyA = world.createBody(); +const fixA = bodyA.createFixture(polygonA); -let bodyB = world.createBody(); -let fixB = bodyB.createFixture(polygonB); +const bodyB = world.createBody(); +const fixB = bodyB.createFixture(polygonB); -testbed.step = function() { - let input = new DistanceInput(); +testbed.step = function () { + const input = new DistanceInput(); input.proxyA.set(polygonA, 0); input.proxyB.set(polygonB, 0); input.transformA.set(transformA); input.transformB.set(transformB); input.useRadii = true; - let cache = new SimplexCache(); + const cache = new SimplexCache(); - let output = new DistanceOutput(); + const output = new DistanceOutput(); Distance(output, cache, input); - testbed.status('Distance', output.distance); - testbed.status('Iterations', output.iterations); + testbed.status("Distance", output.distance); + testbed.status("Iterations", output.iterations); - bodyA.setTransform(transformA); - bodyB.setTransform(transformB); + bodyA.setTransform(transformA.p, transformA.q.getAngle()); + bodyB.setTransform(transformB.p, transformB.q.getAngle()); - let x1 = output.pointA; - let x2 = output.pointB; + const x1 = output.pointA; + const x2 = output.pointB; testbed.drawPoint(x1, 4.0, testbed.color(1.0, 0.0, 0.0)); testbed.drawPoint(x2, 4.0, testbed.color(1.0, 1.0, 0.0)); }; -testbed.keydown = function() { - if (testbed.activeKeys['left']) { +testbed.keydown = function () { + if (testbed.activeKeys["left"]) { positionB.x -= 0.1; } - if (testbed.activeKeys['right']) { + if (testbed.activeKeys["right"]) { positionB.x += 0.1; } - if (testbed.activeKeys['down']) { + if (testbed.activeKeys["down"]) { positionB.y -= 0.1; } - if (testbed.activeKeys['up']) { + if (testbed.activeKeys["up"]) { positionB.y += 0.1; } - if (testbed.activeKeys['Z']) { + if (testbed.activeKeys["Z"]) { angleB += 0.1; } - if (testbed.activeKeys['X']) { + if (testbed.activeKeys["X"]) { angleB -= 0.1; } diff --git a/example/Dominos.js b/example/Dominos.ts similarity index 71% rename from example/Dominos.js rename to example/Dominos.ts index 5410c19e..65edea0a 100644 --- a/example/Dominos.js +++ b/example/Dominos.ts @@ -20,24 +20,32 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; -const { Vec2, World, Edge, Box, RevoluteJoint, DistanceJoint, Circle, Testbed } = planck; +const { + Vec2, + World, + Edge, + Box, + RevoluteJoint, + DistanceJoint, + Circle, + Testbed, +} = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.width = 50; testbed.height = 50; testbed.start(world); -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40, 0), new Vec2(40, 0)), 0); -world - .createBody(new Vec2(-1.5, 10)) - .createFixture(new Box(6, 0.25), 0); +world.createBody(new Vec2(-1.5, 10)).createFixture(new Box(6, 0.25), 0); -let columnShape = new Box(0.1, 1); +const columnShape = new Box(0.1, 1); for (let i = 0; i < 10; ++i) { world @@ -52,27 +60,27 @@ world .createBody(new Vec2(1, 6)) .createFixture(new Box(7, 0.25, new Vec2(), 0.3), 0); -let b2 = world.createBody(new Vec2(-7, 4)); +const b2 = world.createBody(new Vec2(-7, 4)); b2.createFixture(new Box(0.25, 1.5), 0); -let b3 = world.createDynamicBody(new Vec2(-0.9, 1), -0.15); +const b3 = world.createDynamicBody(new Vec2(-0.9, 1), -0.15); b3.createFixture(new Box(6, 0.125), 10); -let jd = { +const jd = { collideConnected: true, }; world.createJoint(new RevoluteJoint(jd, ground, b3, new Vec2(-2, 1))); -let b4 = world.createDynamicBody(new Vec2(-10, 15)); +const b4 = world.createDynamicBody(new Vec2(-10, 15)); b4.createFixture(new Box(0.25, 0.25), 10); world.createJoint(new RevoluteJoint(jd, b2, b4, new Vec2(-7, 15))); -let b5 = world.createDynamicBody(new Vec2(6.5, 3)); +const b5 = world.createDynamicBody(new Vec2(6.5, 3)); { - let fd = { + const fd = { density: 10, friction: 0.1, }; @@ -84,26 +92,28 @@ let b5 = world.createDynamicBody(new Vec2(6.5, 3)); world.createJoint(new RevoluteJoint(jd, ground, b5, new Vec2(6, 2))); -let b6 = world.createDynamicBody(new Vec2(6.5, 4.1)); +const b6 = world.createDynamicBody(new Vec2(6.5, 4.1)); b6.createFixture(new Box(1, 0.1), 30); world.createJoint(new RevoluteJoint(jd, b5, b6, new Vec2(7.5, 4))); -let b7 = world.createDynamicBody(new Vec2(7.4, 1)); +const b7 = world.createDynamicBody(new Vec2(7.4, 1)); b7.createFixture(new Box(0.1, 1), 10); -world.createJoint(new DistanceJoint({ - bodyA: b3, - localAnchorA: new Vec2(6, 0), - bodyB: b7, - localAnchorB: new Vec2(0, -1) -})); +world.createJoint( + new DistanceJoint({ + bodyA: b3, + localAnchorA: new Vec2(6, 0), + bodyB: b7, + localAnchorB: new Vec2(0, -1), + }) +); { - let radius = 0.2; - let circleShape = new Circle(radius); + const radius = 0.2; + const circleShape = new Circle(radius); for (let i = 0; i < 4; ++i) { - let body = world.createDynamicBody(new Vec2(5.9 + 2 * radius * i, 2.4)); + const body = world.createDynamicBody(new Vec2(5.9 + 2 * radius * i, 2.4)); body.createFixture(circleShape, 10); } } diff --git a/example/DynamicTreeTest.js b/example/DynamicTreeTest.ts similarity index 60% rename from example/DynamicTreeTest.js rename to example/DynamicTreeTest.ts index 88070b95..1ee6bf9b 100644 --- a/example/DynamicTreeTest.js +++ b/example/DynamicTreeTest.ts @@ -2,33 +2,34 @@ * MIT License * Copyright (c) 2019 Erin Catto */ +import planck from "../src/main"; const { World, Vec2, DynamicTree, AABB, Math, Testbed } = planck; -let world = new World(); +const world = new World(); const testbed = Testbed.mount(); testbed.start(world); -let ACTOR_COUNT = 128; -let worldExtent = 15.0; -let proxyExtent = 0.5; +const ACTOR_COUNT = 128; +const worldExtent = 15.0; +const proxyExtent = 0.5; -let tree = new DynamicTree(); -let queryAABB = new AABB(); -let rayCastInput = {}; +const tree = new DynamicTree(); +const queryAABB = new AABB(); +const rayCastInput: any = {}; let rayCastOutput = {}; let rayActor; -let actors = []; // Actor[e_actorCount]; +const actors = []; // Actor[e_actorCount]; let automated = false; for (let i = 0; i < ACTOR_COUNT; ++i) { - let actor = actors[i] = new Actor(); + const actor = (actors[i] = new Actor()); getRandomAABB(actor.aabb); actor.proxyId = tree.createProxy(actor.aabb, actor); } -let h = worldExtent; +const h = worldExtent; queryAABB.lowerBound.set(-3.0, -4.0 + h); queryAABB.upperBound.set(5.0, 6.0 + h); @@ -38,15 +39,15 @@ rayCastInput.p2 = new Vec2(7.0, -4.0 + h); // rayCastInput.p2 = new Vec2(0.0, -2.0 + h); rayCastInput.maxFraction = 1.0; -testbed.step = function() { +testbed.step = function () { rayActor = null; for (let i = 0; i < ACTOR_COUNT; ++i) { actors[i].fraction = 1.0; actors[i].overlap = false; } - if (automated == true) { - let actionCount = Math.max(1, ACTOR_COUNT >> 2); + if (automated) { + const actionCount = Math.max(1, ACTOR_COUNT >> 2); for (let i = 0; i < actionCount; ++i) { Action(); @@ -57,9 +58,8 @@ testbed.step = function() { rayCast(); for (let i = 0; i < ACTOR_COUNT; ++i) { - let actor = actors[i]; - if (actor.proxyId == null) - continue; + const actor = actors[i]; + if (actor.proxyId == null) continue; let c = testbed.color(0.9, 0.9, 0.9); if (actor == rayActor && actor.overlap) { @@ -74,50 +74,59 @@ testbed.step = function() { } testbed.drawAABB(queryAABB, testbed.color(0.7, 0.7, 0.7)); - testbed.drawSegment(rayCastInput.p1, rayCastInput.p2, testbed.color(0.9, 0.9, 0.9)); + testbed.drawSegment( + rayCastInput.p1, + rayCastInput.p2, + testbed.color(0.9, 0.9, 0.9) + ); testbed.drawPoint(rayCastInput.p1, 6.0, testbed.color(0.2, 0.9, 0.2)); testbed.drawPoint(rayCastInput.p2, 6.0, testbed.color(0.9, 0.2, 0.2)); if (rayActor) { - let p = Vec2.combine(1 - rayActor.fraction, rayCastInput.p1, rayActor.fraction, rayCastInput.p2); + const p = Vec2.combine( + 1 - rayActor.fraction, + rayCastInput.p1, + rayActor.fraction, + rayCastInput.p2 + ); testbed.drawPoint(p, 6.0, testbed.color(0.2, 0.2, 0.9)); } - let height = tree.getHeight(); - testbed.status('dynamic tree height', height); + const height = tree.getHeight(); + testbed.status("dynamic tree height", height); }; -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case 'Z': - automated = !automated; - break; + case "Z": + automated = !automated; + break; - case 'C': - createProxy(); - break; + case "C": + createProxy(); + break; - case 'X': - destroyProxy(); - break; + case "X": + destroyProxy(); + break; - case 'M': - moveProxy(); - break; + case "M": + moveProxy(); + break; } }; -function queryCallback(proxyId) { - let actor = tree.getUserData(proxyId); // Actor +function queryCallback(proxyId: number) { + const actor: any = tree.getUserData(proxyId); // Actor actor.overlap = AABB.testOverlap(queryAABB, actor.aabb); return true; } -function rayCastCallback(input, proxyId) { - let actor = tree.getUserData(proxyId); +function rayCastCallback(input: planck.RayCastInput, proxyId: number) { + const actor: any = tree.getUserData(proxyId); - let output = {}; // RayCastOutput - let hit = actor.aabb.rayCast(output, input); + const output: any = {}; // RayCastOutput + const hit = actor.aabb.rayCast(output, input); if (hit) { rayCastOutput = output; @@ -136,8 +145,8 @@ function Actor() { this.proxyId; } -function getRandomAABB(aabb) { - let w = new Vec2(2.0 * proxyExtent, 2.0 * proxyExtent); +function getRandomAABB(aabb: planck.AABB) { + const w = new Vec2(2.0 * proxyExtent, 2.0 * proxyExtent); // aabb.lowerBound.x = -proxyExtent; // aabb.lowerBound.y = -proxyExtent + worldExtent; aabb.lowerBound.x = Math.random(-worldExtent, worldExtent); @@ -145,17 +154,18 @@ function getRandomAABB(aabb) { aabb.upperBound = Vec2.add(w, aabb.lowerBound); } -function moveAABB(aabb) { - let d = new Vec2(Math.random(-0.5, 0.5), Math.random(-0.5, 0.5)); +function moveAABB(aabb: planck.AABB) { + const d = new Vec2(Math.random(-0.5, 0.5), Math.random(-0.5, 0.5)); // d.x = 2.0; // d.y = 0.0; aabb.lowerBound.add(d); aabb.upperBound.add(d); - let c0 = Vec2.mid(aabb.lowerBound, aabb.upperBound); - let min = new Vec2(-worldExtent, 0.0); - let max = new Vec2(worldExtent, 2.0 * worldExtent); - let c = Vec2.clamp(c0, min, max); + const c0 = Vec2.mid(aabb.lowerBound, aabb.upperBound); + const min = new Vec2(-worldExtent, 0.0); + const max = new Vec2(worldExtent, 2.0 * worldExtent); + + const c = Vec2.clampVec2(c0, min, max); aabb.lowerBound.add(c).sub(c0); aabb.upperBound.add(c).sub(c0); @@ -163,8 +173,8 @@ function moveAABB(aabb) { function createProxy() { for (let i = 0; i < ACTOR_COUNT; ++i) { - let j = Math.random() * ACTOR_COUNT | 0; - let actor = actors[j]; + const j = (Math.random() * ACTOR_COUNT) | 0; + const actor = actors[j]; if (actor.proxyId == null) { getRandomAABB(actor.aabb); actor.proxyId = tree.createProxy(actor.aabb, actor); @@ -175,8 +185,8 @@ function createProxy() { function destroyProxy() { for (let i = 0; i < ACTOR_COUNT; ++i) { - let j = Math.random() * ACTOR_COUNT | 0; - let actor = actors[j]; + const j = (Math.random() * ACTOR_COUNT) | 0; + const actor = actors[j]; if (actor.proxyId != null) { tree.destroyProxy(actor.proxyId); actor.proxyId = null; @@ -187,34 +197,34 @@ function destroyProxy() { function moveProxy() { for (let i = 0; i < ACTOR_COUNT; ++i) { - let j = Math.random() * ACTOR_COUNT | 0; + const j = (Math.random() * ACTOR_COUNT) | 0; const actor = actors[j]; if (actor.proxyId == null) { continue; } - let aabb0 = actor.aabb; + const aabb0 = actor.aabb; moveAABB(actor.aabb); - let displacement = Vec2.sub(actor.aabb.getCenter(), aabb0.getCenter()); + const displacement = Vec2.sub(actor.aabb.getCenter(), aabb0.getCenter()); tree.moveProxy(actor.proxyId, actor.aabb, displacement); return; } } function Action() { - let choice = Math.random() * 20 | 0; + const choice = (Math.random() * 20) | 0; switch (choice) { - case 0: - createProxy(); - break; + case 0: + createProxy(); + break; - case 1: - destroyProxy(); - break; + case 1: + destroyProxy(); + break; - default: - moveProxy(); + default: + moveProxy(); } } @@ -226,7 +236,7 @@ function runQuery() { continue; } - let overlap = AABB.testOverlap(queryAABB, actors[i].aabb); + const overlap = AABB.testOverlap(queryAABB, actors[i].aabb); // assert(overlap == actors[i].overlap); } } @@ -234,7 +244,7 @@ function runQuery() { function rayCast() { rayActor = null; - let input = rayCastInput; // RayCastInput + const input = rayCastInput; // RayCastInput // Ray cast against the dynamic tree. tree.rayCast(input, rayCastCallback); @@ -247,8 +257,8 @@ function rayCast() { continue; } - let output = {}; // RayCastOutput - let hit = actors[i].aabb.rayCast(output, input); + const output: any = {}; // RayCastOutput + const hit = actors[i].aabb.rayCast(output, input); if (hit) { bruteActor = actors[i]; bruteOutput = output; diff --git a/example/EdgeShapes.js b/example/EdgeShapes.ts similarity index 58% rename from example/EdgeShapes.js rename to example/EdgeShapes.ts index ee5723ad..ad9fc6bc 100644 --- a/example/EdgeShapes.js +++ b/example/EdgeShapes.ts @@ -20,29 +20,30 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { Vec2, World, Edge, Polygon, Box, Circle, Math, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); let pause = false; -let MAX_BODIES = 256; +const MAX_BODIES = 256; -let bodies = []; -let shapes = []; +const bodies = []; +const shapes = []; { - let ground = world.createBody(); + const ground = world.createBody(); let x1 = -20.0; - let y1 = 2.0 * Math.cos(x1 / 10.0 * Math.PI); + let y1 = 2.0 * Math.cos((x1 / 10.0) * Math.PI); for (let i = 0; i < 80; ++i) { - let x2 = x1 + 0.5; - let y2 = 2.0 * Math.cos(x2 / 10.0 * Math.PI); + const x2 = x1 + 0.5; + const y2 = 2.0 * Math.cos((x2 / 10.0) * Math.PI); ground.createFixture(new Edge(new Vec2(x1, y1), new Vec2(x2, y2)), 0.0); @@ -51,16 +52,24 @@ let shapes = []; } } -shapes[0] = new Polygon([new Vec2(-0.5, 0.0), new Vec2(0.5, 0.0), new Vec2(0.0, 1.5)]); +shapes[0] = new Polygon([ + new Vec2(-0.5, 0.0), + new Vec2(0.5, 0.0), + new Vec2(0.0, 1.5), +]); -shapes[1] = new Polygon([new Vec2(-0.1, 0.0), new Vec2(0.1, 0.0), new Vec2(0.0, 1.5)]); +shapes[1] = new Polygon([ + new Vec2(-0.1, 0.0), + new Vec2(0.1, 0.0), + new Vec2(0.0, 1.5), +]); { - let w = 1.0; - let b = w / (2.0 + Math.sqrt(2.0)); - let s = Math.sqrt(2.0) * b; + const w = 1.0; + const b = w / (2.0 + Math.sqrt(2.0)); + const s = Math.sqrt(2.0) * b; - let vertices = []; + const vertices = []; vertices[0] = new Vec2(0.5 * s, 0.0); vertices[1] = new Vec2(0.5 * w, b); vertices[2] = new Vec2(0.5 * w, b + s); @@ -84,24 +93,24 @@ function createItem(index) { world.destroyBody(bodies.shift()); } - let bd = { - position: new Vec2( - Math.random(-10.0, 10.0), - Math.random(10.0, 20.0) - ), + const bd = { + position: new Vec2(Math.random(-10.0, 10.0), Math.random(10.0, 20.0)), angle: Math.random(-Math.PI, Math.PI), - type: 'dynamic', + type: "dynamic", + x: 0, + y: 0, + angularDamping: 0, }; if (index === 4) { bd.angularDamping = 0.02; } - let body = world.createBody(bd); + const body = world.createBody(bd); body.createFixture(shapes[index], { density: 20.0, - friction: 0.3 + friction: 0.3, }); bodies.push(body); @@ -111,33 +120,33 @@ function destroyBody() { world.destroyBody(bodies.shift()); } -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case '1': - createItem(0); - break; - case '2': - createItem(1); - break; - case '3': - createItem(2); - break; - case '4': - createItem(3); - break; - case '5': - createItem(4); - break; - case 'X': - destroyBody(); - break; - case 'Z': - pause = !pause; - break; + case "1": + createItem(0); + break; + case "2": + createItem(1); + break; + case "3": + createItem(2); + break; + case "4": + createItem(3); + break; + case "5": + createItem(4); + break; + case "X": + destroyBody(); + break; + case "Z": + pause = !pause; + break; } }; -testbed.info('1-5: Drop new object, X: Destroy an object'); +testbed.info("1-5: Drop new object, X: Destroy an object"); const rayCastResult = { fixture: null, @@ -145,26 +154,31 @@ const rayCastResult = { normal: null, }; -function rayCastCallback (fixture, point, normal, fraction) { +function rayCastCallback( + fixture: planck.Fixture, + point: planck.Vec2, + normal: planck.Vec2, + fraction: number +) { rayCastResult.fixture = fixture; rayCastResult.point = point; rayCastResult.normal = normal; return fraction; } -function rayCastReset () { +function rayCastReset() { rayCastResult.fixture = null; rayCastResult.point = null; rayCastResult.normal = null; } -testbed.step = function() { - let advanceRay = !pause; // settings.pause == 0 || settings.singleStep; +testbed.step = function () { + const advanceRay = !pause; // settings.pause == 0 || settings.singleStep; - let L = 25.0; - let point1 = new Vec2(0.0, 10.0); - let d = new Vec2(L * Math.cos(angle), -L * Math.abs(Math.sin(angle))); - let point2 = Vec2.add(point1, d); + const L = 25.0; + const point1 = new Vec2(0.0, 10.0); + const d = new Vec2(L * Math.cos(angle), -L * Math.abs(Math.sin(angle))); + const point2 = Vec2.add(point1, d); rayCastReset(); @@ -172,15 +186,23 @@ testbed.step = function() { if (rayCastResult.fixture) { testbed.drawPoint(rayCastResult.point, 5.0, testbed.color(0.4, 0.9, 0.4)); - testbed.drawSegment(point1, rayCastResult.point, testbed.color(0.8, 0.8, 0.8)); - - let head = Vec2.combine(1, rayCastResult.point, 2, rayCastResult.normal); - testbed.drawSegment(rayCastResult.point, head, testbed.color(0.9, 0.9, 0.4)); + testbed.drawSegment( + point1, + rayCastResult.point, + testbed.color(0.8, 0.8, 0.8) + ); + + const head = Vec2.combine(1, rayCastResult.point, 2, rayCastResult.normal); + testbed.drawSegment( + rayCastResult.point, + head, + testbed.color(0.9, 0.9, 0.4) + ); } else { testbed.drawSegment(point1, point2, testbed.color(0.8, 0.8, 0.8)); } if (advanceRay) { - angle += 0.25 * Math.PI / 180.0; + angle += (0.25 * Math.PI) / 180.0; } }; diff --git a/example/EdgeTest.js b/example/EdgeTest.ts similarity index 67% rename from example/EdgeTest.js rename to example/EdgeTest.ts index aca0b63a..d9650866 100644 --- a/example/EdgeTest.js +++ b/example/EdgeTest.ts @@ -21,59 +21,65 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { Vec2, World, Circle, Box, Edge, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let ground = world.createBody(); +const ground = world.createBody(); -let v1 = new Vec2(-10.0, 0.0); -let v2 = new Vec2(-7.0, -2.0); -let v3 = new Vec2(-4.0, 0.0); -let v4 = new Vec2(0.0, 0.0); -let v5 = new Vec2(4.0, 0.0); -let v6 = new Vec2(7.0, 2.0); -let v7 = new Vec2(10.0, 0.0); +const v1 = new Vec2(-10.0, 0.0); +const v2 = new Vec2(-7.0, -2.0); +const v3 = new Vec2(-4.0, 0.0); +const v4 = new Vec2(0.0, 0.0); +const v5 = new Vec2(4.0, 0.0); +const v6 = new Vec2(7.0, 2.0); +const v7 = new Vec2(10.0, 0.0); -let shape1 = new Edge(v1, v2); +const shape1 = new Edge(v1, v2); shape1.setNextVertex(v3); ground.createFixture(shape1, 0.0); -let shape2 = new Edge(v2, v3); +const shape2 = new Edge(v2, v3); shape2.setPrevVertex(v1); shape2.setNextVertex(v4); ground.createFixture(shape2, 0.0); -let shape3 = new Edge(v3, v4); +const shape3 = new Edge(v3, v4); shape3.setPrevVertex(v2); shape3.setNextVertex(v5); ground.createFixture(shape3, 0.0); -let shape4 = new Edge(v4, v5); +const shape4 = new Edge(v4, v5); shape4.setPrevVertex(v3); shape4.setNextVertex(v6); ground.createFixture(shape4, 0.0); -let shape5 = new Edge(v5, v6); +const shape5 = new Edge(v5, v6); shape5.setPrevVertex(v4); shape5.setNextVertex(v7); ground.createFixture(shape5, 0.0); -let shape6 = new Edge(v6, v7); +const shape6 = new Edge(v6, v7); shape6.setPrevVertex(v5); ground.createFixture(shape6, 0.0); -world.createBody({ - type : 'dynamic', - position : new Vec2(-0.5, 0.6), - allowSleep : false -}).createFixture(new Circle(0.5), 1.0); +world + .createBody({ + type: "dynamic", + position: new Vec2(-0.5, 0.6), + allowSleep: false, + }) + .createFixture(new Circle(0.5), 1.0); -world.createBody({ - type : 'dynamic', - position : new Vec2(1.0, 0.6), - allowSleep : false -}).createFixture(new Box(0.5, 0.5), 1.0); +world + .createBody({ + type: "dynamic", + position: new Vec2(1.0, 0.6), + allowSleep: false, + }) + .createFixture(new Box(0.5, 0.5), 1.0); diff --git a/example/Gears.js b/example/Gears.js deleted file mode 100644 index 5423fe78..00000000 --- a/example/Gears.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * MIT License - * Copyright (c) 2019 Erin Catto - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { Vec2, World, Circle, Box, Edge, RevoluteJoint, PrismaticJoint, GearJoint, Testbed } = planck; - -let world = new World(new Vec2(0, -10)); - -const testbed = Testbed.mount(); -testbed.start(world); - -let ground = world.createBody(); -ground.createFixture(new Edge(new Vec2(50.0, 0.0), new Vec2(-50.0, 0.0))); - -let radius1 = 1.0; -let radius2 = 2.0; - -let gearA1 = world.createBody(new Vec2(10.0, 9.0)); -gearA1.createFixture(new Circle(radius1), 5.0); - -let plankA1 = world.createDynamicBody(new Vec2(10.0, 8.0)); -plankA1.createFixture(new Box(0.5, 5.0), 5.0); - -let gearA2 = world.createDynamicBody(new Vec2(10.0, 6.0)); -gearA2.createFixture(new Circle(radius2), 5.0); - -let jointA1 = world.createJoint(new RevoluteJoint({}, plankA1, gearA1, gearA1.getPosition())); -let jointA2 = world.createJoint(new RevoluteJoint({}, plankA1, gearA2, gearA2.getPosition())); - -world.createJoint(new GearJoint({}, gearA1, gearA2, jointA1, jointA2, radius2 / radius1)); - -let gearB1 = world.createDynamicBody(new Vec2(-3.0, 12.0)); -gearB1.createFixture(new Circle(1.0), 5.0); - -let jointB1 = world.createJoint(new RevoluteJoint({}, ground, gearB1, gearB1.getPosition())); - -let gearB2 = world.createDynamicBody(new Vec2(0.0, 12.0)); -gearB2.createFixture(new Circle(2.0), 5.0); - -let jointB2 = world.createJoint(new RevoluteJoint({}, ground, gearB2, gearB2.getPosition())); - -let plankB1 = world.createDynamicBody(new Vec2(2.5, 12.0)); -plankB1.createFixture(new Box(0.5, 5.0), 5.0); - -let jointB3 = world.createJoint(new PrismaticJoint({ - lowerTranslation: -5.0, - upperTranslation: 5.0, - enableLimit: true, -}, ground, plankB1, plankB1.getPosition(), new Vec2(0.0, 1.0))); - -let jointB4 = world.createJoint(new GearJoint({}, gearB1, gearB2, jointB1, jointB2, radius2 / radius1)); -let jointB5 = world.createJoint(new GearJoint({}, gearB2, plankB1, jointB2, jointB3, -1.0 / radius2)); - -testbed.step = function() { - let ratio, value; - - ratio = jointB4.getRatio(); - value = jointB1.getJointAngle() + ratio * jointB2.getJointAngle(); - testbed.status('ratio1', ratio); - testbed.status('theta1 + ratio * delta', value); - - ratio = jointB5.getRatio(); - value = jointB2.getJointAngle() + ratio * jointB3.getJointTranslation(); - - testbed.status('ratio2', ratio); - testbed.status('theta2 + ratio * delta', value); -}; diff --git a/example/Gears.ts b/example/Gears.ts new file mode 100644 index 00000000..7b99ec56 --- /dev/null +++ b/example/Gears.ts @@ -0,0 +1,119 @@ +/* + * MIT License + * Copyright (c) 2019 Erin Catto + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +import planck from "../src/main"; + +const { + Vec2, + World, + Circle, + Box, + Edge, + RevoluteJoint, + PrismaticJoint, + GearJoint, + Testbed, +} = planck; + +const world = new World(new Vec2(0, -10)); + +const testbed = Testbed.mount(); +testbed.start(world); + +const ground = world.createBody(); +ground.createFixture(new Edge(new Vec2(50.0, 0.0), new Vec2(-50.0, 0.0))); + +const radius1 = 1.0; +const radius2 = 2.0; + +const gearA1 = world.createBody(new Vec2(10.0, 9.0)); +gearA1.createFixture(new Circle(radius1), 5.0); + +const plankA1 = world.createDynamicBody(new Vec2(10.0, 8.0)); +plankA1.createFixture(new Box(0.5, 5.0), 5.0); + +const gearA2 = world.createDynamicBody(new Vec2(10.0, 6.0)); +gearA2.createFixture(new Circle(radius2), 5.0); + +const jointA1 = world.createJoint( + new RevoluteJoint({}, plankA1, gearA1, gearA1.getPosition()) +); +const jointA2 = world.createJoint( + new RevoluteJoint({}, plankA1, gearA2, gearA2.getPosition()) +); + +world.createJoint( + new GearJoint({}, gearA1, gearA2, jointA1, jointA2, radius2 / radius1) +); + +const gearB1 = world.createDynamicBody(new Vec2(-3.0, 12.0)); +gearB1.createFixture(new Circle(1.0), 5.0); + +const jointB1 = world.createJoint( + new RevoluteJoint({}, ground, gearB1, gearB1.getPosition()) +); + +const gearB2 = world.createDynamicBody(new Vec2(0.0, 12.0)); +gearB2.createFixture(new Circle(2.0), 5.0); + +const jointB2 = world.createJoint( + new RevoluteJoint({}, ground, gearB2, gearB2.getPosition()) +); + +const plankB1 = world.createDynamicBody(new Vec2(2.5, 12.0)); +plankB1.createFixture(new Box(0.5, 5.0), 5.0); + +const jointB3 = world.createJoint( + new PrismaticJoint( + { + lowerTranslation: -5.0, + upperTranslation: 5.0, + enableLimit: true, + }, + ground, + plankB1, + plankB1.getPosition(), + new Vec2(0.0, 1.0) + ) +); + +const jointB4 = world.createJoint( + new GearJoint({}, gearB1, gearB2, jointB1, jointB2, radius2 / radius1) +); +const jointB5 = world.createJoint( + new GearJoint({}, gearB2, plankB1, jointB2, jointB3, -1.0 / radius2) +); + +testbed.step = function () { + let ratio: number, value: number; + + ratio = jointB4.getRatio(); + value = jointB1.getJointAngle() + ratio * jointB2.getJointAngle(); + testbed.status("ratio1", ratio); + testbed.status("theta1 + ratio * delta", value); + + ratio = jointB5.getRatio(); + value = jointB2.getJointAngle() + ratio * jointB3.getJointTranslation(); + + testbed.status("ratio2", ratio); + testbed.status("theta2 + ratio * delta", value); +}; diff --git a/example/HeavyOnLight.js b/example/HeavyOnLight.ts similarity index 78% rename from example/HeavyOnLight.js rename to example/HeavyOnLight.ts index b9f1c6b9..f30590d3 100644 --- a/example/HeavyOnLight.js +++ b/example/HeavyOnLight.ts @@ -21,15 +21,23 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { Vec2, World, Edge, Circle, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -world.createBody().createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0))); +world + .createBody() + .createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0))); -world.createDynamicBody(new Vec2(0.0, 4.5)).createFixture(new Circle(0.5), 10.0); +world + .createDynamicBody(new Vec2(0.0, 4.5)) + .createFixture(new Circle(0.5), 10.0); -world.createDynamicBody(new Vec2(0.0, 10.0)).createFixture(new Circle(5.0), 10.0); +world + .createDynamicBody(new Vec2(0.0, 10.0)) + .createFixture(new Circle(5.0), 10.0); diff --git a/example/HeavyOnLightTwo.js b/example/HeavyOnLightTwo.ts similarity index 71% rename from example/HeavyOnLightTwo.js rename to example/HeavyOnLightTwo.ts index 61454145..ca9c43fb 100644 --- a/example/HeavyOnLightTwo.js +++ b/example/HeavyOnLightTwo.ts @@ -21,21 +21,29 @@ * SOFTWARE. */ -let { World, Vec2, Circle, Edge, Testbed } = planck; +import planck from "../src/main"; -let world = new World(new Vec2(0, -10)); +const { World, Vec2, Circle, Edge, Testbed } = planck; + +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); -testbed.info('X: Add/Remove heavy circle'); +testbed.info("X: Add/Remove heavy circle"); testbed.start(world); -world.createBody().createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); +world + .createBody() + .createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -world.createDynamicBody(new Vec2(0.0, 2.5)).createFixture(new Circle(0.5), 10.0); +world + .createDynamicBody(new Vec2(0.0, 2.5)) + .createFixture(new Circle(0.5), 10.0); -world.createDynamicBody(new Vec2(0.0, 3.5)).createFixture(new Circle(0.5), 10.0); +world + .createDynamicBody(new Vec2(0.0, 3.5)) + .createFixture(new Circle(0.5), 10.0); -let heavy = null; +let heavy: planck.Body = null; function toggleHeavy() { if (heavy) { @@ -47,10 +55,10 @@ function toggleHeavy() { } } -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case 'X': - toggleHeavy(); - break; + case "X": + toggleHeavy(); + break; } }; diff --git a/example/Mixer.js b/example/Mixer.js deleted file mode 100644 index f075d658..00000000 --- a/example/Mixer.js +++ /dev/null @@ -1,41 +0,0 @@ -const { Vec2, World, Edge, Circle, Box, Chain, Math, Testbed } = planck; - -let world = new World(new Vec2(0, -10)); - -const testbed = Testbed.mount(); -testbed.y = 0; -testbed.start(world); - -let container = world.createKinematicBody(); -container.createFixture(new Edge(new Vec2(15, -5), new Vec2(25, 5))); -container.createFixture(new Circle(new Vec2(-10, -10), 3)); -container.createFixture(new Circle(new Vec2(10, 10), 3)); -container.createFixture(new Box(3, 3, new Vec2(-10, 10))); -container.createFixture(new Box(3, 3, new Vec2(10, -10))); - -container.createFixture(new Chain( - [ - new Vec2(-20, -20), - new Vec2(20, -20), - new Vec2(20, 20), - new Vec2(-20, 20) - ], - true -)); - -const n = 15; - -for (let i = -n; i <= n; i++) { - for (let j = -n; j <= n; j++) { - let particle = world.createDynamicBody(new Vec2(i * 1, j * 1)); - particle.createFixture(Math.random() > 0.5 ? new Circle(0.4) : new Box(0.4, 0.4)); - particle.setMassData({ - mass : 2, - center : new Vec2(), - I : 0.4 - }); - particle.applyForceToCenter(new Vec2(Math.random(-100, 100), Math.random(-100, 100))); - } -} - -container.setAngularVelocity(0.3); diff --git a/example/Mixer.ts b/example/Mixer.ts new file mode 100644 index 00000000..866ef92d --- /dev/null +++ b/example/Mixer.ts @@ -0,0 +1,49 @@ +import planck from "../src/main"; + +const { Vec2, World, Edge, Circle, Box, Chain, Math, Testbed } = planck; + +const world = new World(new Vec2(0, -10)); + +const testbed = Testbed.mount(); +testbed.y = 0; +testbed.start(world); + +const container = world.createKinematicBody(); +container.createFixture(new Edge(new Vec2(15, -5), new Vec2(25, 5))); +container.createFixture(new Circle(new Vec2(-10, -10), 3)); +container.createFixture(new Circle(new Vec2(10, 10), 3)); +container.createFixture(new Box(3, 3, new Vec2(-10, 10))); +container.createFixture(new Box(3, 3, new Vec2(10, -10))); + +container.createFixture( + new Chain( + [ + new Vec2(-20, -20), + new Vec2(20, -20), + new Vec2(20, 20), + new Vec2(-20, 20), + ], + true + ) +); + +const n = 15; + +for (let i = -n; i <= n; i++) { + for (let j = -n; j <= n; j++) { + const particle = world.createDynamicBody(new Vec2(i * 1, j * 1)); + particle.createFixture( + Math.random() > 0.5 ? new Circle(0.4) : new Box(0.4, 0.4) + ); + particle.setMassData({ + mass: 2, + center: new Vec2(), + I: 0.4, + }); + particle.applyForceToCenter( + new Vec2(Math.random(-100, 100), Math.random(-100, 100)) + ); + } +} + +container.setAngularVelocity(0.3); diff --git a/example/Mobile.js b/example/Mobile.ts similarity index 54% rename from example/Mobile.js rename to example/Mobile.ts index 53e3ad40..9c24fbdc 100644 --- a/example/Mobile.js +++ b/example/Mobile.ts @@ -20,10 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { Vec2, World, Box, RevoluteJoint, Testbed } = planck; -let world = new World(new Vec2(0, -1)); +const world = new World(new Vec2(0, -1)); const testbed = Testbed.mount(); testbed.y = -15; @@ -31,30 +32,36 @@ testbed.width = 20; testbed.height = 20; testbed.start(world); -let DEPTH = 4; -let DENSITY = 20.0; +const DEPTH = 4; +const DENSITY = 20.0; -let ground = world.createBody(new Vec2(0.0, 20.0)); +const ground = world.createBody(new Vec2(0.0, 20.0)); -let a = 0.5; -let h = new Vec2(0.0, a); +const a = 0.5; +const h = new Vec2(0.0, a); -let root = addNode(ground, new Vec2(), 0, 3.0, a); +const root = addNode(ground, new Vec2(), 0, 3.0, a); -world.createJoint(new RevoluteJoint({ - bodyA: ground, - bodyB: root, - localAnchorA: new Vec2(0, 0), - localAnchorB: h, -}, ground, root)); +world.createJoint( + /// NEED TO FIX THIS + new RevoluteJoint( + { + bodyA: ground, + bodyB: root, + localAnchorA: new Vec2(0, 0), + localAnchorB: h, + }, + ground, + root + ) +); function addNode(parent, localAnchor, depth, offset, a) { + const h = new Vec2(0.0, a); - let h = new Vec2(0.0, a); - - let node = world.createBody({ - type : 'dynamic', - position : new Vec2(parent.getPosition()).add(localAnchor).sub(h) + const node = world.createBody({ + type: "dynamic", + position: new Vec2(parent.getPosition()).add(localAnchor).sub(h), }); node.createFixture(new Box(0.25 * a, a), DENSITY); @@ -63,24 +70,38 @@ function addNode(parent, localAnchor, depth, offset, a) { return node; } - let left = new Vec2(offset, -a); - let right = new Vec2(-offset, -a); - let leftChild = addNode(node, left, depth + 1, 0.5 * offset, a); - let rightChild = addNode(node, right, depth + 1, 0.5 * offset, a); - - world.createJoint(new RevoluteJoint({ - bodyA: node, - bodyB: leftChild, - localAnchorA: left, - localAnchorB: h, - }, node, leftChild)); - - world.createJoint(new RevoluteJoint({ - bodyA: node, - bodyB: rightChild, - localAnchorA: right, - localAnchorB: h, - }, node, rightChild)); + const left = new Vec2(offset, -a); + const right = new Vec2(-offset, -a); + const leftChild = addNode(node, left, depth + 1, 0.5 * offset, a); + const rightChild = addNode(node, right, depth + 1, 0.5 * offset, a); + + world.createJoint( + /// NEED TO FIX THIS + new RevoluteJoint( + { + bodyA: node, + bodyB: leftChild, + localAnchorA: left, + localAnchorB: h, + }, + node, + leftChild + ) + ); + + world.createJoint( + /// NEED TO FIX THIS + new RevoluteJoint( + { + bodyA: node, + bodyB: rightChild, + localAnchorA: right, + localAnchorB: h, + }, + node, + rightChild + ) + ); return node; } diff --git a/example/MobileBalanced.js b/example/MobileBalanced.ts similarity index 59% rename from example/MobileBalanced.js rename to example/MobileBalanced.ts index 16c9e422..9cc6f7c3 100644 --- a/example/MobileBalanced.js +++ b/example/MobileBalanced.ts @@ -21,10 +21,11 @@ * SOFTWARE. */ -const { World, Vec2, Box, RevoluteJoint, Testbed } = planck; +import planck from "../src/main"; +const { World, Vec2, Box, RevoluteJoint, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.y = -15; @@ -32,30 +33,32 @@ testbed.width = 20; testbed.height = 20; testbed.start(world); -let DEPTH = 4; -let DENSITY = 20.0; +const DEPTH = 4; +const DENSITY = 20.0; -let ground = world.createBody(new Vec2(0.0, 20.0)); +const ground = world.createBody(new Vec2(0.0, 20.0)); -let a = 0.5; -let h = new Vec2(0.0, a); +const a = 0.5; +const h = new Vec2(0.0, a); -let root = addNode(ground, new Vec2(), 0, 3.0, a); +const root = addNode(ground, new Vec2(), 0, 3.0, a); -world.createJoint(new RevoluteJoint({ - bodyA: ground, - bodyB: root, - localAnchorA : new Vec2(), - localAnchorB : h -})); +world.createJoint( + /// NEED TO FIX THIS + new RevoluteJoint({ + bodyA: ground, + bodyB: root, + localAnchorA: new Vec2(), + localAnchorB: h, + }) +); function addNode(parent, localAnchor, depth, offset, a) { + const h = new Vec2(0.0, a); - let h = new Vec2(0.0, a); - - let p = new Vec2(parent.getPosition()).add(localAnchor).sub(h); + const p = new Vec2(parent.getPosition()).add(localAnchor).sub(h); - let node = world.createDynamicBody(p); + const node = world.createDynamicBody(p); node.createFixture(new Box(0.25 * a, a), DENSITY); @@ -65,24 +68,30 @@ function addNode(parent, localAnchor, depth, offset, a) { node.createFixture(new Box(offset, 0.25 * a, new Vec2(0, -a), 0.0), DENSITY); - let right = new Vec2(offset, -a); - let left = new Vec2(-offset, -a); - let rightChild = addNode(node, right, depth + 1, 0.5 * offset, a); - let leftChild = addNode(node, left, depth + 1, 0.5 * offset, a); - - world.createJoint(new RevoluteJoint({ - bodyA: node, - bodyB: rightChild, - localAnchorA: right, - localAnchorB: h, - })); - - world.createJoint(new RevoluteJoint({ - bodyA: node, - bodyB: leftChild, - localAnchorA: left, - localAnchorB: h, - })); + const right = new Vec2(offset, -a); + const left = new Vec2(-offset, -a); + const rightChild = addNode(node, right, depth + 1, 0.5 * offset, a); + const leftChild = addNode(node, left, depth + 1, 0.5 * offset, a); + + world.createJoint( + /// NEED TO FIX THIS + new RevoluteJoint({ + bodyA: node, + bodyB: rightChild, + localAnchorA: right, + localAnchorB: h, + }) + ); + + world.createJoint( + /// NEED TO FIX THIS + new RevoluteJoint({ + bodyA: node, + bodyB: leftChild, + localAnchorA: left, + localAnchorB: h, + }) + ); return node; } diff --git a/example/MotorJoint.js b/example/MotorJoint.ts similarity index 77% rename from example/MotorJoint.js rename to example/MotorJoint.ts index 216c3f59..216bb00e 100644 --- a/example/MotorJoint.js +++ b/example/MotorJoint.ts @@ -24,37 +24,43 @@ // This test shows how to use a motor joint. A motor joint // can be used to animate a dynamic body. With finite motor forces // the body can be blocked by collision with other bodies. +import planck from "../src/main"; const { Vec2, World, MotorJoint, Box, Edge, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); let time = 0; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0))); // Define motorized body -let body = world.createDynamicBody(new Vec2(0.0, 8.0)); +const body = world.createDynamicBody(new Vec2(0.0, 8.0)); body.createFixture(new Box(2.0, 0.5), { - friction : 0.6, - density : 2.0 + friction: 0.6, + density: 2.0, }); -let joint = world.createJoint(new MotorJoint({ - maxForce : 1000.0, - maxTorque : 1000.0 -}, ground, body)); +const joint = world.createJoint( + new MotorJoint( + { + maxForce: 1000.0, + maxTorque: 1000.0, + }, + ground, + body + ) +); -testbed.step = function(dt) { +testbed.step = function (dt) { time += Math.min(dt, 100) / 1000; - joint.setLinearOffset(new Vec2( - 6.0 * Math.sin(2.0 * time), - 8.0 + 4.0 * Math.sin(1.0 * time), - )); + joint.setLinearOffset( + new Vec2(6.0 * Math.sin(2.0 * time), 8.0 + 4.0 * Math.sin(1.0 * time)) + ); joint.setAngularOffset(4.0 * time); }; diff --git a/example/OneSidedPlatform.js b/example/OneSidedPlatform.ts similarity index 66% rename from example/OneSidedPlatform.js rename to example/OneSidedPlatform.ts index d13f5525..ec0777ac 100644 --- a/example/OneSidedPlatform.js +++ b/example/OneSidedPlatform.ts @@ -21,41 +21,40 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { Vec2, World, Edge, Box, Circle, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let radius = 0.5; -let top = 10.0 + 0.5; -let bottom = 10.0 - 0.5; - -let UNKNOWN = 0, ABOVE = +1, BELOW = -1; +const radius = 0.5; +const top = 10.0 + 0.5; -let state = UNKNOWN; +const UNKNOWN = 0; // Ground -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-20.0, 0.0), new Vec2(20.0, 0.0)), 0.0); // Platform -let platform = world.createBody(new Vec2(0.0, 10.0)); -let platformFix = platform.createFixture(new Box(3.0, 0.5), 0.0); +const platform = world.createBody(new Vec2(0.0, 10.0)); +const platformFix = platform.createFixture(new Box(3.0, 0.5), 0.0); // Actor -let character = world.createDynamicBody(new Vec2(0.0, 12.0)); -let characterFix = character.createFixture(new Circle(radius), 20.0); +const character = world.createDynamicBody(new Vec2(0.0, 12.0)); +const characterFix = character.createFixture(new Circle(radius), 20.0); character.setLinearVelocity(new Vec2(0.0, -50.0)); -world.on('pre-solve', function(contact, oldManifold) { - let fixA = contact.getFixtureA(); - let fixB = contact.getFixtureB(); +world.on("pre-solve", function (contact) { + const fixA = contact.getFixtureA(); + const fixB = contact.getFixtureB(); - let isCharPlatformContact = - fixA === platformFix && fixB === characterFix || - fixB === platformFix && fixA === characterFix; + const isCharPlatformContact = + (fixA === platformFix && fixB === characterFix) || + (fixB === platformFix && fixA === characterFix); if (!isCharPlatformContact) { return; @@ -64,7 +63,7 @@ world.on('pre-solve', function(contact, oldManifold) { if (false) { // if character is below platform // disable contact - let p = character.getPosition(); + const p = character.getPosition(); if (p.y < top + radius - 3.0 * /*linearSlop*/ 0.005) { contact.setEnabled(false); @@ -72,14 +71,14 @@ world.on('pre-solve', function(contact, oldManifold) { } else { // if character is moving up // disable contact - let v = character.getLinearVelocity(); + const v = character.getLinearVelocity(); if (v.y > 0.0) { contact.setEnabled(false); } } }); -testbed.step = function() { - let v = character.getLinearVelocity(); - testbed.status('Character Linear Velocity', v.y); +testbed.step = function () { + const v = character.getLinearVelocity(); + testbed.status("Character Linear Velocity", v.y); }; diff --git a/example/Pinball.js b/example/Pinball.ts similarity index 62% rename from example/Pinball.js rename to example/Pinball.ts index 709f9669..64716b84 100644 --- a/example/Pinball.js +++ b/example/Pinball.ts @@ -21,66 +21,83 @@ * SOFTWARE. */ -// This tests bullet collision and provides an example of a gameplay scenario. +// This tests bulconst collision and provides an example of a gameplay scenario. // This also uses a loop shape. +import planck from "../src/main"; const { World, Vec2, Circle, Box, Chain, RevoluteJoint, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); // Ground body -let ground = world.createBody(); -ground.createFixture(new Chain([ - new Vec2(0.0, -2.0), - new Vec2(8.0, 6.0), - new Vec2(8.0, 20.0), - new Vec2(-8.0, 20.0), - new Vec2(-8.0, 6.0) -], true), 0.0); +const ground = world.createBody(); +ground.createFixture( + new Chain( + [ + new Vec2(0.0, -2.0), + new Vec2(8.0, 6.0), + new Vec2(8.0, 20.0), + new Vec2(-8.0, 20.0), + new Vec2(-8.0, 6.0), + ], + true + ), + 0.0 +); // Flippers -let pLeft = new Vec2(-2.0, 0.0); -let pRight = new Vec2(2.0, 0.0); +const pLeft = new Vec2(-2.0, 0.0); +const pRight = new Vec2(2.0, 0.0); -let leftFlipper = world.createDynamicBody(new Vec2(-2.0, 0.0)); -let rightFlipper = world.createDynamicBody(new Vec2(2.0, 0.0)); +const leftFlipper = world.createDynamicBody(new Vec2(-2.0, 0.0)); +const rightFlipper = world.createDynamicBody(new Vec2(2.0, 0.0)); leftFlipper.createFixture(new Box(1.75, 0.1), 1.0); rightFlipper.createFixture(new Box(1.75, 0.1), 1.0); -let jd = { +const jd = { enableMotor: true, maxMotorTorque: 1000.0, enableLimit: true, motorSpeed: 0.0, }; -let leftJoint = new RevoluteJoint({ - ...jd, - lowerAngle: -30.0 * Math.PI / 180.0, - upperAngle: 5.0 * Math.PI / 180.0, -}, ground, leftFlipper, leftFlipper.getPosition()); +const leftJoint = new RevoluteJoint( + { + ...jd, + lowerAngle: (-30.0 * Math.PI) / 180.0, + upperAngle: (5.0 * Math.PI) / 180.0, + }, + ground, + leftFlipper, + leftFlipper.getPosition() +); world.createJoint(leftJoint); -let rightJoint = new RevoluteJoint({ - ...jd, - lowerAngle: -5.0 * Math.PI / 180.0, - upperAngle: 30.0 * Math.PI / 180.0, -}, ground, rightFlipper, rightFlipper.getPosition()); +const rightJoint = new RevoluteJoint( + { + ...jd, + lowerAngle: (-5.0 * Math.PI) / 180.0, + upperAngle: (30.0 * Math.PI) / 180.0, + }, + ground, + rightFlipper, + rightFlipper.getPosition() +); world.createJoint(rightJoint); // Circle character -let ball = world.createBody({ - position : new Vec2(1.0, 15.0), - type : 'dynamic', - bullet : true +const ball = world.createBody({ + position: new Vec2(1.0, 15.0), + type: "dynamic", + bullet: true, }); ball.createFixture(new Circle(0.2), 1.0); -testbed.step = function() { +testbed.step = function () { if (testbed.activeKeys.right) { rightJoint.setMotorSpeed(-20.0); } else { diff --git a/example/PolyCollision.js b/example/PolyCollision.ts similarity index 59% rename from example/PolyCollision.js rename to example/PolyCollision.ts index a300d6e2..ff73fb15 100644 --- a/example/PolyCollision.js +++ b/example/PolyCollision.ts @@ -20,64 +20,80 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; -const { World, Vec2, Transform, Manifold, CollidePolygons, Box, Testbed } = planck; +const { World, Vec2, Transform, Manifold, CollidePolygons, Box, Testbed } = + planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); -testbed.info('Use arrow keys to move and Z or X to rotate.'); +testbed.info("Use arrow keys to move and Z or X to rotate."); testbed.start(world); -let polygonA = new Box(2, 4); -let transformA = new Transform(new Vec2(0.0, 0.0), 0.0); +const polygonA = new Box(2, 4); +const transformA = new Transform(new Vec2(0.0, 0.0), 0.0); -let polygonB = new Box(5, 5); -let positionB = new Vec2(5, 4); +const polygonB = new Box(5, 5); +const positionB = new Vec2(5, 4); let angleB = 1.9160721; -let transformB = new Transform(positionB, angleB); +const transformB = new Transform(positionB, angleB); -testbed.step = function() { - let manifold = new Manifold(); +testbed.step = function () { + const manifold = new Manifold(); new CollidePolygons(manifold, polygonA, transformA, polygonB, transformB); - let worldManifold = manifold.getWorldManifold(null, transformA, polygonA.getRadius(), transformB, polygonB.getRadius()); + const worldManifold = manifold.getWorldManifold( + null, + transformA, + polygonA.getRadius(), + transformB, + polygonB.getRadius() + ); - testbed.status('point count', manifold.pointCount); + testbed.status("point count", manifold.pointCount); - let vA = polygonA.m_vertices.map(v => Transform.mul(transformA, v)); + const vA = polygonA.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformA, v) + ); testbed.drawPolygon(vA, testbed.color(0.9, 0.9, 0.9)); - let vB = polygonB.m_vertices.map(v => Transform.mul(transformB, v)); + const vB = polygonB.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformB, v) + ); testbed.drawPolygon(vB, testbed.color(0.9, 0.9, 0.9)); for (let i = 0; i < manifold.pointCount; ++i) { - testbed.drawPoint(worldManifold.points[i], 4.0, testbed.color(0.9, 0.3, 0.3)); + testbed.drawPoint( + worldManifold.points[i], + 4.0, + testbed.color(0.9, 0.3, 0.3) + ); } }; -testbed.keydown = function() { - if (testbed.activeKeys['left']) { +testbed.keydown = function () { + if (testbed.activeKeys["left"]) { positionB.x -= 0.2; } - if (testbed.activeKeys['right']) { + if (testbed.activeKeys["right"]) { positionB.x += 0.2; } - if (testbed.activeKeys['down']) { + if (testbed.activeKeys["down"]) { positionB.y -= 0.2; } - if (testbed.activeKeys['up']) { + if (testbed.activeKeys["up"]) { positionB.y += 0.2; } - if (testbed.activeKeys['Z']) { + if (testbed.activeKeys["Z"]) { angleB += 0.2; } - if (testbed.activeKeys['X']) { + if (testbed.activeKeys["X"]) { angleB -= 0.2; } diff --git a/example/PolyShapes.js b/example/PolyShapes.ts similarity index 57% rename from example/PolyShapes.js rename to example/PolyShapes.ts index 08be6bd9..9995c213 100644 --- a/example/PolyShapes.js +++ b/example/PolyShapes.ts @@ -20,38 +20,50 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -const { Vec2, Transform, AABB, Circle, Polygon, Edge, Box, World, Distance, Testbed } = planck; - -let world = new World(new Vec2(0, -10)); +import planck from "../src/main"; + +const { + Vec2, + Transform, + AABB, + Circle, + Polygon, + Edge, + Box, + World, + Distance, + Testbed, +} = planck; + +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let MAX_BODIES = 256; +const MAX_BODIES = 256; -let bodies = []; +const bodies = []; -let shapes = []; +const shapes = []; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); shapes[0] = new Polygon([ new Vec2(-0.5, 0.0), new Vec2(0.5, 0.0), - new Vec2(0.0, 1.5) + new Vec2(0.0, 1.5), ]); shapes[1] = new Polygon([ new Vec2(-0.1, 0.0), new Vec2(0.1, 0.0), - new Vec2(0.0, 1.5) + new Vec2(0.0, 1.5), ]); { - let w = 1.0; - let b = w / (2.0 + Math.sqrt(2.0)); - let s = Math.sqrt(2.0) * b; + const w = 1.0; + const b = w / (2.0 + Math.sqrt(2.0)); + const s = Math.sqrt(2.0) * b; shapes[2] = new Polygon([ new Vec2(0.5 * s, 0.0), @@ -74,8 +86,8 @@ function createBody(index) { world.destroyBody(bodies.shift()); } - let bd = { - type: 'dynamic', + const bd: any = { + type: "dynamic", position: new Vec2(Math.random() * 0.4 - 2.0, 10.0), angle: Math.random() * 2 * Math.PI - Math.PI, }; @@ -84,7 +96,7 @@ function createBody(index) { bd.angularDamping = 0.02; } - let body = world.createBody(bd); + const body = world.createBody(bd); body.createFixture(shapes[index % shapes.length], { density: 1.0, @@ -98,79 +110,89 @@ function destroyBody() { world.destroyBody(bodies.shift()); } -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case '1': - createBody(1); - break; - - case '2': - createBody(2); - break; - - case '3': - createBody(3); - break; - - case '4': - createBody(4); - break; - - case '5': - createBody(5); - break; - - case 'Z': - for (let i = 0; i < bodies.length; i += 2) { - let body = bodies[i]; - body.setActive(!body.isActive()); - } - break; - - case 'X': - destroyBody(); - break; + case "1": + createBody(1); + break; + + case "2": + createBody(2); + break; + + case "3": + createBody(3); + break; + + case "4": + createBody(4); + break; + + case "5": + createBody(5); + break; + + case "Z": + for (let i = 0; i < bodies.length; i += 2) { + const body = bodies[i]; + body.setActive(!body.isActive()); + } + break; + + case "X": + destroyBody(); + break; } }; -testbed.info('1-5: Drop new objects, Z: Activate/deactivate some bodies, X: Destroy an object'); +testbed.info( + "1-5: Drop new objects, Z: Activate/deactivate some bodies, X: Destroy an object" +); -testbed.step = function() { +testbed.step = function () { AABBQueryListener.reset(); - let aabb = new AABB(); + const aabb = new AABB(); AABBQueryListener.circle.computeAABB(aabb, AABBQueryListener.transform, 0); world.queryAABB(aabb, AABBQueryListener.callback); - testbed.drawCircle(AABBQueryListener.circle.m_p, AABBQueryListener.circle.m_radius, testbed.color(0.4, 0.7, 0.8)); + testbed.drawCircle( + AABBQueryListener.circle.m_p, + AABBQueryListener.circle.m_radius, + testbed.color(0.4, 0.7, 0.8) + ); }; function drawFixture(fixture) { - let color = testbed.color(0.95, 0.95, 0.6); - let xf = fixture.getBody().getTransform(); + const color = testbed.color(0.95, 0.95, 0.6); + const xf = fixture.getBody().getTransform(); switch (fixture.getType()) { - case 'circle': { - let circle = fixture.getShape(); - - let center = Transform.mul(xf, circle.getCenter()); - let radius = circle.getRadius(); - - testbed.drawCircle(center, radius, color); - } - break; - - case 'polygon': { - let poly = fixture.getShape(); - let vertexCount = poly.m_count; - // assert(vertexCount <= b2_maxPolygonVertices); - let vertices = poly.m_vertices.map(v => Transform.mul(xf, v)); - testbed.drawPolygon(vertices, color); - } - break; - - default: - break; + case "circle": + { + const circle = fixture.getShape(); + + const center = Transform.mul(xf, circle.getCenter()); + const radius = circle.getRadius(); + + testbed.drawCircle(center, radius, color); + } + break; + + case "polygon": + { + const poly = fixture.getShape(); + const vertexCount = poly.m_count; + // assert(vertexCount <= b2_maxPolygonVertices); + const vertices = poly.m_vertices.map((v: planck.Vec2) => + Transform.mul(xf, v) + ); + testbed.drawPolygon(vertices, color); + } + break; + + default: + break; } } @@ -179,29 +201,36 @@ function drawFixture(fixture) { // that overlap an AABB. Of those, we use TestOverlap to determine which fixtures // overlap a circle. Up to 4 overlapped fixtures will be highlighted with a // yellow border. -let AABBQueryListener = (function() { - let def = {}; +const AABBQueryListener = (function () { + const def: any = {}; def.circle = new Circle(new Vec2(0.0, 1.1), 2.0); def.transform = new Transform(); let count = 0; - let MAX_COUNT = 40; + const MAX_COUNT = 40; - def.reset = function() { + def.reset = function () { count = 0; }; // Called for each fixture found in the query AABB. // return false to terminate the query. - def.callback = function(fixture) { + def.callback = function (fixture) { if (count === MAX_COUNT) { return false; } - let body = fixture.getBody(); - let shape = fixture.getShape(); - - let overlap = Distance.testOverlap(shape, 0, def.circle, 0, body.getTransform(), def.transform); + const body = fixture.getBody(); + const shape = fixture.getShape(); + + const overlap = Distance.testOverlap( + shape, + 0, + def.circle, + 0, + body.getTransform(), + def.transform + ); if (overlap) { drawFixture(fixture); diff --git a/example/Prismatic.js b/example/Prismatic.ts similarity index 77% rename from example/Prismatic.js rename to example/Prismatic.ts index 24343652..1d6361d1 100644 --- a/example/Prismatic.js +++ b/example/Prismatic.ts @@ -22,70 +22,73 @@ */ // The motor in this test gets smoother with higher velocity iterations. +import planck from "../src/main"; const { World, Vec2, PrismaticJoint, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let MOTOR_SPEED = 10; +const MOTOR_SPEED = 10; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let body = world.createBody({ - type : 'dynamic', - position : new Vec2(-10.0, 10.0), - angle : 0.5 * Math.PI, - allowSleep : false +const body = world.createBody({ + type: "dynamic", + position: new Vec2(-10.0, 10.0), + angle: 0.5 * Math.PI, + allowSleep: false, }); body.createFixture(new Box(2.0, 0.5), 5.0); // Bouncy limit -let axis = new Vec2(2.0, 1.0); +const axis = new Vec2(2.0, 1.0); axis.normalize(); -let joint = new PrismaticJoint({ - motorSpeed : MOTOR_SPEED, - maxMotorForce : 10000.0, - enableMotor : true, - lowerTranslation : 0.0, - upperTranslation : 20.0, - enableLimit : true -}, ground, body, new Vec2(0.0, 0.0), axis); +const joint = new PrismaticJoint( + { + motorSpeed: MOTOR_SPEED, + maxMotorForce: 10000.0, + enableMotor: true, + lowerTranslation: 0.0, + upperTranslation: 20.0, + enableLimit: true, + }, + ground, + body, + new Vec2(0.0, 0.0), + axis +); // Non-bouncy limit // (ground, body, new Vec2(-10.0, 10.0), new Vec2(1.0, 0.0)); world.createJoint(joint); -testbed.step = function() { +testbed.step = function () { if (testbed.activeKeys.right && !testbed.activeKeys.left) { joint.enableLimit(true); joint.enableMotor(true); joint.setMotorSpeed(+MOTOR_SPEED); - } else if (testbed.activeKeys.left && !testbed.activeKeys.right) { joint.enableLimit(true); joint.enableMotor(true); joint.setMotorSpeed(-MOTOR_SPEED); - } else if (testbed.activeKeys.up && !testbed.activeKeys.down) { joint.enableLimit(false); joint.enableMotor(true); joint.setMotorSpeed(+MOTOR_SPEED); - } else if (testbed.activeKeys.down && !testbed.activeKeys.up) { joint.enableLimit(false); joint.enableMotor(true); joint.setMotorSpeed(-MOTOR_SPEED); - } else { joint.enableLimit(true); joint.enableMotor(false); } - let force = joint.getMotorForce(1 / 60); - testbed.status('Motor Force', force); + const force = joint.getMotorForce(1 / 60); + testbed.status("Motor Force", force); }; diff --git a/example/Pulleys.js b/example/Pulleys.ts similarity index 64% rename from example/Pulleys.js rename to example/Pulleys.ts index 68f2058d..a4375455 100644 --- a/example/Pulleys.js +++ b/example/Pulleys.ts @@ -21,44 +21,57 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { Vec2, World, Circle, Box, PulleyJoint, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let y = 16.0; -let L = 12.0; -let a = 1.0; -let b = 2.0; +const y = 16.0; +const L = 12.0; +const a = 1.0; +const b = 2.0; -let ground = world.createBody(); +const ground = world.createBody(); // ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); ground.createFixture(new Circle(new Vec2(-10.0, y + b + L), 2.0), 0.0); ground.createFixture(new Circle(new Vec2(10.0, y + b + L), 2.0), 0.0); -let shape = new Box(a, b); +const shape = new Box(a, b); // bd.fixedRotation = true; -let box1 = world.createDynamicBody(new Vec2(-10.0, y)); +const box1 = world.createDynamicBody(new Vec2(-10.0, y)); box1.createFixture(shape, 5.0); -let box2 = world.createDynamicBody(new Vec2(10.0, y)); +const box2 = world.createDynamicBody(new Vec2(10.0, y)); box2.createFixture(shape, 5.0); -let anchor1 = new Vec2(-10.0, y + b); -let anchor2 = new Vec2(10.0, y + b); -let groundAnchor1 = new Vec2(-10.0, y + b + L); -let groundAnchor2 = new Vec2(10.0, y + b + L); +const anchor1 = new Vec2(-10.0, y + b); +const anchor2 = new Vec2(10.0, y + b); +const groundAnchor1 = new Vec2(-10.0, y + b + L); +const groundAnchor2 = new Vec2(10.0, y + b + L); -let joint1 = world.createJoint(new PulleyJoint({}, box1, box2, groundAnchor1, groundAnchor2, anchor1, anchor2, 1.5)); +const joint1 = world.createJoint( + new PulleyJoint( + {}, + box1, + box2, + groundAnchor1, + groundAnchor2, + anchor1, + anchor2, + 1.5 + ) +); -testbed.step = function() { - let ratio = joint1.getRatio(); - let L = joint1.getCurrentLengthA() + ratio * joint1.getCurrentLengthB(); - testbed.status('ratio', ratio); - testbed.status('L (L1 * ratio + L2)', L); +testbed.step = function () { + const ratio = joint1.getRatio(); + const L = joint1.getCurrentLengthA() + ratio * joint1.getCurrentLengthB(); + testbed.status("ratio", ratio); + testbed.status("L (L1 * ratio + L2)", L); }; diff --git a/example/Pyramid.js b/example/Pyramid.ts similarity index 80% rename from example/Pyramid.js rename to example/Pyramid.ts index e87a58ef..a8fbf6e4 100644 --- a/example/Pyramid.js +++ b/example/Pyramid.ts @@ -20,31 +20,31 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; const { Vec2, World, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 20; +const COUNT = 20; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let a = 0.5; -let box = new Box(a, a); +const a = 0.5; +const box = new Box(a, a); -let x = new Vec2(-7.0, 0.75); -let y = new Vec2(); -let deltaX = new Vec2(0.5625, 1.25); -let deltaY = new Vec2(1.125, 0.0); +const x = new Vec2(-7.0, 0.75); +const y = new Vec2(); +const deltaX = new Vec2(0.5625, 1.25); +const deltaY = new Vec2(1.125, 0.0); for (let i = 0; i < COUNT; ++i) { y.set(x); for (let j = i; j < COUNT; ++j) { - world.createDynamicBody(y).createFixture(box, 5.0); y.add(deltaY); @@ -52,8 +52,8 @@ for (let i = 0; i < COUNT; ++i) { x.add(deltaX); } -testbed.step = function() { - // let tree = world.m_broadPhase.m_tree; +testbed.step = function () { + // const tree = world.m_broadPhase.m_tree; // if (stepCount++ == 400) { // tree.rebuildBottomUp(); // } diff --git a/example/RayCast.js b/example/RayCast.ts similarity index 63% rename from example/RayCast.js rename to example/RayCast.ts index 0a672992..e89e4e75 100644 --- a/example/RayCast.js +++ b/example/RayCast.ts @@ -25,21 +25,23 @@ // NOTE: we are intentionally filtering one of the polygons, therefore // the ray will always miss one type of polygon. +import planck from "../src/main"; + const { World, Vec2, Transform, Edge, Circle, Polygon, Box, Testbed } = planck; // This callback finds the closest hit. Polygon 0 is filtered. -let RayCastClosest = (function() { - let def = {}; +const RayCastClosest = (function () { + const def: any = {}; - def.reset = function() { + def.reset = function () { def.hit = false; def.point = null; def.normal = null; }; - def.callback = function(fixture, point, normal, fraction) { - let body = fixture.getBody(); - let userData = body.getUserData(); + def.callback = function (fixture, point, normal, fraction) { + const body = fixture.getBody(); + const userData = body.getUserData(); if (userData !== undefined) { if (userData === 0) { // By returning -1, we instruct the calling code to ignore this fixture and @@ -61,21 +63,20 @@ let RayCastClosest = (function() { return def; })(); - // This callback finds any hit. Polygon 0 is filtered. For this type of query we are usually // just checking for obstruction, so the actual fixture and hit point are irrelevant. -let RayCastAny = (function() { - let def = {}; +const RayCastAny = (function () { + const def: any = {}; - def.reset = function() { + def.reset = function () { def.hit = false; def.point = null; def.normal = null; }; - def.callback = function(fixture, point, normal, fraction) { - let body = fixture.getBody(); - let userData = body.getUserData(); + def.callback = function (fixture, point, normal, fraction) { + const body = fixture.getBody(); + const userData = body.getUserData(); if (userData !== undefined) { if (userData === 0) { // By returning -1, we instruct the calling code to ignore this fixture @@ -99,18 +100,18 @@ let RayCastAny = (function() { // This ray cast collects multiple hits along the ray. Polygon 0 is filtered. // The fixtures are not necessary reported in order, so we might not capture // the closest fixture. -let RayCastMultiple = (function() { - let def = {}; - // let MAX_COUNT = 3; +const RayCastMultiple = (function () { + const def: any = {}; + // const MAX_COUNT = 3; - def.reset = function() { + def.reset = function () { def.points = []; def.normals = []; }; - def.callback = function(fixture, point, normal, fraction) { - let body = fixture.getBody(); - let userData = body.getUserData(); + def.callback = function (fixture, point, normal, fraction) { + const body = fixture.getBody(); + const userData = body.getUserData(); if (userData !== undefined) { if (userData === 0) { // By returning -1, we instruct the calling code to ignore this fixture @@ -141,16 +142,18 @@ const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.width = 40; testbed.height = 40; -testbed.info('1-6: Drop new objects, Z: Change mode, X: Destroy an object'); +testbed.info("1-6: Drop new objects, Z: Change mode, X: Destroy an object"); testbed.start(world); -let MAX_BODIES = 256; +const MAX_BODIES = 256; // mode -let CLOSEST = 1, ANY = 2, MULTIPLE = 3; +const CLOSEST = 1, + ANY = 2, + MULTIPLE = 3; -let bodies = []; -let shapes = []; +const bodies = []; +const shapes = []; let angle = 0.0; let mode = CLOSEST; @@ -158,17 +161,17 @@ let mode = CLOSEST; shapes[0] = new Polygon([ new Vec2(-0.5, 0.0), new Vec2(0.5, 0.0), - new Vec2(0.0, 1.5) + new Vec2(0.0, 1.5), ]); shapes[1] = new Polygon([ new Vec2(-0.1, 0.0), new Vec2(0.1, 0.0), - new Vec2(0.0, 1.5) + new Vec2(0.0, 1.5), ]); -let w = 1.0; -let b = w / (2.0 + Math.sqrt(2.0)); -let s = Math.sqrt(2.0) * b; +const w = 1.0; +const b = w / (2.0 + Math.sqrt(2.0)); +const s = Math.sqrt(2.0) * b; shapes[2] = new Polygon([ new Vec2(0.5 * s, 0.0), @@ -178,7 +181,7 @@ shapes[2] = new Polygon([ new Vec2(-0.5 * s, w), new Vec2(-0.5 * w, b + s), new Vec2(-0.5 * w, b), - new Vec2(-0.5 * s, 0.0) + new Vec2(-0.5 * s, 0.0), ]); shapes[3] = new Box(0.5, 0.5); @@ -190,10 +193,10 @@ function createBody(index) { world.destroyBody(bodies.shift()); } - let x = Math.random() * 20 - 10; - let y = Math.random() * 20; + const x = Math.random() * 20 - 10; + const y = Math.random() * 20; - let bd = {}; + const bd: any = {}; bd.position = new Vec2(x, y); bd.angle = Math.random() * 2 * Math.PI - Math.PI; bd.userData = index; @@ -202,11 +205,11 @@ function createBody(index) { bd.angularDamping = 0.02; } - let body = world.createBody(bd); + const body = world.createBody(bd); - let shape = shapes[index % shapes.length]; + const shape = shapes[index % shapes.length]; - body.createFixture(shape, {friction: 0.3}); + body.createFixture(shape, { friction: 0.3 }); bodies.push(body); } @@ -216,38 +219,38 @@ function destroyBody() { body && world.destroyBody(body); } -testbed.keydown = function(code, char) { - switch (char){ - case 'Z': - if (mode === CLOSEST) { - mode = ANY; - } else if (mode === ANY) { - mode = MULTIPLE; - } else if (mode === MULTIPLE) { - mode = CLOSEST; - } - break; - case 'X': - destroyBody(); - break; - case '1': - createBody(0); - break; - case '2': - createBody(1); - break; - case '3': - createBody(2); - break; - case '4': - createBody(3); - break; - case '5': - createBody(4); - break; - case '6': - createBody(5); - break; +testbed.keydown = function (code, char) { + switch (char) { + case "Z": + if (mode === CLOSEST) { + mode = ANY; + } else if (mode === ANY) { + mode = MULTIPLE; + } else if (mode === MULTIPLE) { + mode = CLOSEST; + } + break; + case "X": + destroyBody(); + break; + case "1": + createBody(0); + break; + case "2": + createBody(1); + break; + case "3": + createBody(2); + break; + case "4": + createBody(3); + break; + case "5": + createBody(4); + break; + case "6": + createBody(5); + break; } updateStatus(); @@ -255,91 +258,113 @@ testbed.keydown = function(code, char) { function updateStatus() { switch (mode) { - case CLOSEST: - testbed.status('Ray-cast mode', 'Closest - find closest fixture along the ray'); - break; - - case ANY: - testbed.status('Ray-cast mode', 'Any - check for obstruction'); - break; - - case MULTIPLE: - testbed.status('Ray-cast mode', 'Multiple - gather multiple fixtures'); - break; + case CLOSEST: + testbed.status( + "Ray-cast mode", + "Closest - find closest fixture along the ray" + ); + break; + + case ANY: + testbed.status("Ray-cast mode", "Any - check for obstruction"); + break; + + case MULTIPLE: + testbed.status("Ray-cast mode", "Multiple - gather multiple fixtures"); + break; } } -testbed.step = function() { - let advanceRay = true; +testbed.step = function () { + const advanceRay = true; - let L = 11.0; - let point1 = new Vec2(0.0, 10.0); - let d = new Vec2(L * Math.cos(angle), L * Math.sin(angle)); - let point2 = Vec2.add(point1, d); + const L = 11.0; + const point1 = new Vec2(0.0, 10.0); + const d = new Vec2(L * Math.cos(angle), L * Math.sin(angle)); + const point2 = Vec2.add(point1, d); if (mode === CLOSEST) { RayCastClosest.reset(); world.rayCast(point1, point2, RayCastClosest.callback); if (RayCastClosest.hit) { - testbed.drawPoint(RayCastClosest.point, 5.0, testbed.color(0.4, 0.9, 0.4)); - testbed.drawSegment(point1, RayCastClosest.point, testbed.color(0.8, 0.8, 0.8)); - let head = Vec2.combine(1, RayCastClosest.point, 2, RayCastClosest.normal); - testbed.drawSegment(RayCastClosest.point, head, testbed.color(0.9, 0.9, 0.4)); + testbed.drawPoint( + RayCastClosest.point, + 5.0, + testbed.color(0.4, 0.9, 0.4) + ); + testbed.drawSegment( + point1, + RayCastClosest.point, + testbed.color(0.8, 0.8, 0.8) + ); + const head = Vec2.combine( + 1, + RayCastClosest.point, + 2, + RayCastClosest.normal + ); + testbed.drawSegment( + RayCastClosest.point, + head, + testbed.color(0.9, 0.9, 0.4) + ); } else { testbed.drawSegment(point1, point2, testbed.color(0.8, 0.8, 0.8)); } - } else if (mode === ANY) { RayCastAny.reset(); world.rayCast(point1, point2, RayCastAny.callback); if (RayCastAny.hit) { testbed.drawPoint(RayCastAny.point, 5.0, testbed.color(0.4, 0.9, 0.4)); - testbed.drawSegment(point1, RayCastAny.point, testbed.color(0.8, 0.8, 0.8)); - let head = Vec2.combine(1, RayCastAny.point, 2, RayCastAny.normal); + testbed.drawSegment( + point1, + RayCastAny.point, + testbed.color(0.8, 0.8, 0.8) + ); + const head = Vec2.combine(1, RayCastAny.point, 2, RayCastAny.normal); testbed.drawSegment(RayCastAny.point, head, testbed.color(0.9, 0.9, 0.4)); } else { testbed.drawSegment(point1, point2, testbed.color(0.8, 0.8, 0.8)); } - } else if (mode === MULTIPLE) { RayCastMultiple.reset(); world.rayCast(point1, point2, RayCastMultiple.callback); testbed.drawSegment(point1, point2, testbed.color(0.8, 0.8, 0.8)); for (let i = 0; i < RayCastMultiple.points.length; ++i) { - let p = RayCastMultiple.points[i]; - let n = RayCastMultiple.normals[i]; + const p = RayCastMultiple.points[i]; + const n = RayCastMultiple.normals[i]; testbed.drawPoint(p, 5.0, testbed.color(0.4, 0.9, 0.4)); testbed.drawSegment(point1, p, testbed.color(0.8, 0.8, 0.8)); - let head = Vec2.combine(1, p, 0.5, n); + const head = Vec2.combine(1, p, 0.5, n); testbed.drawSegment(p, head, testbed.color(0.9, 0.9, 0.4)); } } if (advanceRay) { - angle += 0.25 * Math.PI / 180.0; + angle += (0.25 * Math.PI) / 180.0; } if (false) { // This case was failing. - let shape = new Box(22.875, 3.0); + const shape = new Box(22.875, 3.0); - let input = {}; // RayCastInput + const input: planck.RayCastInput = {} as any; // RayCastInput input.p1 = new Vec2(10.2725, 1.71372); input.p2 = new Vec2(10.2353, 2.21807); // input.maxFraction = 0.567623; input.maxFraction = 0.56762173; - let xf = new Transform(new Vec2(23.0, 5.0)); + const xf = new Transform(new Vec2(23.0, 5.0)); - let output = {}; // RayCastOutput - let hit = shape.rayCast(output, input, xf); + const output: planck.RayCastOutput = {} as any; // RayCastOutput + let hit = shape.rayCast(output, input, xf, 0); hit = false; - let color = testbed.color(1.0, 1.0, 1.0); - let vs = shape.vertices.map(v => Transform.mul(xf, v)); + const color = testbed.color(1.0, 1.0, 1.0); + const vs = shape.m_vertices.map((v: planck.Vec2) => Transform.mul(xf, v)); testbed.drawPolygon(vs, color); testbed.drawSegment(input.p1, input.p2, color); diff --git a/example/Revolute.js b/example/Revolute.ts similarity index 55% rename from example/Revolute.js rename to example/Revolute.ts index c1a7fce3..fc7af9bb 100644 --- a/example/Revolute.js +++ b/example/Revolute.ts @@ -20,87 +20,108 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +import planck from "../src/main"; +const { World, Vec2, Edge, Circle, Box, Polygon, RevoluteJoint, Testbed } = + planck; -const { World, Vec2, Edge, Circle, Box, Polygon, RevoluteJoint, Testbed } = planck; - -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -testbed.info('Z: Limits, X: Motor'); +testbed.info("Z: Limits, X: Motor"); -let ground = world.createBody(); +const ground = world.createBody(); -let groundFD = { +const groundFD = { filterCategoryBits: 2, - filterMaskBits: 0xFFFF, + filterMaskBits: 0xffff, filterGroupIndex: 0, }; -ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), groundFD); +ground.createFixture( + new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), + groundFD +); -let rotator = world.createDynamicBody(new Vec2(-10.0, 20.0)); +const rotator = world.createDynamicBody(new Vec2(-10.0, 20.0)); rotator.createFixture(new Circle(0.5), 5.0); -let w = 100.0; +const w = 100.0; rotator.setAngularVelocity(w); rotator.setLinearVelocity(new Vec2(-8.0 * w, 0.0)); -let joint = world.createJoint(new RevoluteJoint({ - motorSpeed: 1.0 * Math.PI, - maxMotorTorque: 10000.0, - enableMotor: true, - lowerAngle: -0.25 * Math.PI, - upperAngle: 0.5 * Math.PI, - enableLimit: false, - collideConnected: true, -}, ground, rotator, new Vec2(-10.0, 12.0))); - -let ball = world.createDynamicBody(new Vec2(5.0, 30.0)); +const joint = world.createJoint( + new RevoluteJoint( + { + motorSpeed: 1.0 * Math.PI, + maxMotorTorque: 10000.0, + enableMotor: true, + lowerAngle: -0.25 * Math.PI, + upperAngle: 0.5 * Math.PI, + enableLimit: false, + collideConnected: true, + }, + ground, + rotator, + new Vec2(-10.0, 12.0) + ) +); + +const ball = world.createDynamicBody(new Vec2(5.0, 30.0)); ball.createFixture(new Circle(3.0), { density: 5.0, // filterMaskBits: 1, }); -let platform = world.createBody({ +const platform = world.createBody({ position: new Vec2(20.0, 10.0), - type: 'dynamic', + type: "dynamic", bullet: true, }); platform.createFixture(new Box(10.0, 0.2, new Vec2(-10.0, 0.0), 0.0), 2.0); -world.createJoint(new RevoluteJoint({ - lowerAngle: -0.25 * Math.PI, - upperAngle: 0.0 * Math.PI, - enableLimit: true, -}, ground, platform, new Vec2(20.0, 10.0))); +world.createJoint( + new RevoluteJoint( + { + lowerAngle: -0.25 * Math.PI, + upperAngle: 0.0 * Math.PI, + enableLimit: true, + }, + ground, + platform, + new Vec2(20.0, 10.0) + ) +); // Tests mass computation of a small object far from the origin -let triangle = world.createDynamicBody(); - -triangle.createFixture(new Polygon([ - new Vec2(17.63, 36.31), - new Vec2(17.52, 36.69), - new Vec2(17.19, 36.36) -]), 1); // assertion hits inside here - -testbed.keydown = function(code, char) { +const triangle = world.createDynamicBody(); + +triangle.createFixture( + new Polygon([ + new Vec2(17.63, 36.31), + new Vec2(17.52, 36.69), + new Vec2(17.19, 36.36), + ]), + 1 +); // assertion hits inside here + +testbed.keydown = function (code, char) { switch (char) { - case 'Z': - joint.enableLimit(!joint.isLimitEnabled()); - break; + case "Z": + joint.enableLimit(!joint.isLimitEnabled()); + break; - case 'X': - joint.enableMotor(!joint.isMotorEnabled()); - break; + case "X": + joint.enableMotor(!joint.isMotorEnabled()); + break; } }; -testbed.step = function() { +testbed.step = function () { // if (stepCount++ == 360) { // ball.setTransform(new Vec2(0.0, 0.5), 0.0); // } - testbed.status('Motor Torque', joint.getMotorTorque(testbed.hz)); + testbed.status("Motor Torque", joint.getMotorTorque(testbed.hz)); // testbed.status('Motor Force', joint.getMaxForce()); }; diff --git a/example/RopeJoint.js b/example/RopeJoint.ts similarity index 83% rename from example/RopeJoint.js rename to example/RopeJoint.ts index 16eea41f..5eeba861 100644 --- a/example/RopeJoint.js +++ b/example/RopeJoint.ts @@ -30,37 +30,40 @@ // This test also shows how to use contact filtering. Filtering is configured // so that the payload does not collide with the chain. +import planck from "../src/main"; + const { Vec2, World, Edge, Box, RevoluteJoint, RopeJoint, Testbed } = planck; -let world = new World({x: 0, y: -10}); +/// NEED TO FIX THIS +const world = new World({ x: 0, y: -10 }); const testbed = Testbed.mount(); -testbed.info('X: Toggle the rope joint'); +testbed.info("X: Toggle the rope joint"); testbed.start(world); -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let segmentDef = { +const segmentDef = { density: 20.0, friction: 0.2, filterCategoryBits: 0x0001, - filterMaskBits: 0xFFFF & ~0x0002, + filterMaskBits: 0xffff & ~0x0002, }; -let segmentJointDef = { +const segmentJointDef = { collideConnected: false, }; -let N = 10; -let y = 15.0; +const N = 10; +const y = 15.0; let prevBody = ground; for (let i = 0; i < N; ++i) { let shape = new Box(0.5, 0.125); - let bd = { - type: 'dynamic', + const bd: any = { + type: "dynamic", position: new Vec2(0.5 + 1.0 * i, y), }; if (i === N - 1) { @@ -71,29 +74,31 @@ for (let i = 0; i < N; ++i) { bd.angularDamping = 0.4; } - let body = world.createBody(bd); + const body = world.createBody(bd); body.createFixture(shape, segmentDef); - let anchor = new Vec2(i, y); + const anchor = new Vec2(i, y); world.createJoint(new RevoluteJoint(segmentJointDef, prevBody, body, anchor)); prevBody = body; } -let ropeJointDef = { +const ropeJointDef = { maxLength: N - 1.0 + 0.01, localAnchorA: new Vec2(0.0, y), localAnchorB: new Vec2(0, 0), }; +/// NEED TO FIX THIS let rope = world.createJoint(new RopeJoint(ropeJointDef, ground, prevBody)); -testbed.keydown = function(code, char) { - if (char === 'X') { +testbed.keydown = function (code, char) { + if (char === "X") { if (rope) { world.destroyJoint(rope); rope = null; } else { + /// NEED TO FIX THIS rope = world.createJoint(new RopeJoint(ropeJointDef, ground, prevBody)); } } @@ -102,7 +107,7 @@ testbed.keydown = function(code, char) { }; function updateStatus() { - testbed.status('Rope', !!rope); + testbed.status("Rope", !!rope); } updateStatus(); diff --git a/example/SensorTest.js b/example/SensorTest.ts similarity index 69% rename from example/SensorTest.js rename to example/SensorTest.ts index 1b55488c..cdd72526 100644 --- a/example/SensorTest.js +++ b/example/SensorTest.ts @@ -22,21 +22,22 @@ */ // This is used to test sensor shapes. +import planck from "../src/main"; const { World, Vec2, Circle, Box, Edge, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 7; +const COUNT = 7; -let sensor; -let bodies = []; -let touching = []; +let sensor: planck.Fixture; +const bodies = []; +const touching = []; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); if (0) { @@ -44,7 +45,6 @@ if (0) { shape: new Box(10.0, 2.0, new Vec2(0.0, 20.0), 0.0), isSensor: true, }); - } else { sensor = ground.createFixture({ shape: new Circle(new Vec2(0.0, 10.0), 5.0), @@ -52,10 +52,10 @@ if (0) { }); } -let circle = new Circle(1.0); +const circle = new Circle(1.0); for (let i = 0; i < COUNT; ++i) { - touching[i] = { touching : false }; + touching[i] = { touching: false }; bodies[i] = world.createDynamicBody(new Vec2(-10.0 + 3.0 * i, 20.0)); bodies[i].setUserData(touching[i]); @@ -63,19 +63,19 @@ for (let i = 0; i < COUNT; ++i) { } // Implement contact listener. -world.on('begin-contact', function(contact) { - let fixtureA = contact.getFixtureA(); - let fixtureB = contact.getFixtureB(); +world.on("begin-contact", function (contact) { + const fixtureA = contact.getFixtureA(); + const fixtureB = contact.getFixtureB(); if (fixtureA === sensor) { - let userData = fixtureB.getBody().getUserData(); + const userData = fixtureB.getBody().getUserData() as any; if (userData) { userData.touching = true; } } if (fixtureB === sensor) { - let userData = fixtureA.getBody().getUserData(); + const userData = fixtureA.getBody().getUserData() as any; if (userData) { userData.touching = true; } @@ -83,26 +83,26 @@ world.on('begin-contact', function(contact) { }); // Implement contact listener. -world.on('end-contact', function(contact) { - let fixtureA = contact.getFixtureA(); - let fixtureB = contact.getFixtureB(); +world.on("end-contact", function (contact) { + const fixtureA = contact.getFixtureA(); + const fixtureB = contact.getFixtureB(); if (fixtureA === sensor) { - let userData = fixtureB.getBody().getUserData(); + const userData = fixtureB.getBody().getUserData() as any; if (userData) { userData.touching = false; } } if (fixtureB === sensor) { - let userData = fixtureA.getBody().getUserData(); + const userData = fixtureA.getBody().getUserData() as any; if (userData) { userData.touching = false; } } }); -testbed.step = function() { +testbed.step = function () { // Traverse the contact results. Apply a force on shapes // that overlap the sensor. for (let i = 0; i < COUNT; ++i) { @@ -110,21 +110,23 @@ testbed.step = function() { continue; } - let body = bodies[i]; - let ground = sensor.getBody(); + const body = bodies[i]; + const ground = sensor.getBody(); + + const circle = sensor.getShape() as planck.CircleShape; - let circle = sensor.getShape(); - let center = ground.getWorldPoint(circle.getCenter()); + /// NEED TO FIX THIS + const center = ground.getWorldPoint(circle.getCenter()); - let position = body.getPosition(); + const position = body.getPosition(); - let d = Vec2.sub(center, position); + const d = Vec2.sub(center, position); if (d.lengthSquared() < 1e-18) { continue; } d.normalize(); - let F = Vec2.mul(d, 100.0); + const F = Vec2.mul(d, 100.0); body.applyForce(F, position, false); } }; diff --git a/example/ShapeCast.js b/example/ShapeCast.ts similarity index 82% rename from example/ShapeCast.js rename to example/ShapeCast.ts index 1d1630d3..4e574ac9 100644 --- a/example/ShapeCast.js +++ b/example/ShapeCast.ts @@ -21,26 +21,43 @@ * SOFTWARE. */ -const { Vec2, Transform, World, Settings, ShapeCastInput, ShapeCastOutput, ShapeCast, DistanceInput, DistanceOutput, Distance, SimplexCache, Testbed } = planck; - -let world = new World(); +import planck from "../src/main"; + +const { + Vec2, + Transform, + World, + Settings, + ShapeCastInput, + ShapeCastOutput, + ShapeCast, + DistanceInput, + DistanceOutput, + Distance, + SimplexCache, + Testbed, +} = planck; + +const world = new World(); const testbed = Testbed.mount(); testbed.width = 40; testbed.height = 40; testbed.start(world); -const vAs = new Array(3).fill().map(() => Vec2.zero()); -let countA; -let radiusA; +const vAs = new Array(3).fill(null).map(() => Vec2.zero()); +let countA: number; +let radiusA: number; -const vBs = new Array(Settings.maxPolygonVertices).fill().map(() => Vec2.zero()); -let countB; -let radiusB; +const vBs = new Array(Settings.maxPolygonVertices) + .fill(null) + .map(() => Vec2.zero()); +let countB: number; +let radiusB: number; -let transformA; -let transformB; -let translationB; +let transformA: planck.Transform; +let transformB: planck.Transform; +let translationB: planck.Vec2; if (true) { vAs[0].set(-0.5, 1.0); @@ -88,7 +105,7 @@ if (true) { translationB = new Vec2(0.0, 0.0399999991); } -testbed.step = function() { +testbed.step = function () { const transformB = Transform.identity(); const input = new ShapeCastInput(); @@ -116,7 +133,7 @@ testbed.step = function() { const simplexCache = new SimplexCache(); simplexCache.count = 0; const distanceOutput = new DistanceOutput(); - + Distance(distanceOutput, simplexCache, distanceInput); testbed.status({ @@ -134,7 +151,10 @@ testbed.step = function() { if (countA == 1) { testbed.drawCircle(vertices[0], radiusA, testbed.color(0.9, 0.9, 0.9)); } else { - testbed.drawPolygon(vertices.slice(0, countA), testbed.color(0.9, 0.9, 0.9)); + testbed.drawPolygon( + vertices.slice(0, countA), + testbed.color(0.9, 0.9, 0.9) + ); } for (let i = 0; i < countB; ++i) { @@ -143,7 +163,10 @@ testbed.step = function() { if (countB == 1) { testbed.drawCircle(vertices[0], radiusB, testbed.color(0.5, 0.9, 0.5)); } else { - testbed.drawPolygon(vertices.slice(0, countB), testbed.color(0.5, 0.9, 0.5)); + testbed.drawPolygon( + vertices.slice(0, countB), + testbed.color(0.5, 0.9, 0.5) + ); } for (let i = 0; i < countB; ++i) { @@ -152,7 +175,10 @@ testbed.step = function() { if (countB == 1) { testbed.drawCircle(vertices[0], radiusB, testbed.color(0.5, 0.7, 0.9)); } else { - testbed.drawPolygon(vertices.slice(0, countB), testbed.color(0.5, 0.7, 0.9)); + testbed.drawPolygon( + vertices.slice(0, countB), + testbed.color(0.5, 0.7, 0.9) + ); } if (hit) { diff --git a/example/ShapeEditing.js b/example/ShapeEditing.ts similarity index 59% rename from example/ShapeEditing.js rename to example/ShapeEditing.ts index b6cca956..45793950 100644 --- a/example/ShapeEditing.js +++ b/example/ShapeEditing.ts @@ -21,56 +21,61 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Edge, Circle, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); -testbed.info('C: Create a shape, X: Destroy a shape, Z: Sensor'); +testbed.info("C: Create a shape, X: Destroy a shape, Z: Sensor"); testbed.start(world); let sensor = true; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let body = world.createDynamicBody(new Vec2(0.0, 10.0)); +const body = world.createDynamicBody(new Vec2(0.0, 10.0)); -let fixture1 = body.createFixture(new Box(4.0, 4.0, new Vec2(0.0, 0.0), 0.0), 10.0); -let fixture2 = null; +const fixture1 = body.createFixture( + new Box(4.0, 4.0, new Vec2(0.0, 0.0), 0.0), + 10.0 +); +let fixture2: planck.Fixture = null; -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case 'C': - if (fixture2 == null) { - let shape = new Circle(new Vec2(0.5, -4.0), 3.0); - fixture2 = body.createFixture(shape, 10.0); - body.setAwake(true); - fixture2.setSensor(sensor); - } - break; + case "C": + if (fixture2 == null) { + const shape = new Circle(new Vec2(0.5, -4.0), 3.0); + fixture2 = body.createFixture(shape, 10.0); + body.setAwake(true); + fixture2.setSensor(sensor); + } + break; - case 'X': - if (fixture2 != null) { - body.destroyFixture(fixture2); - fixture2 = null; - body.setAwake(true); - } - break; + case "X": + if (fixture2 != null) { + body.destroyFixture(fixture2); + fixture2 = null; + body.setAwake(true); + } + break; - case 'Z': - if (fixture2 != null) { - sensor = !sensor; - fixture2.setSensor(sensor); - } - break; + case "Z": + if (fixture2 != null) { + sensor = !sensor; + fixture2.setSensor(sensor); + } + break; } updateStatus(); }; function updateStatus() { - testbed.status('Sensor', sensor); + testbed.status("Sensor", sensor); } updateStatus(); diff --git a/example/Shuffle.js b/example/Shuffle.js deleted file mode 100644 index c1654ef9..00000000 --- a/example/Shuffle.js +++ /dev/null @@ -1,86 +0,0 @@ -const { World, Vec2, Circle, Chain, Settings, Testbed } = planck; - -let width = 10.00, height = 10.00; - -let BALL_R = 0.3; -let BALL_D = 1; - -Settings.velocityThreshold = 0; - -let world = new World(); - -const testbed = Testbed.mount(); -testbed.x = 0; -testbed.y = 0; -testbed.width = width * 1.5; -testbed.height = height * 1.5; -testbed.mouseForce = -100; -testbed.start(world); - -let walls = [ - new Vec2(-width * .5, -height * .5), - new Vec2(-width * .5, +height * .5), - new Vec2(+width * .5, +height * .5), - new Vec2(+width * .5, -height * .5) -]; - -let wallFixDef = { - userData : 'wall' -}; -let ballFixDef = { - friction: 0.1, - restitution: 0.98, - density: 0.8, - userData : 'ball' -}; -let ballBodyDef = { - bullet: true, - linearDamping : 1.6, - angularDamping : 1.6 -}; - -world.createBody().createFixture(new Chain(walls, true), wallFixDef); - -row(1, 8, BALL_R, BALL_D).map(v => Vec2.add(v, new Vec2(height * 0.4, 0))).forEach(function(p) { - let ball = world.createDynamicBody(ballBodyDef); - ball.setPosition(p); - ball.setAngle(Math.PI); - ball.createFixture(new Circle(BALL_R), ballFixDef); - ball.style = {fill : '#ff411a', stroke: 'black'}; -}); - -row(1, 8, BALL_R, BALL_D).map(v => Vec2.add(v, new Vec2(-height * 0.4, 0))).forEach(function(p) { - let ball = world.createDynamicBody(ballBodyDef); - ball.setPosition(p); - ball.createFixture(new Circle(BALL_R), ballFixDef); - ball.style = {fill : '#0077ff', stroke: 'black'}; -}); - -world.on('post-solve', function(contact) { - let fA = contact.getFixtureA(), bA = fA.getBody(); - let fB = contact.getFixtureB(), bB = fB.getBody(); - - let wall = fA.getUserData() === wallFixDef.userData ? bA : fB.getUserData() === wallFixDef.userData ? bB : null; - let ball = fA.getUserData() === ballFixDef.userData ? bA : fB.getUserData() === ballFixDef.userData ? bB : null; - - // do not change world immediately - setTimeout(function() { - if (ball && wall) { - world.destroyBody(ball); - } - }, 1); -}); - -function row(n, m, r, l) { - let d = r * 2; - let balls = []; - for (let i = 0; i < n; i++) { - for (let j = 0; j < m; j++) { - balls.push(new Vec2( - i * l - (n - 1) * .5 * l + Math.random() * r * 0.02, - j * l - (m - 1) * .5 * l + Math.random() * r * 0.02) - ); - } - } - return balls; -} diff --git a/example/Shuffle.ts b/example/Shuffle.ts new file mode 100644 index 00000000..5bb1d79a --- /dev/null +++ b/example/Shuffle.ts @@ -0,0 +1,106 @@ +import planck from "../src/main"; + +const { World, Vec2, Circle, Chain, Settings, Testbed } = planck; + +const width = 10.0, + height = 10.0; + +const BALL_R = 0.3; +const BALL_D = 1; + +Settings.velocityThreshold = 0; + +const world = new World(); + +const testbed = Testbed.mount(); +testbed.x = 0; +testbed.y = 0; +testbed.width = width * 1.5; +testbed.height = height * 1.5; +testbed.mouseForce = -100; +testbed.start(world); + +const walls = [ + new Vec2(-width * 0.5, -height * 0.5), + new Vec2(-width * 0.5, +height * 0.5), + new Vec2(+width * 0.5, +height * 0.5), + new Vec2(+width * 0.5, -height * 0.5), +]; + +const wallFixDef = { + userData: "wall", +}; +const ballFixDef = { + friction: 0.1, + restitution: 0.98, + density: 0.8, + userData: "ball", +}; +const ballBodyDef = { + bullet: true, + linearDamping: 1.6, + angularDamping: 1.6, +}; + +world.createBody().createFixture(new Chain(walls, true), wallFixDef); + +row(1, 8, BALL_R, BALL_D) + .map((v: planck.Vec2) => Vec2.add(v, new Vec2(height * 0.4, 0))) + .forEach(function (p) { + const ball = world.createDynamicBody(ballBodyDef); + ball.setPosition(p); + ball.setAngle(Math.PI); + ball.createFixture(new Circle(BALL_R), ballFixDef); + ball.style = { fill: "#ff411a", stroke: "black" }; + }); + +row(1, 8, BALL_R, BALL_D) + .map((v: planck.Vec2) => Vec2.add(v, new Vec2(-height * 0.4, 0))) + .forEach(function (p) { + const ball = world.createDynamicBody(ballBodyDef); + ball.setPosition(p); + ball.createFixture(new Circle(BALL_R), ballFixDef); + ball.style = { fill: "#0077ff", stroke: "black" }; + }); + +world.on("post-solve", function (contact) { + const fA = contact.getFixtureA(), + bA = fA.getBody(); + const fB = contact.getFixtureB(), + bB = fB.getBody(); + + const wall = + fA.getUserData() === wallFixDef.userData + ? bA + : fB.getUserData() === wallFixDef.userData + ? bB + : null; + const ball = + fA.getUserData() === ballFixDef.userData + ? bA + : fB.getUserData() === ballFixDef.userData + ? bB + : null; + + // do not change world immediately + setTimeout(function () { + if (ball && wall) { + world.destroyBody(ball); + } + }, 1); +}); + +function row(n: number, m: number, r: number, l: number) { + const balls = []; + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + balls.push( + new Vec2( + i * l - (n - 1) * 0.5 * l + Math.random() * r * 0.02, + j * l - (m - 1) * 0.5 * l + Math.random() * r * 0.02 + ) + ); + } + } + return balls; +} diff --git a/example/SliderCrank.js b/example/SliderCrank.ts similarity index 56% rename from example/SliderCrank.js rename to example/SliderCrank.ts index 35c275e5..e7dabab1 100644 --- a/example/SliderCrank.js +++ b/example/SliderCrank.ts @@ -22,69 +22,87 @@ */ // A motor driven slider crank with joint friction. +import planck from "../src/main"; -const { World, Vec2, RevoluteJoint, PrismaticJoint, Edge, Box, Testbed } = planck; +const { World, Vec2, RevoluteJoint, PrismaticJoint, Edge, Box, Testbed } = + planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -testbed.info('Z: Toggle friction, X: Toggle motor'); +testbed.info("Z: Toggle friction, X: Toggle motor"); -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); // Define crank. -let crank = world.createDynamicBody(new Vec2(0.0, 7.0)); +const crank = world.createDynamicBody(new Vec2(0.0, 7.0)); crank.createFixture(new Box(0.5, 2.0), 2.0); -let joint1 = world.createJoint(new RevoluteJoint({ - motorSpeed: Math.PI, - maxMotorTorque: 10000.0, - enableMotor: true -}, ground, crank, new Vec2(0.0, 5.0))); - +const joint1 = world.createJoint( + new RevoluteJoint( + { + motorSpeed: Math.PI, + maxMotorTorque: 10000.0, + enableMotor: true, + }, + ground, + crank, + new Vec2(0.0, 5.0) + ) +); // Define follower. -let follower = world.createDynamicBody(new Vec2(0.0, 13.0)); +const follower = world.createDynamicBody(new Vec2(0.0, 13.0)); follower.createFixture(new Box(0.5, 4.0), 2.0); -world.createJoint(new RevoluteJoint({enableMotor: false}, crank, follower, new Vec2(0.0, 9.0))); +world.createJoint( + new RevoluteJoint({ enableMotor: false }, crank, follower, new Vec2(0.0, 9.0)) +); // Define piston -let piston = world.createBody({ - type: 'dynamic', +const piston = world.createBody({ + type: "dynamic", fixedRotation: true, - position: new Vec2(0.0, 17.0) + position: new Vec2(0.0, 17.0), }); piston.createFixture(new Box(1.5, 1.5), 2.0); world.createJoint(new RevoluteJoint({}, follower, piston, new Vec2(0.0, 17.0))); -let joint2 = world.createJoint(new PrismaticJoint({ - maxMotorForce: 1000.0, - enableMotor: true -}, ground, piston, new Vec2(0.0, 17.0), new Vec2(0.0, 1.0))); +const joint2 = world.createJoint( + new PrismaticJoint( + { + maxMotorForce: 1000.0, + enableMotor: true, + }, + ground, + piston, + new Vec2(0.0, 17.0), + new Vec2(0.0, 1.0) + ) +); // Create a payload -let payload = world.createDynamicBody(new Vec2(0.0, 23.0)); +const payload = world.createDynamicBody(new Vec2(0.0, 23.0)); payload.createFixture(new Box(1.5, 1.5), 2.0); -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case 'Z': - joint2.enableMotor(!joint2.isMotorEnabled()); - joint2.getBodyB().setAwake(true); - break; - - case 'X': - joint1.enableMotor(!joint1.isMotorEnabled()); - joint1.getBodyB().setAwake(true); - break; + case "Z": + joint2.enableMotor(!joint2.isMotorEnabled()); + joint2.getBodyB().setAwake(true); + break; + + case "X": + joint1.enableMotor(!joint1.isMotorEnabled()); + joint1.getBodyB().setAwake(true); + break; } }; -testbed.step = function() { - let torque = joint1.getMotorTorque(1 / 60); - testbed.status('Motor Torque', torque); +testbed.step = function () { + const torque = joint1.getMotorTorque(1 / 60); + testbed.status("Motor Torque", torque); }; diff --git a/example/Soccer.js b/example/Soccer.js deleted file mode 100644 index 06042b15..00000000 --- a/example/Soccer.js +++ /dev/null @@ -1,133 +0,0 @@ -const { World, Vec2, Circle, Chain, Settings, Testbed } = planck; - -const testbed = Testbed.mount(); - -let width = 10.00, height = 6.00; - -let PLAYER_R = 0.35; -let BALL_R = 0.23; - -testbed.x = 0; -testbed.y = 0; -testbed.width = width * 1.6; -testbed.height = height * 1.6; -testbed.mouseForce = -120; - -Settings.velocityThreshold = 0; - -let world = new World(); -testbed.start(world); - -let goal = [ - new Vec2(0, -height * 0.2), - new Vec2(0, +height * 0.2) -]; - -let wallFixDef = { - friction: 0, - restitution: 0, - userData : 'wall' -}; -let goalFixDef = { - friction: 0, - restitution: 1, - userData : 'goal' -}; - -let ballFixDef = { - friction: .2, - restitution: .99, - density: .5, - userData : 'ball' -}; -let ballBodyDef = { - bullet: true, - linearDamping : 3.5, - angularDamping : 1.6 -}; - -let playerFixDef = { - friction: .1, - restitution: .99, - density: .8, - userData : 'player' -}; -let playerBodyDef = { - bullet: true, - linearDamping : 4, - angularDamping : 1.6 -}; - -world.createBody().createFixture(new Chain(walls(), true), wallFixDef); - -world.createBody(new Vec2(-width * 0.5 - BALL_R, 0)).createFixture(new Chain(goal), goalFixDef); -world.createBody(new Vec2(+width * 0.5 + BALL_R, 0)).createFixture(new Chain(goal), goalFixDef); - -let ball = world.createDynamicBody(ballBodyDef); -ball.createFixture(new Circle(BALL_R), ballFixDef); -ball.style = {fill: 'white', stroke : 'black'}; - -team().forEach(function(p) { - let player = world.createDynamicBody(playerBodyDef); - player.setPosition(p); - player.createFixture(new Circle(PLAYER_R), playerFixDef); - player.style = {fill : '#0077ff', stroke: 'black'}; -}); - -team().map(v => new Vec2(-v.x, v.y)).forEach(function(p) { - let player = world.createDynamicBody(playerBodyDef); - player.setPosition(p); - player.setAngle(Math.PI); - player.createFixture(new Circle(PLAYER_R), playerFixDef); - player.style = {fill : '#ff411a', stroke: 'black'}; -}); - -world.on('post-solve', function(contact) { - let fA = contact.getFixtureA(), bA = fA.getBody(); - let fB = contact.getFixtureB(), bB = fB.getBody(); - - let wall = fA.getUserData() === wallFixDef.userData ? bA : fB.getUserData() === wallFixDef.userData ? bB : null; - let ball = fA.getUserData() === ballFixDef.userData ? bA : fB.getUserData() === ballFixDef.userData ? bB : null; - let goal = fA.getUserData() === goalFixDef.userData ? bA : fB.getUserData() === goalFixDef.userData ? bB : null; - - // do not change world immediately - setTimeout(function() { - if (ball && goal) { - ball.setPosition(new Vec2(0, 0)); - ball.setLinearVelocity(new Vec2(0, 0)); - // world.destroyBody(ball); - } - }, 1); -}); - -function team() { - let positions = []; - positions.push(new Vec2(-width * .45, 0)); - positions.push(new Vec2(-width * .3, -height * 0.2)); - positions.push(new Vec2(-width * .3, +height * 0.2)); - positions.push(new Vec2(-width * .1, -height * 0.1)); - positions.push(new Vec2(-width * .1, +height * 0.1)); - return positions; -} - -function walls() { - let chain = [ - new Vec2(-width * .5 +0.2, -height * .5), - new Vec2(-width * .5, -height * .5 +0.2), - new Vec2(-width * .5, -height * .2), - new Vec2(-width * .6, -height * .2), - new Vec2(-width * .6, +height * .2), - new Vec2(-width * .5, +height * .2), - new Vec2(-width * .5, +height * .5 -.2), - new Vec2(-width * .5 +.2, +height * .5), - new Vec2(+width * .5 -.2, +height * .5), - new Vec2(+width * .5, +height * .5 -.2), - new Vec2(+width * .5, +height * .2), - new Vec2(+width * .6, +height * .2), - new Vec2(+width * .6, -height * .2), - new Vec2(+width * .5, -height * .2), - new Vec2(+width * .5, -height * .5 +.2), - new Vec2(+width * .5 -.2, -height * .5) - ]; - return chain; -} diff --git a/example/Soccer.ts b/example/Soccer.ts new file mode 100644 index 00000000..e8b27435 --- /dev/null +++ b/example/Soccer.ts @@ -0,0 +1,156 @@ +import planck from "../src/main"; + +const { World, Vec2, Circle, Chain, Settings, Testbed } = planck; + +const testbed = Testbed.mount(); + +const width = 10.0, + height = 6.0; + +const PLAYER_R = 0.35; +const BALL_R = 0.23; + +testbed.x = 0; +testbed.y = 0; +testbed.width = width * 1.6; +testbed.height = height * 1.6; +testbed.mouseForce = -120; + +Settings.velocityThreshold = 0; + +const world = new World(); +testbed.start(world); + +const goal = [new Vec2(0, -height * 0.2), new Vec2(0, +height * 0.2)]; + +const wallFixDef = { + friction: 0, + restitution: 0, + userData: "wall", +}; +const goalFixDef = { + friction: 0, + restitution: 1, + userData: "goal", +}; + +const ballFixDef = { + friction: 0.2, + restitution: 0.99, + density: 0.5, + userData: "ball", +}; +const ballBodyDef = { + bullet: true, + linearDamping: 3.5, + angularDamping: 1.6, +}; + +const playerFixDef = { + friction: 0.1, + restitution: 0.99, + density: 0.8, + userData: "player", +}; +const playerBodyDef = { + bullet: true, + linearDamping: 4, + angularDamping: 1.6, +}; + +world.createBody().createFixture(new Chain(walls(), true), wallFixDef); + +world + .createBody(new Vec2(-width * 0.5 - BALL_R, 0)) + .createFixture(new Chain(goal), goalFixDef); +world + .createBody(new Vec2(+width * 0.5 + BALL_R, 0)) + .createFixture(new Chain(goal), goalFixDef); + +const ball = world.createDynamicBody(ballBodyDef); +ball.createFixture(new Circle(BALL_R), ballFixDef); +ball.style = { fill: "white", stroke: "black" }; + +team().forEach(function (p) { + const player = world.createDynamicBody(playerBodyDef); + player.setPosition(p); + player.createFixture(new Circle(PLAYER_R), playerFixDef); + player.style = { fill: "#0077ff", stroke: "black" }; +}); + +team() + .map((v: planck.Vec2) => new Vec2(-v.x, v.y)) + .forEach(function (p) { + const player = world.createDynamicBody(playerBodyDef); + player.setPosition(p); + player.setAngle(Math.PI); + player.createFixture(new Circle(PLAYER_R), playerFixDef); + player.style = { fill: "#ff411a", stroke: "black" }; + }); + +world.on("post-solve", function (contact) { + const fA = contact.getFixtureA(), + bA = fA.getBody(); + const fB = contact.getFixtureB(), + bB = fB.getBody(); + + const wall = + fA.getUserData() === wallFixDef.userData + ? bA + : fB.getUserData() === wallFixDef.userData + ? bB + : null; + const ball = + fA.getUserData() === ballFixDef.userData + ? bA + : fB.getUserData() === ballFixDef.userData + ? bB + : null; + const goal = + fA.getUserData() === goalFixDef.userData + ? bA + : fB.getUserData() === goalFixDef.userData + ? bB + : null; + + // do not change world immediately + setTimeout(function () { + if (ball && goal) { + ball.setPosition(new Vec2(0, 0)); + ball.setLinearVelocity(new Vec2(0, 0)); + // world.destroyBody(ball); + } + }, 1); +}); + +function team() { + const positions = []; + positions.push(new Vec2(-width * 0.45, 0)); + positions.push(new Vec2(-width * 0.3, -height * 0.2)); + positions.push(new Vec2(-width * 0.3, +height * 0.2)); + positions.push(new Vec2(-width * 0.1, -height * 0.1)); + positions.push(new Vec2(-width * 0.1, +height * 0.1)); + return positions; +} + +function walls() { + const chain = [ + new Vec2(-width * 0.5 + 0.2, -height * 0.5), + new Vec2(-width * 0.5, -height * 0.5 + 0.2), + new Vec2(-width * 0.5, -height * 0.2), + new Vec2(-width * 0.6, -height * 0.2), + new Vec2(-width * 0.6, +height * 0.2), + new Vec2(-width * 0.5, +height * 0.2), + new Vec2(-width * 0.5, +height * 0.5 - 0.2), + new Vec2(-width * 0.5 + 0.2, +height * 0.5), + new Vec2(+width * 0.5 - 0.2, +height * 0.5), + new Vec2(+width * 0.5, +height * 0.5 - 0.2), + new Vec2(+width * 0.5, +height * 0.2), + new Vec2(+width * 0.6, +height * 0.2), + new Vec2(+width * 0.6, -height * 0.2), + new Vec2(+width * 0.5, -height * 0.2), + new Vec2(+width * 0.5, -height * 0.5 + 0.2), + new Vec2(+width * 0.5 - 0.2, -height * 0.5), + ]; + return chain; +} diff --git a/example/SphereStack.js b/example/SphereStack.ts similarity index 89% rename from example/SphereStack.js rename to example/SphereStack.ts index 5f72270a..c42af3aa 100644 --- a/example/SphereStack.js +++ b/example/SphereStack.ts @@ -21,20 +21,22 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Edge, Circle, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 10; -let bodies = []; +const COUNT = 10; +const bodies = []; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0)), 0.0); -let circle = new Circle(1.0); +const circle = new Circle(1.0); for (let i = 0; i < COUNT; ++i) { bodies[i] = world.createDynamicBody(new Vec2(0.0, 4.0 + 3.0 * i)); diff --git a/example/TheoJansen.js b/example/TheoJansen.ts similarity index 56% rename from example/TheoJansen.js rename to example/TheoJansen.ts index febeb902..c3fdc24b 100644 --- a/example/TheoJansen.js +++ b/example/TheoJansen.ts @@ -24,128 +24,181 @@ // Inspired by a contribution by roman_m // Dimensions scooped from APE (http://www.cove.org/ape/index.htm) -const { World, Vec2, Edge, Circle, Box, Polygon, RevoluteJoint, DistanceJoint, Testbed } = planck; - -let world = new World(new Vec2(0, -10)); +import planck from "../src/main"; + +const { + World, + Vec2, + Edge, + Circle, + Box, + Polygon, + RevoluteJoint, + DistanceJoint, + Testbed, +} = planck; + +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let motorSpeed = 2.0; -let motorOn = true; +const motorSpeed = 2.0; +const motorOn = true; -let offset = new Vec2(0.0, 8.0); -let pivot = new Vec2(0.0, 0.8); +const offset = new Vec2(0.0, 8.0); +const pivot = new Vec2(0.0, 0.8); // Ground -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-50.0, 0.0), new Vec2(50.0, 0.0)), 0.0); -ground.createFixture(new Edge(new Vec2(-50.0, 0.0), new Vec2(-50.0, 10.0)), 0.0); +ground.createFixture( + new Edge(new Vec2(-50.0, 0.0), new Vec2(-50.0, 10.0)), + 0.0 +); ground.createFixture(new Edge(new Vec2(50.0, 0.0), new Vec2(50.0, 10.0)), 0.0); // Balls for (let i = 0; i < 40; ++i) { - world.createDynamicBody(new Vec2(-40.0 + 2.0 * i, 0.5)).createFixture(new Circle(0.25), 1.0); + world + .createDynamicBody(new Vec2(-40.0 + 2.0 * i, 0.5)) + .createFixture(new Circle(0.25), 1.0); } // Chassis -let chassis = world.createDynamicBody(Vec2.add(pivot, offset)); +const chassis = world.createDynamicBody(Vec2.add(pivot, offset)); chassis.createFixture(new Box(2.5, 1.0), { density: 1.0, - filterGroupIndex: -1 + filterGroupIndex: -1, }); -let wheel = world.createDynamicBody(Vec2.add(pivot, offset)); +const wheel = world.createDynamicBody(Vec2.add(pivot, offset)); wheel.createFixture(new Circle(1.6), { density: 1.0, - filterGroupIndex: -1 + filterGroupIndex: -1, }); -let motorjoint = world.createJoint(new RevoluteJoint({ - collideConnected: false, - motorSpeed: motorSpeed, - maxMotorTorque: 400.0, - enableMotor: motorOn -}, wheel, chassis, Vec2.add(pivot, offset))); - -let wheelAnchor = new Vec2(0.0, -0.8).add(pivot); +const motorjoint = world.createJoint( + new RevoluteJoint( + { + collideConnected: false, + motorSpeed: motorSpeed, + maxMotorTorque: 400.0, + enableMotor: motorOn, + }, + wheel, + chassis, + Vec2.add(pivot, offset) + ) +); + +const wheelAnchor = new Vec2(0.0, -0.8).add(pivot); createLeg(-1.0, wheelAnchor); createLeg(1.0, wheelAnchor); -wheel.setTransform(wheel.getPosition(), 120.0 * Math.PI / 180.0); +wheel.setTransform(wheel.getPosition(), (120.0 * Math.PI) / 180.0); createLeg(-1.0, wheelAnchor); createLeg(1.0, wheelAnchor); -wheel.setTransform(wheel.getPosition(), -120.0 * Math.PI / 180.0); +wheel.setTransform(wheel.getPosition(), (-120.0 * Math.PI) / 180.0); createLeg(-1.0, wheelAnchor); createLeg(1.0, wheelAnchor); -function createLeg(s, wheelAnchor) { - - let p1 = new Vec2(5.4 * s, -6.1); - let p2 = new Vec2(7.2 * s, -1.2); - let p3 = new Vec2(4.3 * s, -1.9); - let p4 = new Vec2(3.1 * s, 0.8); - let p5 = new Vec2(6.0 * s, 1.5); - let p6 = new Vec2(2.5 * s, 3.7); +function createLeg(s: number, wheelAnchor: planck.Vec2) { + const p1 = new Vec2(5.4 * s, -6.1); + const p2 = new Vec2(7.2 * s, -1.2); + const p3 = new Vec2(4.3 * s, -1.9); + const p4 = new Vec2(3.1 * s, 0.8); + const p5 = new Vec2(6.0 * s, 1.5); + const p6 = new Vec2(2.5 * s, 3.7); - let poly1, poly2; + let poly1: planck.PolygonShape, poly2: planck.PolygonShape; if (s > 0.0) { poly1 = new Polygon([p1, p2, p3]); poly2 = new Polygon([new Vec2(), Vec2.sub(p5, p4), Vec2.sub(p6, p4)]); - } else { poly1 = new Polygon([p1, p3, p2]); poly2 = new Polygon([new Vec2(), Vec2.sub(p6, p4), Vec2.sub(p5, p4)]); } - let body1 = world.createDynamicBody({ + const body1 = world.createDynamicBody({ position: offset, - angularDamping: 10.0 + angularDamping: 10.0, }); body1.createFixture(poly1, { density: 1.0, - filterGroupIndex: -1 + filterGroupIndex: -1, }); - let body2 = world.createDynamicBody({ + const body2 = world.createDynamicBody({ position: Vec2.add(p4, offset), - angularDamping: 10.0 + angularDamping: 10.0, }); body2.createFixture(poly2, { density: 1.0, - filterGroupIndex: -1 + filterGroupIndex: -1, }); // Using a soft distance constraint can reduce some jitter. // It also makes the structure seem a bit more fluid by // acting like a suspension system. - let djd = { + const djd = { dampingRatio: 0.5, - frequencyHz: 10.0 + frequencyHz: 10.0, }; - world.createJoint(new DistanceJoint(djd, body1, body2, Vec2.add(p2, offset), Vec2.add(p5, offset))); - world.createJoint(new DistanceJoint(djd, body1, body2, Vec2.add(p3, offset), Vec2.add(p4, offset))); - world.createJoint(new DistanceJoint(djd, body1, wheel, Vec2.add(p3, offset), Vec2.add(wheelAnchor, offset))); - world.createJoint(new DistanceJoint(djd, body2, wheel, Vec2.add(p6, offset), Vec2.add(wheelAnchor, offset))); - - world.createJoint(new RevoluteJoint({}, body2, chassis, Vec2.add(p4, offset))); + world.createJoint( + new DistanceJoint( + djd, + body1, + body2, + Vec2.add(p2, offset), + Vec2.add(p5, offset) + ) + ); + world.createJoint( + new DistanceJoint( + djd, + body1, + body2, + Vec2.add(p3, offset), + Vec2.add(p4, offset) + ) + ); + world.createJoint( + new DistanceJoint( + djd, + body1, + wheel, + Vec2.add(p3, offset), + Vec2.add(wheelAnchor, offset) + ) + ); + world.createJoint( + new DistanceJoint( + djd, + body2, + wheel, + Vec2.add(p6, offset), + Vec2.add(wheelAnchor, offset) + ) + ); + + world.createJoint( + new RevoluteJoint({}, body2, chassis, Vec2.add(p4, offset)) + ); } -testbed.step = function() { +testbed.step = function () { if (testbed.activeKeys.right && testbed.activeKeys.left) { motorjoint.setMotorSpeed(0.0); motorjoint.enableMotor(false); - } else if (testbed.activeKeys.right) { motorjoint.setMotorSpeed(motorSpeed); motorjoint.enableMotor(true); - } else if (testbed.activeKeys.left) { motorjoint.setMotorSpeed(-motorSpeed); motorjoint.enableMotor(true); - } else { motorjoint.setMotorSpeed(0.0); motorjoint.enableMotor(true); @@ -153,7 +206,6 @@ testbed.step = function() { if (wheel.getPosition().x > testbed.x + 10) { testbed.x = wheel.getPosition().x - 10; - } else if (wheel.getPosition().x < testbed.x - 10) { testbed.x = wheel.getPosition().x + 10; } diff --git a/example/Tiles.js b/example/Tiles.ts similarity index 68% rename from example/Tiles.js rename to example/Tiles.ts index 76626724..1843d36a 100644 --- a/example/Tiles.js +++ b/example/Tiles.ts @@ -23,26 +23,27 @@ // This stress tests the dynamic tree broad-phase. This also shows that tile // based collision is _not_ smooth due to Box2D not knowing about adjacency. +import planck from "../src/main"; const { World, Vec2, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 20; +const COUNT = 20; let fixtureCount = 0; { - let a = 0.5; - let ground = world.createBody(new Vec2(0, -a)); - + const a = 0.5; + const ground = world.createBody(new Vec2(0, -a)); + /// NEED TO CHECK if (true) { - let N = 200; - let M = 10; - let position = new Vec2(); + const N = 200; + const M = 10; + const position = new Vec2(); position.y = 0.0; for (let j = 0; j < M; ++j) { position.x = -N * a; @@ -53,11 +54,10 @@ let fixtureCount = 0; } position.y -= 2.0 * a; } - } else { - let N = 200; - let M = 10; - let position = new Vec2(); + const N = 200; + const M = 10; + const position = new Vec2(); position.x = -N * a; for (let i = 0; i < N; ++i) { position.y = 0.0; @@ -70,22 +70,21 @@ let fixtureCount = 0; } } { - let a = 0.5; - let shape = new Box(a, a); + const a = 0.5; + const shape = new Box(a, a); - let x = new Vec2(-7.0, 0.75); - let y = new Vec2(); - let deltaX = new Vec2(0.5625, 1.25); - let deltaY = new Vec2(1.125, 0.0); + const x = new Vec2(-7.0, 0.75); + const y = new Vec2(); + const deltaX = new Vec2(0.5625, 1.25); + const deltaY = new Vec2(1.125, 0.0); for (let i = 0; i < COUNT; ++i) { y.set(x); for (let j = i; j < COUNT; ++j) { - // bd.allowSleep = !(i == 0 && j == 0) - let body = world.createDynamicBody(y); + const body = world.createDynamicBody(y); body.createFixture(shape, 5.0); ++fixtureCount; y.add(deltaY); @@ -94,20 +93,20 @@ let fixtureCount = 0; x.add(deltaX); } } -let createTime = Date.now(); +const createTime = Date.now(); -testbed.step = function() { - let height = world.getTreeHeight(); - let leafCount = world.getProxyCount(); - let minimumNodeCount = 2 * leafCount - 1; - let minimumHeight = Math.ceil(Math.log(minimumNodeCount) / Math.log(2.0)); +testbed.step = function () { + const height = world.getTreeHeight(); + const leafCount = world.getProxyCount(); + const minimumNodeCount = 2 * leafCount - 1; + const minimumHeight = Math.ceil(Math.log(minimumNodeCount) / Math.log(2.0)); - testbed.status('dynamic tree height', height); - testbed.status('min', minimumHeight); - testbed.status('create time', createTime + 'ms'); - testbed.status('fixture count', fixtureCount); + testbed.status("dynamic tree height", height); + testbed.status("min", minimumHeight); + testbed.status("create time", createTime + "ms"); + testbed.status("fixture count", fixtureCount); - // let tree = world.m_broadPhase.m_tree; + // const tree = world.m_broadPhase.m_tree; // if (stepCount++ == 400) { // tree.rebuildBottomUp(); // } diff --git a/example/TimeOfImpact.js b/example/TimeOfImpact.ts similarity index 71% rename from example/TimeOfImpact.js rename to example/TimeOfImpact.ts index 3ace826d..a9a36cb8 100644 --- a/example/TimeOfImpact.js +++ b/example/TimeOfImpact.ts @@ -20,10 +20,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -const { World, Transform, Box, TimeOfImpact, Sweep, TOIInput, TOIOutput, stats, Testbed } = planck; - -let world = new World(); +import planck from "../src/main"; + +const { + World, + Transform, + Box, + TimeOfImpact, + Sweep, + TOIInput, + TOIOutput, + stats, + Testbed, +} = planck; + +const world = new World(); const testbed = Testbed.mount(); testbed.width = 80; @@ -32,16 +43,16 @@ testbed.x = 0; testbed.y = 0; testbed.start(world); -let shapeA = new Box(25.0, 5.0); -let sweepA = new Sweep(); +const shapeA = new Box(25.0, 5.0); +const sweepA = new Sweep(); sweepA.c0.set(0, 0); sweepA.a0 = 0.1; sweepA.c.set(sweepA.c0); sweepA.a = sweepA.a0; sweepA.localCenter.setZero(); -let shapeB = new Box(2.5, 2.5); -let sweepB = new Sweep(); +const shapeB = new Box(2.5, 2.5); +const sweepB = new Sweep(); sweepB.c0.set(20, 20); sweepB.a0 = 0.1; // - 162.0 * Math.PI; sweepB.c.set(-20, -20); @@ -51,47 +62,57 @@ sweepB.localCenter.setZero(); // sweepB.a0 -= 300.0 * Math.PI; // sweepB.a -= 300.0 * Math.PI; -let input = new TOIInput(); +const input = new TOIInput(); input.proxyA.set(shapeA, 0); input.sweepA.set(sweepA); input.proxyB.set(shapeB, 0); input.sweepB.set(sweepB); input.tMax = 1.0; -let output = new TOIOutput(); +const output = new TOIOutput(); TimeOfImpact(output, input); -testbed.step = function() { +testbed.step = function () { // "max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters - testbed.status('toi', output.t); + testbed.status("toi", output.t); testbed.status(stats); let vertices = []; - let transformB = new Transform(); + const transformB = new Transform(); for (let t = 0.1; t < 1.0; t += 0.1) { sweepB.getTransform(transformB, t); - vertices = shapeB.m_vertices.map(v => Transform.mul(transformB, v)); + vertices = shapeB.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformB, v) + ); testbed.drawPolygon(vertices, testbed.color(0.2, 0.2, 0.2)); } - let transformA = new Transform(); + const transformA = new Transform(); sweepA.getTransform(transformA, 0.0); - vertices = shapeA.m_vertices.map(v => Transform.mul(transformA, v)); + vertices = shapeA.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformA, v) + ); testbed.drawPolygon(vertices, testbed.color(0.7, 0.7, 0.7)); sweepB.getTransform(transformB, 0.0); - vertices = shapeB.m_vertices.map(v => Transform.mul(transformB, v)); + vertices = shapeB.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformB, v) + ); testbed.drawPolygon(vertices, testbed.color(1, 1, 1)); sweepB.getTransform(transformB, output.t); - vertices = shapeB.m_vertices.map(v => Transform.mul(transformB, v)); + vertices = shapeB.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformB, v) + ); testbed.drawPolygon(vertices, testbed.color(1, 0, 0)); sweepB.getTransform(transformB, 1.0); - vertices = shapeB.m_vertices.map(v => Transform.mul(transformB, v)); + vertices = shapeB.m_vertices.map((v: planck.Vec2) => + Transform.mul(transformB, v) + ); testbed.drawPolygon(vertices, testbed.color(1, 1, 1)); }; diff --git a/example/Tumbler.js b/example/Tumbler.ts similarity index 74% rename from example/Tumbler.js rename to example/Tumbler.ts index f5f023d8..7a306d9f 100644 --- a/example/Tumbler.js +++ b/example/Tumbler.ts @@ -21,20 +21,22 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Box, RevoluteJoint, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -let COUNT = 200; +const COUNT = 200; -let ground = world.createBody(); +const ground = world.createBody(); -let container = world.createDynamicBody({ +const container = world.createDynamicBody({ allowSleep: false, - position: new Vec2(0, 10) + position: new Vec2(0, 10), }); container.createFixture(new Box(0.5, 20, new Vec2(20, 0), 0), 5); @@ -42,17 +44,26 @@ container.createFixture(new Box(0.5, 20, new Vec2(-20, 0), 0), 5); container.createFixture(new Box(20, 0.5, new Vec2(0, 20), 0), 5); container.createFixture(new Box(20, 0.5, new Vec2(0, -20), 0), 5); -world.createJoint(new RevoluteJoint({ - motorSpeed: 0.08 * Math.PI, - maxMotorTorque: 1e8, - enableMotor: true, -}, ground, container, new Vec2(0, 10))); +world.createJoint( + new RevoluteJoint( + { + motorSpeed: 0.08 * Math.PI, + maxMotorTorque: 1e8, + enableMotor: true, + }, + ground, + container, + new Vec2(0, 10) + ) +); -let shape = new Box(0.5, 0.5); +const shape = new Box(0.5, 0.5); let count = 0; while (count < COUNT) { - let body = world.createDynamicBody(); - body.setPosition(new Vec2(Math.random() * 20 - 10, 10 + Math.random() * 20 - 10)); + const body = world.createDynamicBody(); + body.setPosition( + new Vec2(Math.random() * 20 - 10, 10 + Math.random() * 20 - 10) + ); body.createFixture(shape, 1); ++count; } diff --git a/example/VaryingFriction.js b/example/VaryingFriction.ts similarity index 75% rename from example/VaryingFriction.js rename to example/VaryingFriction.ts index 9395aeb8..3847b6c4 100644 --- a/example/VaryingFriction.js +++ b/example/VaryingFriction.ts @@ -21,26 +21,36 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Edge, Box, Testbed } = planck; -let world = new World(new Vec2(0, -10)); +const world = new World(new Vec2(0, -10)); const testbed = Testbed.mount(); testbed.start(world); -world.createBody().createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0))); +world + .createBody() + .createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0))); -world.createBody(new Vec2(-4.0, 22.0), -0.25).createFixture(new Box(13.0, 0.25), 0.0); +world + .createBody(new Vec2(-4.0, 22.0), -0.25) + .createFixture(new Box(13.0, 0.25), 0.0); world.createBody(new Vec2(10.5, 19.0)).createFixture(new Box(0.25, 1.0), 0.0); -world.createBody(new Vec2(4.0, 14.0), 0.25).createFixture(new Box(13.0, 0.25), 0.0); +world + .createBody(new Vec2(4.0, 14.0), 0.25) + .createFixture(new Box(13.0, 0.25), 0.0); world.createBody(new Vec2(-10.5, 11.0)).createFixture(new Box(0.25, 1.0), 0.0); -world.createBody(new Vec2(-4.0, 6.0), -0.25).createFixture(new Box(13.0, 0.25), 0.0); +world + .createBody(new Vec2(-4.0, 6.0), -0.25) + .createFixture(new Box(13.0, 0.25), 0.0); -const friction = [ 0.75, 0.5, 0.35, 0.1, 0.0 ]; +const friction = [0.75, 0.5, 0.35, 0.1, 0.0]; const circle = new Box(0.5, 0.5); @@ -48,6 +58,6 @@ for (let i = 0; i < friction.length; ++i) { const ball = world.createDynamicBody(new Vec2(-15.0 + 4.0 * i, 28.0)); ball.createFixture(circle, { density: 25.0, - friction: friction[i] + friction: friction[i], }); } diff --git a/example/VaryingRestitution.js b/example/VaryingRestitution.ts similarity index 93% rename from example/VaryingRestitution.js rename to example/VaryingRestitution.ts index 2c88da56..18bd94eb 100644 --- a/example/VaryingRestitution.js +++ b/example/VaryingRestitution.ts @@ -23,6 +23,7 @@ // Note: even with a restitution of 1.0, there is some energy change // due to position correction. +import planck from "../src/main"; const { World, Vec2, Circle, Edge, Testbed } = planck; @@ -34,7 +35,7 @@ testbed.start(world); const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0))); -const restitution = [ 0.0, 0.1, 0.3, 0.5, 0.75, 0.9, 1.0 ]; +const restitution = [0.0, 0.1, 0.3, 0.5, 0.75, 0.9, 1.0]; const circle = new Circle(1.0); @@ -42,6 +43,6 @@ for (let i = 0; i < restitution.length; ++i) { const ball = world.createDynamicBody(new Vec2(-10.0 + 3.0 * i, 20.0)); ball.createFixture(circle, { density: 1.0, - restitution: restitution[i] + restitution: restitution[i], }); } diff --git a/example/VerticalStack.js b/example/VerticalStack.ts similarity index 65% rename from example/VerticalStack.js rename to example/VerticalStack.ts index ec3a905c..01773e78 100644 --- a/example/VerticalStack.js +++ b/example/VerticalStack.ts @@ -21,84 +21,86 @@ * SOFTWARE. */ +import planck from "../src/main"; + const { World, Vec2, Edge, Circle, Box, Testbed } = planck; -let world = new World({ +const world = new World({ gravity: new Vec2(0, -10), blockSolve: true, }); const testbed = Testbed.mount(); -testbed.info('X: Launch a bullet'); +testbed.info("X: Launch a bullet"); testbed.start(world); const columnCount = 3; const rowCount = 20; -let bullet; -let bodies = []; -let indices = []; +let bullet: planck.Body; +const bodies = []; +const indices = []; -let ground = world.createBody(); +const ground = world.createBody(); ground.createFixture(new Edge(new Vec2(-40.0, 0.0), new Vec2(40.0, 0.0))); ground.createFixture(new Edge(new Vec2(20.0, 0.0), new Vec2(20.0, 20.0))); -let xs = [ 0.0, -10.0, -5.0, 5.0, 10.0 ]; +const xs = [0.0, -10.0, -5.0, 5.0, 10.0]; -let shape = new Box(0.5, 0.5); +const shape = new Box(0.5, 0.5); for (let j = 0; j < columnCount; ++j) { for (let i = 0; i < rowCount; ++i) { - let n = j * rowCount + i; + const n = j * rowCount + i; indices[n] = n; - let x = 0.0; - // let x = Math.random() * 0.04 - 0.02; - // let x = i % 2 == 0 ? -0.01 : 0.01; + const x = 0.0; + // const x = Math.random() * 0.04 - 0.02; + // const x = i % 2 == 0 ? -0.01 : 0.01; - let body = world.createDynamicBody(); + const body = world.createDynamicBody(); body.setUserData(indices[n]); body.setPosition(new Vec2(xs[j] + x, 0.55 + 1.1 * i)); body.createFixture(shape, { - density : 1.0, - friction : 0.3 + density: 1.0, + friction: 0.3, }); bodies[n] = body; } } -testbed.keydown = function(code, char) { +testbed.keydown = function (code, char) { switch (char) { - case 'X': - if (bullet != null) { - world.destroyBody(bullet); - bullet = null; - } - - bullet = world.createBody({ - type: 'dynamic', - bullet: true, - position: new Vec2(-31.0, 5.0), - }); - - bullet.createFixture({ - shape: new Circle(0.25), - density: 20.0, - restitution: 0.05, - }); - - bullet.setLinearVelocity(new Vec2(400.0, 0.0)); - break; - - case 'Z': - world.m_blockSolve = !world.m_blockSolve; - break; + case "X": + if (bullet != null) { + world.destroyBody(bullet); + bullet = null; + } + + bullet = world.createBody({ + type: "dynamic", + bullet: true, + position: new Vec2(-31.0, 5.0), + }); + + bullet.createFixture({ + shape: new Circle(0.25), + density: 20.0, + restitution: 0.05, + }); + + bullet.setLinearVelocity(new Vec2(400.0, 0.0)); + break; + + case "Z": + world.m_blockSolve = !world.m_blockSolve; + break; } }; let stepCount = 1; -testbed.step = function() { - testbed.status('Blocksolve', world.m_blockSolve); +testbed.step = function () { + testbed.status("Blocksolve", world.m_blockSolve); if (stepCount++ % 300 == 0) { if (bullet != null) { @@ -107,7 +109,7 @@ testbed.step = function() { } bullet = world.createBody({ - type: 'dynamic', + type: "dynamic", bullet: true, position: new Vec2(-31.0, 5.0), }); diff --git a/example/Web.js b/example/Web.js deleted file mode 100644 index e28fe290..00000000 --- a/example/Web.js +++ /dev/null @@ -1,145 +0,0 @@ -/* - * MIT License - * Copyright (c) 2019 Erin Catto - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -// This tests distance joints, body destruction, and joint destruction. - -const { World, Vec2, Box, DistanceJoint, Testbed } = planck; - -const world = new World(); - -const testbed = Testbed.mount(); -testbed.start(world); - -let ground = world.createBody(); - -const bodies = []; -let joints = []; - -const box = new Box(0.5, 0.5); - -bodies[0] = world.createDynamicBody(new Vec2(-5.0, 5.0)); -bodies[0].createFixture(box, 5.0); - -bodies[1] = world.createDynamicBody(new Vec2(5.0, 5.0)); -bodies[1].createFixture(box, 5.0); - -bodies[2] = world.createDynamicBody(new Vec2(5.0, 15.0)); -bodies[2].createFixture(box, 5.0); - -bodies[3] = world.createDynamicBody(new Vec2(-5.0, 15.0)); -bodies[3].createFixture(box, 5.0); - -const jd = { - frequencyHz: 2.0, - dampingRatio: 0.0 -}; - -world.createJoint(joints[0] = new DistanceJoint({ - ...jd, - bodyA: ground, - localAnchorA: new Vec2(-10.0, 0.0), - bodyB: bodies[0], - localAnchorB: new Vec2(-0.5, -0.5) -})); - -world.createJoint(joints[1] = new DistanceJoint({ - ...jd, - bodyA: ground, - localAnchorA: new Vec2(10.0, 0.0), - bodyB: bodies[1], - localAnchorB: new Vec2(0.5, -0.5) -})); - -world.createJoint(joints[2] = new DistanceJoint({ - ...jd, - bodyA: ground, - localAnchorA: new Vec2(10.0, 20.0), - bodyB: bodies[2], - localAnchorB: new Vec2(0.5, 0.5) -})); - -world.createJoint(joints[3] = new DistanceJoint({ - ...jd, - bodyA: ground, - localAnchorA: new Vec2(-10.0, 20.0), - bodyB: bodies[3], - localAnchorB: new Vec2(-0.5, 0.5) -})); - -world.createJoint(joints[4] = new DistanceJoint({ - ...jd, - bodyA: bodies[0], - localAnchorA: new Vec2(0.5, 0.0), - bodyB: bodies[1], - localAnchorB: new Vec2(-0.5, 0.0) -})); - -world.createJoint(joints[5] = new DistanceJoint({ - ...jd, - bodyA: bodies[1], - localAnchorA: new Vec2(0.0, 0.5), - bodyB: bodies[2], - localAnchorB: new Vec2(0.0, -0.5) -})); - -world.createJoint(joints[6] = new DistanceJoint({ - ...jd, - bodyA: bodies[2], - localAnchorA: new Vec2(-0.5, 0.0), - bodyB: bodies[3], - localAnchorB: new Vec2(0.5, 0.0) -})); - -world.createJoint(joints[7] = new DistanceJoint({ - ...jd, - bodyA: bodies[3], - localAnchorA: new Vec2(0.0, -0.5), - bodyB: bodies[0], - localAnchorB: new Vec2(0.0, 0.5) -})); - -testbed.keydown = function(code, char) { - switch (char) { - case 'X': - if (bodies.length) { - world.destroyBody(bodies.pop()); - } - break; - - case 'Z': - if (joints.length) { - world.destroyJoint(joints.pop()); - } - break; - } -}; - -testbed.info('This demonstrates a soft distance joint.\nX: Delete a body, Z: Delete a joint'); - -world.on('remove-joint', function(joint) { - for (let i = 0; i < 8; ++i) { - joints = joints.filter(function(j) { - return j !== joint; - }); - } -}); diff --git a/example/Web.ts b/example/Web.ts new file mode 100644 index 00000000..01894421 --- /dev/null +++ b/example/Web.ts @@ -0,0 +1,164 @@ +/* + * MIT License + * Copyright (c) 2019 Erin Catto + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// This tests distance joints, body destruction, and joint destruction. +import planck from "../src/main"; + +const { World, Vec2, Box, DistanceJoint, Testbed } = planck; + +const world = new World(); + +const testbed = Testbed.mount(); +testbed.start(world); + +const ground = world.createBody(); + +const bodies: planck.Body[] = []; +let joints = []; + +const box = new Box(0.5, 0.5); + +bodies[0] = world.createDynamicBody(new Vec2(-5.0, 5.0)); +bodies[0].createFixture(box, 5.0); + +bodies[1] = world.createDynamicBody(new Vec2(5.0, 5.0)); +bodies[1].createFixture(box, 5.0); + +bodies[2] = world.createDynamicBody(new Vec2(5.0, 15.0)); +bodies[2].createFixture(box, 5.0); + +bodies[3] = world.createDynamicBody(new Vec2(-5.0, 15.0)); +bodies[3].createFixture(box, 5.0); + +const jd = { + frequencyHz: 2.0, + dampingRatio: 0.0, +}; + +world.createJoint( + (joints[0] = new DistanceJoint({ + ...jd, + bodyA: ground, + localAnchorA: new Vec2(-10.0, 0.0), + bodyB: bodies[0], + localAnchorB: new Vec2(-0.5, -0.5), + })) +); + +world.createJoint( + (joints[1] = new DistanceJoint({ + ...jd, + bodyA: ground, + localAnchorA: new Vec2(10.0, 0.0), + bodyB: bodies[1], + localAnchorB: new Vec2(0.5, -0.5), + })) +); + +world.createJoint( + (joints[2] = new DistanceJoint({ + ...jd, + bodyA: ground, + localAnchorA: new Vec2(10.0, 20.0), + bodyB: bodies[2], + localAnchorB: new Vec2(0.5, 0.5), + })) +); + +world.createJoint( + (joints[3] = new DistanceJoint({ + ...jd, + bodyA: ground, + localAnchorA: new Vec2(-10.0, 20.0), + bodyB: bodies[3], + localAnchorB: new Vec2(-0.5, 0.5), + })) +); + +world.createJoint( + (joints[4] = new DistanceJoint({ + ...jd, + bodyA: bodies[0], + localAnchorA: new Vec2(0.5, 0.0), + bodyB: bodies[1], + localAnchorB: new Vec2(-0.5, 0.0), + })) +); + +world.createJoint( + (joints[5] = new DistanceJoint({ + ...jd, + bodyA: bodies[1], + localAnchorA: new Vec2(0.0, 0.5), + bodyB: bodies[2], + localAnchorB: new Vec2(0.0, -0.5), + })) +); + +world.createJoint( + (joints[6] = new DistanceJoint({ + ...jd, + bodyA: bodies[2], + localAnchorA: new Vec2(-0.5, 0.0), + bodyB: bodies[3], + localAnchorB: new Vec2(0.5, 0.0), + })) +); + +world.createJoint( + (joints[7] = new DistanceJoint({ + ...jd, + bodyA: bodies[3], + localAnchorA: new Vec2(0.0, -0.5), + bodyB: bodies[0], + localAnchorB: new Vec2(0.0, 0.5), + })) +); + +testbed.keydown = function (code, char) { + switch (char) { + case "X": + if (bodies.length) { + world.destroyBody(bodies.pop()); + } + break; + + case "Z": + if (joints.length) { + world.destroyJoint(joints.pop()); + } + break; + } +}; + +testbed.info( + "This demonstrates a soft distance joint.\nX: Delete a body, Z: Delete a joint" +); + +world.on("remove-joint", function (joint) { + for (let i = 0; i < 8; ++i) { + joints = joints.filter(function (j) { + return j !== joint; + }); + } +}); diff --git a/src/common/Math.ts b/src/common/Math.ts index df4d9a82..2f6921c0 100644 --- a/src/common/Math.ts +++ b/src/common/Math.ts @@ -24,7 +24,6 @@ /** @internal */ const math_random = Math.random; - export const EPSILON = 1e-9; /** @internal @deprecated */ @@ -39,11 +38,11 @@ export const isFinite = Number.isFinite; * yields the next largest power of 2. For a 32-bit value: */ export function nextPowerOfTwo(x: number): number { - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; return x + 1; } @@ -54,10 +53,10 @@ export function isPowerOfTwo(x: number): boolean { /** @deprecated */ export function mod(num: number, min?: number, max?: number): number { - if (typeof min === 'undefined') { + if (typeof min === "undefined") { max = 1; min = 0; - } else if (typeof max === 'undefined') { + } else if (typeof max === "undefined") { max = min; min = 0; } @@ -91,10 +90,10 @@ export function clamp(num: number, min: number, max: number): number { * If one arg is passed between 0 to 1. */ export function random(min?: number, max?: number): number { - if (typeof min === 'undefined') { + if (typeof min === "undefined") { max = 1; min = 0; - } else if (typeof max === 'undefined') { + } else if (typeof max === "undefined") { max = min; min = 0; } diff --git a/src/common/Vec2.ts b/src/common/Vec2.ts index 0d8e78f7..afb198a4 100644 --- a/src/common/Vec2.ts +++ b/src/common/Vec2.ts @@ -22,17 +22,16 @@ * SOFTWARE. */ -import { EPSILON } from "./Math"; +import { clamp, EPSILON } from "./Math"; - -/** @internal */ const _ASSERT = typeof ASSERT === 'undefined' ? false : ASSERT; -/** @internal */ const _CONSTRUCTOR_FACTORY = typeof CONSTRUCTOR_FACTORY === 'undefined' ? false : CONSTRUCTOR_FACTORY; +/** @internal */ const _ASSERT = typeof ASSERT === "undefined" ? false : ASSERT; +/** @internal */ const _CONSTRUCTOR_FACTORY = + typeof CONSTRUCTOR_FACTORY === "undefined" ? false : CONSTRUCTOR_FACTORY; /** @internal */ const math_abs = Math.abs; /** @internal */ const math_sqrt = Math.sqrt; /** @internal */ const math_max = Math.max; /** @internal */ const math_min = Math.min; - export interface Vec2Value { x: number; y: number; @@ -43,17 +42,17 @@ export class Vec2 { y: number; constructor(x: number, y: number); - constructor(obj: { x: number, y: number }); + constructor(obj: { x: number; y: number }); constructor(); // tslint:disable-next-line:typedef constructor(x?, y?) { if (_CONSTRUCTOR_FACTORY && !(this instanceof Vec2)) { return new Vec2(x, y); } - if (typeof x === 'undefined') { + if (typeof x === "undefined") { this.x = 0; this.y = 0; - } else if (typeof x === 'object') { + } else if (typeof x === "object") { this.x = x.x; this.y = x.y; } else { @@ -67,7 +66,7 @@ export class Vec2 { _serialize(): object { return { x: this.x, - y: this.y + y: this.y, }; } @@ -108,14 +107,14 @@ export class Vec2 { * Does this vector contain finite coordinates? */ static isValid(obj: any): boolean { - if (obj === null || typeof obj === 'undefined') { + if (obj === null || typeof obj === "undefined") { return false; } return Number.isFinite(obj.x) && Number.isFinite(obj.y); } static assert(o: any): void { - _ASSERT && console.assert(!Vec2.isValid(o), 'Invalid Vec2!', o); + _ASSERT && console.assert(!Vec2.isValid(o), "Invalid Vec2!", o); } clone(): Vec2 { @@ -142,7 +141,7 @@ export class Vec2 { */ // tslint:disable-next-line:typedef set(x, y?) { - if (typeof x === 'object') { + if (typeof x === "object") { _ASSERT && Vec2.assert(x); this.x = x.x; this.y = x.y; @@ -160,7 +159,7 @@ export class Vec2 { * * @returns this */ - setNum(x: number, y: number) { + setNum(x: number, y: number) { _ASSERT && console.assert(Number.isFinite(x)); _ASSERT && console.assert(Number.isFinite(y)); this.x = x; @@ -184,7 +183,7 @@ export class Vec2 { /** @internal @deprecated Use setCombine or setMul */ wSet(a: number, v: Vec2Value, b?: number, w?: Vec2Value): Vec2 { - if (typeof b !== 'undefined' || typeof w !== 'undefined') { + if (typeof b !== "undefined" || typeof w !== "undefined") { return this.setCombine(a, v, b, w); } else { return this.setMul(a, v); @@ -233,7 +232,7 @@ export class Vec2 { /** @internal @deprecated Use addCombine or addMul */ wAdd(a: number, v: Vec2Value, b?: number, w?: Vec2Value): Vec2 { - if (typeof b !== 'undefined' || typeof w !== 'undefined') { + if (typeof b !== "undefined" || typeof w !== "undefined") { return this.addCombine(a, v, b, w); } else { return this.addMul(a, v); @@ -273,11 +272,12 @@ export class Vec2 { * @deprecated Use subCombine or subMul */ wSub(a: number, v: Vec2Value, b?: number, w?: Vec2Value): Vec2 { - if (typeof b !== 'undefined' || typeof w !== 'undefined') { + if (typeof b !== "undefined" || typeof w !== "undefined") { return this.subCombine(a, v, b, w); } else { return this.subMul(a, v); - }} + } + } /** * Subtract linear combination of v and w: `a * v + b * w` @@ -400,7 +400,10 @@ export class Vec2 { static areEqual(v: Vec2Value, w: Vec2Value): boolean { _ASSERT && Vec2.assert(v); _ASSERT && Vec2.assert(w); - return v === w || typeof w === 'object' && w !== null && v.x === w.x && v.y === w.y; + return ( + v === w || + (typeof w === "object" && w !== null && v.x === w.x && v.y === w.y) + ); } /** @@ -425,16 +428,14 @@ export class Vec2 { /** Cross product between a scalar and a vector */ static cross(v: number, w: Vec2Value): Vec2; static cross(v: any, w: any): any { - if (typeof w === 'number') { + if (typeof w === "number") { _ASSERT && Vec2.assert(v); _ASSERT && console.assert(Number.isFinite(w)); return Vec2.neo(w * v.y, -w * v.x); - - } else if (typeof v === 'number') { + } else if (typeof v === "number") { _ASSERT && console.assert(Number.isFinite(v)); _ASSERT && Vec2.assert(w); return Vec2.neo(-v * w.y, v * w.x); - } else { _ASSERT && Vec2.assert(v); _ASSERT && Vec2.assert(w); @@ -468,12 +469,11 @@ export class Vec2 { /** Returns `a + (v x w)` */ static addCross(a: Vec2Value, v: number, w: Vec2Value): Vec2; static addCross(a: Vec2Value, v: any, w: any): Vec2 { - if (typeof w === 'number') { + if (typeof w === "number") { _ASSERT && Vec2.assert(v); _ASSERT && console.assert(Number.isFinite(w)); return Vec2.neo(w * v.y + a.x, -w * v.x + a.y); - - } else if (typeof v === 'number') { + } else if (typeof v === "number") { _ASSERT && console.assert(Number.isFinite(v)); _ASSERT && Vec2.assert(w); return Vec2.neo(-v * w.y + a.x, v * w.x + a.y); @@ -508,7 +508,7 @@ export class Vec2 { /** @hidden @deprecated */ static wAdd(a: number, v: Vec2Value, b: number, w: Vec2Value): Vec2 { - if (typeof b !== 'undefined' || typeof w !== 'undefined') { + if (typeof b !== "undefined" || typeof w !== "undefined") { return Vec2.combine(a, v, b, w); } else { return Vec2.mulNumVec2(a, v); @@ -528,12 +528,11 @@ export class Vec2 { static mul(a: Vec2Value, b: number): Vec2; static mul(a: number, b: Vec2Value): Vec2; static mul(a: any, b: any): Vec2 { - if (typeof a === 'object') { + if (typeof a === "object") { _ASSERT && Vec2.assert(a); _ASSERT && console.assert(Number.isFinite(b)); return Vec2.neo(a.x * b, a.y * b); - - } else if (typeof b === 'object') { + } else if (typeof b === "object") { _ASSERT && console.assert(Number.isFinite(a)); _ASSERT && Vec2.assert(b); return Vec2.neo(a * b.x, a * b.y); @@ -602,10 +601,14 @@ export class Vec2 { return r; } + static clampVec2(v: Vec2Value, min?: Vec2, max?: Vec2): Vec2 { + return Vec2.neo(clamp(v.x, min?.x, max?.x), clamp(v.y, min?.y, max?.y)); + } + /** @hidden @deprecated */ static scaleFn(x: number, y: number) { // todo: this was used in examples, remove in the future - return function(v: Vec2Value): Vec2 { + return function (v: Vec2Value): Vec2 { return Vec2.neo(v.x * x, v.y * y); }; } @@ -613,7 +616,7 @@ export class Vec2 { /** @hidden @deprecated */ static translateFn(x: number, y: number) { // todo: this was used in examples, remove in the future - return function(v: Vec2Value): Vec2 { + return function (v: Vec2Value): Vec2 { return Vec2.neo(v.x + x, v.y + y); }; } diff --git a/src/dynamics/Fixture.ts b/src/dynamics/Fixture.ts index 27451e1d..78e8e039 100644 --- a/src/dynamics/Fixture.ts +++ b/src/dynamics/Fixture.ts @@ -22,18 +22,17 @@ * SOFTWARE. */ -import * as matrix from '../common/Matrix'; -import { options } from '../util/options'; -import { Vec2Value } from '../common/Vec2'; -import { AABB, RayCastInput, RayCastOutput } from '../collision/AABB'; -import { Shape, ShapeType } from '../collision/Shape'; +import * as matrix from "../common/Matrix"; +import { options } from "../util/options"; +import { Vec2Value } from "../common/Vec2"; +import { AABB, RayCastInput, RayCastOutput } from "../collision/AABB"; +import { Shape, ShapeType } from "../collision/Shape"; import { Body, MassData } from "./Body"; import { BroadPhase } from "../collision/BroadPhase"; import { TransformValue } from "../common/Transform"; -import { Style } from '../util/Testbed'; +import { Style } from "../util/Testbed"; - -/** @internal */ const _ASSERT = typeof ASSERT === 'undefined' ? false : ASSERT; +/** @internal */ const _ASSERT = typeof ASSERT === "undefined" ? false : ASSERT; /** @internal */ const synchronize_aabb1 = new AABB(); /** @internal */ const synchronize_aabb2 = new AABB(); @@ -82,15 +81,15 @@ export interface FixtureDef extends FixtureOpt { } /** @internal */ const FixtureDefDefault: FixtureOpt = { - userData : null, - friction : 0.2, - restitution : 0.0, - density : 0.0, - isSensor : false, - - filterGroupIndex : 0, - filterCategoryBits : 0x0001, - filterMaskBits : 0xFFFF + userData: null, + friction: 0.2, + restitution: 0.0, + density: 0.0, + isSensor: false, + + filterGroupIndex: 0, + filterCategoryBits: 0x0001, + filterMaskBits: 0xffff, }; /** @@ -146,9 +145,8 @@ export class Fixture { if (shape.shape) { def = shape; shape = shape.shape; - - } else if (typeof def === 'number') { - def = {density : def}; + } else if (typeof def === "number") { + def = { density: def }; } def = options(def, FixtureDefDefault); @@ -271,6 +269,15 @@ export class Fixture { return this.m_userData; } + /** + * Get a field of user data + * @experimental @hidden + */ + + getUserDataField(key: string): any { + return this.m_userData?.[key]; + } + /** * Set the user data. Use this to store your application specific data. */ @@ -278,6 +285,17 @@ export class Fixture { this.m_userData = data; } + /** + * Change value of a field of user data. + * @experimental @hidden + */ + setUserDataField(key: string, value: any): void { + if (this.m_userData === null) { + this.m_userData = {}; + } + this.m_userData[key] = value; + } + /** * Get the parent body of this fixture. This is null if the fixture is not * attached. @@ -349,8 +367,17 @@ export class Fixture { /** * Cast a ray against this shape. */ - rayCast(output: RayCastOutput, input: RayCastInput, childIndex: number): boolean { - return this.m_shape.rayCast(output, input, this.m_body.getTransform(), childIndex); + rayCast( + output: RayCastOutput, + input: RayCastInput, + childIndex: number + ): boolean { + return this.m_shape.rayCast( + output, + input, + this.m_body.getTransform(), + childIndex + ); } /** @@ -367,7 +394,8 @@ export class Fixture { * more accurate AABB, compute it using the shape and the body transform. */ getAABB(childIndex: number): AABB { - _ASSERT && console.assert(0 <= childIndex && childIndex < this.m_proxies.length); + _ASSERT && + console.assert(0 <= childIndex && childIndex < this.m_proxies.length); return this.m_proxies[childIndex].aabb; } @@ -402,7 +430,11 @@ export class Fixture { * Updates this fixture proxy in broad-phase (with combined AABB of current and * next transformation). */ - synchronize(broadPhase: BroadPhase, xf1: TransformValue, xf2: TransformValue): void { + synchronize( + broadPhase: BroadPhase, + xf1: TransformValue, + xf2: TransformValue + ): void { for (let i = 0; i < this.m_proxyCount; ++i) { const proxy = this.m_proxies[i]; // Compute an AABB that covers the swept shape (may miss some rotation @@ -423,7 +455,11 @@ export class Fixture { * time step when either parent body is active and awake. This automatically * calls refilter. */ - setFilterData(filter: { groupIndex: number, categoryBits: number, maskBits: number }): void { + setFilterData(filter: { + groupIndex: number; + categoryBits: number; + maskBits: number; + }): void { this.m_filterGroupIndex = filter.groupIndex; this.m_filterCategoryBits = filter.categoryBits; this.m_filterMaskBits = filter.maskBits; @@ -503,8 +539,10 @@ export class Fixture { * overlap. */ shouldCollide(that: Fixture): boolean { - - if (that.m_filterGroupIndex === this.m_filterGroupIndex && that.m_filterGroupIndex !== 0) { + if ( + that.m_filterGroupIndex === this.m_filterGroupIndex && + that.m_filterGroupIndex !== 0 + ) { return that.m_filterGroupIndex > 0; } diff --git a/src/dynamics/World.ts b/src/dynamics/World.ts index cfb9aa86..863e0ea1 100644 --- a/src/dynamics/World.ts +++ b/src/dynamics/World.ts @@ -22,21 +22,20 @@ * SOFTWARE. */ -import { options } from '../util/options'; -import { Vec2, Vec2Value } from '../common/Vec2'; -import { BroadPhase } from '../collision/BroadPhase'; -import { Solver, ContactImpulse, TimeStep } from './Solver'; -import { Body, BodyDef } from './Body'; -import { Joint } from './Joint'; -import { Contact } from './Contact'; +import { options } from "../util/options"; +import { Vec2, Vec2Value } from "../common/Vec2"; +import { BroadPhase } from "../collision/BroadPhase"; +import { Solver, ContactImpulse, TimeStep } from "./Solver"; +import { Body, BodyDef } from "./Body"; +import { Joint } from "./Joint"; +import { Contact } from "./Contact"; import { AABBValue, RayCastInput, RayCastOutput } from "../collision/AABB"; import { Fixture, FixtureProxy } from "./Fixture"; import { Manifold } from "../collision/Manifold"; - -/** @internal */ const _ASSERT = typeof ASSERT === 'undefined' ? false : ASSERT; -/** @internal */ const _CONSTRUCTOR_FACTORY = typeof CONSTRUCTOR_FACTORY === 'undefined' ? false : CONSTRUCTOR_FACTORY; - +/** @internal */ const _ASSERT = typeof ASSERT === "undefined" ? false : ASSERT; +/** @internal */ const _CONSTRUCTOR_FACTORY = + typeof CONSTRUCTOR_FACTORY === "undefined" ? false : CONSTRUCTOR_FACTORY; export interface WorldDef { /** [default: { x : 0, y : 0}] */ @@ -65,14 +64,14 @@ export interface WorldDef { } /** @internal */ const DEFAULTS: WorldDef = { - gravity : Vec2.zero(), - allowSleep : true, - warmStarting : true, - continuousPhysics : true, - subStepping : false, - blockSolve : true, - velocityIterations : 8, - positionIterations : 3 + gravity: Vec2.zero(), + allowSleep: true, + warmStarting: true, + continuousPhysics: true, + subStepping: false, + blockSolve: true, + velocityIterations: 8, + positionIterations: 3, }; /** @@ -81,7 +80,7 @@ export interface WorldDef { * Called for each fixture found in the query. * The returned value replaces the ray-cast input maxFraction. * You control how the ray cast proceeds by returning a numeric/float value. - * + * * - `0` to terminate the ray cast * - `fraction` to clip the ray cast at current point * - `1` don't clip the ray and continue @@ -94,7 +93,12 @@ export interface WorldDef { * * @returns A number to update the maxFraction */ -export type WorldRayCastCallback = (fixture: Fixture, point: Vec2, normal: Vec2, fraction: number) => number; +export type WorldRayCastCallback = ( + fixture: Fixture, + point: Vec2, + normal: Vec2, + fraction: number +) => number; /** * Called for each fixture found in the query AABB. It may return `false` to terminate the query. @@ -126,20 +130,19 @@ export class World { // TODO /** @internal */ _listeners: { - [key: string]: any[] + [key: string]: any[]; }; /** * @param def World definition or gravity vector. */ - constructor(def?: WorldDef | Vec2 | null) { + constructor(def?: WorldDef | Vec2Value | null) { if (_CONSTRUCTOR_FACTORY && !(this instanceof World)) { return new World(def); } this.s_step = new TimeStep(); - if (!def) { def = {}; } else if (Vec2.isValid(def)) { @@ -193,7 +196,7 @@ export class World { for (let j = this.getJointList(); j; j = j.getNext()) { // @ts-ignore - if (typeof j._serialize === 'function') { + if (typeof j._serialize === "function") { joints.push(j); } } @@ -390,9 +393,10 @@ export class World { * @param callback Called for each fixture found in the query AABB. It may return `false` to terminate the query. */ queryAABB(aabb: AABBValue, callback: WorldAABBQueryCallback): void { - _ASSERT && console.assert(typeof callback === 'function'); + _ASSERT && console.assert(typeof callback === "function"); const broadPhase = this.m_broadPhase; - this.m_broadPhase.query(aabb, function(proxyId: number): boolean { // TODO GC + this.m_broadPhase.query(aabb, function (proxyId: number): boolean { + // TODO GC const proxy = broadPhase.getUserData(proxyId); return callback(proxy.fixture); }); @@ -407,28 +411,39 @@ export class World { * @param point2 The ray ending point * @param callback A function that is called for each fixture that is hit by the ray. You control how the ray cast proceeds by returning a numeric/float value. */ - rayCast(point1: Vec2Value, point2: Vec2Value, callback: WorldRayCastCallback): void { - _ASSERT && console.assert(typeof callback === 'function'); + rayCast( + point1: Vec2Value, + point2: Vec2Value, + callback: WorldRayCastCallback + ): void { + _ASSERT && console.assert(typeof callback === "function"); const broadPhase = this.m_broadPhase; - this.m_broadPhase.rayCast({ - maxFraction : 1.0, - p1 : point1, - p2 : point2 - }, function(input: RayCastInput, proxyId: number): number { // TODO GC - const proxy = broadPhase.getUserData(proxyId); - const fixture = proxy.fixture; - const index = proxy.childIndex; - // @ts-ignore - const output: RayCastOutput = {}; // TODO GC - const hit = fixture.rayCast(output, input, index); - if (hit) { - const fraction = output.fraction; - const point = Vec2.add(Vec2.mulNumVec2((1.0 - fraction), input.p1), Vec2.mulNumVec2(fraction, input.p2)); - return callback(fixture, point, output.normal, fraction); + this.m_broadPhase.rayCast( + { + maxFraction: 1.0, + p1: point1, + p2: point2, + }, + function (input: RayCastInput, proxyId: number): number { + // TODO GC + const proxy = broadPhase.getUserData(proxyId); + const fixture = proxy.fixture; + const index = proxy.childIndex; + // @ts-ignore + const output: RayCastOutput = {}; // TODO GC + const hit = fixture.rayCast(output, input, index); + if (hit) { + const fraction = output.fraction; + const point = Vec2.add( + Vec2.mulNumVec2(1.0 - fraction, input.p1), + Vec2.mulNumVec2(fraction, input.p2) + ); + return callback(fixture, point, output.normal, fraction); + } + return input.maxFraction; } - return input.maxFraction; - }); + ); } /** @@ -520,8 +535,8 @@ export class World { let def: BodyDef = {}; if (!arg1) { } else if (Vec2.isValid(arg1)) { - def = { position : arg1, angle: arg2 }; - } else if (typeof arg1 === 'object') { + def = { position: arg1, angle: arg2 }; + } else if (typeof arg1 === "object") { def = arg1; } @@ -537,11 +552,11 @@ export class World { let def: BodyDef = {}; if (!arg1) { } else if (Vec2.isValid(arg1)) { - def = { position : arg1, angle: arg2 }; - } else if (typeof arg1 === 'object') { + def = { position: arg1, angle: arg2 }; + } else if (typeof arg1 === "object") { def = arg1; } - def.type = 'dynamic'; + def.type = "dynamic"; return this.createBody(def); } @@ -552,11 +567,11 @@ export class World { let def: BodyDef = {}; if (!arg1) { } else if (Vec2.isValid(arg1)) { - def = { position : arg1, angle: arg2 }; - } else if (typeof arg1 === 'object') { + def = { position: arg1, angle: arg2 }; + } else if (typeof arg1 === "object") { def = arg1; } - def.type = 'kinematic'; + def.type = "kinematic"; return this.createBody(def); } @@ -585,7 +600,7 @@ export class World { const je0 = je; je = je.next; - this.publish('remove-joint', je0.joint); + this.publish("remove-joint", je0.joint); this.destroyJoint(je0.joint); b.m_jointList = je; @@ -610,7 +625,7 @@ export class World { const f0 = f; f = f.m_next; - this.publish('remove-fixture', f0); + this.publish("remove-fixture", f0); f0.destroyProxies(this.m_broadPhase); b.m_fixtureList = f; @@ -634,7 +649,7 @@ export class World { --this.m_bodyCount; - this.publish('remove-body', b); + this.publish("remove-body", b); return true; } @@ -775,7 +790,7 @@ export class World { } } - this.publish('remove-joint', joint); + this.publish("remove-joint", joint); } /** @internal */ @@ -789,8 +804,12 @@ export class World { * * @param timeStep Time step, this should not vary. */ - step(timeStep: number, velocityIterations?: number, positionIterations?: number): void { - this.publish('pre-step', timeStep); + step( + timeStep: number, + velocityIterations?: number, + positionIterations?: number + ): void { + this.publish("pre-step", timeStep); if ((velocityIterations | 0) !== velocityIterations) { // TODO: remove this in future @@ -850,7 +869,7 @@ export class World { this.m_locked = false; - this.publish('post-step', timeStep); + this.publish("post-step", timeStep); } /** @@ -859,7 +878,8 @@ export class World { */ findNewContacts(): void { this.m_broadPhase.updatePairs( - (proxyA: FixtureProxy, proxyB: FixtureProxy) => this.createContact(proxyA, proxyB) + (proxyA: FixtureProxy, proxyB: FixtureProxy) => + this.createContact(proxyA, proxyB) ); } @@ -939,7 +959,7 @@ export class World { // Update awake contacts. let c: Contact; let next_c = this.m_contactList; - while (c = next_c) { + while ((c = next_c)) { next_c = c.getNext(); const fixtureA = c.getFixtureA(); const fixtureB = c.getFixtureB(); @@ -1005,7 +1025,6 @@ export class World { --this.m_contactCount; } - /** * Called when two fixtures begin to touch. * @@ -1019,7 +1038,7 @@ export class World { * * Warning: You cannot create/destroy world entities inside these callbacks. */ - on(name: 'begin-contact', listener: (contact: Contact) => void): World; + on(name: "begin-contact", listener: (contact: Contact) => void): World; /** * Called when two fixtures cease to touch. * @@ -1033,7 +1052,7 @@ export class World { * * Warning: You cannot create/destroy world entities inside these callbacks. */ - on(name: 'end-contact', listener: (contact: Contact) => void): World; + on(name: "end-contact", listener: (contact: Contact) => void): World; /** * This is called after a contact is updated. This allows you to inspect a * contact before it goes to the solver. If you are careful, you can modify the @@ -1046,7 +1065,10 @@ export class World { * * Warning: You cannot create/destroy world entities inside these callbacks. */ - on(name: 'pre-solve', listener: (contact: Contact, oldManifold: Manifold) => void): World; + on( + name: "pre-solve", + listener: (contact: Contact, oldManifold: Manifold) => void + ): World; /** * This lets you inspect a contact after the solver is finished. This is useful * for inspecting impulses. Note: the contact manifold does not include time of @@ -1056,19 +1078,22 @@ export class World { * * Warning: You cannot create/destroy world entities inside these callbacks. */ - on(name: 'post-solve', listener: (contact: Contact, impulse: ContactImpulse) => void): World; + on( + name: "post-solve", + listener: (contact: Contact, impulse: ContactImpulse) => void + ): World; /** Listener is called whenever a body is removed. */ - on(name: 'remove-body', listener: (body: Body) => void): World; + on(name: "remove-body", listener: (body: Body) => void): World; /** Listener is called whenever a joint is removed implicitly or explicitly. */ - on(name: 'remove-joint', listener: (joint: Joint) => void): World; + on(name: "remove-joint", listener: (joint: Joint) => void): World; /** Listener is called whenever a fixture is removed implicitly or explicitly. */ - on(name: 'remove-fixture', listener: (fixture: Fixture) => void): World; + on(name: "remove-fixture", listener: (fixture: Fixture) => void): World; /** * Register an event listener. */ // tslint:disable-next-line:typedef on(name, listener) { - if (typeof name !== 'string' || typeof listener !== 'function') { + if (typeof name !== "string" || typeof listener !== "function") { return this; } if (!this._listeners) { @@ -1081,19 +1106,25 @@ export class World { return this; } - off(name: 'begin-contact', listener: (contact: Contact) => void): World; - off(name: 'end-contact', listener: (contact: Contact) => void): World; - off(name: 'pre-solve', listener: (contact: Contact, oldManifold: Manifold) => void): World; - off(name: 'post-solve', listener: (contact: Contact, impulse: ContactImpulse) => void): World; - off(name: 'remove-body', listener: (body: Body) => void): World; - off(name: 'remove-joint', listener: (joint: Joint) => void): World; - off(name: 'remove-fixture', listener: (fixture: Fixture) => void): World; + off(name: "begin-contact", listener: (contact: Contact) => void): World; + off(name: "end-contact", listener: (contact: Contact) => void): World; + off( + name: "pre-solve", + listener: (contact: Contact, oldManifold: Manifold) => void + ): World; + off( + name: "post-solve", + listener: (contact: Contact, impulse: ContactImpulse) => void + ): World; + off(name: "remove-body", listener: (body: Body) => void): World; + off(name: "remove-joint", listener: (joint: Joint) => void): World; + off(name: "remove-fixture", listener: (fixture: Fixture) => void): World; /** * Remove an event listener. */ // tslint:disable-next-line:typedef off(name, listener) { - if (typeof name !== 'string' || typeof listener !== 'function') { + if (typeof name !== "string" || typeof listener !== "function") { return this; } const listeners = this._listeners && this._listeners[name]; @@ -1120,22 +1151,22 @@ export class World { /** @internal */ beginContact(contact: Contact): void { - this.publish('begin-contact', contact); + this.publish("begin-contact", contact); } /** @internal */ endContact(contact: Contact): void { - this.publish('end-contact', contact); + this.publish("end-contact", contact); } /** @internal */ preSolve(contact: Contact, oldManifold: Manifold): void { - this.publish('pre-solve', contact, oldManifold); + this.publish("pre-solve", contact, oldManifold); } /** @internal */ postSolve(contact: Contact, impulse: ContactImpulse): void { - this.publish('post-solve', contact, impulse); + this.publish("post-solve", contact, impulse); } /** @@ -1154,4 +1185,4 @@ export class World { * * Moved to Fixture. */ -} \ No newline at end of file +} diff --git a/testbed/index.html b/testbed/index.html index 923a65c4..768841aa 100644 --- a/testbed/index.html +++ b/testbed/index.html @@ -34,7 +34,7 @@

Planck.js