Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/*
Interactive Drawing Assignment

d20

Nathan Powless-Lynes @2015.9.18

A 20-sided die in the middle of the screen will react to the spotlight aimed by the mouse. The brightness of each side
is dependant on the distance of the cursor, which acts as a beam of light. The background consists of bricks, which act
just like the die. Clicking will cue a critical (20) to be "rolled", and lighting strikes to simulate the tension that
may be experienced in an actual RPG.

Version history:

Version 1.0: features a twenty-sided die that lights accordingly to the position of the mouse. A spotlight follows
the cursor.

Version 1.1: added a shadow that is cast by the die. The shadow has both umbra and penumbra.

Version 1.2: added random planets in an effort to think of a new background.

Version 1.3: added critical hit when the mouse is clicked. The die glows red, and a "20" appears on the die.

Version 1.4: shows critical on release, making it possible for the screen to flash rapidly. Tentatively replaced the
space background with a forest.

Version 1.5 (current): finally settled on a brick background. The cracks between bricks flash when the mouse is clicked,
simulating lighting.
*/

/*

setup()

This function is in every program in Processing. It literally just "sets up" all required elements for the program. Code
in here will be done once only, so it should be used for things that will never need to be changed or redrawn.

*/
void setup()
{
  size(400, 400);//the size of the canvas
  strokeWeight(5);//the thickness of any lines drawn. This will come in use for the "20" and the lightning
}

/*

draw()

This function is useful for any dynamic program in Processing. Anything program that needs things to be drawn over and
over as they change can utilize the draw() function. Code written in this function will be executed from top to bottom
as usual, but once the end of draw() is reached, it will loop back to the start of draw() and start again. In this
manner, the elements in the interactive drawing can appear to be animated and interact with the motion of the mouse.

Most of the code for this interactive drawing is in the draw() function.

*/

void draw()
{
  /*
  
  A brick background, setting the scene in a dark dungeon
  
  Distance of each brick from the light source is determined by using Pythagorean Theorem. You
  can see the code version of this theorem at every fill for the bricks. The difference between the X-components of
  both the cursor position and the midpoint of the brick is used for B, as it is the horizontal distance between the
  two. Similarly, the difference between the Y-components of the two are used for C, or the vertical distance. The
  square-root is taken of them, multiplied by some number (in this case, 0.23) to make the change more gradual, and
  subtract the whole thing from the base colour (85 or 75). In this manner, the greater the distance between the cursor
  and a brick, the darker it will get, as more is being taken away from its base colour.
  
  bricks listed starting from the top-left corner
  
  */
  
  //top row, first brick
  fill(85 - 0.23*sqrt(((80 - mouseX)*(80 - mouseX) + (40 - mouseY)*(40 - mouseY))));
  rect(0, 0, 160, 80);
  
  //top row, second brick
  fill(85 - 0.23*sqrt(((240 - mouseX)*(240 - mouseX) + (40 - mouseY)*(40 - mouseY))));
  rect(160, 0, 160, 80);
  
  //top row, third brick
  fill(85 - 0.23*sqrt(((400 - mouseX)*(400 - mouseX) + (40 - mouseY)*(40 - mouseY))));
  rect(320, 0, 160, 80);
  
  //second row, first brick
  fill(85 - 0.23*sqrt(((0 - mouseX)*(0 - mouseX) + (120 - mouseY)*(120 - mouseY))));
  rect(-80, 80, 160, 80);
  
  //second row, second brick
  //this one's base colour is darker because it is mostly covered by the die
  fill(75 - 0.23*sqrt(((160 - mouseX)*(160 - mouseX) + (120 - mouseY)*(120 - mouseY))));
  rect(80, 80, 160, 80);
  
  //second row, third brick
  fill(85 - 0.23*sqrt(((320 - mouseX)*(320 - mouseX) + (120 - mouseY)*(120 - mouseY))));
  rect(240, 80, 160, 80);
  
  //third row, first brick
  fill(85 - 0.23*sqrt(((80 - mouseX)*(80 - mouseX) + (200 - mouseY)*(200 - mouseY))));
  rect(0, 160, 160, 80);
  
  //third row, second brick is covered completely by the die, so it need not be drawn
  
  //third row, third brick
  fill(85 - 0.23*sqrt(((400 - mouseX)*(400 - mouseX) + (200 - mouseY)*(200 - mouseY))));
  rect(320, 160, 160, 80);
  
  //fourth row, first brick
  fill(85 - 0.23*sqrt(((0 - mouseX)*(0 - mouseX) + (280 - mouseY)*(280 - mouseY))));
  rect(-80, 240, 160, 80);
  
  //fourth row, second brick
  //this one's base colour is darker because it is mostly covered by the die
  fill(75 - 0.23*sqrt(((160 - mouseX)*(160 - mouseX) + (280 - mouseY)*(280 - mouseY))));//
  rect(80, 240, 160, 80);
  
  //fourth row, third brick
  fill(85 - 0.23*sqrt(((320 - mouseX)*(320 - mouseX) + (280 - mouseY)*(280 - mouseY))));
  rect(240, 240, 160, 80);
  
  //bottom row, first brick
  fill(85 - 0.23*sqrt(((80 - mouseX)*(80 - mouseX) + (360 - mouseY)*(360 - mouseY))));
  rect(0, 320, 160, 80);
  
  //bottom row, second brick
  fill(85 - 0.23*sqrt(((240 - mouseX)*(240 - mouseX) + (360 - mouseY)*(360 - mouseY))));
  rect(160, 320, 160, 80);
  
  //bottom row, third brick
  fill(85 - 0.23*sqrt(((400 - mouseX)*(400 - mouseX) + (360 - mouseY)*(360 - mouseY))));
  rect(320, 320, 160, 80);
  
  
  //making sure the lightning effect takes place only on the wall. When stroke is applied in "mousePressed()", it stays
  //in effect until here
  noStroke();
  
  /* 
  
  The die's shadow, cast by the spotlight on the cursor.
  
  The shadow features two parts: penumbra (outer part) and umbra (inner part). This is a natural phenomenon that occurs
  with most kinds of lighting, so it seemed appropriate to add a sense of realism to the drawing.
  
  This is made from a custom shape, which is initiated by "beginShape()", states each vertex, and then closes the shape
  with "endShape();"
  
  Each vertex must move as the mouse does to simulate a shadow. Each vertex has a location that it will be at when the
  mouse is in the top-left corner, or when mouseX and mouseY are 0. Then, as each value increases, the corresponding
  coordinate for the vertex must change inversely. This causes the shadow to always be on the other side of the light
  source.
  
  Just like the bricks (see detailed description on line 64), distance is determined using Pythagorean Theorem, but this
  time, it is the distance of the mouse from the centre of the canvas. This makes it so the shadows get darker as they
  approach the edges of the canvas.
  
  */
  
  //penumbra (outer shadow)
  //slightly larger than the umbra
  fill(30 - 0.4*(sqrt((200 - mouseX)*(200 - mouseX) + (200 - mouseY)*(200 - mouseY))), 30- 0.4*(sqrt((200 - mouseX)*(200 - mouseX) + (200 - mouseY)*(200 - mouseY))), 30 - 0.4*(sqrt((200 - mouseX)*(200 - mouseX) + (200 - mouseY)*(200 - mouseY))), 100);
  beginShape();
  vertex(400 - mouseX, 230 - mouseY);
  vertex(550 - mouseX, 310 - mouseY);
  vertex(550 - mouseX, 490 - mouseY);
  vertex(400 - mouseX, 580 - mouseY);
  vertex(250 - mouseX, 490 - mouseY);
  vertex(250 - mouseX, 310 - mouseY);
  endShape();
  
  //umbra (inner shadow)
  //slightly smaller than the penumbra
  //uses the same fill as the penumbra, but overlaps it to look darker
  beginShape();
  vertex(400 - mouseX, 264 - mouseY);
  vertex(520 - mouseX, 328 - mouseY);
  vertex(520 - mouseX, 472 - mouseY);
  vertex(400 - mouseX, 544 - mouseY);
  vertex(280 - mouseX, 472 - mouseY);
  vertex(280 - mouseX, 328 - mouseY);
  endShape();
  
  /*
  
  The 20-Sided Die
  
  The die operates in very much the same way as the wall; the greater the distance each side is from the light source,
  the darker it gets (see line 64 for detailed distance formula). However, it is slightly different by the manner in
  which the base colours for each side differ depending on how direct the beam of light will hit it. This is just like
  reality, where a direct beam of light will illuminate a surface better.
  
  There are no numbers on this die (except when the mouse is clicked. See "mousePressed()", as the focus should be
  the play of light on the angled surfaces. The illusion of three-dimensionality can be given just by the way the
  die is lit.
  
  Sides listed in symmetrical pairs from top to bottom (by midpoint)
  
  */
  
  //top pair, left
  fill(90 - 0.2*sqrt(((160 - mouseX)*(160 - mouseX) + (80 - mouseY)*(80 - mouseY))));
  triangle(50, 110, 200, 30, 200, 100);
  
  //top pair, right
  fill(90 - 0.2*sqrt(((240 - mouseX)*(240 - mouseX) + (80 - mouseY)*(80 - mouseY))));
  triangle(350, 110, 200, 30, 200, 100);
  
  //second from top pair, left
  fill(95 - 0.21*sqrt(((120 - mouseX)*(120 - mouseX) + (150 - mouseY)*(150 - mouseY))));
  triangle(50, 110, 110, 250, 200, 100);
  
  //second from top pair, right
  fill(95 - 0.21*sqrt(((280 - mouseX)*(280 - mouseX) + (150 - mouseY)*(150 - mouseY))));
  triangle(350, 110, 290, 250, 200, 100);
  
  //middle pair, top (20)
  fill(100 - 0.22*sqrt(((200 - mouseX)*(200 - mouseX) + (190 - mouseY)*(190 - mouseY))));
  triangle(200, 100, 110, 250, 290, 250);
  
  //middle pair, bottom
  fill(90 - 0.2*sqrt(((200 - mouseX)*(200 - mouseX) + (300 - mouseY)*(300 - mouseY))));
  triangle(200, 380, 110, 250, 290, 250);
  
  //side pair, left
  fill(85 - 0.2*sqrt(((70 - mouseX)*(70 - mouseX) + (220 - mouseY)*(220 - mouseY))));
  triangle(50, 110, 50, 290, 110, 250);
  
  //side pair, right
  fill(85 - 0.2*sqrt(((330 - mouseX)*(330 - mouseX) + (220 - mouseY)*(220 - mouseY))));
  triangle(350, 110, 350, 290, 290, 250);
  
  //bottom pair, left
  fill(85 - 0.2*sqrt(((120 - mouseX)*(120 - mouseX) + (310 - mouseY)*(310 - mouseY))));
  triangle(200, 380, 50, 290, 110, 250);
  
  //bottom pair, right
  fill(85 - 0.2*sqrt(((280 - mouseX)*(280 - mouseX) + (310 - mouseY)*(310 - mouseY))));
  triangle(200, 380, 350, 290, 290, 250);

  /*
  
  The Spotlight
  
  This is a simple trick made by overlapping a number of translucent ellipses. They are all centred at (mouseX, mouseY),
  so they will always be drawn directly under the cursor.
  
  Although the spotlight does not "interact" with anything by changing values, its transparent ellipses do offer some
  actual brightness to whatever is under them. Also, it makes a lot of sense to have the light source LOOK like a real
  light source, again adding to the realism of the drawing.
  
  */
  
  //the ellipses, largest to smallest
  fill(255, 255, 0, 20);//translucent yellow
  ellipse(mouseX, mouseY, 220, 220);
  ellipse(mouseX, mouseY, 110, 110);
  ellipse(mouseX, mouseY, 50, 50);
  fill(255, 255, 200, 80); //the smallest ellipse is the most focused, so it is the whitest and brightest
  ellipse(mouseX, mouseY, 20, 20);
  
}

/*

mousePressed()

This function is run through once from top to bottom when a button on the mouse is pressed.

In the case of this drawing, when the mouse is pressed, the die "rolls" a 20. This the highest number the die can roll,
and is known as a "critical hit" in RPGs, so it made sense to add some drama when this occurs. The number 20 appears,
the die glows red and lightning seems to strike behind the wall. Crazy things happen when you get a critical hit.

The glowing effect is achieved by drawing a translucent red ellipse on top of the die. Then, the number 20 is made of a
couple of lines, an arc and an ellipse. The stroke colour is changed so that when the bricks are redrawn, they have a
white outline for a moment that makes it look like there was a flash of lighting.

*/

void mousePressed()
{
  //glowing on crit
  fill(255, 0, 0, 60);//translucent red
  ellipse(200, 200, 300, 300);//just as wide as the die
  
  //number 20
  
  noFill();//so the arc will not fill with colour
  stroke(255);//white for the 20, also for the lighting
  
  //the "2"
  line(190, 230, 160, 230);
  line(160, 230, 188, 193);
  arc(175, 200, 30, 60, PI+0.3, 2*PI - 0.3, OPEN);
  
  //the "0"
  ellipse(228, 200, 30, 60);
}

/*

mouseReleased()

This function is run through once from top to bottom when a button on the mouse is released.

This function serves the same purpose as mousePressed(), making the 20, the glow and the lighting. It just makes the 
same things happen on the release of the mouse instead of the press, making the lighting flash quicker than possible
with just mousePressed().

*/
void mouseReleased()
{
  //glowing on crit
  fill(255, 0, 0, 60);//translucent red
  ellipse(200, 200, 300, 300);//just as wide as the die
  
  //number 20
  
  noFill();//so the arc will not fill with colour
  stroke(255);//white for the 20, also for the lighting
  
  //the "2"
  line(190, 230, 160, 230);
  line(160, 230, 188, 193);
  arc(175, 200, 30, 60, PI+0.3, 2*PI - 0.3, OPEN);
  
  //the "0"
  ellipse(228, 200, 30, 60);
}