MADrigal's simulators
NEWS ARCHIVE INFO & FAQ TUTORIAL DOWNLOAD PRESS REV. CREDITS   Facebook page   email

» How to code your own handheld game simulator

Note: this tutorial hasn't been updated since 2000.

» Table of contents

» Foreword

Many people often ask me the way I build my simulators.
Well, I hope that this brief tutorial is useful for them to understand the ease and fun of this kind of programming!
Please keep in mind that I use Borland Delphi 4.0 for Windows 95, so this document mainly regards Delphi developers.

» Requirements

To make your own simulator, the first thing you need is the electronic game itself.
You might just have the scans, the sound samples and a high-detailed description about the way the game works; but be sure that the result would be much less accurate!
The hardware required is simple: a PC and a colour scanner. Also, if you wish to use the original sound samples, you'll also need a sound card and a microphone.

I work on a PC with P166MMX processor, 32MB RAM, a table scanner, a SB16 compatible sound card and a very cheap microphone.
The software I use: Win95, Borland Delphi 4.0 (by Borland, Win95's Sound Recorder, GoldWave 3.02 (by Chris Craig), Paint Shop Pro 5.0 (by Jasc Software), Microangelo 2.1 (by Impact Software).

» Chapter 1: Acquiring images

Let's start by getting the scans of the videogame.
The first thing to consider is that the game isn't flat at all, so the scanner must have some kind of 3D object detection feature turned on, otherwise it won't bring good pictures of the LCD screen. Actually most of the recent scanners do have this feature.

Now let's choose the DPI setting of the scans.
Remember: save scanned images in 24-bit bitmap format, so they won't lose their details! You'll have to convert them to JPG or GIF format just at the very end of the coding phase!
Most of the users of these simulators have an 800x600 resolution setting for their desktop. So your image shouldn't be wider than that. Anyway, that depends on the dimension of the handheld game.
For example, my Motor Cross Simulator's background picture is more than 800 pixels long, but actually the LCD screen is MUCH smaller! You may play the game at 640x480 or 800x600 and you'll still have a good comprehension of the handheld.
I usually make scans at 80-150 DPI: my aim is to have the background 750 pixels wide or 580 pixels long. Anyway you're absolutely free to choose your favourite resolution, but notice that as the LCD screen comes bigger, your sprites will have better quality.

OK, let's scan the game now.
Two scans are usually enough for most games. Do the first scan with the game turned off (to scan the background of the LCD screen) and the second scan with the game turned on (to get the sprites).
Place the handheld on the scanner glass, and make the first scan. Now proceed to the second scan: the one with the sprites turned on.

LCD screens usually have a polarizing filter, which makes the sprites have some kind of "direction" to see them best. Place the handheld game so that the light of the scanner enlightens the upper side of it (this will make the light source come from the right direction to see the sprites the best way!).

Now try to get ALL the sprites turned on.
Most games have an ACL button, which is used at the factory to check whether or not the screen works fine. That button usually turns all LCD sprites on for a while or for many minutes.
If your game has an ACL button, it will probably be easier to scan all the LCD sprites at once.
But in case there is no ACL button, or if that button turns the sprites OFF (as for Las Vegas from Bandai), you'll have to work harder to take pictures of all the objects: more scans will be needed and then you'll have to join all the images together to obtain a fully detailed screen (use a drawing tool as Paint Shop Pro for retouching; MS PaintBrush is fine too).
Some handheld games show all of their LCD set by pushing ALL buttons at once; you may use some adhesive tape to keep all buttons pressed while scanning the screen.
Otherwise you may try to cause a CPU failure by inserting/taking the batteries out of the game repeatedly: the CPU stops operating, and usually many sprites are shown at once!

Now check out your scans. Are they detailed enough? If so, then continue to chapter 2, otherwise read below.
Sprites may seem too much confused and mixed to the background. If you feel that these images are not useful, open the handheld and manage to place a white rectangular paper between the backdrop and the LCD screen, so you'll see your sprites on a white background, and you'll get MANY more details!
If the sprites' colour is not fully black or dark gray, then the polarizing filter may be "out of order". Go to a photograph shop, buy a new one and replace it.
Then make a new scan (or more), keeping the same DPI setting as for the previous images.

If the game works with LEDs (or VFDs) and not with LCDs, this procedure won't work at all: the light of the LEDs will disturb the scanner and you'll get messed graphics. Use a digital camera instead.
Then proceed to the graphic retouch.

» Chapter 2: Retouching the scanned images

Open all of your images with any drawing tool and check them out again.
Your aim is to obtain TWO images:
1) a "background image of the game turned OFF, having XxY resolution;
2) a "sprites" image of the game turned >ON, having the same XxY resolution.
This means that you'll have to take the background image and place all of the sprites on it, (be sure that they are placed in the right position!); then this "merged" image will be used as source for sprites and their relative position.

Now get the colour of one sprite ("dropper" tool with Paint Shop Pro) and note its properties onto a paper sheet: this becomes your reference colour for all sprites. Then take the "pen" tool and retrace all the contours for all of the sprites. This may be the longest and most boring job, but the result is guaranteed!

After tracing each contour, "fill" the sprite with the same colour, but you may prefer to use a slightly darker colour for the inside and a lighter colour for the contour (or vice-versa). That's your choice.

When all sprites have been retouched, proceed and trace a rectangle around the borders of the LCD screen; then copy that rectangle and its content to clipboard. Finally paste as "transparent selection" to the background image, placing the rectangle in the correct position!

Now you can save this image as a kind of repository for all of your sprites.

At this point, you'll have TWO background images: the former having no sprites on it (let's call it BASE.BMP and the latter having the entire LCDset on it (let's call it SPRITES.BMP).

Next step is getting single files for sprites: one image per each sprite.
Select a sprite, make an "image crop" and then downgrade the colours palette to TWO (or 16, depending on how many colours you'll need for your sprites). You'll obtain a black & white image. Now edit the current colours palette and insert your sprite reference colour (look at your paper sheet). Then finally let your sprite have that colour, then save the image as a 1-bit (or 4-bit) bitmap (requires less memory than an 8-bit JPG or GIF!). White (border) colour will be considered transparent by Delphi, and the sprite only will be visible over the background!

Repeat this procedure per each sprite, and save all sprites images in a single folder.
You'll also need the entire numbers set in LCD format: take an "8" and make combinations with all the LCD lines, until you get all 10 numbers (and, maybe, some letters). Save all of these images too.

UPDATE (Aug 23rd, 2000): Robert Kacsich, author of the great "Coleco Head to Head" and "Neko Don Don!" simulators, sent me a small article to show me a different retouching process, which he uses for his Visual Basic simulators. Check it by clicking here.

Now you can work on sounds...

» Chapter 3: Getting and cleaning beeps

You'll have to use your microphone now.
First you'll have to select the recording volume. I usually use a quite high recording volume and the "+20db" option disabled. Make some tries and then choose...
Turn the handheld game on and begin a new game. Place a microphone by the game speaker and start recording (Windows' Sound Recorder will do) at 44Khz, 16-bit, stereo quality.
Try to let the game play all of the sounds: game-start music, in-game beeps, mistake music and game over. There may also be a few bonus musics. Record them all.

Now play the recorded sounds and check them out. If the WAV file's volume is too low, you may pump it up until it reaches a suitable volume level, but keep an ear to the quality anyway.
Now you can proceed and downgrade the sound quality. This depends on the quality of the game's sound. If you're simulating a stereo game... well, your WAV files must be stereo, otherwise choose the sound quality by yourself.
I found that 22Khz, 16-bit, mono is a good quality. But if a lower quality sound seems good anyway, downgrade the WAV file again and you'll save MUCH more memory.

Then proceed with the sound cleaning, using a simple tool as GoldWave or CoolEdit. Trim the main sound sequences and you'll obtain a few WAV files. Each WAV file must contain one beep only or an entire music; but there must not be silence between the beginning of the WAV file and the beginning of the music, otherwise sounds won't be synchronized to the game!

Take note of the duration of each sound: this is useful to measure the speed of the game!
Example: record some beep-beep's at the very beginning of a game; then record some more beep-beep's after five minutes. If the game's speed has increased, you'll measure both two WAV files' length and you'll get informations about the routines which make the game become harder. You should also use this kind of procedure to understand which differences there are between "game A" and "game B". That's cool, isn't it?

Now you're ready to proceed with Delphi.

» Chapter 4: Setting the main form

Before getting started, let's set the scaled property of your form to "false", so it won't be resized by Windows if you use the "big fonts" setting; then use a 96DPI resolution. Don't set the formstyle to "resizable" and then make the maximize and minimize system icons disappear from the main bar menu! By doing so, you'll be sure that the form will always be viewed the proper way!

Place your BASE.BMP image in the form, and let the form's client height and width have the same size as the image.
Now you can place all sprites on the base image. Open SPRITES.BMP with a drawing application (Paint Shop Pro will do), and get infos about the coordinates of each image; then place all of the LCD sprites' images onto the base image over Delphi's form, and give them the same coordinates of the sprites in SPRITES.BMP. I hope I've been clear enough.

You may want to simulate the pressing of the buttons by using a graphic effect. You'll have to get a piece of BASE.BMP (containing the button only), select the button shape only, and save it as JPG (let's call it BUTTON1.JPG) (no quality loss) as a separate image: you'll use it in an Image.OnMouseDown procedure.
Then consider BASE.BMP again and increase or decrease that button's lightness (your choice), then overwrite this image to the original one, and load it into Delphi again.
Now place BUTTON1.JPG over the background image: it will cover the enlightened (or darkened) button on the background image.

You may also want to let the form be dragged around your desktop by clicking on it: make a Form.OnMouseDown and a Form.OnMouseMove procedure to manage this. These procedures MUST be associated to EVERY sprite in the LCD screen and to the background graphics, but NOT to buttons or switches!

» Chapter 5: Starting the game

You'll need many global variables: time/demo/game modes, score, hiscores, lives left, current level; but you'll also have to define some variables to enable/disable controls (depending on game events) and to make the simulator understand whether you're playing or the game is in "demo" or "time" mode.

You'll have to place ALL of the initializations required in the Form.OnCreate procedure:
1) you'll have to set all arrays of TImage (and of Integer, of course) if you use any;
2) make each MediaPlayer component load one WAV file only and keep it allocated in memory: you'll need many MediaPlayers, wasting some Kbytes, but you'll save MUCH time during gameplay, as the simulator won't access your HD anymore!
3) initialize all of the variables regarding controls and time/game modes.

Create a few procedures to simulate all buttons presses, then start managing with timers.
Begin with the "game start" procedure, then proceed to the movements procedures.

» Chapter 6: Timer components

The Timer component is one of the most important resources for this kind of programming.
A timer executes a certain amount of operations (the ones included in its OnTimer procedure) at every certain amount of milliseconds (declared previously).
For example, if your form has a timer called "Timer_A", having an interval property set to 400, and a procedure like this:

  procedure Timer_ATimer (Sender: TObject);
  begin
    Img_LeftSprite.visible := not Img_LeftSprite.visible;
  end;

the result is that at every 0.4 seconds the image called "Img_LeftSprite" will shift from visible to invisible and vice-versa repeatedly.

Remember: timers can be active or inactive, depending on what you wish to do with it. Also remember that the interval property can be redefined every time you want, letting you use a single timer component to make many variations to your routines!
Anyway, for a handheld simulator you may need to use up to 20 different timers or even more!

» Chapter 7: MediaPlayer components

If you wish to include wave samples of the original game sounds, this resource becomes necessary.
You'll need many MediaPlayers: my advice is to create one mediaplayer object per EACH sound sample.
In fact if one MediaPlayer component shares more wave samples, your application will need to load the .wav file suddenly before playing it, making the game call your HD many times during game playing! This will certainly make your simulator MUCH slower!

You must hide the MediaPlayer components by setting their "visible" properties to false: seeing them is not useful at all!

Make your Form.OnCreate procedure load and open all wav files at once:

  MPlay_MusicStart.FileName := '.\SOUND\START.WAV';
  MPlay_MusicStart.Open;

  MPlay_MusicBeep3.FileName := '.\SOUND\BEEP3.WAV';
  MPlay_MusicBeep3.Open;

and so on...

Then you'll just need to place instructions like

  MPlay_<????>.Play;

where <????> means the reference name to the MediaPlayer in your in-game procedures. Easy isn't it?

» Chapter 8: Moving your character's sprite

First, set your form's keypreview property to TRUE, otherwise the Form.OnKeyPress, Form.OnKeyDown and Form.OnKeyUp procedures won't work at all. You need these procedures to manage the movement of your character's sprite.

You may either use the Form.OnKeyDown and Form.OnKeyUp events or the Form.OnKeyPress one only, depending on the game's specifics.
I'll show you the former method of the two.

The Form.OnKeyDown procedure must contain ALL of the movement routines; if your sprite can just move from left to right and vice-versa, your procedure will include something like this:

  if (GameStarted = true) and (Controls = true) then
    Controls := false; // disables controls until key is released

  if key = VK_LEFT then
    if Position > 1 then
      begin
        Char_Sprite[position].visible := false; // hides the "old-positioned" sprite
        Position := Position - 1;               // updates the sprite's position
        Char_Sprite[position].visible := true;  // shows the "new-positioned" sprite
      end;

  if key = VK_RIGHT then
    if Position < 3 then
      begin
        Char_Sprite[position].visible := false; // hides the "old-positioned" sprite
        Position := Position + 1;               // updates the sprite's position
        Char_Sprite[position].visible := true;  // shows the "new-positioned" sprite
      end;

The Form.OnKeyUp procedure will just set the Controls variable to true:

  if (GameStarted = true) and (Controls = false) then
    Controls:=true;

» Chapter 9: LCD numbers display

The conversion from pure integer numbers to a sequence of LCD numbers is quite difficult, and requires a good knowledge of some arithmetic functions as mod and div.

The first thing you must do is to place the numbers' images anywhere on the form, and then hide them (ex: Number5.visible:=false).
Then place some EMPTY images where the LCD numbers must appear (ex: NumberPosition2: TImage)
Every time some number must appear on the LCD display, a procedure like this will be necessary:

  NumberPosition2.picture := Number5.picture; // (*)

The best way to call images' pictures is by associating them to an array of TImage and then by indexing them.
You probably have called the numbers images as Number1, Number2 and so on.
Declare a Number_Array: array [0..9] of TImage in the declariation section, then associate each number-image to an element of that array in the Form.OnCreate procedure.

procedure TForm1.FormCreate(Sender: TObject);
  begin
    Number_Array[0] := Number0;
    Number_Array[1] := Number1;
    <...>
    Number_Array[9] := Number9;
  end;

so the previous instruction (*) becomes

  Number_Position2.picture := Number_Array[5].picture;

Next step is splitting the score in its units, tenths, hundreds and so on: learn how to use the mod, div, IntToStr and StrToInt functions: that's all.

» Chapter 10: Conclusions

I wish you enjoyed this small tutorial. Well, I know that my English is all but perfect, and I wish I've been clear enough with my explanations.
Actually I discovered that there are still a great amount of procedures I could explain to you, but I believe that this tutorial is enough to help you to at least start in the best way.
Experience and a good comprehension of the Delphi Help will teach you the right way to proceed.

If you have any questions feel free to ask.

Good luck to you, young programmer!