拍球
点击小球使之不落地
源代码
window.onload = function () { // 全局变量 var canvas, ctx, w, h, zoom, world, ballBody, bottomPlaneBody; var ballRadius = 1, gameWidth = 6, gameHeight = 8; // 初始化并开始渲染 init(); resetGame(); requestAnimationFrame(animate); // 初始化画布、物理引擎和鼠标事件 function init() { // 初始化画布 canvas = document.getElementById("renderCanvas"); w = canvas.width; h = canvas.height; ctx = canvas.getContext("2d"); ctx.lineWidth = 0.05; ctx.fillStyle = "white"; // 初始化物理引擎 world = new p2.World(); // 使物理世界的摩擦为零、恢复系数为0.5(表现为反弹时的弹性大小) world.defaultContactMaterial.friction = 0; world.defaultContactMaterial.restitution = 0.5; // 创建一个body对象,用于要控制的球 ballBody = new p2.Body({ mass: 1, position: [0, -2] }); ballBody.addShape(new p2.Circle({ radius: ballRadius })); world.addBody(ballBody); // 在四周添加墙 bottomPlaneBody = createPlane([0, -gameHeight / 2], 0); // 底部 createPlane([0, gameHeight / 2 + ballRadius * 2], Math.PI); // 顶部 createPlane([-gameWidth / 2, 0], -Math.PI / 2); // 左边 createPlane([gameWidth / 2, 0], Math.PI / 2); // 右边 // 如果球碰到底部地板,则游戏失败 world.on('beginContact', function (evt) { if ((evt.bodyA === ballBody && evt.bodyB === bottomPlaneBody) || evt.bodyA === bottomPlaneBody && evt.bodyB === ballBody) { resetGame(); } }); // 对画布进行变换操作 // 因为画布的像素坐标系统的y轴向下,但物理系统的y轴向上,所以需要翻转画布的y方向 ctx.save(); ctx.translate(w / 2, h / 2); // 将画布原点移动到画布中央(默认在左上角) zoom = w < h ? w / gameWidth : h / gameHeight; ctx.scale(zoom, -zoom); // 对画布进行缩放并反转y轴 // 监听鼠标事件 canvas.addEventListener('mousedown', onKeyDown); canvas.addEventListener('touchstart', onKeyDown); } var inputType; function onKeyDown(event) { if (inputType && event.type !== inputType) { return; } inputType = event.type; // 将画布坐标转换为物理系统坐标 var position = getPhysicsCoord(event); // 检测鼠标是否点击到小球 var didHitBall = world.hitTest(position, [ballBody]).length !== 0; if (didHitBall) { var count = world.gravity[1] === 0 ? 0 : parseInt(counter.innerHTML) + 1; counter.innerHTML = count; // 如果点击到小球,则对小球施加一个冲量 var applyPoint = [0, 0]; var dx = ballBody.position[0] - position[0]; var dy = 2; var len = Math.sqrt(dx * dx + dy * dy); var impulseSize = 15 + count / 3; var impulse = [ dx / len * impulseSize, dy / len * impulseSize ]; ballBody.applyImpulse(impulse, applyPoint); // 增加重力加速度,从而可以增加难度 world.gravity[1] = -10 - count; } } // 重置游戏:将重力加速度设置为零,并重新将小球放置到屏幕中央 function resetGame() { world.gravity[0] = world.gravity[1] = 0; ballBody.position[0] = 0; ballBody.position[1] = -2; ballBody.velocity[0] = ballBody.velocity[1] = 0; } // 将画布坐标转换为物理系统坐标 function getPhysicsCoord(mouseEvent) { var rect = canvas.getBoundingClientRect(); var clientX = mouseEvent.touches ? mouseEvent.touches[0].clientX : mouseEvent.clientX; var clientY = mouseEvent.touches ? mouseEvent.touches[0].clientY : mouseEvent.clientY; var x = (clientX - rect.left) * window.devicePixelRatio; var y = (clientY - rect.top) * window.devicePixelRatio; x = (x - w / 2) / zoom; y = -(y - h / 2) / zoom; return [x, y]; } // 在指定位置创建墙壁 function createPlane(position, angle) { var planeBody = new p2.Body({ position: position, angle: angle }); planeBody.addShape(new p2.Plane()); world.addBody(planeBody); return planeBody; } // 动画循环 var lastTime; var maxSubSteps = 5; var fixedDeltaTime = 1 / 30; function animate(time) { requestAnimationFrame(animate); // 获取一帧所需的时间 var deltaTime = lastTime ? (time - lastTime) / 1000 : 0; // 确保一帧的时间不致太大(如果用户切换浏览器标签便会发生这种情况) deltaTime = Math.min(1 / 10, deltaTime); // 进行物理模拟 world.step(fixedDeltaTime, deltaTime, maxSubSteps); lastTime = time; // 绘制场景 render(); } function render() { // 清除画布 ctx.fillRect( -gameWidth, -gameHeight, gameWidth * 2, gameHeight * 2 ); // 绘制小球 ctx.beginPath(); ctx.arc( ballBody.interpolatedPosition[0], ballBody.interpolatedPosition[1], ballRadius, 0, 2 * Math.PI ); ctx.fill(); ctx.stroke(); // 绘制周围墙壁 ctx.beginPath(); ctx.moveTo(-gameWidth / 2, -gameHeight / 2); ctx.lineTo(gameWidth / 2, -gameHeight / 2); ctx.lineTo(gameWidth / 2, gameHeight / 2); ctx.lineTo(-gameWidth / 2, gameHeight / 2); ctx.lineTo(-gameWidth / 2, -gameHeight / 2); ctx.stroke(); } }
发布时间:2017/1/1 下午9:56:59 阅读次数:4646