Mscape Help


How To: Make a portable game

Portable games are mediascapes that can be played anywhere. The usual mechanism is to get the user to place the regions needed in the game. This tutorial will take you through a step by step account of how the game "Stamp the Mole" was created. It is a first hand account so that you can get an idea of the thought process used and the steps that are taken.

Making the Stamp the Mole Game

Coming up with the idea.

I wanted to make a simple game to act as a tutorial. I also wanted to make it portable so that it can be played anywhere. I thought of different ideas that used the simple game mechanic of moving between different regions. The first idea I had was to do a physical version of “low to high” where you had to remember the positions of the lowest to the highest numbers flashed on the screen by walking to their positions. However this seemed a bit too complex for a simple first game. I then thought of the fairground mole bashing game where moles pop up from holes and you hit them with a rubber mallet. I thought it might translate well to a physical game as you can walk to a region and stamp on a virtual mole. So that is what I am going to do.

Designing the game.

I thought I would just have 3 regions as it is a simple game, I don’t want it to take too long to set up and you want to be able to move quite quickly. I thought of having cute mole graphics – but I am not a graphics person and it would take too long so I will stick with something very basic using the map displayer and the ability to move a pin around on it. So I will have a very simple pin that says “THE MOLE IS HERE” which will move from region to region and you have to get to that region and stamp. I have decided the goal of the game is to stamp on 10 moles to win otherwise you loose and the moles will dig up your garden. I will have a timer so that if you get to the mole in time it is a success, if not you fail. Each time you succeed the timer will decrease by 2 seconds. My initial thoughts are to try it with a time of 30 seconds to get to the mole decreasing by 2 seconds so that by the end you only have 10 seconds to get to the mole. I will have to test this out and maybe change the timings as a result of testing. So now I think I have my overall game design worked out I will start coding!

In the maker.

I have opened up the mscape maker. I know this is going to be a portable game so I don’t need a map with real world co-ordinates. But I do need a map to put regions on. So I do the following

Make a blank image map.

Select Tools – Create Map From Image In the dialog box that say Choose the source of your co-ordinates. I choose Don’t bother with co-ordinates I then import an image which is just a completely white jpeg (320 * 320 pixels big). This is because I want the pin to show up on a white screen so I don’t want a fussy background picture.

I then save this as a maplib called gamearea.maplib. ( I happen to have a directory called maplibs that I put all of my mscape maplibs.).

Import the map into the maker.

Now I want to use the maplib I just made so I do the following Select the Map icon (top toolbar of the maker) – On the dialog box that says How do you want to import the map? I choose From file. I then navigate to where I saved the maplib and choose gamearea.maplib.

Add the three mole regions.

Now I want to add the three regions that will be where the moles pop up. I click on the Circle icon and then change the properties of the circle to be Name : MoleRegion1 Radius : 5 – the radius is in meters so this will give me 10 meter diameter circles. I add two more circles and call them MoleRegion2 and MoleRegion3 and set their radius to 5 as well. I choose circles because they are the easiest to set their co-ordinates to move them to my current GPS location, they have a center point X,Y position and a radius.

Add three buffer regions.

Now I need 3 buffer regions to help me when I ask the user to place the mole regions. I don’t want the user to place the regions too close together or on top of each other so I am going to add some logic which tests whether the user is in a buffer region and if they are clear of a buffer region then I will let them add a mole region. I add three circles and change their properties so that they are a light grey color with name buffer1, buffer2, buffer2 each with a radius of 10. My screen now looks like this (the map is zoomed in so that you can see the regions)


pic1.gif

Make the fixed images

Now I need to make a number of screens for the user interface - to place the mole holes, prompt the user, introduction, win and loose etc. I make these screens as 320*240 pixel jpeg images – as I have decided to make this game landscape. (If it was a portrait game I would have made them 240*320 pixels big).

I was tempted to get carried away with some nice graphics – but I resisted doing that now as I know it is important to test the game. When it works it is really easy to replace the images with more exciting ones.

Now I import these images into the mediascape. I click on the Image icon. Navigate to the stamp the mole folder and select all of the images. They now appear in the object list in my mediascape.

Save Mediascape

I have done a fair amount so it is now time to save my mediascape. I click on File - Save as. A Mediascape Description dialog box pops up.


pic2.gif

I set the orientation to Landscape and make sure that Allow Debugging is checked. This is so that when I go out to test it if anything is wrong I can get to a debug screen and look at the values of variables. I save the mediascape in the stamp the mole folder. Now at this stage the urge to have a cute picture of a mole is so strong that I go and ask my friend Ben to draw one for me – one for the mediascape icon image and one with a mole about to be stamped on and a win and loose image. Once he has drawn it I will scan it in (or take a photo of it) and make the image size 320 * 240 so that it does not exceed the memory size of my iPAQ.

Add “welcome – tap screen to continue” when the mediascape first loads.

When the mediascape starts up I want the welcome screen to show and for the user to tap the screen to continue. I click on the Mediascape object. In the script OnLoaded event I add the following code welcome.Show(); I do this by dragging the welcome object over to the script window. This saved me typing in the name. (I had to be careful not to actually select the welcome object as this would change the script window – it’s a select and drag without clicking on the object). Then after the name I put the decimal point and this brought up a list of auto complete actions and I chose Show. Now as I want the whole screen to be live so that the user can tap anywhere I add a hotspot and leave the size at their defaults as this will cover the whole screen. I right click on the welcome image object and select add hotspot.

Add GPS code for detecting a fix.

In the script window associated with the hotspot I write the following code
if (GPS.HasFix == true)
   placemolehole.Show();
else
   img_GPSfix_personal.Show();
As the game will not work unless the GPS is working well then whenever the GPS does not have a fix I want to put up the “Waiting for GPS” screen. I select the GPS object. There are a number of tabs. In the OnGotFix tab I add img_GPSfix_personal.Hide(); In the OnLostFix tab I add img_GPSfix_personal.Show();

Add the code to place the regions

Now I need to add the code which prompts the user to place the regions. I have done this before in the Doubloons game so I open that up in another window so that I can copy the code.

First I add a variable to track how many holes I have placed. I scroll down the object list to the State object. I right click on State and add number. I change the name to HolesPlaced and leave the value as 0. I also add two more number state variables (Right click on State – Add number) I make their names currentX and currentY. I then select the gamearea object and enter the following code in the script window

if (placedStatus.Value != "allplaced")
{
   currentX.Value = x;
   currentY.Value = y;
   if ((buffer1.IsInside == false) &&
          (buffer2.IsInside == false) &&
          (buffer3.IsInside == false) )
   {
   // clear of otherholes so show button
   tooclose.Hide();
   placemolehole.Show();
   }
   else
   {
   // not clear of islands show map displayer
   // MapDisplayer.Show();
   tooclose.Show();
   }   
}


pic3.gif

Every time the GPS location changes this event will get called. If you have not yet placed all the holes it will copy the GPS reading x and y into our variables x and y. It also tests if you are inside a buffer region or not and if not is puts up the placemolehole dialog box.

Add the Place region code.

The placemolehole image has a button on it. We need to know the pixel co-ordinates of the top left point of the button and the image width to define a hot spot on the iPAQ screen. To do this I open up the image in the Paint program. As you move the cursor around the image the pixel co-ordinates show up in the bottom of the window. Make a note of the co-ordinates of the top left edge, the top right edge and the bottom left edge.


pic4.gif

For this image they are Top Left (84,116) Bottom Left (84,192) Top Right (208,116). This makes the button area 124 pixels wide (208 minus 84) and 76 pixels high (192 minus 116).

Right click on the placemolehole image object and choose Add Hotspot. Select the Hotspot and fill in the parameters. Height 124, Width 76, X 84 and Y 116 Add the following code

switch (placedStatus.Value) 
{
case "none" :
   // set the first mole hole and its buffer
   MoleRegion1.X = currentX.Value;
   MoleRegion1.Y = currentY.Value;
   buffer1.X = currentX.Value;
   buffer1.Y = currentY.Value;
   placedStatus.Value = "one";
   break;
case "one" :
   // set the first mole hole and its buffer
   MoleRegion2.X = currentX.Value;
   MoleRegion2.Y = currentY.Value;
   buffer2.X = currentX.Value;
   buffer2.Y = currentY.Value;
   placedStatus.Value = "two";
   break;
case "two" :
   // set the first mole hole and its buffer
   MoleRegion3.X = currentX.Value;
   MoleRegion3.Y = currentY.Value;
   buffer3.X = currentX.Value;
   buffer3.Y = currentY.Value;
   placedStatus.Value = "three";
   break;
}
This code basically tests to see what stage of hole placing you are at and then setting the regions and buffer x and y to your current position. We then move the stage to the next hole. After I added the code I did a check for syntax errors by clicking on the green tick. I then tested the mediascape in the tester. I clicked around on the screen to simulate GPS position and I pressed the button. The regions move to where my position is and it appears to work as I intended. Now need to add in more logic to start the game after all regions have been placed.

In the mean time Ben has finished the mole pictures. They are great! So I have imported them as well.

Add the Map Displayer and Pin.

The map displayer automatically displays your current position on the screen. Pin objects have a property to display on the map displayer. I will use this to programmatically display and hide a pin with a label “THE MOLE IS HERE” which will be set to the center point of the hole regions.

I right click on the Tools object and choose add Map Displayer. I set the Place Name property of the mapdisplayer to be gamearea.

I right click on the map in the maker and choose Add Pin. I change the name to THE MOLE IS HERE.

Add timers.

I add two timers. One for showing a Watch for the moles screen and the other for time to find the mole. I right click on Tools and choose add Timer. Then I right click on Timer and add Alarm. I set the name to watchForMoles and the period to 10. I right click on Timer again and add Alarm. I set the name to molesOut and the period to 30. The periods are in seconds so this should allow 10 seconds to show the prompt and then 30 seconds to get to the mole.

Now I go back to the OnTapped code of the Hotspot02 in the placemolehole object. After the placedStatus.Value = "allplaced"; line I add the following two lines of code Mole.Show(); watchForMoles.Start();

This will show the mole picture and start the 10 second timer.

Random function to set the mole pin

I now need to work out how best to implement my design for randomly choosing the hole that the mole should pop up from. Bascially I need to know which hole I am at currently, and then randomly choose one of the others. I know how to generate a random number by declaring a local Random variable r which if you call next with a number generates a random number in that range so the following code Random r = new Random(); r.Next(10); generates a number between 0 and 9. I add the following code to the OnRing function of the WatchForMoles Timer.
// add logic to decide which region to set the mole pin
MapDisplayer.Show();
Random r = new Random();
//r.Next(2) generates a random number between zero and 1
switch (currentHole.Value){
   case "MoleRegion1" :
   if (r.Next(2) == 0) {
      currentHole.Value = "MoleRegion2";
      THE_MOLE_IS_HERE.X = MoleRegion2.X;
      THE_MOLE_IS_HERE.Y = MoleRegion2.Y;
      }
   else {
      currentHole.Value = "MoleRegion3";
      THE_MOLE_IS_HERE.X = MoleRegion3.X;
      THE_MOLE_IS_HERE.Y = MoleRegion3.Y;
      }
   break;
   case "MoleRegion2" :
   if (r.Next(2) == 0) {
      currentHole.Value = "MoleRegion1";
      THE_MOLE_IS_HERE.X = MoleRegion1.X;
      THE_MOLE_IS_HERE.Y = MoleRegion1.Y;
      }
   else {
      currentHole.Value = "MoleRegion3";
      THE_MOLE_IS_HERE.X = MoleRegion3.X;
      THE_MOLE_IS_HERE.Y = MoleRegion3.Y;
      }
   break;
   case "MoleRegion3" :
      if (r.Next(2) == 0) {
      currentHole.Value = "MoleRegion1";
      THE_MOLE_IS_HERE.X = MoleRegion1.X;
      THE_MOLE_IS_HERE.Y = MoleRegion1.Y;
      }
   else {
      currentHole.Value = "MoleRegion2";
      THE_MOLE_IS_HERE.X = MoleRegion2.X;
      THE_MOLE_IS_HERE.Y = MoleRegion2.Y;
      }
   break;
}

THE_MOLE_IS_HERE.ShowOnMapDisplayer = true;
MapDisplayer.Show();
molesOut.Start();
That sets the pin to a random hole and if the map displayer is shown will display that pin because the ShowOnMapDisplayer? property is true. It then displays the MapDisplayer and starts the timer to get to the mole.

Now it is time to save and test on the tester. Seems to work – I think I will need to add some sound effects and audio later. Now we shall add code to the molesOut timer to implement what happens if you don’t get to the mole on time. I add the code YouLose.Show(); to the OnRing Event. This will be the end of the game – I will probably need to add an audio that says – oh dear you did not get to the mole on time so you have lost and your garden will not be over run with moles. I shall test the game with it like this. The alternative implementation I could try is to let you always have 10 tries and if you don’t get all ten then you loose. With this implementation the first time you fail the game ends.

Add logic for stamping the mole.

If you do get to the mole on time we want to show the STAMP screen and then decrement the timer and go back to watch for moles. In the OnEnter event of MoleRegion1 I add the following code

if (currentHole.Value == "MoleRegion1" && placedStatus.Value == "allplaced")
{
   MoleFoot.Show();
   molesOut.Stop();
   molesOut.Period = molesOut.Period - 2.0;
   watchForMoles.Start();
}
I copy the code and paste it into MoleRegion2 and MoleRegion3 and change the test to check the currentHole.Value to the appropriate region. Another quick test on the tester shows this is basically working.

Now I need to add a variable to keep a count of the number of stamps so that you end the game with ten stamps.

I right click on State add a Number and change its name to molesStamped and leave the value as 0.

Now I modify the code in MoleRegion1 to say

if (currentHole.Value == "MoleRegion1" && placedStatus.Value == "allplaced")
{
   MoleFoot.Show();
   molesOut.Stop();
   molesStamped.Value = molesStamped.Value + 1;
   if (molesStamped.Value == 10) {
      // You have won
      YouWin.Show();
   }
   else {
      molesOut.Period = molesOut.Period - 2.0;
      watchForMoles.Start();
   }
}
And edit MoleRegion2 and MoleRegion3 as well.

Now I try it on the tester. Hurrah it works. Time for my first outside test. So I will copy the whole directory over to my SD card, pop it into my iPAQ and go outside to test.

Not too bad as a first test – even though I lost! What I found was the region size is probably about right. The zoom level of the map displayer was not in enough and the MOLE IS HERE pin was a bit ambiguous as to which hole was active. I will modify the mediascape so that there are three pins – one for each hole you placed – and I will programmatically make them visible or invisible rather than move the one pin.

Aesthetically I need to make some of the images have a landscape orientation so that they look nicer. I also need a hole has been successfully placed image to show before the prompt to walk and place another.

I shall also try to make some audio prompts and sound effects. I have a digital recorder so I can easily record my own audio files. Add 3 pins – change the logic. I add three pins to the mediascape and name them Mole_at_Hole_1, Mole_at_Hole_2, Mole_at_Hole_3. I now need to change the logic of the watch for moles so that instead of moving one pin I make the right pin visible. I change the logic to this

// add logic to decide which region to set the mole pin
Random r = new Random();
//r.Next(2) generates a random number between zero and 1
switch (currentHole.Value){
   case "MoleRegion1" :
   Mole_at_Hole_1.ShowOnMapDisplayer = false;
   if (r.Next(2) == 0) {
      currentHole.Value = "MoleRegion2";
      Mole_at_Hole_2.ShowOnMapDisplayer = true;
      }
   else {
      currentHole.Value = "MoleRegion3";
      Mole_at_Hole_3.ShowOnMapDisplayer = true;
      }
   break;
   case "MoleRegion2" :
   Mole_at_Hole_2.ShowOnMapDisplayer = false;
   if (r.Next(2) == 0) {
      currentHole.Value = "MoleRegion1";
      Mole_at_Hole_2.ShowOnMapDisplayer = true;
      }
   else {
      currentHole.Value = "MoleRegion3";
      Mole_at_Hole_3.ShowOnMapDisplayer = true;
      }
   break;
   case "MoleRegion3" :
   Mole_at_Hole_3.ShowOnMapDisplayer = false;
   if (r.Next(2) == 0) {
      currentHole.Value = "MoleRegion2";
      Mole_at_Hole_2.ShowOnMapDisplayer = true;
      }
   else {
      currentHole.Value = "MoleRegion1";
      Mole_at_Hole_1.ShowOnMapDisplayer = true;
      }
   break;
}

MapDisplayer.Show();
molesOut.Start();
I no longer need the MOLE IS HERE pin so I want to delete it. But first I want to check it is not used in the mediascape. I right click on the MOLE IS HERE pin and choose Find uses of “THE MOLE IS HERE”. A dialog box pops up with an empty list so I know it is not used anywhere and it is safe to delete.

I delete it and check syntax (green tick) . All good so I test it on the tester. In the test I realize I have not yet added the code to move the pins to where you place the holes. I edit the code in Hotspot02 of the placethemole image. I add the two lines to set the X,Y of each pin in each of the region placements. The amended code now looks like this

Mole_at_Hole_1.ShowOnMapDisplayer = false;
Mole_at_Hole_2.ShowOnMapDisplayer = false;
Mole_at_Hole_3.ShowOnMapDisplayer = false;
// add logic to decide which region to set the mole pin
Random r = new Random();
//r.Next(2) generates a random number between zero and 1
switch (currentHole.Value){
   case "MoleRegion1" : {
      if (r.Next(2) == 0) {
         currentHole.Value = "MoleRegion2";
         Mole_at_Hole_2.ShowOnMapDisplayer = true;
         }   
      else {
         currentHole.Value = "MoleRegion3";
         Mole_at_Hole_3.ShowOnMapDisplayer = true;
         }
      }
   break;
   case "MoleRegion2" :{
      if (r.Next(2) == 0) {
         currentHole.Value = "MoleRegion1";
         Mole_at_Hole_1.ShowOnMapDisplayer = true;
         }
      else {
         currentHole.Value = "MoleRegion3";
         Mole_at_Hole_3.ShowOnMapDisplayer = true;
         }
      }
   break;
   case "MoleRegion3" :{
      if (r.Next(2) == 0) {
         currentHole.Value = "MoleRegion2";
         Mole_at_Hole_2.ShowOnMapDisplayer = true;
         }
      else {
         currentHole.Value = "MoleRegion1";
         Mole_at_Hole_1.ShowOnMapDisplayer = true;
         }
      }
   break;
}

MapDisplayer.Show();
molesOut.Start();
I also set the zoom level of the map displayer to 10.

Time for another test. Happy with that now to record some audio.

I record all my audio on my dat recorder, copy the files onto my PC and edit them with Audacity. I save them as mp3 files and now need to import them into my mediascape.

Add audio to my mediascape.

On the OnLoaded event of my mediascape I add welcome1.Play(); to play my audio welcome when the mediascape starts up.

I change the code in the Hotspot01 of the welcome screen so that instead of showing the placemolehole image I play the placehole audio.

I cut the placemolehole.Show(); code and replace it with placehole.play(). Then in the placehole audio OnStarted event I paste placemolehole.Show(); This means that when the audio starts playing the image will show. In the OnTapped event of Hotspot02 I add moleplacedok.Play(); to cases none and one. This means that when you tap the screen and place a hole you will hear a success message.

I also add moleplacedok.Play(); in the case two part of the code so that when you have placed them all you hear that you have placed them all.

I add placeanother.Play(); to the OnFinished event of the moleplacedok audio.

I add watchscreen.Play(); to the OnFinished event of the gothimaudio so that as soon as that audio finishes you are told to watch the screen.

I add molealert.Play(); just before I display the mapdisplayer in the OnRing event of watchForMoles timer.

I add youwin1.Play(); to the win condition code in the OnEnter event of each of the mole regions.

I add gothim.Play(); to the else condition code in the OnEnter event of each of the mole regions.

I add watchscreen.Play(); to the OnFinished event of the gothim audio.

I test things on the tester and when I am happy I try it again on the iPAQ.

It is mostly good – I get an odd behaviour after I loose that I then still get the mole. I realize I have not put a test in the region code to see if the game has ended. So I add a true/false variable – right click on State. And call it endgame. I set it to true in the region code and in the OnRing event of molesOut (when you loose). The region code now looks like this

if (currentHole.Value == "MoleRegion3" 
      && placedStatus.Value == "allplaced"
      &&       endgame.Value == false)
{
   MoleFoot.Show();
   molesOut.Stop();
   molesStamped.Value = molesStamped.Value + 1;
   if (molesStamped.Value == 10) {
      // You have won
      youwin1.Play();
      YouWin.Show();
      endgame.Value = true;
   }
   else {
      gothim.Play();
      molesOut.Period = molesOut.Period - 2.0;
      watchForMoles.Start();
   }
}
A couple more tests outside and then I am finished!

I then upload the mediascape to the mscapers website and attach these notes to the description.

Ready to
get started?

Download Mscape Suite Version 2.1 | 10.5 MB

Ask the Mscape Community

Forums