Saturday, January 7, 2012

KAPOW! Tile Creation Part: Three

Now, we want to use the "cell" array to place the tiles on the page.

We need to create a function called "placeTiles"...

function placeTiles(){}

This function will go through the array "cell" and check the value of "bgImage".  If "bgImage" == undefined, we will do nothing, if it is defined, we'll place a tile and use the properties of the cell to determine the style of the div element we create.

Create a <div> with JavaScript
To create an element, we use "document.createElement()" like so:
var newDiv = document.createElement('div');
  This will store a <div> as the variable "newDiv".  Now with our new div element stored as this variable, we can change the attributes of it and the style of it pretty easily.

However, for this example we only want to create a div element if the bgImage property is set.  This means we need to cycle through the items in cell and check the property bgImage.
for(idNum in cell){}
This FOR LOOP will cycle through all the cells and return idNum.  idNum is the index of each item and do the code in {}'s for each item.

Currently, this FOR LOOP does nothing... let's change that.
for(idNum in cell){
     if(cell[idNum].bgImage != undefined){}
}
Now, we're checking the bgImage property of cell[idNum] for each idNum that is returned by the FOR LOOP.
!= is the same as saying NOT EQUAL
If this if statement returns true, it will execute whatever code in the {} following it.


What do we do if the bgImage is defined?
This is when we want to create our <div>.  And set a variable for the "id" of the div that is more easily read.
for(idNum in cell){
     if(cell[idNum].bgImage != undefined){
     var newDiv = document.createElement('div');
     var dId = idNum;
  }
}
setAttribute()
We'll use "setAttribute()" to change the attributes we'd normally set in html like this
<div id="someID" class="myDivClass">
This becomes:
newDiv.setAttribute('id',dId);
newDiv.setAttribute('class','gamePiece');
We can use this for any of the attributes we want to change that would normally be written into the HTML to modify the object.

Notice that 'id' and dId are seperated by a comma and not an =.  This is because setAttribute() is a function and 'id' is the attribute we want to pass to it as an argument of the function.  And dId is another argument the function uses to set the value of 'id'.  Make sense?

newDiv.style
"style" is a property of newDiv.  This property is an associative array of properties that can be set and are interpreted as CSS3.
newDiv.style.backgroundImage = "url('images/" + cell[idNum].bgImage + ".png')";
Here, we're setting the backgroundImage property of style to "url('images/...png')";

If we were going to write the style in CSS3, it would be written as follows:
background:"url('../images/purpleTile.png')";
But remember, the url is being set relative to the document and not the CSS3 document linked in the HTML file.  SO we don't need the "../".  Also, the image is going to change based on the property in bgImage, so we need to concatenate the string with that property.  To do this, we use the + symbol.

When you use + against two strings like "dog" and "cat" it will make the string "dogcat" so you need to add spaces explicitly. "dog" + " " + "cat" will return "dog cat".  if you want to add a string to a variable you do "dog" + variable + "cat".  If the value of variable is hamburger, you will get "doghamburgercat".  So you have to add the spaces if you want them like in the previous example.  In this example, we're adding the bgImage property, so that's why we're using:
"url('images/" + cell[idNum].bgImage + ".png')"
If the value of bgImage is purpleTile it will return:
"url('images/purpleTile.png')"
Try it yourself in the console.  Set some variables to strings, then add them together like you would numbers.

function placeTiles(){}
function placeTiles(size){
    var gF = document.getElementById('gameFrame');

    for(idNum in cell){
        if(cell[idNum].bgImage != undefined){
        var newDiv = document.createElement('div');

        var dId = idNum;

        console.log(dId + ": current Div ID");
        newDiv.setAttribute('class', "gamePiece");
        newDiv.setAttribute('id', dId);

        newDiv.style.margin = "0px";
        newDiv.style.backgroundImage = "url('images/" + cell[idNum].bgImage + ".png')";
        newDiv.style.backgroundPosition = "0px, 0px";
        newDiv.style.backgroundSize = "100% 100%";
        newDiv.style.position = "absolute";
        newDiv.style.width = size + "px";
        newDiv.style.height = size + "px";
        newDiv.style.top = (cell[idNum].row * size) + 21 + "px";
        newDiv.style.left = (cell[idNum].column * size) + 21 + "px";
        newDiv.style.zIndex = 100;

        gF.appendChild(newDiv);       
        }
    }
}
Setting CSS3 Properties through JavaScript
Notice style.width and style.height for a second.
   newDiv.style.width = size + "px";
   newDiv.style.height = size + "px";
We're taking the argument size that is passed when the placeTile() function is called, and adding the string "px" to it.  But why?

This is because CSS3 doesn't know what numbers mean without context.  So you have to tell it how to interpret those units.  All the values that are passed to the style of an object MUST be strings, otherwise they won't do anything.  Passing 12 to your CSS3 will result in nothing happening.  Passing "12px" or "12%" for instance is something the CSS3 can interpret.

Setting the .top and .left properties
When we first set the properties of our tile in the "cell" array, we gave it information about the x and y position.  A number between 0 and rows = y and a number between 0 and columns = x.  These values are used to get the pixel position of our tile.

We do this by multiplying the row and column by the size of the tile.
   newDiv.style.top = (cell[idNum].row * size) +"px";
   newDiv.style.left = (cell[idNum].column * size)+"px";
But if we only do this, we'll be off because we have to account for our padding.  This can be kinda tricky, but for now I simply added 21 to the top and left value because i know the padding value of the gameFrame div is 20.  This could be acquired by getting that element, and it's style data and grabbing the .padding value of that, but It's a constant value, and it's a known value, so i didn't bother.  If your padding value is 0, don't worry about this part... or if your value of padding is different you may want to get this number dynamically, or grab it from your own .css file.
newDiv.style.top = (cell[idNum].row * size) + 21 + "px";
newDiv.style.left = (cell[idNum].column * size) + 21 + "px";

var gF = document.getElementById('gameFrame');
 This variable is set to define the parent of our new div.  'gameFrame' should be a <div> in your HTML file.  This div will contain your game objects and canvas.
     <div class="container" id="master">
         <div class="content" id="gameFrame">
             <canvas class="gameScreen" id="background" width="1024" height="768">
             </canvas>
         </div>
     </div>
Now that we have our variable defined for the parent element, we use appendChild() to add the new <div> to the page.

gf.appendChild(newDiv);

after you've set all the style rules and attributes of your new div element, all that's left to do in this function is to call "appendChild()" and pass the argument of your "newDiv" variable.  This will add the <div> element you've created and stored to the actual page, and make it visible to the user.

Calling placeTiles()
All that's left to do for this part is to call, "placeTiles()" in your init() function, just after "createTiles()".  You also need to pass the variable tileSize, which will be stored in the size argument of placeTiles();
function init(){
    tilesRange = 10;
    tileSize = 64;

    window.canvas = document.getElementById('background');
    window.ctx = canvas.getContext("2d");

    window.screenWidth = canvas.width;
    window.screenHeight = canvas.height;

    console.log("Setting screen width to:" + " " + screenWidth);
    console.log("Setting screen height to:" + " " + screenHeight);

    tilesWidth = screenWidth/tileSize;
    tilesHeight = screenHeight/tileSize;

    createTiles(tilesWidth, tilesHeight, tilesRange, tileSize);

    placeTiles(tileSize);
}
That's it for now.  Next we'll talk about transitions!

At this point you should be able to see the tiles, they don't do anything, but that's ok.  We'll do interaction in the next post.

1 comment:

  1. Hey Don, I was wondering if you would be interested in working with me on a website design. I don't know where you are in your learning curve, but it could be a great exercise and expand your skill. Let me know if you are interested. c . newton(at)eovonline(dot)com

    ReplyDelete