Introduction
As an educational exercise, I have created a platform game. It's a beginner's Mario-type platformer using JavaScript, CSS and HTML only. It runs on Internet Explorer 5+ and Firefox. The game stars Dee, our hero, who must leap onto baddies' heads and collect lemons. 100 gives an extra life. Along the way, he will encounter cannons, moving platforms, water and a flying bird that drops eggs onto his head. Realistic, eh? This is my first attempt at writing a platformer game. I was using JavaScript to move tables around a screen when I thought about the possibility of capturing the user's keyboard input and allowing them to control the HTML tables using JavaScript.
Development
The idea grew to having a little image which moves in response to the keyboard arrow keys. Then I placed an HTML table on the screen. After each keyboard input, I checked if the image was in the bounding box of the table, namely if it was between the left & right
and top & bottom
co-ordinates. If so, I stopped the movement, creating the illusion of collision. I drew a few more tables and set them out over the screen. Then I added some expando properties to the hero image. This allows me to add things not in the official <IMG>
tag, but it is useful for my game. For example, my game hero tag has:
<IMG SRC='hero.gif' id=hero width=10 height=10 ohdestspeed=3
destx=100 desty=999>
Now see ohdestspeed
, which is an expando property of the <IMG>
tag that allows me to set and vary the player's speed. destx
is the player's destination when you push the right arrow. Using JavaScript, I set the destx
property to be the player's current posLeft
plus ohdestspeed
(3 pixels). In JavaScript:
Onkeydown="if(event.keyCode==39){
document.getElementById('hero').style.posLeft+= document.getElementById(
'hero').ohdestspeed;}"
For the left arrow, I subtract the player's posLeft
, etc. For jumping, I set the desty
to be whatever the player's posTop
is and subtract 60
. This means he will start to move up 60 pixels. When he reaches there, I add in code to make him fall. This sets the desty
property to be the bottom of the screen (screen.clientHeight
). When I added water later, to make the player slower, I just changed ohdestspeed
to be 1
. So, instead of 3 pixels per move, he now only moves 1.
All Things Must Port
Making the game run in Firefox required some changes, as the custom expando tag attributes do not work the same. Instead, I put all of the custom attributes of each object in a comma-seperated list in the title tag. This is read into an array at runtime and works as before. Previously, I used document.all
for parsing through elements. However, for the cross-browser approach, I now look through the document.body.childNodes
collection which happily runs in both browsers. Element positioning in IE allows me to use element.style.pixelLeft
(and pixelTop
) and return an integer, fast and convenient. Yet in Firefox, I have to use element.style.left
( and .top
), which returns a string like "144 px." Sadly, I have to use the parseInt()
function, which makes this numerical much slower.
Let It Roll
With moving objects, I made a function using JavasScript's setTimeout
timer that runs every millisecond or so. Basically, this function called u1()
moves enemies, checking their destx
and desty
and setting their posLeft
and posRight
properties. In this function, the player's position is checked against the co-ordinates of the tables (enemies and walls are tables). Because setInterval
updates every millisecond, it gives the illusion of real movement. The display waits for the script to finish before updating, so that's why there is an interval (setInterval
) between u1()
function calls. During this interval, the display engine updates the screen and we resume. According to MSDN, "These timers cannot be relied on as being exact for timing purposes down to the exact millisecond." This does not argue well for crystal-precision updating and animation, but it works passably on my old 500 MHz test machine.
Eventually, it got more elaborate. As the levels got bigger, I added scrolling which checks if the player's posLeft is near the middle of the screen and scrolls the screen using JavaScript's document.body.scrollLeft
(scrollTo
in Firefox) property. I have hidden the scrollbars in the game frame so only the game can scroll ahead. Moving platforms scroll the player when he's on them and water changes the player's speed. Cannons in the game are easy: the cannon balls are just moving platforms that hurt! For scenery, I added clouds and leaves on the ground that have no interaction with the player.
Inner Workings
The file main.htm holds the lives counter, time and lemon counter. It contains the game screen in an IFRAME. It also contains a 2 hidden IFRAMEs. One contains the game engine which updates the game IFRAME and the other contains the level HTML code. The level only loads once into this hidden IFRAME and then I transfer the level anew to the main screen each time the hero dies. When the level loads, its onLoad
event tells the top score frame (main.htm) to load the file opiframe1.htm into the other IFRAME. This starts the game updating. The guts of the game are in opiframe1.htm and this is where you will need the script debugger turned on!
So, I've ended up with a mini-platformer which has my own amateur graphics using Paint! Try to finish it and then create your own levels!
Updates!
- May 2007 - (v1.41) Fixed level loading bug and tweaked level 3
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below. A list of licenses authors might use can be found here.