diff --git a/src/body/Body.js b/src/body/Body.js index a8a8f2b..94997eb 100644 --- a/src/body/Body.js +++ b/src/body/Body.js @@ -38,11 +38,14 @@ var Body = {}; restitution: 0, friction: 0.1, frictionAir: 0.01, - path: 'L 0 0 L 40 0 L 40 40 L 0 40', - fillStyle: options.isStatic ? '#eeeeee' : Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']), - lineWidth: 1.5, groupId: 0, - slop: 0.05 + slop: 0.05, + render: { + visible: true, + sprite: null, + path: 'L 0 0 L 40 0 L 40 40 L 0 40', + lineWidth: 1.5 + } }; var body = Common.extend(defaults, options); @@ -77,7 +80,7 @@ var Body = {}; */ Body.updateProperties = function(body) { // calculated properties - body.vertices = body.vertices || Vertices.fromPath(body.path); + body.vertices = body.vertices || Vertices.fromPath(body.render.path); body.axes = body.axes || Axes.fromVertices(body.vertices); body.area = Vertices.area(body.vertices); body.bounds = Bounds.create(body.vertices); @@ -87,7 +90,8 @@ var Body = {}; body.inverseInertia = 1 / body.inertia; body.positionPrev = body.positionPrev || { x: body.position.x, y: body.position.y }; body.anglePrev = body.anglePrev || body.angle; - body.strokeStyle = body.strokeStyle || Common.shadeColor(body.fillStyle, -20); + body.render.fillStyle = body.render.fillStyle || (body.isStatic ? '#eeeeee' : Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58'])); + body.render.strokeStyle = body.render.strokeStyle || Common.shadeColor(body.render.fillStyle, -20); // update geometry Vertices.create(body.vertices, body); @@ -103,7 +107,7 @@ var Body = {}; body.friction = 1; body.mass = body.inertia = body.density = Infinity; body.inverseMass = body.inverseInertia = 0; - body.lineWidth = 1; + body.render.lineWidth = 1; } Sleeping.set(body, body.isSleeping); diff --git a/src/factory/Bodies.js b/src/factory/Bodies.js index 786ef89..46bbd61 100644 --- a/src/factory/Bodies.js +++ b/src/factory/Bodies.js @@ -25,9 +25,11 @@ var Bodies = {}; options = options || {}; var rectangle = { - position: { x: x, y: y }, + position: { x: x, y: y }, + render: { path: 'L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height - }; + } + }; return Body.create(Common.extend({}, rectangle, options)); }; @@ -54,9 +56,11 @@ var Bodies = {}; x3 = x2 + x1; var trapezoid = { - position: { x: x, y: y }, + position: { x: x, y: y }, + render: { path: 'L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0' - }; + } + }; return Body.create(Common.extend({}, trapezoid, options)); }; @@ -118,9 +122,11 @@ var Bodies = {}; } var polygon = { - position: { x: x, y: y }, + position: { x: x, y: y }, + render: { path: path - }; + } + }; return Body.create(Common.extend({}, polygon, options)); }; diff --git a/src/render/Render.js b/src/render/Render.js index 63d09a9..84f9aac 100644 --- a/src/render/Render.js +++ b/src/render/Render.js @@ -47,9 +47,25 @@ var Render = {}; render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height); render.context = render.canvas.getContext('2d'); + Render.setBackground(render, render.options.background); + return render; }; + /** + * Sets the background CSS property of the canvas + * @method setBackground + * @param {render} render + * @param {string} background + */ + Render.setBackground = function(render, background) { + if (render.currentBackground !== background) { + render.canvas.style.background = background; + render.canvas.style.backgroundSize = "contain"; + render.currentBackground = background; + } + }; + /** * Description * @method world @@ -64,12 +80,16 @@ var Render = {}; i; if (options.wireframes) { - context.fillStyle = options.wireframeBackground; + Render.setBackground(render, options.wireframeBackground); } else { - context.fillStyle = options.background; + Render.setBackground(render, options.background); } - + + // clear the canvas with a transparent fill, to allow the canvas background to show + context.globalCompositeOperation = 'source-in'; + context.fillStyle = "transparent"; context.fillRect(0, 0, canvas.width, canvas.height); + context.globalCompositeOperation = 'source-over'; if (options.showShadows && !options.wireframes) for (i = 0; i < world.bodies.length; i++) @@ -242,34 +262,49 @@ var Render = {}; c.stroke(); } - // body polygon - if (body.circleRadius) { - c.beginPath(); - c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI); - c.closePath(); - } else { - c.beginPath(); - c.moveTo(body.vertices[0].x, body.vertices[0].y); - for (var j = 1; j < body.vertices.length; j++) { - c.lineTo(body.vertices[j].x, body.vertices[j].y); - } - c.closePath(); - } + // draw body + if (body.render.visible) { + if (body.render.sprite && !options.wireframes) { + // body sprite + var sprite = body.render.sprite; + c.save(); + c.webkitImageSmoothingEnabled = true; + c.translate(body.position.x, body.position.y); + c.rotate(body.angle); + c.drawImage(sprite.image, sprite.width * -0.5 * sprite.xScale, sprite.height * -0.5 * sprite.yScale, + sprite.width * sprite.xScale, sprite.height * sprite.yScale); + c.restore(); + } else { + // body polygon + if (body.circleRadius) { + c.beginPath(); + c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI); + c.closePath(); + } else { + c.beginPath(); + c.moveTo(body.vertices[0].x, body.vertices[0].y); + for (var j = 1; j < body.vertices.length; j++) { + c.lineTo(body.vertices[j].x, body.vertices[j].y); + } + c.closePath(); + } - if (!options.wireframes) { - c.fillStyle = body.fillStyle; - if (options.showSleeping && body.isSleeping) - c.fillStyle = Common.shadeColor(body.fillStyle, 50); - c.lineWidth = body.lineWidth; - c.strokeStyle = body.strokeStyle; - c.fill(); - c.stroke(); - } else { - c.lineWidth = 1; - c.strokeStyle = '#bbb'; - if (options.showSleeping && body.isSleeping) - c.strokeStyle = 'rgba(255,255,255,0.2)'; - c.stroke(); + if (!options.wireframes) { + c.fillStyle = body.render.fillStyle; + if (options.showSleeping && body.isSleeping) + c.fillStyle = Common.shadeColor(body.render.fillStyle, 50); + c.lineWidth = body.render.lineWidth; + c.strokeStyle = body.render.strokeStyle; + c.fill(); + c.stroke(); + } else { + c.lineWidth = 1; + c.strokeStyle = '#bbb'; + if (options.showSleeping && body.isSleeping) + c.strokeStyle = 'rgba(255,255,255,0.2)'; + c.stroke(); + } + } } // angle indicator @@ -282,7 +317,7 @@ var Render = {}; if (options.wireframes) { c.strokeStyle = 'indianred'; } else { - c.strokeStyle = body.strokeStyle; + c.strokeStyle = body.render.strokeStyle; } c.stroke(); } @@ -298,7 +333,7 @@ var Render = {}; if (options.wireframes) { c.strokeStyle = 'indianred'; } else { - c.strokeStyle = body.strokeStyle; + c.strokeStyle = body.render.strokeStyle; } c.stroke(); }