diff --git a/main.js b/main.js index f20e0c5..b11f74c 100644 --- a/main.js +++ b/main.js @@ -1,58 +1,182 @@ import * as PIXI from 'pixi.js'; - +import * as p2 from 'p2' import './style.css' +function randomInt(max) { + return Math.floor(Math.random() * (max + 1)) +} -// Create the application helper and add its render target to the page -let app = new PIXI.Application({ width: 640, height: 360 }); +const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) +const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) + +let app = new PIXI.Application({ + width: vw, + height: vh, + antialias: true, + backgroundColor: 0xffffff +}); document.body.appendChild(app.view); -// Create window frame -let frame = new PIXI.Graphics(); -frame.beginFill(0x666666); -frame.lineStyle({ color: 0xffffff, width: 4, alignment: 0 }); -frame.drawRect(0, 0, 208, 208); -frame.position.set(320 - 100, 180 - 100); -app.stage.addChild(frame); -// Create a graphics object to define our mask -let mask = new PIXI.Graphics(); -// Add the rectangular area to show -mask.beginFill(0xffffff); -mask.drawRect(0,0,200,200); -mask.endFill(); +class PhysicsObject { + body; + shape; + graphics; + parentContainer; -// Add container that will hold our masked content -let maskContainer = new PIXI.Container(); -// Set the mask to use our graphics object from above -maskContainer.mask = mask; -// Add the mask as a child, so that the mask is positioned relative to its parent -maskContainer.addChild(mask); -// Offset by the window's frame width -maskContainer.position.set(4,4); -// And add the container to the window! -frame.addChild(maskContainer); + constructor(body, shape, graphics) { + this.body = body; + this.shape = shape; + this.graphics = graphics; -// Create contents for the masked container -let text = new PIXI.Text( - 'This text will scroll up and be masked, so you can see how masking works. Lorem ipsum and all that.\n\n' + - 'You can put anything in the container and it will be masked!', - { - fontSize: 24, - fill: 0x1010ff, - wordWrap: true, - wordWrapWidth: 180 + this.body.addShape(this.shape); + + this.graphics.interactive = true; + this.graphics.on('click', (e) => { + this.body.applyImpulse([0, 25]); + }) } -); -text.x = 10; -maskContainer.addChild(text); -// Add a ticker callback to scroll the text up and down -let elapsed = 0.0; + assign(world, container) { + world.addBody(this.body); + container.addChild(this.graphics); + } + + update() { + // Transfer positions of the physics objects to Pixi.js + this.graphics.position.x = this.body.position[0]; + this.graphics.position.y = this.body.position[1]; + this.graphics.rotation = this.body.angle; + } +} + +let worldObjects = []; + +let zoom = 15; +let world = new p2.World({ gravity: [0, -9.81] }); +// Add a plane + +// let planeShape = new p2.Plane(); +// let planeBody = new p2.Body({ +// position: [0, -2] +// }); +// planeBody.addShape(planeShape); +// world.addBody(planeBody); + +let container = new PIXI.Container(); +container.interactive = true; +container.position.x = app.renderer.width / 2; // center at origin +container.position.y = app.renderer.height / 2 + 50; +container.scale.x = zoom; // zoom in +container.scale.y = -zoom; // Note: we flip the y axis to make "up" the physics "up" +container.on('mousedown', e => { + console.log(e.data.global.x, e.data.global.y) +}) +app.stage.addChild(container); + +// Add a box +let box = new PhysicsObject( + new p2.Body({ + mass: 1, + position: [0, 2], + angularVelocity: 1 + }), + new p2.Box({ + width: 2, + height: 1 + }), + new PIXI.Graphics() +) +box.graphics.beginFill(randomInt(0xffffff)); +box.graphics.drawRect( + -box.shape.width / 2, -box.shape.height / 2, + box.shape.width, box.shape.height); +box.graphics.endFill(); + +box.assign(world, container); +worldObjects.push(box); + +let box2 = new PhysicsObject( + new p2.Body({ + mass: 2, + position: [-1, 3], + angularVelocity: 0 + }), + new p2.Box({ + width: 2, + height: 1 + }), + new PIXI.Graphics() +) +box2.graphics.beginFill(0x00ff00); +box2.graphics.drawRect( + -box.shape.width / 2, -box.shape.height / 2, + box.shape.width, box.shape.height); +box2.graphics.endFill(); + +box2.assign(world, container); +worldObjects.push(box2); + + +// static ground box +let box3 = new PhysicsObject( + new p2.Body({ + mass: 0, + position: [0, -2] + }), + new p2.Box({ + width: 50, + height: 0.2 + }), + new PIXI.Graphics() +) +box3.graphics.beginFill(0x666666); +box3.graphics.drawRect( + -box3.shape.width / 2, -box3.shape.height / 2, + box3.shape.width, box3.shape.height); +box3.graphics.endFill(); + +box3.assign(world, container); +worldObjects.push(box3); + app.ticker.add((delta) => { - // Update the text's y coordinate to scroll it - elapsed += delta; - text.y = 10 + -100.0 + Math.cos(elapsed/50.0) * 100.0; + world.step(1 / 60); + worldObjects.forEach(o => o.update()); }); +function randomBox() { + let width = 1 + Math.random() * 3; + let height = 1 + Math.random() * 3; + // Add a box + let box = new PhysicsObject( + new p2.Body({ + mass: 0.5 * Math.sqrt(width * height), + position: [randomInt(25) - 12.5, randomInt(10) + 5], + angularVelocity: 0 + }), + new p2.Box({ + width: width, + height: height + }), + new PIXI.Graphics() + ) + box.graphics.beginFill(randomInt(0xffffff)); + box.graphics.drawRect( + -box.shape.width / 2, -box.shape.height / 2, + box.shape.width, box.shape.height); + box.graphics.endFill(); + box.assign(world, container); + worldObjects.push(box); + + return box; +} + +function doZoom(e) { + zoom += -e.deltaY * 0.05; + zoom = Math.min(Math.max(1, zoom), 100) + container.scale.x = zoom; // zoom in + container.scale.y = -zoom; // Note: we flip the y axis to make "up" the physics +} +window.addEventListener('wheel', doZoom) +window.addEventListener('click', randomBox) \ No newline at end of file diff --git a/package.json b/package.json index 0b646e1..f8a947c 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "vite": "^2.5.2" }, "dependencies": { + "p2": "^0.7.1", "pixi.js": "^6.1.2" } } diff --git a/style.css b/style.css index 852de7a..7116a45 100644 --- a/style.css +++ b/style.css @@ -1,8 +1,3 @@ -#app { - font-family: Avenir, Helvetica, Arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-align: center; - color: #2c3e50; - margin-top: 60px; -} +body { + margin: 0; padding: 0; overflow: hidden; +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 35f5ee2..cd890fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -251,6 +251,13 @@ object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +p2@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/p2/-/p2-0.7.1.tgz#25f2474d9bc3a6d3140a1da26a67c9e118ac9543" + integrity sha1-JfJHTZvDptMUCh2iamfJ4RislUM= + dependencies: + poly-decomp "0.1.1" + path-parse@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -297,6 +304,11 @@ pixi.js@^6.1.2: "@pixi/ticker" "6.1.2" "@pixi/utils" "6.1.2" +poly-decomp@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/poly-decomp/-/poly-decomp-0.1.1.tgz#9f68c4fa558663791c9ba4c2df7283f3096c23c9" + integrity sha1-n2jE+lWGY3kcm6TC33KD8wlsI8k= + postcss@^8.3.6: version "8.3.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"