I'm trying to make a game with paper.js but something is not working so i've simplified things and.. not working again.
I've tried to make with paper.js with already-made namespace paperscript but it was too hard to debug so i've tried to use javascript directly.
Even with super simple code moving a ball around the browser.. it is not working.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Bouncing ball</title>
<link rel="stylesheet" href="../css/style.css">
<script type="text/javascript" src="../../lib/paper.js"></script>
<script type="text/javascript">
var ball;
function game(_view) {
console.log("game!");
ball = new Ball();
this.view = _view;
console.log(ball);
}
paper.install(window);
window.onload = function() {
var canvas = document.getElementById('canvas');
paper.setup(canvas);
view.onFrame = onFrame;
game(view);
}
var Ball = Base.extend({
initialize: function() {
this.position = new Point(100, 100);
this.velocity = new Point(3, 0);
this.path = new Path.Circle(location, 25);
this.path.strokeColor = 'black';
this.path.fillColor = 'black';
},
iterate: function() {
this.position += this.velocity;
this.path.position = this.position;
return this;
}
});
function onFrame(event) {
ball.iterate();
//console.log(ball);
};
</script>
</head>
<body>
<canvas id="canvas" resize></canvas>
</body>
</html>
I'm keeping on getting this error:
Uncaught TypeError: Cannot call method 'iterate' of undefined
When you assign the onFrame handler, a setter function setOnFrame is called, which immediately invokes the frame handler. Since ball is not initialized at this point, the function call fails.
setOnFrame: function(onFrame) {
this._onFrame = onFrame;
if (!onFrame) {
delete this._onFrameCallback;
return;
}
var that = this,
requested = false,
before,
time = 0,
count = 0;
this._onFrameCallback = function(param, dontRequest) {
requested = false;
if (!that._onFrame)
return;
paper = that._scope;
requested = true;
if (!dontRequest) {
DomEvent.requestAnimationFrame(that._onFrameCallback,
that._canvas);
}
var now = Date.now() / 1000,
delta = before ? now - before : 0;
that._onFrame(Base.merge({
delta: delta,
time: time += delta,
count: count++
}));
before = now;
that.draw(true);
};
if (!requested)
this._onFrameCallback(); //here your onFrame function is called
},
If you look at this jsFiddle, and make sure you set break on exceptions in your dev tools, you can see the stack. The solution would then be to initialize ball before assigning the handler.
There is only one possible reason, ballis not yet defined when onFrame is called. Either assign onFrameafter the creation of ball, or check ball inside onFrame.
I've created a library folio.js for taking care of exactly this. It also handles animations. Here is your example using folio.js.
<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--><html class="no-js"> <!--<![endif]-->
<head>
<!-- META -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="">
<title>Ball</title>
<script type="text/javascript" src="paper-core.js"></script>
<script type="text/javascript" src="paper.folio.js"></script>
<script type="text/javascript">
// ------------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------------
// the core folio namespace
var f = folio;
// define ball variable
var ball;
// ------------------------------------------------------------------------
// Setup
// ------------------------------------------------------------------------
function Setup() {
ball = new Ball();
};
// ------------------------------------------------------------------------
// Update
// ------------------------------------------------------------------------
/*
* Update() is called every frame
*/
function Update(event) {
ball.iterate();
};
// ------------------------------------------------------------------------
// Draw
// ------------------------------------------------------------------------
function Draw() {
};
// ------------------------------------------------------------------------
// Classes
// ------------------------------------------------------------------------
var Ball = Base.extend({
initialize: function() {
this.position = new Point(100, 100);
this.velocity = new Point(3, 0);
this.path = new Path.Circle(this.position, 25);
this.path.strokeColor = 'black';
this.path.fillColor = 'black';
},
iterate: function() {
this.path.position.x += this.velocity.x;
this.path.position.y += this.velocity.y;
return this;
}
});
</script>
<meta http-equiv="x-dns-prefetch-control" content="off"/>
</head>
<body>
<canvas resize="true" id="canvas"></canvas>
</body>
</html>
Related
I am Japanese and I apologize for my unnatural English, but I would appreciate it if you could read it.
I learned how to convert paperscript to javascript from the official documentation.
Its means are as follows
Change the type attribute of the script tag to text/paperscript. <script type="text/paperscript" src="./main.js"></script>
Enable Paperscope for global use.  paper.install(window)
Specify the target of the canvas. paper.setup(document.getElementById("myCanvas"))
Write the main code in the onload window.onload = function(){ /* add main code */ }
Finally, add paper.view.draw()
The onFrame and onResize transforms as follows. view.onFrame = function(event) {}
onMouseDown, onMouseUp, onMouseDrag, onMouseMove, etc. are converted as follows. var customTool = new Tool(); customTool.onMouseDown = function(event) {};
I have tried these methods, but applying these to the Examples on the paper.js official site does not work correctly.
The following code is the result of trying these.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://unpkg.com/paper"></script>
<script type="text/javascript" src="./main.js"></script>
<title>Document</title>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>
paper.install(window);
console.log("run test")
var myCanvas = document.getElementById("myCanvas")
var customTool = new Tool();
window.onload = function(){
paper.setup(myCanvas)
var points = 25;
// The distance between the points:
var length = 35;
var path = new Path({
strokeColor: '#E4141B',
strokeWidth: 20,
strokeCap: 'round'
});
var start = view.center / [10, 1];
for (var i = 0; i < points; i++)
path.add(start + new Point(i * length, 0));
customTool.onMouseMove=function(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
var vector = segment.point - nextSegment.point;
vector.length = length;
nextSegment.point = segment.point - vector;
}
path.smooth({ type: 'continuous' });
}
customTool.onMouseDown=function(event) {
path.fullySelected = true;
path.strokeColor = '#e08285';
}
customTool.onMouseUp=function(event) {
path.fullySelected = false;
path.strokeColor = '#e4141b';
}
view.draw();
}
The original paperscript can be found here.
What is the problem with this code?
Thank you for reading to the end!
The var vector in the for loop is not getting the correct values in your code. Change the math operators and it will work like the paperjs demo.
Math operators (+ - * /) for vector only works in paperscript. In Javascript, use .add() .subtract() .multiply() .divide(). see http://paperjs.org/reference/point/#subtract-point
// paperscript
segment.point - nextSegment.point
// javascript
segment.point.subtract(nextSegment.point)
Here's a working demo of your example
paper.install(window);
console.log("run test")
var myCanvas = document.getElementById("myCanvas")
var customTool = new Tool();
window.onload = function() {
paper.setup(myCanvas)
var points = 15; //25
// The distance between the points:
var length = 20; //35
var path = new Path({
strokeColor: '#E4141B',
strokeWidth: 20,
strokeCap: 'round'
});
var start = view.center / [10, 1];
for (var i = 0; i < points; i++) {
path.add(start + new Point(i * length, 0));
}
customTool.onMouseMove = function(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
//var vector = segment.point - nextSegment.point;
var vector = segment.point.subtract(nextSegment.point);
vector.length = length;
//nextSegment.point = segment.point - vector;
nextSegment.point = segment.point.subtract(vector);
}
path.smooth({
type: 'continuous'
});
}
customTool.onMouseDown = function(event) {
path.fullySelected = true;
path.strokeColor = '#e08285';
}
customTool.onMouseUp = function(event) {
path.fullySelected = false;
path.strokeColor = '#e4141b';
}
view.draw();
}
html,
body {
margin: 0
}
canvas {
border: 1px solid red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://unpkg.com/paper"></script>
<!-- you can add this back in -->
<!-- <script type="text/javascript" src="./main.js"></script> -->
<title>Document</title>
</head>
<body>
<!-- set any size you want, or use CSS/JS to make this resizable -->
<canvas id="myCanvas" width="600" height="150"></canvas>
</body>
</html>
Essentially I would like for all these disparate lines to be connected in one single path.
I am using vector.add() because I would like a cumulative result. Maybe that's the issue?
Or perhaps it's how I'm accessing the previous element of the array?
Please take a look at this snippet:
let lifespan = 200;
let genes = [];
let previous;
let prevpos;
function setup(){
createCanvas(window.innerWidth, window.innerHeight);
background(255);
genes[0] = createVector(50,50);
stroke(0);
strokeWeight(1);
beginShape(LINES)
vertex(genes[0].x, genes[0].y);
for (let i = 1; i < lifespan; i++) {
previous = genes[i-1];
genes[i] = previous.add(createVector(random(-10,10),random(-10,10)));
// vertex(previous.x, previous.y);
vertex(genes[i].x, genes[i].y);
}
endShape()
}
function draw(){
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id='sketch'> </div>
<script language="javascript" type="text/javascript" src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.min.js"></script>
<script src="sketch.js"></script>
<script>
</script>
</body>
</html>
I thought I had tried this already but I just needed to uncomment a line.
beginShape(LINES)
vertex(genes[0].x, genes[0].y);
for (let i = 1; i < lifespan; i++) {
previous = genes[i-1];
genes[i] = previous.add(createVector(random(-10,10),random(-10,10)));
vertex(previous.x, previous.y); //<-- uncomment this
vertex(genes[i].x, genes[i].y);
}
endShape()
I am new to Phaserjs, and I am trying to make a shooting game. I want the damage function to fire when a bullet touches plane2, that is the green plane. Can somone please tell me what am I doing wrong here?
Here is my code:
var config = {
type: Phaser.AUTO,
width: 800,
height: 800,
parent:"game",
physics: {
default: 'arcade',
arcade: {
debugging:true,
gravity: {y: 0}
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var plane1
var plane2
var hp;
var botHp;
function preload (){
this.load.setBaseURL('https://shoot.abaanshanid.repl.co/assets');
this.load.image("bg", "bg.jpg");
this.load.image("plane1", "plane1.png");
this.load.image("plane2", "plane2.png");
this.load.image("bullet", "bullet.png");
}
function create (){
this.background = this.add.image(400, 400, "bg");
plane1 = this.physics.add.sprite(400,700,"plane1");
plane2 = this.physics.add.sprite(400,100,"plane2");
plane1.enableBody = true;
}
function update(){
keys = this.input.keyboard.createCursorKeys();
if (keys.left.isDown) {
plane1.x = plane1.x - 7.5;
}else if(keys.right.isDown){
plane1.x = plane1.x + 7.5;
}else if(keys.space.isDown){
var bullet = this.physics.add.sprite(plane1.x,600,"bullet");
bullet.enableBody = true;
setInterval(function(){
bullet.y = bullet.y - 25;
},50);
this.physics.overlap(bullet,plane2,this.damage);
}
}
function damage(){
console.log("less HP")
}
var game = new Phaser.Game(config);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.54.0/phaser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.54.0/phaser-arcade-physics.min.js"></script>
</head>
<body>
<div id="game"></div>
<script defer src="script.js"></script>
</body>
</html>
Here is the link to the game if needed https://shoot.abaanshanid.repl.co/
This works:
this.physics.add.overlap(bullet,plane2,damage);
but its kinda laggy. Id try to destroy bullet on impact and i also found:
this.physics.add.collider(bullet,plane2,damage);
I have a problem. I'm using HTML5 and Javascript to draw a box onto a canvas. This box is supposed to move up and down, but after it gets rendered for the first time, it doesn't want to re-render at the new position. This is the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="sl" lang="sl">
<head>
<title>Spletna stran Portfolio - Domaca stran</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" href="css/style.css" type="text/css" media="all" />
<script>
var isMoving = true;
var gradienty = 0;
var gradientheight = 100;
var gradientyVel = 1;
var gradientImage = new Image();
gradientImage.src = "grafika/gradient.gif";
function main() {
var c = document.getElementById("menuCanvas");
var ctx = c.getContext("2d");
ctx.drawImage(gradientImage, 0, gradienty);
if(isMoving == true) {
gradienty += gradientyVel;
if((gradienty+gradientheight)==c,height || gradienty<=0) {
gradientyVel *= -1;
}
}
}
function mainLoop() {
setInterval(main(), 10);
}
</script>
</head>
<body onload="mainLoop()">
<canvas id="menuCanvas" width="195" height="400"></canvas>
</body>
</html>
I have no clue why the box isn't moving. It's like after I draw it for the first time it won't draw again the next time. Also, I use mainLoop() function as my main loop. Every 10 miliseconds I basically call the main() function, which does the drawing and the logic.
Any help would be much appreciated. :)
A few coding problems:
You need to give your image time to load, then start the animation
var gradientImage = new Image();
gradientImage.onload=function(){
setInterval(main, 20);
}
gradientImage.src = "house16x16.png";
setInterval takes in a function pointer (no parentheses):
setInterval will fire only as fast as 16ms, so your 10ms value is too small
setInterval(main, 20);
Here's revised code and a Demo: http://jsfiddle.net/m1erickson/U6K9j/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var c=document.getElementById("menuCanvas");
var ctx=c.getContext("2d");
var isMoving = true;
var gradienty = 0;
var gradientheight = 100;
var gradientyVel = 1;
var gradientImage = new Image();
gradientImage.onload=function(){
setInterval(main, 20);
}
gradientImage.src = "house16x16.png";
function main() {
ctx.clearRect(0,0,c.width,c.height);
ctx.drawImage(gradientImage, 0, gradienty);
if(isMoving == true) {
gradienty += gradientyVel;
if((gradienty+gradientheight)==c.height || gradienty<=0) {
gradientyVel *= -1;
}
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="menuCanvas" width=300 height=300></canvas>
</body>
</html>
You're calling main and then passing the RESULT to setInterval. Just change
function mainLoop() {
setInterval(main(), 10);
}
to
function mainLoop() {
setInterval(main, 10);
}
That'll get you started, but you'll also need to clear the canvas in between draws. (As you'll notice if you run this)
I'm writing a canvas game with easeljs. Almost everything is working correctly in this project, only problem is I can't add static objects to the field.
Here is the link my demo: http://insidejs.com/game/
I don't want to enter to the colored areas with shopping cart. Player should turn around these areas. This game illustrates what I need to do.: http://www.kokogames.com/free-games/91/racing-games/138/e-racer.htm
Thanks.
My Project:
<!DOCTYPE html>
<!--[if IE 7]> <html class="no-js ie7"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="tr"><!--<![endif]-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Game</title>
<!-- css -->
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css" />
<link href="assets/css/screen.css" rel="stylesheet" type="text/css" />
<!-- css -->
<!-- javascript -->
<script type="text/javascript" src="assets/js/jquery.js"></script>
<script type="text/javascript" src="assets/js/bootstrap.min.js"></script>
<script type="text/javascript" src="assets/js/easeljs-0.6.1.min.js"></script>
<script type="text/javascript">
var CANVAS, STAGE, Shopping, GAME;
$(function () {
window.Shopping= {
Game: {}
};
GAME = Shopping.Game;
GAME = new Application();
CANVAS = document.getElementById("game");
STAGE = new createjs.Stage(CANVAS);
GAME.init();
});
var Application = function () {
};
Application.prototype = {
vehicle: null,
vehicleImg: new Image(),
map: null,
mapImg: new Image(),
TURN_FACTOR: 3,
MAX_THRUST: 1,
MAX_VELOCITY: 10,
KEYCODE_UP: 38,
KEYCODE_LEFT: 37,
KEYCODE_RIGHT: 39,
KEYCODE_DOWN: 40,
RIGHT_KEY: false,
LEFT_KEY: false,
UP_KEY: false,
DOWN_KEY: false,
map: null,
init: function () {
GAME.mapImg.src = "assets/images/map.jpg";
GAME.mapImg.name = 'map';
GAME.mapImg.onload = GAME.loadImage();
GAME.vehicleImg.src = "assets/images/vehicle.png";
GAME.vehicleImg.name = 'vehicle';
GAME.vehicleImg.onload = GAME.loadImage();
if (!createjs.Ticker.hasEventListener("tick")) {
createjs.Ticker.addEventListener("tick", GAME.tick);
}
$(document).keydown(GAME.handleKeyDown);
$(document).keyup(GAME.handleKeyUp);
},
loadImage: function () {
GAME.vehicle = new createjs.Bitmap(GAME.vehicleImg);
GAME.vehicle.x = CANVAS.width / 2;
GAME.vehicle.y = CANVAS.height / 2;
GAME.vehicle.width = 100;
GAME.vehicle.height = 69;
GAME.vehicle.regX = GAME.vehicle.width / 2;
GAME.vehicle.regY = GAME.vehicle.height / 2;
GAME.map = new createjs.Bitmap(GAME.mapImg);
GAME.map.scaleX = 1;
GAME.map.scaleY = 1;
GAME.map.width = 3000;
GAME.map.height = 2000;
GAME.map.regX = GAME.map.width / 2;
GAME.map.regY = GAME.map.height / 2;
GAME.map.x = CANVAS.width / 2;
GAME.map.y = CANVAS.height / 2 - 300;
GAME.map.speed = 0;
GAME.map.vX = 0;
GAME.map.vY = 0;
STAGE.addChild(GAME.map);
STAGE.addChild(GAME.vehicle);
STAGE.update();
},
//game listener
tick: function (event) {
if (GAME.LEFT_KEY) {
GAME.vehicle.rotation -= GAME.TURN_FACTOR;
}
if (GAME.RIGHT_KEY) {
GAME.vehicle.rotation += GAME.TURN_FACTOR;
}
if (GAME.UP_KEY) {
GAME.accelarate();
if (GAME.LEFT_KEY) {
GAME.vehicle.rotation -= 5;
}
if (GAME.RIGHT_KEY) {
GAME.vehicle.rotation += 5;
}
}
if (GAME.DOWN_KEY) {
GAME.decelerate();
if (GAME.LEFT_KEY) {
GAME.vehicle.rotation -= 5;
}
if (GAME.RIGHT_KEY) {
GAME.vehicle.rotation += 5;
}
}
STAGE.update(event);
},
handleKeyDown: function (e) {
if (!e) {
var e = window.event;
}
switch (e.keyCode) {
case GAME.KEYCODE_LEFT:
GAME.LEFT_KEY = true;
break;
case GAME.KEYCODE_RIGHT:
GAME.RIGHT_KEY = true;
break;
case GAME.KEYCODE_UP:
e.preventDefault();
GAME.UP_KEY = true;
break;
case GAME.KEYCODE_DOWN:
e.preventDefault();
GAME.DOWN_KEY = true;
break;
}
},
handleKeyUp: function (e) {
if (!e) {
var e = window.event;
}
switch (e.keyCode) {
case GAME.KEYCODE_LEFT:
GAME.LEFT_KEY = false;
break;
case GAME.KEYCODE_RIGHT:
GAME.RIGHT_KEY = false;
break;
case GAME.KEYCODE_UP:
GAME.UP_KEY = false;
break;
case GAME.KEYCODE_DOWN:
GAME.DOWN_KEY = false;
break;
}
},
accelarate: function () {
var angle = GAME.vehicle.rotation;
if (GAME.LEFT_KEY) {
angle -= 5;
}
if (GAME.RIGHT_KEY) {
angle += 5;
}
GAME.map.vX -= Math.cos(angle * Math.PI / 180) * 3;
GAME.map.vY -= Math.sin(angle * Math.PI / 180) * 3;
GAME.map.vX = Math.min(GAME.MAX_VELOCITY, Math.max(-GAME.MAX_VELOCITY, GAME.map.vX));
GAME.map.vY = Math.min(GAME.MAX_VELOCITY, Math.max(-GAME.MAX_VELOCITY, GAME.map.vY));
GAME.map.x += GAME.map.vX;
GAME.map.y += GAME.map.vY;
},
decelerate: function () {
var angle = GAME.vehicle.rotation;
if (GAME.LEFT_KEY) {
angle -= 5;
}
if (GAME.RIGHT_KEY) {
angle += 5;
}
GAME.map.vX += Math.cos(angle * Math.PI / 180) * 3;
GAME.map.vY += Math.sin(angle * Math.PI / 180) * 3;
GAME.map.vX = Math.min(GAME.MAX_VELOCITY, Math.max(-GAME.MAX_VELOCITY, GAME.map.vX));
GAME.map.vY = Math.min(GAME.MAX_VELOCITY, Math.max(-GAME.MAX_VELOCITY, GAME.map.vY));
GAME.map.x += GAME.map.vX;
GAME.map.y += GAME.map.vY;
}
//class end
};
</script>
<!-- javascript -->
</head>
<body>
<div id="page">
<canvas id="game" width="640" height="480"></canvas>
</div>
</body>
</html>
To make a collision detection work for your game you will need to make quite some changes to your project:
Currently you have one big JPG as a map, which is not a good idea, if you try to have objects collide with other objects.
1) If you are willing to split up the big JPG map(probably quickest acceptable solution): You can use one big grey JPG als the floor and place single green Bitmaps on top of that floor. Then you can use the Collision Detection suggested by #WiredPrairie (https://github.com/olsn/Collision-Detection-for-EaselJS) - doing the collision check this way should be about 3-4lines of code (+the work of splitting up your current map.jpg).
2) If you want to keep that JPG as map: I suggest you either create custom rectangles for the green areas and check every frame if the shopping cart is inside such a rectangle. Another option would be to implement a physics library like Box2D (I know, this will take some time to get into Box2D or other libraries, and I'm guessing you are looking for a quick solution, but trust me: It'll be worth it)
As a non-related hint: For projects like yours it's really worth taking a look at Box2D or other physic engines, once you get the hang of how it works, it's really a big help to use a physics library ;-)