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 阅读次数:5529
