Friday, September 20, 2013

Having Fun With the Camera (part 2)

At this point, we have the code ready to flip the camera movement back and forth.  But we don't have any code to regularly 'time' this flipping at set intervals.  This is where we need another if(condition)-type statement to check whether or not it is time to flip the camera going the opposite direction.  There are 2 ways of doing this.  We could make an artificial clock timer and at set times, flip the switch.  We might see this timer element later in our games, but for now I want to try the other easier option.  All we will do is set a distance limit that our camera can travel. Once it reaches this limit, we stop the camera, flip the switch, and send it in the opposite direction.  Here's the new 'if' statement that we will add:
if(camera.position.z > 10){
   camera.position.z = 10;
   forwardFlag = true;
}
Remember that when our program starts, the forwardFlag is set to 'false' and therefore the camera is constantly moving backwards with the '+' sign version of the camera movement code.  It starts out with a position.z value of 5 and every frame it is adding + 0.1 to that number (5.1, 5.2, 5.3, 5.4, etc.).  What the above code does is continually monitor the position and it watches for when the 'camera.position.z' passes the 10 boundary mark.  When it is indeed greater than 10, such as 10.1, it then executes the code right beneath the if statement.  Everything that is inside the curly braces { } will get executed.  If the condition is NOT met however and camera.position.z is still less than 10, it will keep skipping over the code right beneath it and resume the normal program flow after the curly braces { }.  

Also notice that we have a new if(condition) comparison above: using the greater-than sign ( > ) .  In the first 'if' statement that we learned about, we tested for 'is equal' by using the == (double equals sign).  In this new 'if' statement however, we are testing for 'greater-than', by using the > symbol.  As you can guess, we can also test for less-than ( < ), greater-than-or-equal-to ( >= ) and less-than-or-equal-to ( <= ).  We will at some later point use all of these tests throughout our code.  They really come in handy!

So, looking at the above code, if camera.position.z has crossed our boundary and is indeed greater than 10, what should we do?  Well, we use a technique I like to call 'snapping' or clamping.  We essentially snap the camera's position back into place right at the limit that we set, which is 10 units.  Notice that we use the single equals sign ( = ) to actually fill the variable with a new value, 10.  We'll take a look at why this snapping back into place is important in another later post.  Just understand now that this avoids the camera getting stuck at the extreme boundaries.
 By the way, we could have used another value besides '10' as our boundary, but I chose 10 because it looked good for this demo; it didn't let the camera get too far away from the cube.
After this snap-back, we need to flip the direction switch.  The very next line (forwardFlag = true;) now 'flips' the forwardFlag switch on, or in other words, forwardFlag is switched to 'true'.  And from our earlier code, you know what happens when forwardFlag is equal to 'true' right?  We use the ' - ' version of the camera movement code, and now our camera is going in the opposite direction, or towards the cube - which is what we want!

Almost done.  Now we have to test for the opposite condition - if the camera gets too close to the green cube, we must 'snap' it back and switch it to go in the opposite direction again.  The following code should now make sense:
if(camera.position.z < 1){
   camera.position.z = 1;
   forwardFlag = false;
}
In the above code, we perform the same type of test but in reverse.  We continually monitor the camera's position and once it crosses our boundary of 1 units (gets too close to the cube), it is time to 'snap' and 'switch'!  We 'snap' the camera.position.z to 1, which is at our boundary.  Then we flip 'forwardFlag' back to 'false' again.  This will have the effect of sending the camera back where it came from.  Also note that I chose a boundary of 1 unit from the cube, which is really close; almost touching.  This number 1 for the near boundary, like the other far boundary at 10 units away, looked good for this particular demo.  Just know that we are free to pick any number we want to be the boundaries.  

That's it - whew!  I know that was a lot of new info in the last couple of blog posts for you to digest, but don't worry; we will re-visit these topics and techniques again and again in the future.  Pretty soon this game coding will be second-nature to you.  Just hang in there!

Since we made a lot of changes to our .js file, here it is printed in its entirety.  Just 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.MeshBasicMaterial({ color:'rgb(0,255,0)' });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

camera.position.z = 5;
var forwardFlag = false;
animate();

function animate(){
   
   requestAnimationFrame(animate);

   cube.rotation.x = cube.rotation.x + 0.02;
   cube.rotation.y = cube.rotation.y + 0.03;

   if(forwardFlag == false){
      camera.position.z = camera.position.z + 0.1;
   }
   if(forwardFlag == true){
      camera.position.z = camera.position.z - 0.1;
   } 
      
   if(camera.position.z > 10){
      camera.position.z = 10;
      forwardFlag = true;
   }
       
   if(camera.position.z < 1){
      camera.position.z = 1;
      forwardFlag = false;
   }
      
   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 the cube 'oscillating' (remember our new technique?), or quickly moving back and forth, towards you and away from you.  And who said math was not fun? :-)

Next time we will look at coloring our cube different colors.  We will also learn how to add a light source so that we can more clearly see all 6 sides of the cube - some in light, and some in shadow.  Don't miss it!