typescript

This commit is contained in:
Rüdiger Diedrich 2021-09-03 14:56:12 +02:00
parent 0fa8b899d4
commit 03d9a398e9
9 changed files with 247 additions and 189 deletions

View File

@ -8,6 +8,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.js"></script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

183
main.js
View File

@ -1,183 +0,0 @@
import * as PIXI from 'pixi.js';
import * as p2 from 'p2'
import './style.css'
function randomInt(max) {
return Math.floor(Math.random() * (max + 1))
}
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);
class PhysicsObject {
body;
shape;
graphics;
parentContainer;
constructor(body, shape, graphics) {
this.body = body;
this.shape = shape;
this.graphics = graphics;
this.body.addShape(this.shape);
this.graphics.interactive = true;
this.graphics.on('click', (e) => {
this.body.applyImpulse([0, 25]);
})
}
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) => {
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)
window.addEventListener('touchstart', randomBox)

View File

@ -1,15 +1,22 @@
{
"name": "pixi",
"name": "physik-piet",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"build": "tsc && vite build",
"serve": "vite preview"
},
"prettier": {
"trailingComma": "none",
"semi": false
},
"devDependencies": {
"@types/p2": "^0.7.39",
"typescript": "^4.3.2",
"vite": "^2.5.2"
},
"dependencies": {
"@types/offscreencanvas": "^2019.6.3",
"p2": "^0.7.1",
"pixi.js": "^6.1.2"
}

52
src/lib/PhysicsObject.ts Normal file
View File

@ -0,0 +1,52 @@
import * as PIXI from "pixi.js"
import * as p2 from "p2"
export class PhysicsObject {
body
shape
graphics
alive = true
world?: p2.World
constructor(body: p2.Body, shape: p2.Box, graphics: PIXI.Graphics) {
this.body = body
this.shape = shape
this.graphics = graphics
this.body.addShape(this.shape)
this.graphics.interactive = true
this.graphics.on("click", (_e) => {
this.body.applyImpulse([0, 25])
})
}
assign(world: p2.World, container: PIXI.Container) {
this.world = world
world.addBody(this.body)
container.addChild(this.graphics)
}
destroy() {
this.graphics.parent.removeChild(this.graphics)
this.graphics.destroy()
this.world!.removeBody(this.body)
this.alive = false
}
update() {
if (!this.alive) {
return
}
// 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
if (this.graphics.position.y < -25) {
this.destroy()
}
}
}

141
src/main.ts Normal file
View File

@ -0,0 +1,141 @@
import * as PIXI from "pixi.js"
import * as p2 from "p2"
import "./style.css"
import { PhysicsObject } from "./lib/PhysicsObject"
const vw = Math.max(
document.documentElement.clientWidth || 0,
window.innerWidth || 0
)
const vh = Math.max(
document.documentElement.clientHeight || 0,
window.innerHeight || 0
)
let zoom = 15
function randomInt(max: number) {
return Math.floor(Math.random() * (max + 1))
}
function makeApp() {
let app = new PIXI.Application({
width: vw,
height: vh,
antialias: true,
backgroundColor: 0xffffff
})
document.body.appendChild(app.view)
return app
}
function makeBox(
mass = 1,
x = 0,
y = 2,
width = 2,
height = 1,
color = 0xff0000
) {
let body = new p2.Body({
mass: mass,
position: [x, y],
angularVelocity: mass === 0 ? 0 : 1
}),
shape = new p2.Box({
width: width,
height: height
}),
graphics = new PIXI.Graphics()
let box = new PhysicsObject(body, shape, graphics)
box.graphics.beginFill(color)
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 makeContainer() {
let container = new PIXI.Container()
container.interactive = true
container.position.x = app.renderer.width / 2
container.position.y = app.renderer.height / 2 + 50
container.scale.x = zoom // zoom in
container.scale.y = -zoom // flip the y axis for physics
return container
}
function makeFloor() {
// zero mass box == static
return makeBox(0, 0, -2, 50, 0.2, 0x666666)
}
function makeRandomBox() {
const width = 1 + Math.random() * 3,
height = 1 + Math.random() * 3,
mass = 0.5 * Math.sqrt(width * height),
position = [randomInt(25) - 12.5, randomInt(10) + 5],
color = randomInt(0xffffff)
let box = makeBox(mass, position[0], position[1], width, height, color)
box.body.angularVelocity = Math.random() * 2
return box
}
const app = makeApp()
let worldObjects: PhysicsObject[] = []
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 = makeContainer()
app.stage.addChild(container)
// Add a box
makeBox()
// static ground box
makeFloor()
app.ticker.add((_delta) => {
// cleanup dead objects
if (worldObjects.length > 100) {
worldObjects = worldObjects.filter((o) => o.alive)
console.log(worldObjects.length)
}
world.step(1 / 60)
worldObjects.forEach((o) => o.update())
})
function doZoom(e: WheelEvent) {
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", makeRandomBox)
window.addEventListener("touchstart", makeRandomBox)
window.setInterval(() => {
makeRandomBox()
}, 100)

1
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

18
tsconfig.json Normal file
View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true
},
"include": ["./src"]
}

View File

@ -192,6 +192,23 @@
resolved "https://registry.yarnpkg.com/@types/earcut/-/earcut-2.1.1.tgz#573a0af609f17005c751f6f4ffec49cfe358ea51"
integrity sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==
"@types/offscreencanvas@^2019.6.3":
version "2019.6.3"
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.6.3.tgz#0508eec9641f3228bf8a27009670166887dc966c"
integrity sha512-957DsU187Y90EmlXneuqrqnwmwCkC9oPyQ/IEGwmDRpMfuhcGtjIz72Me7HvdK04ZC16A0VWmv0TSNLwC9ZvXw==
dependencies:
"@types/webgl2" "*"
"@types/p2@^0.7.39":
version "0.7.39"
resolved "https://registry.yarnpkg.com/@types/p2/-/p2-0.7.39.tgz#ba6c2328083e36afb841e8183c33d9616d4630e7"
integrity sha512-aDRdPLYKTNpVCE5RBrjvckOZvjc42ycKVRCtElZ0IDsBYE0MQ7o06BmrGrd7UNDGjQOfQwF6uOmQmqiiu/4F1g==
"@types/webgl2@*":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.6.tgz#1ea2db791362bd8521548d664dbd3c5311cdf4b6"
integrity sha512-50GQhDVTq/herLMiqSQkdtRu+d5q/cWHn4VvKJtrj4DJAjo1MNkWYa2MA41BaBO1q1HgsUjuQvEOk0QHvlnAaQ==
colorette@^1.2.2:
version "1.3.0"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af"
@ -203,9 +220,9 @@ earcut@^2.2.2:
integrity sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==
esbuild@^0.12.17:
version "0.12.24"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.24.tgz#21966fad25a80f368ed308101e88102bce0dc68f"
integrity sha512-C0ibY+HsXzYB6L/pLWEiWjMpghKsIc58Q5yumARwBQsHl9DXPakW+5NI/Y9w4YXiz0PEP6XTGTT/OV4Nnsmb4A==
version "0.12.25"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.25.tgz#c2131cef022cf9fe94aaa5e00110b27fc976221a"
integrity sha512-woie0PosbRSoN8gQytrdCzUbS2ByKgO8nD1xCZkEup3D9q92miCze4PqEI9TZDYAuwn6CruEnQpJxgTRWdooAg==
eventemitter3@^3.1.0:
version "3.1.2"
@ -353,6 +370,11 @@ source-map-js@^0.6.2:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
typescript@^4.3.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86"
integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"