Last Good Quote: Son's are the seasoning on our lives. - Someone on Facebook

Monday, April 5

Code: Simple 2D Javascript Map - Part 5

This code will show how to create enemies and move them around the screen. It's going to randomly create 5 red boxes which will "fall" from the top of the grid to the bottom. The user can click a tile and the green box will move to the tile clicked. There is no collision detection...yet. I'm keeping this as simple as possible so in this example, "enemies" will drop from the top of the screen. Your job is to dodge them.

The play function will get called every one second (playSpeed). It will add a new enemy until it has added 5 enemies. It chooses a random location at the top of the map, places the unit there.

It will then pick a random speed and set the y velocity (think downward speed) equal to this random speed value.

The second piece has the magic. It cycles through all enemy units and sets their next location to 3 spaces below where the unit currently is. Notice that this where our new functions get called.

var playSpeed = 1000;
var numUnits = 0;
var maxNumUnits = 5;
function play()
{
if(numUnits < unitid =" 1001+numUnits" x =" Math.floor(Math.random()*9);" speed =" Math.floor(Math.random()*3);" unit =" document.getElementById(" i="0;i= mapHeight)
{
x = Math.floor(Math.random()*9);
y=0;
jumpUnit(unitID, x, y);
}
moveUnit(1001+i, x,y);
}

setTimeout("play()",playSpeed);
}


Other changes



Again, we have some plain Jane functions to get the tile location (x and y) of where our units is located. Make a note to yourself, there is plenty of room to optimize this code. It's dog slow.


function getTileX(unitID)
{
var unit = document.getElementById("unit_" + unitID);
x = getLeft(unit)/tileSize - originX;
y = getTop(unit)/tileSize - originY;

return x;
}

function getTileY(unitID)
{
var unit = document.getElementById("unit_" + unitID);
x = getLeft(unit)/tileSize - originX;
y = getTop(unit)/tileSize - originY;

return y;
}


We also need to create a style for our enemy units. So I added this to the style.

.enemy {
background:red;
border:1px solid #999;
position:absolute;
top:0px;left:0px;
width:5px;height:5px;
overflow:hidden
}


Since we are moving random objects around, we need to start tracking the map height and width. So I changed the build map function.

var mapHeight = 0;
var mapWidth =0;
function buildMap(width, height)
{
mapHeight = height;
mapWidth = width;

for(x=0;x<width;x++) y=0;y<height;y++);x++)


Again, because we are moving enemies around randomly, need a bit of error catching added to the move function. If we try to move to a tile that does not exist, just stop moving.

function moveUnit(unitID, tileDestX, tileDestY)
{
var unit = document.getElementById("unit_" + unitID);
var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
if(!tile)
{
return;
}
x = getLeft(unit);
y = getTop(unit);
destX = getLeft(tile)
......


Finally, I needed a function which will take an existing unit and "jump" them to a specific place on the map. This means they don't "move" one pixel at a time, but instead are immediately placed at that location:

function jumpUnit(unitID, tileDestX, tileDestY)
{
var unit = document.getElementById("unit_" + unitID);
var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
if(!tile)
{
return;
}
unit.style.left = getLeft(tile);
unit.style.top = getTop(tile);
}


Last but not least, we have to call our new play function from within the body tag.

<body onload="buildMap(10,10); addUnit(1000,4,4); play()">





Finally, the entire page looks like this:


<html>
<style>
.tile {
background:#BBB;
border:1px solid #999;
position:absolute;
top:0px;left:0px;
width:5px;height:5px;
overflow:hidden
}

.unit {
background:green;
border:1px solid #999;
position:absolute;
top:0px;left:0px;
width:5px;height:5px;
overflow:hidden
}

.enemy {
background:red;
border:1px solid #999;
position:absolute;
top:0px;left:0px;
width:5px;height:5px;
overflow:hidden
}
</style>
<script language=javascript>

var originX = 0;
var originY = 0;
var tileSize = 32;
var mapHeight = 0;
var mapWidth =0;
function buildMap(width, height)
{
mapHeight = height;
mapWidth = width;

for(x=0;x<width;x++)
for(y=0;y<height;y++)
{
var d = document.createElement("DIV");
d.className="tile";
d.setAttribute("ID","tile_" + x + "_" + y);
d.style.top = originY + (y*tileSize);
d.style.left = originX + (x*tileSize);
d.style.width = tileSize;
d.style.height = tileSize;
d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
document.getElementById("divMap").appendChild(d);
}
}

function tileClicked(x,y)
{
//var tile = document.getElementById("tile_" + x + "_" + y)
//tile.style.background = "yellow"

moveUnit(1000, x, y);
}

function addUnit(unitID, x,y)
{
var d = document.createElement("DIV");
var tile = document.getElementById("tile_" + x + "_" + y)
if(unitID == 1000)
{
d.className="unit";
}
else
{
d.className="enemy";
}
d.setAttribute("xVel", 0);
d.setAttribute("yVel", 0);
d.setAttribute("ID","unit_" + unitID);
d.style.top = tile.style.top;
d.style.left = tile.style.left;
d.style.width = tileSize;
d.style.height = tileSize;
document.getElementById("divMap").appendChild(d);
}


function jumpUnit(unitID, tileDestX, tileDestY)
{
var unit = document.getElementById("unit_" + unitID);
var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
if(!tile)
{
return;
}
unit.style.left = getLeft(tile);
unit.style.top = getTop(tile);
}



function moveUnit(unitID, tileDestX, tileDestY)
{
var unit = document.getElementById("unit_" + unitID);
var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
if(!tile)
{
return;
}
x = getLeft(unit);
y = getTop(unit);
destX = getLeft(tile);
destY = getTop(tile);
newX = x;
newY = y;

if(x > destX) newX--;
if(x < destX) newX++;
if(y > destY) newY--;
if(y < destY) newY++;

unit.style.left = newX;
unit.style.top = newY;

if(newX != destX || newY != destY)
{
setTimeout("moveUnit(" + unitID + "," + tileDestX +"," + tileDestY+")",5);
}

}


function getTop(obj)
{
if(obj)
{
return parseInt(obj.style.top.replace("px",""));
}

return 0;
}

function getLeft(obj)
{
if(obj)
{
return parseInt(obj.style.left.replace("px",""));
}

return 0;
}

function getTileX(unitID)
{
var unit = document.getElementById("unit_" + unitID);
x = getLeft(unit)/tileSize - originX;
y = getTop(unit)/tileSize - originY;

return x;
}

function getTileY(unitID)
{
var unit = document.getElementById("unit_" + unitID);
x = getLeft(unit)/tileSize - originX;
y = getTop(unit)/tileSize - originY;

return y;
}


var playSpeed = 1000;
var numUnits = 0;
var maxNumUnits = 5;
function play()
{
if(numUnits < maxNumUnits)
{
unitID = 1001+numUnits
x = Math.floor(Math.random()*9);
speed = Math.floor(Math.random()*3);
addUnit(unitID,x,0);
var unit = document.getElementById("unit_" + unitID);
unit.setAttribute("xVel", 0);
unit.setAttribute("yVel", speed+1);
numUnits++;
}

for(i=0;i<numUnits;i++)
{
unitID = 1001+i;
var unit = document.getElementById("unit_" + unitID);
x = getTileX(unitID) + parseInt(unit.getAttribute("xVel"));
y = getTileY(unitID) + parseInt(unit.getAttribute("yVel"));

if(y >= mapHeight)
{
x = Math.floor(Math.random()*9);
y=0;
jumpUnit(unitID, x, y);
}
moveUnit(1001+i, x,y);
}

setTimeout("play()",playSpeed);
}


</script>
<body onload="buildMap(10,10); addUnit(1000,4,4); play()">

<div id="divMap"></div>

</body>
</html>

0 comments:

Post a Comment

Followers