2013-08-11

Canvas Disco Rain

Intro

Another post in the "canvas drawing series". You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains
  5. Canvas, circular motions and networks
  6. Canvas Wipers
  7. DIY Canvas Fountain
  8. Canvas Random Spherical Effects
  9. Canvas Ant Colony Optimization
  10. Canvas Space Battle
  11. Canvas Simple Game

Canvas Disco Rain

The idea behind it is pretty random. I saw a couple of demos about rain falling and stars moving in the space and thought ... why not make it a bit more "funky" :) Every drop is glowing while falling and there is an option to show all drops in the same color or display them random.

Flash math

The flash is modeled with a help of a logarithmic function. The flash starts at it's maximum size and then decays reaching 0. When the flash reaches 0 it starts to glow again. To add a bit more noise to example it expands to a random width. There is also a Flash Factor so that we can influence the general length of a burst.

 this.r = flashfactor * (Math.log(this.r) / Math.LN10);

 if (this.r <= 0) {
  this.r = randomMax(radiusmax);
 }

Flash looks

Every flash is brightest at it's middle and then darker the further away from the center. To achieve this effect a gradient is used:

 ctx.beginPath();

 var fillStyle = ctx.createRadialGradient(
  this.x,
  this.y, 
  this.r * 0.2, 
  this.x, 
  this.y, 
  this.r
 );
 
 fillStyle.addColorStop(0, this.color);
 fillStyle.addColorStop(1, particleBackground);

 ctx.fillStyle = fillStyle;
 ctx.beginPath();
 ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
 ctx.fill();

The light properties of flash emitting body, human eye or camera lens cause us to perceive the flashes with a cross centered in the middle of the flash. This animation rotates this angle to add a bit more randomness to the example (it looks nicer). The cross drawing code looks like this:

 ctx.strokeStyle = this.color;
 
 ctx.beginPath();
 ctx.moveTo(
  this.x - Math.cos(this.angle) * this.r,
  this.y - Math.sin(this.angle) * this.r
 );
 ctx.lineTo(
  this.x + Math.cos(this.angle) * this.r,
  this.y + Math.sin(this.angle) * this.r
 );
 ctx.stroke();

 ctx.beginPath();
 ctx.moveTo(
  this.x - Math.cos(this.angle + Math.PI / 2) * this.r,
  this.y - Math.sin(this.angle + Math.PI / 2) * this.r
 );
 ctx.lineTo(
  this.x + Math.cos(this.angle + Math.PI / 2) * this.r,
  this.y + Math.sin(this.angle + Math.PI / 2) * this.r
 );
 ctx.stroke();

We use gradients, but the flash is in the end just a circle shrinking. That causes one flashes light to "cover" the light of the other flash and we all know this is not happening in the real world. To compensate for that we use the globalCompositeOperation on the 2d canvas context. Explaining this is a bit out of the scope of this post, put there is a very nice code pen explaining that made by aptary. Disco rain uses 'lighter' mode:

 ctx.globalCompositeOperation = 'lighter';

And here's my example on:
CSSDeck
Codepen

Canvas Simple Game

Intro

Another post in the "canvas drawing series". You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains
  5. Canvas, circular motions and networks
  6. Canvas Wipers
  7. DIY Canvas Fountain
  8. Canvas Random Spherical Effects
  9. Canvas Ant Colony Optimization
  10. Canvas Space Battle

Canvas Simple Game

I hope I'll develop some kind of "serious" game in the future, but as always the first steps are pretty modest. The Canvas Simple Game is sort of a testing playground for a Shoot 'Em Up Game type. Also, @loktar00 had an idea about growing this example to "online shmup creator". Most of the techniques used in this example are described in the previous posts. So I won't cover the basics as much. The stuff I researched the most for this example is javascript keyboard event handling. So I'll concentrate on that.

Keyboard events javascript style

Since the games usually require more of the keys pressed at the same time I've developed a simple example. Every key has it's state stored in an associative array. The keydown and keyup events can have multiple keys pressed at once, so on every key up or down the key state is changed:

  var activeKeys = [];

  function setKeysTo(e, state) {

   if(e.keyCode == 37) {
     activeKeys['left'] = state;
   } else if(e.keyCode == 39) {
     activeKeys['right'] = state;
   }  else if(e.keyCode == 38) {
     activeKeys['up'] = state;
   } else if(e.keyCode == 40) {
     activeKeys['down'] = state;
   } else if (e.keyCode == 32) {
     activeKeys['shoot'] = state;
   }

   return false;
  }

  document.onkeydown = function(e) {
   return setKeysTo(e, true);
  };

  document.onkeyup = function(e) {
   return setKeysTo(e, false);
  };

Now the application logic can check for key combinations and update stuff in the animation loop. The displayed code might be a bit redundant but it's down to the point. Perhaps this blog entry name could be javascript multiple key events handling :)

And here's my example on:
Codepen

CSS Windmill

CSS Windmill

I always wanted to make a pen with pure css and I always wanted to make a pen about windmills. So, I've created the CSS windmill.

Animation parts

I'll just show HAML code used to crate the animation:

 #windmill
  .post
  .engine
  .flaps
   .flap
   .flap
   .flap
  .head
  .bulb
 

Flaps

Flaps is a big div containing the flaps. It moves around with this simple animation (I just love css animations):

 @keyframes "rotatemill" {
  0% {
     transform:rotate(0deg);
  }
  100% {
     transform:rotate(-360deg);
  }
 }

Rounding flap tops

This is so much easier with the css (just one line of code and so much magic):

 border-top-left-radius: 5px 20px;

Light

The light on top is an ordinary circle. To keep it simple, I've put it in the back so that it looks like a half circle :) and all the magic is contained in this animation:

 @keyframes "lightbulblight" {
  0% {
     background: $bulbcolor;
     box-shadow: 0 0 0 $bulbcolor;
  }
  50% {
     background: lighten($bulbcolor, 60%);
     box-shadow: 0 0 $bulbLight lighten($bulbcolor, 60%);
  }
 }

And here's my example on:
Codepen

Canvas Space Battle

Intro

Another post in the "canvas drawing series". You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains
  5. Canvas, circular motions and networks
  6. Canvas Wipers
  7. DIY Canvas Fountain
  8. Canvas Random Spherical Effects
  9. Canvas Ant Colony Optimization

Canvas Space Battle

I always liked watching Star Trek. The thing I love the most are space battle scenes. Especially the ones that are on the epic scales :)

Ship types

The battle is between the Cardassian, the United Federation of Planets and the Romulans. Every race has it's own ship property, for instance:

 shipTypes.push({
  color : '#CAD8DB',
  warpTrailColor : 'rgba(141, 189, 240, 0.5)',
  trailLife : 30,
  impulseSpeedMax : 3,
  newDirectionCycle : 40,
  warpCycleMin : 350,
  warpCycleVar : 900,
  range : 33,
  fireColor : 'rgba(237, 209, 133, 0.8)',
  fireRecharge : 40,
  fireDischarge : 10
 });

Why Warp trails?

The tactical warp jumps are inspired by the following wiki:

In 2355, the Stargazer was seriously damaged in a battle with an unknown enemy vessel, later discovered to be a Ferengi ship. Picard managed to destroy the enemy vessel using the Stargazer's warp engines in a unique tactical maneuver (later named the "Picard Maneuver").

Ship movement

Ship movement is based upon a counter, every time the counter drops to zero the ship selects new direction to move to and resets the counter. There is a second counter (with substantially greater value) that's in charge for the warp jump. Upon jumping to warp the ship moves to random new coordinates and leaves a warp trail.

Warp trails

Warp trails are stored in linked list because storing them in arrays would perhaps be to operation heavy especially if the number of the ships would increase or the warp jumping interval would shorten for a certain race. The other advantage is that every trail can remove itself from the animation loop upon its end of life.

Phaser fire

Phaser firing is determined by counters. There is impulse duration counter and time between phaser pulse counter. It's race specific and configurable. When shooting there is small random offset so that if the other ship is shooting back the trail is still visible.

And here's my example on:
Codepen

Canvas Ant Colony Optimization

Intro

Another post in the "canvas drawing series". You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains
  5. Canvas, circular motions and networks
  6. Canvas Wipers
  7. DIY Canvas Fountain
  8. Canvas Random Spherical Effects

Canvas Ant Colony Optimization

The inspiration for this animation came from a youtube video. In short, the ants explore various paths and leave pheromone trails. Over time the most efficient trails have the greatest amount of pheromones and the ants tend to follow that paths.

Graph creation

I've spent most of the development time for this example on the graph creation part. I wanted to create an algorithm that would turn an imaginary table into graph. Every joint has to have at least one exit point and no connections should cross over. Also, the connections are formed just between the neighbouring imaginary columns. In the development process I've found two variations of connection knitting. To keep the post as short as possible, I'll just show the upper knitting:

 var minPossible = 0;

 for (i = 0; i < jointsBefore.length; i++) {

  selection = randomInInterval(minPossible, possibleNodes.length - 1);

  if (selection > minPossible) {
   minPossible = selection;
  }

  jointsBefore[i].connections[0] = possibleNodes[selection];
  newConnectedNodes[selection] = true;

  selection = randomInInterval(minPossible, possibleNodes.length - 1);

  if (selection > minPossible) {
   minPossible = selection;
  }

  if (jointsBefore[i].connections[0].id !== selection) {
   jointsBefore[i].connections[1] = possibleNodes[selection];
   newConnectedNodes[selection] = true;
  }
 }

Ant path selection

Upon every node selection we're checking if the ant is exploring (going to path with lesser pheromones level) or taking the more visited path. And that's all:

 var selectedNode;

 if (joint.connections.length > 1) {

  if (Math.random() > globals.explorationProbability) {
   selectedNode = joint.selections[0] >= joint.selections[1] ? 0 : 1;
  } else {
   this.exploring = true;
   selectedNode = joint.selections[0] <= joint.selections[1] ? 0 : 1;
  }
  
 } else {
  selectedNode = 0;
 }

 this.destination = joint.connections[selectedNode];
 joint.selections[selectedNode]++;
 this.orientToPoint(this.destination);

And here's my example on:
Codepen

Canvas Random Spherical Effects

Intro

Another post in the "canvas drawing series". You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains
  5. Canvas, circular motions and networks
  6. Canvas Wipers
  7. DIY Canvas Fountain

Canvas Random Spherical effects

The main motivation for this was making demo with particles that leave trails. To move the particles around a simple sphere equation is used. An important part of this demo is "dat.gui".

Leaving particle trails

There are several techniques for the particles to leave trails. I won't go into them now but one of the simplest is using transparent rectangles to clear the canvas in the animation loop. The transparent rectangle has a color of the desired background. The more the clearing rectangle is transparent the longer particles trails are. Just two lines of code in the animation loop do all the magic (usually it's a very small number and one has to experiment with it):

 var trailLength = 0.08;
 (function animloop(){
  requestAnimFrame(animloop);
  ctx.fillStyle = 'rgba(1, 1, 1, ' + trailLength + ')';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

Sphere math

To make the things as simple as possible the particles are moved around with the help of angle coordinates. The drawing of particles is from then on just a couple of equations:

 this.xangle += angleSpeedx;
 this.yangle += angleSpeedy;
 // size factor is responsible for 3d effect
 var sizeFactor = (0.5 + (Math.cos(this.xangle) + 1) / 2);
 ctx.arc(
  centerx +
    ~~((Math.sin(this.xangle) * Math.cos(this.yangle)) * sphereRadius),
  centery +
    ~~((Math.sin(this.xangle) * Math.sin(this.yangle)) * sphereRadius),
  particleSize * sizeFactor, 
  0,
  Math.PI * 2
 );

And here's my example on:
Codepen

DIY Canvas Fountain

Intro

Another post in the "canvas drawing series". You can look up the basics of drawing etc. in the previous posts:

  1. Canvas Crossroad
  2. Canvas Balloons
  3. Canvas Bus
  4. Canvas Trains
  5. Canvas, circular motions and networks
  6. Canvas Wipers

DIY Canvas Fountain

Particle fountains are very common inspiration for the graphical demos. To be honest I didn't feel I had much to contribute to this area. Then It came to me that perhaps it would be a nice demo to build an interface that would enable the users to construct their very own fountain. An important part of this demo is "dat.gui".

Mouse events

Handling the mouse events is the backbone of this demo. Two basic events are mousedown and mousemove. First, we have to register our functions to the events:

 canvas.addEventListener.apply(canvas, ['mousedown', mouseClick, false]);
 canvas.addEventListener.apply(canvas, ['mousemove', mouseMove, false]);

Mouse coordinates

As a parameter to the above registered function an event is passed. The event has coordinates clientX and clientY, but the coordinates are not corresponding to the coordinates on the canvas, so there is a short pattern that we have to apply to convert event coordinates to canvas coordinates:

 var mouseX = event.clientX - document.documentElement.scrollLeft 
     - canvas.offsetLeft;
    var mouseY = event.clientY - document.documentElement.scrollTop 
        - canvas.offsetTop;

Particle physics

Every particle is fired at an angle with initial speed. This is 2D space, so we'll split the speed into two parts. After that on every draw call we'll update the coordinates.

 this.dx = speed * Math.cos(angle - Math.PI / 2);
 this.dy = speed * Math.sin(angle - Math.PI / 2);
 // and then in the draw function
 this.x += this.dx;
 this.y += this.dy;

Gravity

Gravity is an important part of this example. I've given a lot of thought on how to simulate it and found a simple solution. Since the gravity is a force the falling speed has to increase over time. The simplest method is to increase the y speed with a gravity constant ... as simple as one line:

 this.dy += fountainProps.gravity;

And here's my example on:
Codepen