Thursday, November 21, 2013

Starting Our First Game, SpacePong3D!

If you have been following along with this blog, you might be saying "These graphics demos and code examples are nice, but when are we going to start making a real 3D game?"  Well, I'm happy to tell you that we are finally ready to start our first game!  

Sorry if the game setup blog posts before this were kind of dull.  But this is a necessary chore for anyone wanting to create a computer game.  Here's the good news:  now that we have gotten the boring setup code out of the way, we can now focus on the fun part: designing and building a real 3D game!  And because we have some basic template code in place to handle different devices, different speeds of hardware,  and different methods of user input, we can relax and feel confident that whatever games we make will work and run smoothly on most devices in the world today.

So, what kind of game should we start with?  There's a saying I like that goes, "Learn to walk before you run."  This phrase applies to a lot of things in life, and I believe it applies to game programming as well.  We must start somewhere to get some experience with coding games.  And what better place to start, than with one of the first and most popular computer games of all time - Pong.  

This may date me, but my first video game experience as a kid was playing Pong on my new Atari 2600 home system.  It is a simple game with simple elements, but it is a classic that stands the test of time.  Countless clones and emulations have been made from its original concept.  Although we will not be the first, nor the last, we will make a 3D version of this classic with some extra tricks.  I chose Pong because it is an excellent teaching example.  The lessons we learn by building a simple 3D game like this will carry over to our more ambitious future game projects.

Since the name Pong is already taken, I thought maybe we could spice up our game's name and call it SpacePong3D.  As the name implies, it will be a Pong-style game set in outer space, with true 3D graphics!  We will take an old flat 2D game and make it pop out into the 3rd dimension.  Sound fun?  I hope so - let's get started!           

Before we start coding, let's familiarize ourselves with the original Pong game.  Here's a screenshot:



The gameplay is sort of like Table Tennis, as viewed from high above the table (but nowhere near as fast as real Table Tennis matches!) .   Actually the game environment is more like Air Hockey because Air Hockey is a flat 2D game where as Table Tennis is 3D (you can go up-and-down as well as side-to-side and forwards and backwards).  Anyway, in Pong, 2 Human players can play against each other, or you can have 1 Human player vs. a Computer-controlled AI opponent.  Each player controls a paddle which hits a small ball back and forth.  A player tries to score against their opponent by having their opponent miss the ball.  When the ball slips past a player's paddle, their opponent receives 1 point.  When a pre-determined score number is reached, for example 10 points,  the player who reaches that score first wins the game.

OK so now we now the basics of Pong.  How do we add something new to the game?  One way is to make the paddles and ball have depth as well.  The rectangles pictured above can be turned into elongated cubes and the ball could be turned into a sphere with depth.  However many clones like this have already been made.  Plus, those re-makes are not being played in true 3D (they have no up and down motion, only side to side).  The gameplay, the motion of the ball, is still confined to a flat table.

Let's go one step further!  Instead of confining the play to a flat 2D table, let's give the table depth as well, and make it a hollow cube!  Now the paddles and ball will be able to move around freely inside the 3D cube space.  And since we have the awesome Three.js library on our side, this 3D updating of the classic game will be within our reach!     

We have been using the same old file names for our demo projects up until now.  I think it's time to create some new files with new names for our game.  The good news is that we don't have to start from scratch.  We can just use our existing code inside example01.html and tempGame.js, and change them to meet our new needs.  Always keep these old files around - that's why I called it tempGame.js - it stands for 'template Game'.   We might update tempGame.js somewhere in the future if we want to add some more functionality to every game, but for now we are just going to copy, paste, and rename.

  Here is our old 'example01.html' file.  Copy and Paste the following code, but save as 'SpacePong3D.html' instead.  You can place it right beside the old example01.html file in the same folder

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <div id="help" style="position:fixed; left:40%; top:4%; color:grey;">
         Desktop: Press W A S D keys, or Click/Drag Mouse to move the cube
      </div>

      <div id="help2" style="position:fixed; left:40%; top:8%; color:grey;">
         Mobile: Hold finger down and slow Swipe to move the cube
      </div>

      <div id="debug1" style="position:fixed; left:5%; top:4%; color:grey;">
         Debug Info 
      </div>

      <div id="debug2" style="position:fixed; left:5%; top:8%; color:grey;">
         Debug Info 
      </div>

      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script>
      <script src="js/virtualjoystick.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>


Now Copy and Paste the following old tempGame.js code, but instead save it as 'pongGame.js' , and place it inside your 'js' folder, right beside the old tempGame.js:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var clock = new THREE.Clock();

var keyboard = new THREEx.KeyboardState();
var joystick = new VirtualJoystick({
                      mouseSupport: true
                   });

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

var debugText1 = document.getElementById("debug1");
var debugText2 = document.getElementById("debug2");

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   
   if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
   }
   if( keyboard.pressed("A") ){
 cube.position.x = cube.position.x - 60 * frameTime;
   }
   if( keyboard.pressed("W") ){
 cube.position.y = cube.position.y + 60 * frameTime;
   }
   if( keyboard.pressed("S") ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   if( joystick.right() ){
 cube.position.x = cube.position.x + 60 * frameTime;    
   }
   if( joystick.left() ){
 cube.position.x = cube.position.x - 60 * frameTime;     
   }
   if( joystick.up() ){
 cube.position.y = cube.position.y + 60 * frameTime;       
   }
   if( joystick.down() ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   renderer.render( scene, camera );
   
   debugText1.innerHTML = "Cube position X: " + cube.position.x.toFixed(1);
   debugText2.innerHTML = "Cube position Y: " + cube.position.y.toFixed(1);
   
}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}


Looking at the entire project, by now you should have a file called SpacePong3D.html and a 'js' folder that sits right beside it.  Inside this 'js' folder, you should have a file called pongGame.js, as well as ones that we have been using:  three.min.js , virtualjoystick.js , and threex.keyboardstate.js . 

If you have all these files and folders in the right place, we are now ready to start coding!  We will begin with the SpacePong3D.html file in the next post.

See you soon!

Friday, November 15, 2013

Adding Mobile Touch and Mouse Input (part 2)

We have successfully included the new Mobile Touch/Mouse input helper file.  But how do we access it?  Well, Jerome Etienne, creator of this helper file, has designed his library to be intuitive and easy to use.  As we have done many times before, we must first declare a variable that will hold the 'virtualjoystick' object and all its properties and functionality.

Open up our 'tempGame.js' file and add the following line near the top:    
var joystick = new VirtualJoystick({
                      mouseSupport: true
                   });
There is some difference in the look of the above code compared to how we declared a 'keyboard' variable a couple of posts back.  Going line by line, we use the 'var' keyword followed by a name for our game controller, in this case 'joystick'.  Then comes the '= new' which fills 'joystick' with whatever comes next.  And what comes next is a call to 'VirtualJoystick({ });'  Notice this function has curly braces { } inside its parentheses.  These curly braces let us know that there will be 'key: value' pairs inside.  The purpose of these 'key: value' pairs is to further customize this joystick object to our liking.  Jerome has offered a number of parameters that can be placed here, but the one we want for this project right now is called 'mouseSupport'.  'mouseSupport' can be set to either true or false.  We DO want to be able to read the mouse, if the user has one, so we put 'mouseSupport: true' inside the curly braces. 

This style of object creation is kind of like what we saw with 'var material = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' }); '  - except that this was all written on one line.  We could have done this with VirtualJoystick as well, but I like the 'mouseSupport: true' part being on its own line.  It makes this function and its parameters a little more readable.

Moving on, the 'joystick' object we just created now contains all the information and parameters that we wanted it to have.  We can access the data coming from the player's touch/or mouse input by calling functions on 'joystick'.  

Here's how we determine if the user is moving the game controller joystick to the right:
if( joystick.right() ){
     cube.position.x = cube.position.x + 60 * frameTime;    
}
Let's take a look at each line above.  Remember the 'if' statement tests for whether something is true or not.  And what we want to test for is if the user is moving their game controller joystick in a certain direction.  Jerome has designed a function for the joystick object called '.right( )' .  This simple function tests whether the user is moving the virtual joystick to the right or not.  It returns 'true' if yes, and 'false' if no.

Also recall that if this test comes back as 'true', then the code inside the 'if' statement's curly braces { } gets executed.  So if indeed the user is moving the joystick to the right, we move the green cube's x position to the right by adding positively to it.  Similarly, we can test for 'joystick.left( )', joystick.up( )', and 'joystick.down( )', and then perform the appropriate actions on the cube for each case.   

Here's how that looks:
if( joystick.right() ){
     cube.position.x = cube.position.x + 60 * frameTime;    
}
if( joystick.left() ){
     cube.position.x = cube.position.x - 60 * frameTime;     
}
if( joystick.up() ){
     cube.position.y = cube.position.y + 60 * frameTime;       
}
if( joystick.down() ){
     cube.position.y = cube.position.y - 60 * frameTime;
}
What's really cool is that Jerome's 'joystick' helper also can handle diagonal movements.    If you move the joystick right AND up at the same time, the cube will combine movement right (+60) and up (+60) at the same time, which is diagonally upper-right motion.  We now have 8 possible movement directions, similar to the old 1980's game controller sticks and gamepads!   

All we have to do now is add all the above lines back into our tempGame.js file.  Copy and Paste the following code and save it as 'tempGame.js', overwriting the old one:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var clock = new THREE.Clock();

var keyboard = new THREEx.KeyboardState();
var joystick = new VirtualJoystick({
                      mouseSupport: true
                   });

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

var debugText1 = document.getElementById("debug1");
var debugText2 = document.getElementById("debug2");

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   
   if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
   }
   if( keyboard.pressed("A") ){
 cube.position.x = cube.position.x - 60 * frameTime;
   }
   if( keyboard.pressed("W") ){
 cube.position.y = cube.position.y + 60 * frameTime;
   }
   if( keyboard.pressed("S") ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   if( joystick.right() ){
 cube.position.x = cube.position.x + 60 * frameTime;    
   }
   if( joystick.left() ){
 cube.position.x = cube.position.x - 60 * frameTime;     
   }
   if( joystick.up() ){
 cube.position.y = cube.position.y + 60 * frameTime;       
   }
   if( joystick.down() ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   renderer.render( scene, camera );
   
   debugText1.innerHTML = "Cube position X: " + cube.position.x.toFixed(1);
   debugText2.innerHTML = "Cube position Y: " + cube.position.y.toFixed(1);
   
}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Go back and open the 'example01.html' file with your browser.  If you saved everything correctly, you should be able to use your mobile device (smartphone or tablet), or your mouse (if you are at your desktop/laptop).  When you touch and hold (or hold down the mouse button) you will see our new virtual joystick appear exactly where you touched or clicked!  Then, while holding down your finger (or mouse button) try moving around.  On a mobile touch device, this would be like a slow 'swipe' motion.  On the mouse, its known as a click and 'drag' motion.  

The green cube now magically responds to your touch / mouse input and moves where you want it to.  If you lift off the screen (or let go of the mouse button), the joystick base and stick circles will disappear.  But just touch or click again and they will turn back on, and instantly be ready to control your game's characters!

Thanks to Jerome Etienne's awesome helper libraries, we now have complete support for all the users out there that might be playing our games on a desktop, laptop, tablet, or even smartphone.  

Guess what?  We are now ready to make 3D games like I promised!  We have completed most of the template or set-up code so that now we can focus on creating an actual playable game.  There are some minor house-keeping techniques that we must learn, but I will fill in the remaining pieces along the way as we are making our first game.  

Hang in there - it's about to get real!  

Thursday, November 14, 2013

Adding Mobile Touch and Mouse Input (part 1)

We want our future games to be playable on the widest variety of devices.  This includes support for keyboard (which we have already added a couple of posts ago), as well as Mouse input and mobile Touch input.  If our games respond to any and all types of player input, then our games will be more widely enjoyed and shared.    

So, it's time to add support for Mouse and mobile Touch input.  As we saw with keyboard input, we could try to develop a helper library from scratch that handles all the various types of events for both Mouse and Mobile devices.  But why re-invent the wheel?  If there is already an existing library in place that we could use, let's use it!

Once again we turn to Jerome Etienne from Paris, France.  Remember he's the one who developed the 'keyboardstate.js' helper that we used a couple of posts back.  Well, it just so happens that Jerome also has a nifty helper file for adding Touch input as well as Mouse input - it's called 'virtualjoystick.js'.  What Jerome was trying to accomplish with this helper is to make a tablet or smartphone behave like a joystick/gamepad.   And since tablets and smartphones are flat, with no analog sticks protruding from them, Jerome made a virtual representation of a joystick that is displayed on the flat screen - hence the name 'Virtual'Joystick. 

Let's take a moment and think about what a gamepad or joystick does.  When you pull the controller stick/pad to the left, you expect the game character to go left.  Same goes for right.  When you push the stick up, you expect the character to move upwards (or similar action like 'jump').  And when you pull the stick down, you expect the character to move down (or similar action like 'crouch').  

Jerome's virtualjoystick.js emulates this game-controller behavior by waiting for the user to touch the screen (or click if they only have a mouse).  Once the player touches(or clicks), a blue circle is drawn on the screen precisely at the point of touch contact (or click location).  This circle is called the 'base' and does not move.  Now, while the base is sitting still, a smaller circle is drawn inside of the base - this is called the 'stick' and this DOES move.  It can move completely outside the bigger circle if you want. Whenever the user swipes (or drags with the mouse button down) in a direction, the 'stick' will follow, just like a game controller stick.  

So, if the user swipes right, the 'stick' circle will follow the user's finger and the controller stick will go right also.  If the user swipes down, the stick moves down as well. Similarly, if the user only has a mouse, then when they move the mouse right, the 'stick' circle moves to the right also.  Even if the user goes crazy and moves in circles, the virtual stick will accurately follow! 

The only requirement for all this to work is that the user's finger must remain somewhere on the screen.  If the user lifts their finger (or mouse users let go of the mouse button), then the base and stick both disappear.  Not to worry though - nothing is lost.  The cool thing is that you can just touch (or click) anywhere on the screen again, and that new point becomes your new joystick 'base'!  It is now instantly ready to accept control movements from the player again.  

At some point we may want to make the base always 'on' and permanently displayed onscreen, no matter what the user does.  The solution will depend on the type of game we are making and the type of situation that we are dealing with.  

Enough talk - let's add this helper library to our project so we can use it!  Click on the following link:

virtualjoystick.js

Once you're there, Right-Click and Save as... 'virtualjoystick.js' .  Place it next to our other .js files inside your 'js' folder.  

We need to access this new file from our example01.html webpage.  By now, you should be an expert at adding libraries to html pages, right?  Just in case though, here's how to do it:         
<script src="js/virtualjoystick.js"></script> 
Remember order matters when you are adding these libraries (or dependencies) to your project.  Place the above line in between threex.keyboardstate.js and tempGame.js .  'virtualjoystick.js' will now be 3rd place in the list of 4 total .js files.   

Here is our updated 'example01.html' file with the new 'virtualjoystick.js' library added in correct order:

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <div id="help" style="position:fixed; left:40%; top:4%; color:grey;">
         Desktop: Press W A S D keys, or Click/Drag Mouse to move the cube
      </div>

      <div id="help2" style="position:fixed; left:40%; top:8%; color:grey;">
         Mobile: Hold finger down and slow Swipe to move the cube
      </div>

      <div id="debug1" style="position:fixed; left:5%; top:4%; color:grey;">
         Debug Info 
      </div>

      <div id="debug2" style="position:fixed; left:5%; top:8%; color:grey;">
         Debug Info 
      </div>

      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script>
      <script src="js/virtualjoystick.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>

Copy and paste the above code and save it as 'example01.html', writing over the old one.  Notice also that I added another div element with an id of "help2".  This is another line of help text placed directly below the older help text.  It tells the mobile (smartphone and tablet) users what to do in order to move the green cube on their devices.

In part 2 of this post, we will access this new helper file and learn how to apply it to our project.  Then our demo/future games will be playable on any device - laptop, desktop, tablet, and smartphone! 

(Continued in part 2)...

Thursday, November 7, 2013

Printing Real-Time Game Data to the Screen (part 2)

Now we can access our new text 'div' elements through our JavaScript file, 'tempGame.js'.  First we must create a couple of variables that hold references to the new 'div' text elements back on our webpage.  This is how it's done: 
var debugText1 = document.getElementById("debug1");
Using the 'var' keyword, we create a variable called 'debugText1' that will hold the handle or reference to a text element.  But which webpage text element - there could be hundreds?  Well, remember back in part 1 of this post, inside our HTML file 'example01.html' we created a 'div' element and gave it an 'id' named "debug1".  In case you forgot, here is the line taken from 'example01.html' :
<div id="debug1" style="position:fixed; left:5%; top:4%; color:grey;"> ....
This is our target div that we want.  How do we access it from our 'tempGame.js' file when it's located on another file, example01.html?  Well, for just this purpose, all browsers come with some handy methods/functions that we can call from the 'document' object.  One of these is 'getElementById( )'.  Inside the parentheses goes the id name that you gave to the element, in this case "debug1".  Now this function will go and find the correct target element on our html webpage document and give us access to it so that we can change it, add to it, remove it, color it, anything we want.   Since we made the var 'debugText1' refer to the target element 'debug1', they are permanently linked. 

We also need to do this for the other div element which has the id of 'debug2'.  If you recall "debug2" sits right underneath "debug1" on our webpage.  Here's both lines of code for referencing "debug1" and "debug2" webpage elements:
var debugText1 = document.getElementById("debug1");
var debugText2 = document.getElementById("debug2");
All I did was change the '1's to '2's.  Now we have handles named 'debugText1' and 'debugText2' that give us access to their corresponding elements back on our webpage. We can now type for example 'debugText1.someFunction' where 'someFunction' is a method of our choice to change its target webpage element ("debug1").    

One of these functions/methods is '.innerHTML = ' and its purpose is to change the element's text content instantly.  After the equals sign ( = ) goes the new text that we want to be displayed on our webpage.  So if I type debugText1.innerHTML = "Hello World";  then our webpage will display the words "Hello World" right where that particular target 'div' ("debug1") element is located.  Whatever text that was stored in "debug1" will be erased and the words "Hello World" will now appear in their place. 

The cool thing about '.innerHTML = ' is that in addition to static text like "Hello World", we can also put dynamic variable text, like a game value that is constantly changing while our game runs.  For this demo I chose our green cube's X and Y position to be displayed as dynamic changing text output.  If you recall, any code that deals with quickly changing things MUST be placed inside our animate( ) function, so that it gets refreshed as fast as possible.

Here are the 2 lines of code dealing with the real-time text output.  These two lines will be placed inside our 'animate( )' function and will be executed as quickly as our program can run. The first line changes its target div element "debug1" (which is linked by reference now) and the second line changes its target div element "debug2":
debugText1.innerHTML = "Cube position X: " + cube.position.x.toFixed(1);
debugText2.innerHTML = "Cube position Y: " + cube.position.y.toFixed(1);
Don't be alarmed by the '.toFixed(1)' stuff - I will explain that in a moment.  For now,  let's review what is happening here:  'debugText1' refers to the "debug1" element on our webpage.  We use the '.innerHTML = ' method to change its text content.  In double quotes, we write any static text that we want.  So in this case we type "Cube position X: " .  This will now appear in the top left-hand corner of the webpage and it will not change or move at all - it is static.  However, the next part WILL change very quickly - many times a second.  First we use the plus sign ( + ) to add some more text that will appear immediately after the static words "Cube position X: ".  And this extra text will be in the form of our 'cube.position.x' variable, whatever that happens to be at the moment.  Finally I used the '.toFixed(1)' method to make this number have a fixed decimal place.  You see, JavaScript numbers have many precision decimal places after them (sometimes 0.000000000000000, or 15 decimal places!) .  We are not doing scientific measurements so we do not need to clutter up our webpage readouts with all these precision decimal places.  And just for this occasion, there is a handy function called 'toFixed( )' that shortens the number of precision decimal places to your liking.  Inside the parentheses goes the number of decimal places that you want.  So 'toFixed(1)' will give a fixed decimal place of 1 so that our text printout '0.000000000000000' will be shortened to '0.0' , which is much more readable and just fine for our game purposes. 

The same is done above for 'debugText2', which refers to the "debug2" element on the webpage.  Although its text reads "Cube position Y: " and then the 'cube.position.y' variable is used instead, with the 'toFixed( )' method tacked on the end as well so that it is also shortened nicely.

All we have to do now is add all the above lines into our 'tempGame.js' file.  Copy and Paste the following code and save it as 'tempGame.js', overwriting the old one:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var clock = new THREE.Clock();

var keyboard = new THREEx.KeyboardState();

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

var debugText1 = document.getElementById("debug1");
var debugText2 = document.getElementById("debug2");

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   
   if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
   }
   if( keyboard.pressed("A") ){
 cube.position.x = cube.position.x - 60 * frameTime;
   }
   if( keyboard.pressed("W") ){
 cube.position.y = cube.position.y + 60 * frameTime;
   }
   if( keyboard.pressed("S") ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   renderer.render( scene, camera );
   
   debugText1.innerHTML = "Cube position X: " + cube.position.x.toFixed(1);
   debugText2.innerHTML = "Cube position Y: " + cube.position.y.toFixed(1);
}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}


Go back and open the 'example01.html' file with your browser.  If you saved everything correctly, you should see the "Cube position X and Cube position Y" and their respective values printed in the top left-hand corner of our webpage.  Go ahead and move the green cube around with the W, A, S, and D keys.  When you do this, notice that the position numbers refresh themselves in real-time, telling us their value!

This new debug text is for our programming eyes only.  We will remove it for the release of our future games so that end-users will not see the debug text.  But while we are creating the demos/games, this is a helpful feature to have.  Being able to watch certain game numbers behind the scenes has helped me a lot in my past game programming adventures.  Hopefully this small feature will help you too!  

Next time we will learn how to respond to mouse button and mouse movement events.  After that, we'll take a look at handling touch input from a smartphone or tablet, so that anyone, regardless of their device, can play our games!  

Tuesday, November 5, 2013

Printing Real-Time Game Data to the Screen (part 1)

One very useful routine our future games can have is the ability to print real-time game data to the screen.  It often helps to see the raw numbers behind our game's objects to make sure that they are functioning properly.  

And, being human, we will make mistakes while coding, which leads to program errors, or 'bugs' as we programmers like to call them.  Therefore to get rid of all the bugs/mistakes, or 'debug', it helps to have game variables' numbers (position, speed, etc.) and flag variables' states (true, false, on, off, etc.) displayed quickly to our screen while the game is running so we can better spot the problem.  Chances are that if we see weird or unexpected raw data being output to the screen, then that is the source of the bug.  We can then quickly locate it inside the code and fix it.

In the last post we learned how to add simple instruction text to the top of the browser window to help first-time players know what to do.  Now we will add some 'debug' info text to the top left-hand corner of the browser window.  We will also update the text inside the animate( ) loop so that the numbers on-screen will quickly change as fast as the game updates.  This will indicate what's going on with all the game objects that we want to inspect more closely.        

Just for reference, here's how we added the help info text last time:      
<div id="help" style="position:fixed; left:40%; top:4%; color:grey;"> 
   Press W, A, S, and D keys to move the cube 
</div>

And here's our new code to add the debug text:
<div id="debug1" style="position:fixed; left:5%; top:4%; color:grey;"> 
   Debug Info 
</div>

Can you spot the small differences?  First, the 'id' is now named "debug1" instead of "help", which is representative of what this HTML code does.  The style properties are the same except for 'left: 5%;' , which places this text only 5% from the left edge of the browser window.  Finally, the 'Debug Info' text on the next line is what the user will actually see displayed in the browser window.  However, we will update this so quickly that you probably won't have time to see the words 'Debug Info' - instead it will be replaced by whatever numbers and data that we want to quickly print to the screen.  I just put the words 'Debug Info' in there for code readability.  
Let's add a second line of debug text.  This will be almost identical to the code above: 
<div id="debug2" style="position:fixed; left:5%; top:8%; color:grey;"> 
   Debug Info 
</div>
Notice that I changed the id name to "debug2" to help keep it separate from the "debug1" id.  Finally, in the style properties, all that is changed is the vertical positioning of the text by typing 'top:8%;'.  This text is now placed 8% from the top, which is a little farther down than 4%.  If we didn't change this, the "debug2" text would be displayed right on top of the "debug1" text, making it impossible to read.   

Here is the updated example01.html file with our new "debug1" and "debug2"  text 'div' elements:

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <div id="help" style="position:fixed; left:40%; top:4%; color:grey;">
         Press W, A, S, and D keys to move the cube 
      </div>

      <div id="debug1" style="position:fixed; left:5%; top:4%; color:grey;">
         Debug Info 
      </div>

      <div id="debug2" style="position:fixed; left:5%; top:8%; color:grey;">
         Debug Info 
      </div>

      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>

Copy and paste the above code and save it as 'example01.html', writing over the old one.  In part 2 of this post, we will add a few lines of code inside our 'tempGame.js' file to quickly update the debug1 and debug2 texts in real-time.  Then we will see data quickly flowing to the screen!

(Continued in part 2)...

Thursday, October 31, 2013

Adding Keyboard Input (part 2)

Now that we have included the new keyboard input helper file, how do we access it?  Well, Jerome Etienne designed his 'threex.keyboardstate.js' to work a lot like Three.js does, so we should feel comfortable using it. 

Open up our 'tempGame.js' file and add the following line near the top:    
var keyboard = new THREEx.KeyboardState();
That looks familiar doesn't it?  There IS a small difference however in this variable declaration.  Notice the small letter 'x' placed right after the word 'THREE' .  This tells us that the variable 'keyboard' will be using the new THREEx library rather than the older THREE library that we have had since the beginning of our project.  Other than that, it's identical in syntax, so we should feel right at home.

The 'keyboard' object now holds all the properties and functionality designed by Jerome to aid us in scanning the player's keyboard for keypresses in real time.  And since we want our game to quickly scan the keyboard on every animation frame (as fast as it can), we will put the actual scanning code inside the animation function.  Here's how the new keyboard scanning code lines look:
if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
}
Let's take a look at each line above.  Remember our 'if( )' statement a while back.  This 'if' statement tests for whether something is true or not.  And what we want to test for is if the user is pressing the 'D' key on their keyboard.  Jerome has designed a function for the keyboard object called '.pressed(" ")' .  Inside the double quotes we place the key on the keyboard that we want to test for.  In this case it's the 'D' key, so we type 'keyboard.pressed("D")' .  This will return 'true' if the 'D' key is pressed, and 'false' if it is not pressed.

Also recall that if the test comes back as 'true', then the 'if' statement will execute whatever is inside its curly braces { }.  In this case I have put a line of code to move our green cube's position to the right (positive x).  I chose '60' because it is medium-fast and looked good for this demo (feel free to experiment with this number).  Notice I also put ' * frameTime; ' at the end.  Get used to doing this for every line of code that deals with motion or animation.  Using 'frameTime' like this on all the game's moving objects will make sure that it looks the same on everyone's computer, no matter what the specs are for their device.

All that's left to do now is add the tests for the other 3 keys : the W, A, and S keys.  Here's how the whole thing looks now:
if( keyboard.pressed("D") ){
   cube.position.x = cube.position.x + 60 * frameTime;
}
if( keyboard.pressed("A") ){
   cube.position.x = cube.position.x - 60 * frameTime;
}
if( keyboard.pressed("W") ){
   cube.position.y = cube.position.y + 60 * frameTime;
}
if( keyboard.pressed("S") ){
   cube.position.y = cube.position.y - 60 * frameTime;
}
The above statements test for the 4 keys that most games use as input: the WASD keys.  Looking at each case above, the 'D' key will move the cube right (positive x), the 'A' key will move the cube left (negative x), the 'W' key will move the cube up (positive y) and the 'S' key will move the cube down (negative y).  

What's really cool is that Jerome's keyboard helper also can handle multiple keypresses.  So, if you hold down 'D' and 'A' at the same time, the +60 and -60 will cancel each other out, and you will see the cube stop.  If you hold the 'D' and the 'W' key at the same time, the cube will combine movement right (+60) and up (+60) at the same time, which is diagonally upper-right motion.  We now have 8 possible movement directions!  Thinking in a clockwise manner, they are: up, upper-right, right, lower-right, down, lower-left, left, and upper-left.  

All we have to do now is add all the above lines back into our tempGame.js file.  Copy and Paste the following code and save it as 'tempGame.js', overwriting the old one:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var clock = new THREE.Clock();

var keyboard = new THREEx.KeyboardState();

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   
   if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
   }
   if( keyboard.pressed("A") ){
 cube.position.x = cube.position.x - 60 * frameTime;
   }
   if( keyboard.pressed("W") ){
 cube.position.y = cube.position.y + 60 * frameTime;
   }
   if( keyboard.pressed("S") ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   renderer.render( scene, camera );
   
}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Go back and open the example01.html file with your browser.  If you saved everything correctly, you should see our new help text at the top of the webpage that reads: "Press W, A, S, and D keys to move the cube".  And when you press them - the cube moves!  We now have a responsive, interactive graphics demo.  It is not a game yet, but we are getting there.

I should note that this demo only works on desktops and laptops that have a physical keyboard attached.  For smart phones and tablets, we will have to figure out how to handle touch input on those devices.  We want ALL users to be able to play our games right?  Luckily, there are some libraries and helper routines that we can quickly add to make the demos/games work on mobile devices as well.  We will take a look at those in the near future. 

It's pretty awesome though that we only added about 10 lines of code and now we have user input, making our demo truly interactive.  That is the magic of JavaScript and helper libraries!

In the next posts we will add debug/info text to the top left-hand corner of our webpage that will tell us the number values of any game object that we want to inspect more closely.  This is really helpful when monitoring game performance, game variables that are quickly changing, and also when something isn't quite working how we want - it can help us correct any problems that come up. 

See you soon!

Wednesday, October 30, 2013

Adding Keyboard Input (part 1)

At this point we have the makings of a fun graphics demo, but it is not responsive yet for the player.  Other than re-sizing the browser window, the user has no way of interacting with our program.  It's time to remedy that!  What we will do in this post is add a simple keyboard input file to our project.  When we've done that, our demo (future game) will respond to keyboard key-presses in real time.   

You may recall back when we added the Three.js library file to our project, I said that it makes our 3D game programming lives much easier.  Three.js takes care of the not-so-fun raw GL graphics / math initialization for us, so that we can focus on the fun stuff.   However, Three.js is meant to only aid in 3D graphics rendering inside the browser.  It purposefully leaves out libraries of keyboard/mouse/touch input, AI, networking, game physics, audio, and other various components that we might need for our future games.  If it DID include all those, the Three.js library would grow into a huge, unmanageable file that would be slow to download over the internet for people wanting to try our games. Rather, Three.js focuses on just the rendering so that you, the programmer, can add in different components only as you need them.  This makes your game projects just big enough to work correctly, but not too big because of unused features and unnecessary components.  And everyone's component needs will vary, depending on their type of project, so this makes sense.

So now we have to add in our own keyboard input code.  We could try this from scratch, but why re-invent the wheel?  If someone has already coded it and packaged it up nicely for you, why not use it?   There are all sorts of additional helper files and functions floating around out there on the internet that are meant to be used in conjunction with Three.js.  These smaller, specialized files take care of various tasks that aren't inside the main Three.js library (like handling user keyboard input).  In fact, one such brave programmer has made it his mission to help everyone in their Three.js journey.  His name is Jerome Etienne from Paris, France.  He has been kind enough to create and share small helper files for Three.js and game programming in general.  And one of these files is devoted to Keyboard input, which we need.  

Click on the following link and after the new page loads, Right-Click on the webpage and Save As... 'threex.keyboardstate.js'  . Save this inside the 'js' folder where our 'tempGame.js' and 'three.min.js' are already located.  

threex.keyboardstate.js

Now you should have a total of 3 different .js (JavaScript) files in your 'js' folder : tempGame.js, three.min.js, and now threex.keyboardstate.js  .  This last file we just added to our project is kind of like a 'plugin' for game programming in the browser.  Thanks to Jerome's fine work, his helper file will allow us to query the keyboard for keypresses in real time.  We can then use this information to move the characters/objects in our game and make it truly interactive!

We haven't changed our old 'example01.html' file in a while; but we need to update it now because the browser has to be able to locate the new 'threex.keyboardstate.js' file that we just added to our project.   

Do you remember how to include a new JavaScript file in html?  We do it with the 'script' tag like this:      
<script src="js/threex.keyboardstate.js"></script> 
With the addition of the above line, we will have 3 different lines with the script tag, each loading in a different component (or dependency).  At this point, it's worth noting that the 3 script lines must be placed in the right order, otherwise we'll get errors in the browser console and our game won't work correctly.  Take a look below at our new example01.html file and how I ordered the 3 script tag lines: 

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>

If you follow each script line from top to bottom, this .html code first loads the most important library, 'three.min.js' .  Then it loads our new helper file, 'threex.keyboardstate.js'.  Lastly, it loads our 'tempGame.js' which holds the future game code that we are writing.  This file is dependent on the other two .js files to be already in place, so it must be loaded last.

While we have this .html file open, there's one more thing I want to add.  It will be a line of text that is placed at the top of our webpage that instructs the user what to do, and what keys to press.  It is like a mini help file and I really appreciate when others add it to their demos/games, so we will do it too.

Here's how to add a line of text using the html 'div' tag:
<div id="help" style="position:fixed; left:40%; top:4%; color:grey;"> 
         Press W, A, S, and D keys to move the cube 
</div>
This 'div' (short for 'division') element has an id named "help".  I chose that because it is descriptive of what this 'div' does.  Next we set the style by typing style = " " and inside the double quotes we put key:value pairs.  First comes the key/attribute followed by a colon ( : ) and then its value.  A semicolon ( ; ) follows each pair.  Then comes the next pair and so on.  The first key:value pair is 'position:fixed;' .  This sets the text to a fixed position on the webpage so that it is in relation to the browser window itself and not some other element on the page.  Next comes 'left:40%;' which pushes the left margin of the text over to 40% the width of the webpage (which is almost half way over).  Similarly, 'top:4%;' pushes the top margin down just a little, 4% down the webpage.  Finally, 'color:grey;' sets the text color to a stock grey.  
On the next line we type 'Press W, A....' which is the actual content of our text.  These instructions will make it more clear what to do for first-time users.  

Here is the updated example01.html file with our new 'div' text element and our new 'script' tag line which includes the keyboard helper library to our project: 

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <div id="help" style="position:fixed; left:40%; top:4%; color:grey;"> 
         Press W, A, S, and D keys to move the cube 
      </div>

      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>

Copy and paste the above code and save it as 'example01.html', writing over the old one.  In part 2 of this post, we will actually use this new keyboard helper in our tempGame.js file.  We will then have a truly interactive demo!  See you in the next part!

(Continued in part 2)...

Friday, October 18, 2013

Timing on Different Systems with Three.js

Let's consider the effect of timing on games.   Typically, all moving game objects and players/characters are updated every cycle through the game code.  This means that if you instruct the game to "move a character/object by 1 unit", it will indeed move by 1 unit on every pass through your game program.  
 Take our sun light object for example.  On every frame of animation we want its height to move smoothly, so we type:
sunHeight = sunHeight + 1;
Just like we expect, the sun will rise smoothly, and it will work on any computing device or smartphone.  That's all good, until you consider that not everyone's device is running at the same rate.  A powerful desktop computer might loop through this statement 60 times a second, while a smartphone or old computer might only get around to it 20 times a second.  That means that the person playing your game on their powerful desktop computer will see and feel a different game experience than the person playing on a smartphone or older computer system. 

How do we fix this problem?  We turn to time-based animation.  Essentially we measure how fast the user's system is looping through our game code per second, and then we multiply that time delay by the game objects' speed.  Here's how the above example will look now:
sunHeight = sunHeight + 1 * frameTime;
In the above snippet, the 'sunHeight' variable is still being raised at 1 unit every animation frame, just like before.  But now we have multiplied this amount by a new variable called 'frameTime'.  'frameTime' holds the amount of time it took for the user's system to complete 1 animation loop.  And this 'frameTime' value is continually refreshed on each loop through our game code (as we all know, computers can have performance hiccups now and then).  As with racing times, and your cholesterol, lower numbers are better for 'frameTime' - and higher numbers are worse.  A good computing system will quickly lap around your program, giving a lower frameTime.  A smaller or older device will take longer to do those laps around your code and will result in a higher number for frameTime.  But not to worry if you are one of the users of the less powerful systems!  The above equation is the great equalizer when it comes to game performance. 

To see how, let's imagine running through the above code with a fast computer. The 'frameTime' result will be a lower number.  Let's say it clocks out at 16 milliseconds, which is around 0.016 seconds. So  after the multiplication is performed, 'sunHeight' in this instance gets a small number added to it every frame and smoothly rises on our screen.  Now run the same game on an old computer or phone, and their 'frameTime' result may be as high as 50 milliseconds, or 0.05 seconds.  So after the multiplication is performed, 'sunHeight' in this instance gets a larger number added to it every animation frame.   This little 'frameTime' equation gives the slower computers a boost, so that they catch up to the faster computers.   If you put the fast and the slow systems side-by-side, the game's objects will move at the same rate!

The only downside to all this is that the slower computers will look a little more choppy and less-smooth than the faster computers, because the slower devices have to cover more ground each animation frame to catch up.  But the important thing is that all players of our games, regardless of their system specs, will see and feel the same game timing and movement that we wanted them to experience!   Just think if we could apply this method to Olympic racing athletes; all countries would be winners - actually they would all tie for the Gold medal!  :-)

The next order of business is somehow timing the end-user's system each animation loop so that we can apply the right amount of boost.  Three.js to the rescue!  The folks on the Three.js team have provided us with the perfect tool for this very purpose:  the 'THREE.Clock()' object. 

Here's how we declare a new clock variable in our game code: 
var clock = new THREE.Clock();

This kind of Three.js declaration should look familiar by now, right?  We name a variable 'clock' and fill it by typing '= new' and a call to the 'THREE.Clock()' object.  Now the variable 'clock' has all the accuracy and functionality of a real-life digital stopwatch that can measure how fast something is running.  To use it, we have to declare one more variable - the 'frameTime' variable that we saw earlier.  That's easily done by typing:
var frameTime = 0;
We initially set 'frameTime' equal to 0.  Then, as the game program runs, it will be refreshed every animation frame, so it will correctly hold the results of the system's performance.

One last thing to do is sample the 'clock' object every frame, so we get an accurate timing measurement.  In Three.js, this is accomplished by typing:
frameTime = clock.getDelta();
'frameTime' is now filled using the equals ( = ) sign and a call to one of our 'clock' object's helper functions, called getDelta.  So we type 'clock.getDelta();'  Delta is a mathematical term for how much something has changed - in this case how much the time has changed (or how much time has gone by).  A smaller Delta means a little time has passed, and a bigger Delta means a larger amount of time has passed.  

One more thing to mention is that when applying this equation to our old sunHeight code, it moved too slowly, compared with how it used to move before our changes.  So I had to tweak the initial speed of the sunHeight variable to something bigger.  It used to be 1, as in:
sunHeight = sunHeight + 1 * frameTime;
But now it is: 
sunHeight = sunHeight + 60 * frameTime;

I know that's a big jump in the speed amount, but it actually works out to look the same as our old example.  That's because 'frameTime' on most decent computers comes back with really small numbers, making the overall sunHeight movement very small.  Using the old number '1', the Sun light crawled up too slowly.  However with a simple change to '60', and after the new frameTime calculation, it moves very much like we intended it to do, which is pretty fast up and down in the sky.  If you wanted a realistic simulation of the Sun rising, you could try '0.05' or something.  It will rise VERY slowly.  You would have to wait all day to see the results!

I've included our new clock and frameTime code in the tempGame.js file.  Copy and Paste the following code and then save it as 'tempGame.js' , overwriting the old one:   

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var clock = new THREE.Clock();

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   renderer.render( scene, camera );

}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}


Once you have saved it, go back to your example01.html file and open with your Chrome browser.  Now the yellow Sun light will move up and down smoothly on your device.  And no matter what system you are running this code on, the Sun will reach high noon and sunset at exactly the same time for you.  If you are running this on an old device or a less-powerful smartphone, it might appear a little choppy.  But the important thing to note is that our future games will animate with the same timing, and the gameplay will be consistent and positive for everyone!

Till next time... 

Tuesday, October 15, 2013

Handling Window Re-sizing in the Browser

It's time to do a little house-keeping maintenance on our game template.  I know, that doesn't sound as exciting as player movement and dynamic lighting, but it is just as important.  What we are looking to do in this post is learn how to handle when the user suddenly changes the browser window size.  This happens quite frequently, so we need to have code in place to quickly re-size our game graphics too.  Otherwise, our viewport will get stretched out of proportion or it might get cut off so the user cannot see the whole picture.  Let's take a look at how to keep the browser view centered and in proportion.

  Every webpage on the internet has a global 'window' object that contains the entire webpage.  The 'window' is like the trunk of a tree and our game is somewhere out on the branches.  Everything on our webpage is connected back to the 'window' object.  The window object is created for us when we open a browser, and it comes with some helpful functions.  One of these is called 'addEventListener()'.  This helper function listens for events such as mouse clicks, window re-sizing, etc..  When it detects that one of these user events has happened, it performs a function of your choosing.  This way, your webpage will become interactive and responsive to the user's actions.  

Here's how to create an eventListener on the window object of our webpage:  
window.addEventListener('resize', onWindowResize, false); 

We type 'window' which refers to the browser window object, then a period ( . ) which is about to call a function on that object, then 'addEventListener();'  You'll notice that this function takes 3 parameters inside its parentheses ( ). The first, 'resize', is telling the browser what we want to listen for - in this case, a browser window re-size by the user. The second parameter, 'onWindowResize' , is the name of our function that will be executed if a 'resize' is detected.  Don't worry about the third parameter which is set to 'false'.  This is an optional parameter that we can leave out, but the W3C advises to put it in anyway to be compatible with older browsers.  

We will define our 'onWindowResize' function now. When the browser detects that a re-size has happened, it will look for a function called 'onWindowResize' and execute whatever code is inside that function.  So at the bottom of our program, we will add the definition of this 'onWindowResize' function.  Here's how the definition looks: 
function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Think of the above code snippet as a 'design' for a function.  This code does nothing on its own - it only provides the instructions of what to do if it is called.  You can also tell that this is just a design by looking at the final curly brace ( } ) by itself on the very last line.  Notice it does not have a semi-colon ( ; ) after it.  So it's not really an action statement that just happens on its own.  This function has to be called by something else.  And that something else is our 'addEventListener' that we just created inside the window object.  When addEventListener detects a browser re-size, it will find this 'onWindowResize' function and execute all the code inside of its curly braces.  
Let's take a look at each line of code inside this function.  The first line accesses the 'aspect' property of the 'camera' that we created at the top of the program.  Remember 'aspect' means the ratio of width to height of your computer/device screen.  This first line fills the 'aspect' property with the new width and height of the browser window, now that the user has suddenly changed them.  
The next line calls a function on our camera object called 'updateProjectionMatrix()' .  Without getting too technical, this helper function recalculates the camera's viewing frustum (a sort of pyramid with the pyramid top at your eye location, the sides extending outward from you, and the pyramid base located back in the distance where you are looking).
The final line should look familiar.  It is an exact copy of our initial renderer set-up code.  This call just refreshes everything so that the final image is correct.

And that's it!  Now that we have everything we need to handle re-sizing, let's add this code back into our game template.  Here's how the final tempGame.js file looks now.  Copy and Paste the following code and then save it as 'tempGame.js' , overwriting the old one:   

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 1;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 1;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   renderer.render( scene, camera );

}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Once you have saved it, go back to your example01.html file and open with your Chrome browser.  Now while the Sun is moving up and down, try to drag the window edges of your browser around.  Try minimizing, maximizing, and squashing the dimensions of the browser window.  No matter what you do now, our code will efficiently handle these window 're-sizes' and correctly display our game graphics.  Pretty handy!

Next up... Timing on different users' machines with the Three.js Clock.  

Tuesday, October 8, 2013

Adding Lights with Three.js (part 3)

At this point, we have our green cube responding correctly to an off-screen light source that is moving up and down.  In this final part of "Adding Lights with Three.js", we will learn how to create a yellow sphere (representing the Sun) and place it where the light is coming from.  Then we will pull back the camera a bit so we can see the cube being lit while the yellow Sun is moving up and down, all in the same view.

First let's see how to make a yellow sphere with Three.js.  Here's how it looks:  
var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);
In the first line, we name a variable 'sphereGeometry' that will hold the design or blueprint of the sphere shape.  We fill this variable using the equals sign ( = ) and a call to THREE.SphereGeometry();  This function takes a number of optional parameters inside its parentheses.  For now, we will only use the most important one, which is size.  This size parameter represents how big the sphere's radius will be.  I arbitrarily chose '5' units for the radius.  You can try other values if you like and see how it affects the scene.  
On the next line we name a variable 'sphereMaterial' which will hold the information about the sphere's material or skin.  Since the Sun itself does not have a shadow, but rather glows bright yellow on all sides, we can just use 'MeshBasicMaterial' (which has no shading) that we used a while back for the green cube.  For the rgb color parameter, we use '255,255,0' which is the rgb code for the brightest yellow. 
The final 2 lines above should look familiar.  We create a mesh variable called 'sphere' that will hold the combination of the Sun's shape (sphereGeometry) and skin (sphereMaterial).  The var 'sphere' now represents everything we need to know about the Sun object.  One last thing to do - add the Sun to our scene.  That is accomplished by typing 'scene.add(sphere);'. 

Inside the animate() loop we will set this newly created sphere to be located exactly where the light source is located.   We do this by typing:
sphere.position = light.position; 
That's pretty intuitive right? Now our Sun sphere will move exactly with the light position as it moves up and down. 

Before we try out this example in the browser,  I want to tell you about some minor changes that I made to make all of the objects fit inside the view at the same time.   First I pulled the camera back so we can see the Sun go all the way up.  So now the camera.position.z variable is set to 160 units (+Z goes behind you which is what we want).  Also, in order to see the Sun sphere rise all the way to the top, I moved the camera up as well.  Remember that the +Y axis goes up.  So now we set the camera.position.y to 40 units.
Here's how the new camera position lines look now:
camera.position.y = 40;
camera.position.z = 160;
One last minor change:  when pulling the camera back like this, I found I couldn't see the green cube very well anymore - it was too small in the distance.  So I just increased the original dimensions of the cube to 20 units on all sides (it was 1 before).   

Well, that covers all the changes.  Copy and Paste the following code and then save it as 'tempGame.js' , overwriting the old one:   

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 1;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 1;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);
   sphere.position = light.position;

   renderer.render( scene, camera );

}

Once you have saved it, go back to your example01.html file and open with your Chrome browser.  If you saved everything correctly, you should see our green cube, now a little farther away, being lit up by the rising and setting Sun sphere object.  This little demo proves that the light is indeed coming from exactly where the yellow sphere is located, which is physically accurate.

Hopefully you are starting to get the hang of creating new Three.js objects, whether they be cubes, spheres, or lights.  We will return to lighting later in this blog series.  But in the next posts, we are going to add some code that will re-size and re-center our view correctly, in case the user suddenly changes their browser window dimensions.  We will also take a look at timing and the Three.js Clock object for handling faster vs. slower computers efficiently, so that everyone,  regardless of their system that they are running our future games on, will have a good experience.

Stay tuned!

Friday, October 4, 2013

Adding Lights with Three.js (part 2)

In the last post we looked at different types of lights and lighted materials in Three.js.  We then learned how to add a point light and change the material of the cube to correctly accept lighting.  Let's have some fun with the light object itself.  Just as you can manipulate the cube position/rotation (spinning),  and the camera position (as we did a while back), you can also change the light position dynamically in real time.
We will now essentially pick up the Sun (carefully - ouch!) and move it up in the sky to high noon, and back down again to sunset, back and forth over and over, like an outdoor time-lapse video on endless loop.  

We will take our trusty oscillation (back and forth) code that we learned a few posts back and use it to lift the sun up high, and then yank it back down again.  Take a look at the following oscillation code:

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 1;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 1;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }
This code should look familiar by now right?  All I did was change the variable names so it will work on our light position.  Our on/off switch, 'sunRiseFlag', will be turned to 'true' at the beginning of the program.  Looking at the code above, if 'sunRiseFlag' is equal to 'true', then the 'sunHeight' position variable will rise every animation frame.  If it gets to 150, which is a limit I chose, we cap it to 150 and then flip the 'sunRiseFlag' switch to 'false'.  Then if 'sunRiseFlag' is equal to 'false', we subtract 1 from the sunHeight variable every frame.  The Sun will now quickly set.  If it gets to 0, which is the ground level, we again cap it to 0, flip the switch back to 'true', and the Sun will rise again.  

Finally we just have to fill the actual light position variable with our 'sunHeight' variable.  Here's how we do that:
light.position.set(50,sunHeight,50);
We already saw this code in the last blog post, but notice the different variable that is in the y coordinate spot.  I took out the '50' that was there earlier, and replaced it now with our oscillating variable 'sunHeight'.  By doing this, we directly affect the light's position every animation frame.  And since we set the cube up to correctly receive lighting, we will now see it's lighted and shaded sides smoothly change as the Sun rises and sets.  
One more thing before we try out this example.  I took out the cube rotation code so that it will sit still.  This makes it easier to follow the lighted/shaded sides of the cube as the Sun moves up and down.  Since we don't need to animate the cube, I cut those rotation lines of code and moved them outside the animate() function.  They are now located nearer the top of the program.  Here's how these lines look now:
cube.rotation.x = 0.4;
cube.rotation.y = 0.6;
Notice that the addition ( + ) is gone now, and the rotation is just set one time only.  The cube will appear rotated already when you start the program, and it will stay there for the rest of the demo.  I chose 0.4 and 0.6 as the rotation numbers, but again, you can choose what you like.  I rotated the cube slightly like this so that we can see 3 of the different sides of the cube all at once, and better see how the cube reacts to the moving sunlight.    

Copy and Paste the following code and then save it as 'tempGame.js' , overwriting the old one:   

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
light.position.set(50,0,50);
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;

camera.position.z = 3;
cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 1;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 1;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);

   renderer.render( scene, camera );

}

Once you have saved it, go back to your example01.html file and open with your Chrome browser.  If you saved everything correctly, you should now see our old green cube slightly turned toward us and remaining still.  Meanwhile the sunlight on the right-hand side will quickly rise in the sky and then fall back down again, then rise, then fall, etc.  The cube will correctly respond to where the Sun is located in the sky, just like in reality.

We now have real-time dynamic lighting in our browsers!  This hopefully shows the cool effects we can make with just a few lines of code and the awesome Three.js library.  In part 3 of this Lighting post, we will add a yellow sphere object to our world so you can see where the Sun is located throughout the animation. 

continued in part 3...