RayCast——光线投射
演示
Any All Closest
源代码
window.onload = function () { 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(){ // 初始化画布 canvas = document.getElementById("renderCanvas"); w = canvas.width; h = canvas.height; ctx = canvas.getContext("2d"); ctx.lineWidth = 0.02; ctx.fillStyle = 'white'; // 初始化物理引擎 world = new p2.World({ gravity: [0, 0] }); // 添加一个盒子 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); // 添加一个圆 circleShape = new p2.Circle({ radius: 0.5 }); circleBody = new p2.Body({ mass:1, position:[0,-1], angularVelocity:1 }); circleBody.addShape(circleShape); world.addBody(circleBody); // 添加一个胶囊 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); // 添加一个平面 planeShape = new p2.Plane(); planeBody = new p2.Body({ position: [3,0], angle: Math.PI / 3 }); planeBody.addShape(planeShape); world.addBody(planeBody); // 添加一个五边形 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)]; // 注意:顶点要以逆时针顺序进行定义 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); ctx.rotate(boxBody.interpolatedAngle); 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; // 绘制胶囊两侧的圆 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(); // 绘制胶囊中部的矩形 ctx.beginPath(); ctx.moveTo(-len/2, -radius); ctx.lineTo( len/2, -radius); ctx.lineTo( len/2, radius); ctx.lineTo(-len/2, radius); ctx.fill(); // 绘制连线 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); // 绘制碰撞点 if(result.hasHit()){ ctx.beginPath(); ctx.arc(hitPoint[0],hitPoint[1],0.1,0,2*Math.PI); ctx.stroke(); } // 绘制碰撞法线 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){ // 绘制射线 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 / 2000) * 4; end[0] = 5; end[1] = Math.sin(time / 2000); // 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){ // 清除画布 ctx.clearRect(0,0,w,h); // 将画布放大,中心移至画布中央 ctx.save(); ctx.translate(w/2, h/2); ctx.scale(scaleX, scaleY); // 绘制所有形状 drawbox(); drawPlane(); drawCircle(); drawCapsule(); drawConvex(); drawRays(time); ctx.restore(); } var lastTime, timeStep = 1 / 60, maxSubSteps = 5; // 动画循环 function animate(time) { requestAnimationFrame(animate); var dt = lastTime ? (time - lastTime) / 1000 : 0; dt = Math.min(1 / 10, dt); lastTime = time; // 进行物理模拟 world.step(timeStep, dt, maxSubSteps); // 绘制场景 render(time); } }
发布时间:2017/1/2 下午10:18:42 阅读次数:4885