Canvas
Basic usage of the HTML canvas element is covered in the Canvas Crossroad post.
Picking colors
Balloons in the night look pretty awesome, although it's generally not advisable to fly them at night. The Balloons are displayed in various random colors, but the basic color has to be dark. The RGB color code describes the intensity of each color component. In order to keep the colors dark, one has to limit the amount of each color intensity to a rather low level. (in this case up to 50 from possible 255).
function getBalloonColor() { var r = randomInt(50).toString(16); var g = randomInt(50).toString(16); var b = randomInt(50).toString(16); r = r.length < 2 ? '0' + r : r; g = g.length < 2 ? '0' + g : g; b = b.length < 2 ? '0' + b : b; return '#' + r + g + b; }
While the balloon changes climbing state it's color has to be darken or lighten by some percentage to simulate the flame. It's done by this function:
function shadeColor(color, percent) { var num = parseInt(color.slice(1),16), amt = Math.round(2.55 * percent), R = (num >> 16) + amt, B = (num >> 8 & 0x00FF) + amt, G = (num & 0x0000FF) + amt; return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (B < 255 ? B < 1 ? 0 : B : 255) * 0x100 + (G < 255 ? G < 1 ? 0 : G : 255)).toString(16).slice(1); }
The color of a climbing balloon should be darker further away from the flame. So a gradient is used. The HTML canvas gradient works only within a predefined range on a canvas. The example bellow shows a linear gradient from the top to the bottom of a balloon. Notice that the horizontal component is set to 0 (this is a vertical linear gradient):
var linGrad = ctx.createLinearGradient(0, this.y, 0, this.y + this.height); linGrad.addColorStop(0, ballonColor); linGrad.addColorStop(1, shadeColor(ballonColor, ballonFlameLighter)); ballonColor = linGrad;
Balloon shape
The balloon shape is drawn with
- half circle
- triangle
- flame - small circle
- basket - small rectangle
// top balloon circle ctx.beginPath(); ctx.arc(this.x + this.width / 2, this.y + this.radius, this.radius, Math.PI, 0, false); ctx.fill(); // triangle ctx.beginPath(); ctx.moveTo(this.x, this.y + this.radius - 1); ctx.lineTo(this.x + this.width / 2, this.y + this.height - this.boxHeight); ctx.lineTo(this.x + this.width / 2 + 1, this.y + this.height - this.boxHeight); ctx.lineTo(this.x + this.width, this.y + this.radius - 1); ctx.lineTo(this.x, this.y + this.radius - 1); ctx.fill(); // flame if (this.climbing) { ctx.fillStyle = canvasBackground; ctx.beginPath(); ctx.arc(this.x + this.width / 2, this.y + this.height - this.boxHeight, flameSize, 0, 2 * Math.PI, true); ctx.fill(); } // basket ctx.fillStyle = gondolaColor; ctx.fillRect( this.x + this.width / 4 + this.width / 8, this.y + this.height - this.boxHeight, this.width / 4, this.boxHeight );
Collision detection
The collision detection between two balloons is bounding rectangles based. Before every balloon movement there is a collision check to the current positions of the other balloons. To detect collision between two rectangles I've used the following function:
function checkCollision(obj1, obj2) { return !( (obj1.y + obj1.height < obj2.y) || (obj1.y > obj2.y + obj2.height) || (obj1.x > obj2.x + obj2.width) || (obj1.x + obj1.width < obj2.x) ); }
Detecting keyboard keyes
In order to make the simulation interactive the parameters can be controlled with the keyboard keys. The key detection in JavaScript is pretty straight forward:
document.onkeydown = function(e) { if(e.keyCode == 37) { // left } else if(e.keyCode == 39) { // right } else if(e.keyCode == 38) { // up } else if(e.keyCode == 40) { // down } else if (e.keyCode == 13) { // enter key } return false; };
And here's my example on:
Codepen
GitHub