UNPKG

p2s

Version:

A JavaScript 2D physics engine.

327 lines (279 loc) 8.9 kB
<!DOCTYPE html> <html lang="en"> <head> <title>p2.js Canvas raycast example</title> <meta charset="utf-8"> <script src="../../build/p2.js"></script> </head> <body> <p> <span style="color:red">Any</span> <span style="color:green">All</span> <span style="color:blue">Closest</span> </p> <!-- The canvas, where we draw stuff --> <canvas width="600" height="400" id="myCanvas"></canvas> <script> var canvas, ctx, w, h, world, boxBody, planeBody; var scaleX = 50, scaleY = -50; var start = [0,0]; var end = [0,0]; var result = new p2.RaycastResult(); var hitPoint = p2.vec2.create(); var rayClosest = new p2.Ray({ mode: p2.Ray.CLOSEST }); var rayAll = new p2.Ray({ mode: p2.Ray.ALL, callback: function(result){ drawRayResult(result, rayAll); } }); var rayAny = new p2.Ray({ mode: p2.Ray.ANY }); var raycastOptions = {}; init(); requestAnimationFrame(animate); function init(){ // Init canvas canvas = document.getElementById("myCanvas"); w = canvas.width; h = canvas.height; ctx = canvas.getContext("2d"); ctx.lineWidth = 0.02; ctx.fillStyle = 'white'; // Init p2.js world = new p2.World({ gravity: [0, 0] }); // Add a box boxShape = new p2.Box({ width: 2, height: 1 }); boxBody = new p2.Body({ mass:1, position:[0,2], angularVelocity:1, angularDamping: 0 }); boxBody.addShape(boxShape); world.addBody(boxBody); // Add a circle circleShape = new p2.Circle({ radius: 0.5 }); circleBody = new p2.Body({ mass:1, position:[0,-1], angularVelocity:1 }); circleBody.addShape(circleShape); world.addBody(circleBody); // Add a capsule capsuleShape = new p2.Capsule({ length: 1, radius: 0.5 }); capsuleBody = new p2.Body({ mass:1, position:[-1.5,0], angularVelocity:1, angularDamping: 0 }); capsuleBody.addShape(capsuleShape); world.addBody(capsuleBody); // Add a plane planeShape = new p2.Plane(); planeBody = new p2.Body({ position: [3,0], angle: Math.PI / 3 }); planeBody.addShape(planeShape); world.addBody(planeBody); // Add a convex var vertices = []; var size = 1; for(var i=0, N=5; i<N; i++){ var a = 2*Math.PI / N * i; var vertex = [size*0.5*Math.cos(a), size*0.5*Math.sin(a)]; // Note: vertices are added counter-clockwise vertices.push(vertex); } convexShape = new p2.Convex({ vertices: vertices }); convexBody = new p2.Body({ mass: 1, position: [1,0], angle: Math.PI / 3, angularVelocity: 1 }); convexBody.addShape(convexShape); world.addBody(convexBody); } function drawbox(){ ctx.beginPath(); var x = boxBody.interpolatedPosition[0], y = boxBody.interpolatedPosition[1]; ctx.save(); ctx.translate(x, y); // Translate to the center of the box ctx.rotate(boxBody.interpolatedAngle); // Rotate to the box body frame ctx.rect(-boxShape.width/2, -boxShape.height/2, boxShape.width, boxShape.height); ctx.stroke(); ctx.restore(); } function drawPlane(){ ctx.beginPath(); var x = planeBody.interpolatedPosition[0], y = planeBody.interpolatedPosition[1]; ctx.save(); ctx.translate(x, y); ctx.rotate(planeBody.interpolatedAngle); ctx.moveTo(-100, 0); ctx.lineTo(100, 0); ctx.stroke(); ctx.restore(); } function drawCircle(){ ctx.beginPath(); var x = circleBody.interpolatedPosition[0], y = circleBody.interpolatedPosition[1]; ctx.save(); ctx.translate(x, y); ctx.rotate(circleBody.interpolatedAngle); ctx.arc(0,0,circleShape.radius,0,2*Math.PI); ctx.stroke(); ctx.restore(); } function drawConvex(){ ctx.beginPath(); var x = convexBody.interpolatedPosition[0], y = convexBody.interpolatedPosition[1]; ctx.save(); ctx.translate(x, y); ctx.rotate(convexBody.interpolatedAngle); ctx.moveTo(convexShape.vertices[0][0], convexShape.vertices[0][1]); for (var i = 1; i < convexShape.vertices.length+1; i++) { ctx.lineTo(convexShape.vertices[i%convexShape.vertices.length][0], convexShape.vertices[i%convexShape.vertices.length][1]); } ctx.stroke(); ctx.restore(); } function drawCapsule(){ var x = capsuleBody.interpolatedPosition[0], y = capsuleBody.interpolatedPosition[1]; ctx.save(); ctx.translate(x, y); ctx.rotate(capsuleBody.interpolatedAngle); var radius = capsuleShape.radius; var len = capsuleShape.length; // Draw circles at ends ctx.beginPath(); var c = Math.cos(capsuleBody.interpolatedAngle); var s = Math.sin(capsuleBody.interpolatedAngle); ctx.arc(-len/2, 0, capsuleShape.radius, 0, 2*Math.PI); ctx.arc( len/2, 0, capsuleShape.radius, -Math.PI, Math.PI); ctx.fill(); ctx.stroke(); // Draw rectangle ctx.beginPath(); ctx.moveTo(-len/2, -radius); ctx.lineTo( len/2, -radius); ctx.lineTo( len/2, radius); ctx.lineTo(-len/2, radius); ctx.fill(); // Draw lines in between ctx.beginPath(); ctx.moveTo(-len/2, -radius); ctx.lineTo( len/2, -radius); ctx.stroke(); ctx.beginPath(); ctx.lineTo( len/2, radius); ctx.lineTo(-len/2, radius); ctx.stroke(); ctx.restore(); } function drawRayResult(result, ray){ result.getHitPoint(hitPoint, ray); // Draw hit point if(result.hasHit()){ ctx.beginPath(); ctx.arc(hitPoint[0],hitPoint[1],0.1,0,2*Math.PI); ctx.stroke(); } // Draw hit normal ctx.beginPath(); ctx.moveTo(hitPoint[0], hitPoint[1]); ctx.lineTo( hitPoint[0] + result.normal[0], hitPoint[1] + result.normal[1] ); ctx.stroke(); }; function drawRay(start, end){ // Draw line ctx.beginPath(); ctx.moveTo(start[0], start[1]); ctx.lineTo(end[0], end[1]); ctx.stroke(); } function drawRays(time){ start[0] = -3; start[1] = Math.sin(time / 1000) * 4; end[0] = 5; end[1] = Math.sin(time / 1000); // Closest p2.vec2.copy(rayClosest.from, start); p2.vec2.copy(rayClosest.to, end); rayClosest.update(); ctx.strokeStyle = 'blue'; drawRay(start, end); result.reset(); world.raycast(result, rayClosest); drawRayResult(result, rayClosest); start[1] += 0.5; end[1] += 0.5; // All p2.vec2.copy(rayAll.from, start); p2.vec2.copy(rayAll.to, end); rayAll.update(); ctx.strokeStyle = 'green'; drawRay(start, end); result.reset(); world.raycast(result, rayAll); // drawRayResult start[1] += 0.5; end[1] += 0.5; // Any p2.vec2.copy(rayAny.from, start); p2.vec2.copy(rayAny.to, end); rayAny.update(); ctx.strokeStyle = 'red'; drawRay(start, end); result.reset(); world.raycast(result, rayAny); drawRayResult(result, rayAny); ctx.strokeStyle = 'black'; } function render(time){ // Clear the canvas ctx.clearRect(0,0,w,h); // Transform the canvas ctx.save(); ctx.translate(w/2, h/2); // Translate to the center ctx.scale(scaleX, scaleY); // Draw all bodies drawbox(); drawPlane(); drawCircle(); drawCapsule(); drawConvex(); drawRays(time); // Restore transform ctx.restore(); } var lastTime, timeStep = 1 / 60, maxSubSteps = 5; // Animation loop function animate(time){ requestAnimationFrame(animate); var dt = lastTime ? (time - lastTime) / 1000 : 0; dt = Math.min(1 / 10, dt); lastTime = time; // Move physics bodies forward in time world.step(timeStep, dt, maxSubSteps); // Render scene render(time); } </script> </body> </html>