Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

29. August 2012

 

As the title says, I have inserted a new book into the Unity book list, 3D Games Monetization with Unity and Leadbolt. I do however use the word book in the loosest terms possible, as it is in electronic format only and it weighs in at a mere 37 pages.

 

That said, it also weights in at a mere 3$, so there is that…

 

I will admit, before discovering this book, I had never heard of Leadbolt. they are a mobile ad provider in the vein of adMob, but with a world more options than simple banners.

 

 

Ads can be added at the application entry point, while running and at the exit point.

 

I personally HATE ads in mobile games, and gladly pay a premium for an ad free version ( which sadly most developers do not embrace, at least not on Android ), but perhaps ads in a different format will make a difference.

 

Anyways, if you are a Unity developer and are interested in monetization, you have a new book to check out.

 

It is my intention to keep the list as comprehensive as possible, so if I have missed a title or you are the author of an upcoming title, please let me know.

General ,

28. August 2012

 

Cocos2D-html is an HTML5 port of the popular Cocos2d-x library, enabling you to make games that run in a browser, using a syntax that works virtually unchanged on a number of platforms.Cocos2dHTML5

 

You can download the source as a zip right here.

 

The project is also available on GitHub.

 

 

In anticipation of this release, the Cocos2D tutorials on this site where all updated to the new API, so should work unchanged.  There were some pretty major changes in the API as detailed here.

 

 

Finally, there have been a series of Cocos2D related books published that could prove helpful in puzzling things out. ( Of course, start with the tutorials! Winking smile ).

News

28. August 2012

 

This guide will run through the process of creating and building an Android host for use with Moai.

 

There are a number of installs and configurations you need to perform before you can build Moai for Android.  If you need details on any of the individual steps, click the link to jump to more details on that part of the process.  If you think it seems like quite a list… you are right, it is!  Fortunately you only have to do it once!

 

In order to build the Android host you need to:

 

Install and configure all of those items before continuing these instructions.  Seriously, you need everything above, so install and perform every configuration step or the following is guaranteed to fail!

 

 

Creating an Android Host

 

Open a cygwin terminal

Change directory to where you want to install the Moai source code.  I am going to install to C:\, which under cygwin is /cygdrive/c, so:

cd /cygdrive/c

Now run git to download the newest Moai source code, enter:

git clone git://github.com/moai/moai-dev.git

Let git run, it will download and clone the most recent source code to the folder c:\moai-dev.  Make a cup of coffee, it might take a few minutes.

 

 

Now we want to build our Android host, to do so, change into the folder c:\moai-dev\ant\ and run the script make-host.sh.  You pass in the name of the  package you want created in Java form ( reverse url, com.yourdomain.yourappname ) like so:

cd /cygdrive/c/moai-dev/ant

./make-host.sh –p com.gamefromscratch.moai

It should run and complete without issue.  Should being the operative word, in my case I was actually getting a permission denied error on one the library files.  A quick chmod 644 permission setting on the file fixed that issue.  Once the script completes, it will have created a directory in the /ant folder called untitled-host.

 

 

In untitled-host, locate and edit the file settings-local.sh, locate the the line android_sdk_root and edit it to match the path to your android sdk ( note, SDK not NDK! ), mine looks like:

android_sdk_root=”/cygdrive/c/android-sdk”

Then scroll down to the section src_dirs and set it to the directory containing your Lua project, such as:

src_dirs=( "cygdrive/c/luasource" )

Save your changes and exit.

 

Now optionally edit settings-global.sh.  Most importantly, locate the line:

requires=( "miscellaneous" "adcolony" "google-billing" "chartboost" "crittercism" "facebook" "google-push" "tapjoy" )

and change it to just:

requires=( "miscellaneous"  )

 

Unless you specifically need to include those libraries.  Tapjoy and Facebook are currently broken though, so if you include them, you will have trouble later!  You can optionally set your app name, version number, icon names, etc at this point. (Actually, this part seems to be ignored anyways…)

Save settings-global.sh and exit.

 

Not type ( in the untitled-host folder ) :

./run-host.sh

 

So long as you didn’t get any errors, your project should now have been created. 

 

Loading and running the generated project in Eclipse

 

Fire up Eclipse.

Select the menu File->Import…

Select General->Existing Project into Workspace, like so:

image

 

Click Next.

 

Check Select root directory and navigate to c:\moai-dev\ant\untitled-host\build\project like so:

image

 

Click Finish.

 

As you can see, even though you said you didn’t want them, Facebook and Tapjoy are still included, and are still broken.

 

image

 

Right click and choose Delete for each one.

 

Once those are removed ( or you can optionally find and fix the external libraries they depend on instead of removing them. ), your application should build just fine.  Make sure your Android device is plugged in and has debugging enabled ( in the settings on the device ).  Right click your project, select Run As… Android Application

image

 

A few seconds later, your application should appear on your device.

 

The actual lua code for your application will be located in the lua folder within the assets folder.

 

image

 

Happy Androiding!

 

 

If these instructions don’t work for you, do not be surprised.

 

1- Moai is under active development

2- The whole Java build system is horrifically complex and exceedingly fragile

3- Eclipse is the devil

 

 

 

Installing Cygwin

 

Cygwin is a unix like environment for windows and is critical to successfully building the Android hosts with Moai.  First thing download setup.exe from here (direct link to exe).  Your browser may fight you a bit about downloading an executable directly.

 

Once downloaded, run setup.exe, saying yes to any security prompts.

 

Select Download from Internet.

image

Click Next.

 

Pick whatever directory you want to install to, I kept the default of c:\Cygwin. 

image

Click Next.

 

Next you need to pick the directory to download to, again I just went with the defaults:

image

Click Next.

 

Defaults again unless there is something odd about your internet connection:

image

Click Next.

 

Select the download location that is closest to you, then click Next:

image

 

 

The downloader will run for a few seconds.  You may get a prompt saying this is the first time you have installed Cygwin and be sure to check the documentation.  Simply click OK.  At this point, you will get a window asking you to select the packages to install, like so:

image

 

 

Install the devel selection of tools, simply click the icon beside the Devel tree and it will switch from Default to Install, like this:

 

NOTE: *** You don’t actually need the entire Devel tree and this process will take a really long time to complete ( two hours on my laptop ) if you select the full Devel tree.  However, selecting all developer tools guarantees that you get everything required as part of the build process.  You can experiment with selecting individual packages if you wish.

image

Click Next.

 

You will most likely get a prompt about resolving dependencies, like so:

 

image

This is normal, click Next.

 

 

Setup will now download all of the packages you have selected:

 

image

 

 

This process is not… short.  Have patience, lots of patience.  Have you considered picking up a new hobby?  Knitting perhaps?  Go for it!  You have plenty of time.

 

Cygwin installation is now complete.

 

image

 

 

You can always run setup.exe again if you want to enable or remove features in the future.

 

Cygwin is now configured.

 

Installing the Android NDK

 

Head over to the Android NDK page and download the appropriate file. I went with android-ndk-r8b-windows.zip, but this will obviously change in version name over time.

 

Once downloaded, open the archive and extract the folder inside to somewhere on your drive.  In my case the folder was called android-ndk-r8b and I extracted it to c:\.  After it is extracted, rename it to android-ndk.  There are 17,000+ files in that archive, so expect it to take a while to extract.

 

Later in the process, Moai will need to know the location of the NDK, specifically ndk-build.  The easiest way to make this file discoverable is to add it to your path environment variable, this can be configured via the command line:

 

setx PATH ‘%PATH;c:\android-ndk’.

 

The NDK is now installed.

 

 

Installing the Java JDK and set the JAVA_HOME environment variable

 

You need to have a Java JDK installed and configured.

 

Download the JDK from this website.  Chose whichever version you want, it shouldn’t matter.  There are some annoyances with using Android tools with Java 7 ( 1.7 ), so Java 6 may be the best choice for now.

 

Once downloaded and installed, be sure that JAVA_HOME is set to your install directory.  Mine for example is c:\Program Files\Java\jdk1.7.0_03

 

Once again, you can set this environment variable from the command line using the setx command.

 

 

 

Installing Apache Ant

 

Go here to the Apache Ant download page and download the zip file.  I selected http://apache.mirror.nexicom.net//ant/binaries/apache-ant-1.8.4-bin.zip.

Open the archive and extract the folder (apache-ant-1.8.4 in this case ) to a location on your drive.  I went with c:\ again.

 

Set the environment variable ANT_HOME and point it to this directory ( c:\apache-ant-1.8.4 in my case), you can do this from the command prompt with the command:

setx ANT_HOME c:\apache-ant-1.8.4

Like so:

image

 

Ant is now configured.

 

 

Installing the Android SDK, Eclipse and the Android Plugins

 

You can download the Android SDK here, which full instructions here.  Be sure to install at least the Android 2.2 ( Platform 10 ) platform as described here.

 

The first half of this guide covers the installation process for installing Eclipse.  You need to install Eclipse as well as the Google ADT to complete this process. Eclipse 3.7 or 3.8 will work, although might require a minor change during the install process.

Programming , ,

27. August 2012

 

A game isn’t much of a game if you can’t interact with it.  In this tutorial we are going to look at how to handle touch and click events with Moai.  This is however going to present a bit of a problem, you are going to need to have an Android or iOS device in order to test the touch events.  The code will still run in the Windows host, but you won’t be able to test touch events.

 

Speaking of the code:

 

screenWidth = MOAIEnvironment.screenWidth
screenHeight = MOAIEnvironment.screenHeight
print("Starting up on:" .. MOAIEnvironment.osBrand  .. " version:" .. MOAIEnvironment.osVersion)

if screenWidth == nil then screenWidth =640 end
if screenHeight == nil then screenHeight = 480 end

MOAISim.openWindow("Window",screenWidth,screenHeight)

viewport = MOAIViewport.new()
viewport:setSize(screenWidth,screenHeight)
viewport:setScale(screenWidth,screenHeight)

layer = MOAILayer2D.new()
layer:setViewport(viewport)

MOAIRenderMgr.pushRenderPass(layer)


sprite = MOAIGfxQuad2D.new()
sprite:setTexture("smile.png")
sprite:setRect(-200,-200,200,200)

prop = MOAIProp2D.new()
prop:setDeck(sprite)
prop:setLoc(0,0)
layer:insertProp(prop)

MOAIGfxDevice.setClearColor(1,1,1,1)

function handleClickOrTouch(x,y)
    prop:setLoc(layer:wndToWorld(x,y))
end


if MOAIInputMgr.device.pointer then
    MOAIInputMgr.device.mouseLeft:setCallback(
        function(isMouseDown)
            if(isMouseDown) then
                handleClickOrTouch(MOAIInputMgr.device.pointer:getLoc())
            end
            -- Do nothing on mouseUp
        end
    )
    MOAIInputMgr.device.mouseRight:setCallback(
        function(isMouseDown)
            if(isMouseDown) then
                MOAIGfxDevice.setClearColor(math.random(0,1),math.random(0,1),math.random(0,1),1)
            end
        end
    )
else
-- If it isn't a mouse, its a touch screen... or some really weird device.
    MOAIInputMgr.device.touch:setCallback (

        function ( eventType, idx, x, y, tapCount )
            if (tapCount > 1) then
                MOAIGfxDevice.setClearColor(math.random(0,1),math.random(0,1),math.random(0,1),1)
            elseif eventType == MOAITouchSensor.TOUCH_DOWN then
                handleClickOrTouch(x,y)
            end
        end
    )
end

 

Once again, we are building on our earlier example; and once again, we will not be covering those parts we already covered.  We are changing the functionality slightly.  Now in the event of a touch or left click, we are repositioning the happy sprite to the location the user clicked.  If the user double taps or right clicks, we change the background color… what can I say, not everyone loves white or hot pink. 

 

Here is the program in action:

image

 

 

Let’s take a look at the new code, starting from the top:

 

function handleClickOrTouch(x,y)
    prop:setLoc(layer:wndToWorld(x,y))
end

 

Touch and click events are two different events, but we want to share the same code when they happen, in this case a method called handleClickOrTouch.  It takes the x and y locations of the mouse cursor or finger that the touch/click happened at.  In the event of a touch, we simply want to move the happy face prop to the location of the touch.  First though, we need to translate the touch coordinates from window space to world space, which is accomplished with layer:wndToWorld().

 

if MOAIInputMgr.device.pointer then

MOAITInputMgr is a global object containing the various input devices that host platform supports.  Keep in mind, if your host does not support a given device, it will not exist in MOAIInputManager.  That is exactly what we are checking here, to see if device.pointer has been defined, which will only be defined if the host supports a mouse. 

 

The following types of input are *potentially* supported:

  • MOAIButtonSensor
  • MOAICompassSensor
  • MOAIJoystickSensor
  • MOAIKeyboardSensor
  • MOAILocationSensor
  • MOAIMotionSensor
  • MOAIPointerSensor
  • MOAITouchSensor
  • MOAIWheelSensor

 

The official documentation for MOAIInputMgr is completely empty, so if you are looking for more details, the course file MOAIInputMgr.cpp is perhaps your best source for more information.

 

Once we have determined that the host device does in fact support a mouse pointer, we run the following code:

    MOAIInputMgr.device.mouseLeft:setCallback(
        function(isMouseDown)
            if(isMouseDown) then
                handleClickOrTouch(MOAIInputMgr.device.pointer:getLoc())
            end
            -- Do nothing on mouseUp
        end
    )
    MOAIInputMgr.device.mouseRight:setCallback(
        function(isMouseDown)
            if(isMouseDown) then
                MOAIGfxDevice.setClearColor(math.random(0,1),math.random(0,1),math.random(0,1),1)
            end
        end
    )

 

First we register a callback function for mouseLeft, which takes a single bool parameter, indicating if the mouse button was pressed or released.  In the event that the mouse button was indeed pressed, we call the handleClickOrTouch function, passing in the mouse coordinates be obtain by calling MOAIInputMgr.device.pointer:getLoc().  We simply do nothing in the event of a mouse up, um.. event.

 

Next we register another callback, this time for the right mouse button.  In this case if the right mouse button was indeed pressed, we change the background to a random color.

 

So, that is what happens if we detected a mouse; if we don’t detect a mouse, we instead register a touch event handlers:

 

else
-- If it isn't a mouse, its a touch screen... or some really weird device.
    MOAIInputMgr.device.touch:setCallback (

        function ( eventType, idx, x, y, tapCount )
            if (tapCount > 1) then
                MOAIGfxDevice.setClearColor(math.random(0,1),math.random(0,1),math.random(0,1),1)
            elseif eventType == MOAITouchSensor.TOUCH_DOWN then
                handleClickOrTouch(x,y)
            end
        end
    )
end

 

While the left/rightButton event callbacks were passed a simple bool, the touch callback get’s a fair bit more information.  The following values are passed to the touch callback function:

eventType: The type of event that occurred. The value will be either TOUCH_UP or TOUCH_DOWN

idx: It touch index in case multiple simultaneous touches occurred

x: The x coordinates of where the touch happened on screen

y: The y coordinates of where the touch happened on screen

tapCount: the number of taps that occurred 

 

In the event that multiple taps occurred, we change the window background color to a random RGB value.  Otherwise, it was a single touch, in which case we call handleClicksOrTouch passing in the x,y value passed in the touch callback.

 

The parameters for the touch callback function were also not documented, so it took a little bit of digging to divine exactly what they are.  If you are interested, the actual code for setting the parameters is in the method MOAITouchSensor::HandleEvent, in the file MOAITouchSensor.cpp

 

Now we have the ability to be all touchy feely, we are yet another step further along in our adventures in Moai-land.  Stay tuned for the next exciting episode where we journey even deeper!  There may even be a prize at the end(*)!!!

 

 

(*) – the prize is a lie.

 

 

 

 

 

Programming , ,

27. August 2012

 

As the title suggests, Blitz Basic Plus is currently free right now, marked down from the regular price of 60$.  bbasiclogo

 

Blitz Basic, in their own words, is:

BlitzPlus provides developers with a complete 2D programming solution for the PC. Utilising a BASIC/C hybrid language for use with its compiler, BlitzPlus is capable of creating any type of 2D program, with minimal development-time and with minimal hassle. Just run the included IDE (or use one of your own), type your code and your Windows executable file will be created, ready to be run on any computer running Windows 95/NT 4 or later.

 

While the Blitz Basic language is:

 

BlitzPlus' language is a BASIC/C hybrid. As well featuring the classic BASIC constructs such as goto and gosub, it also features C influences such as functions and types. On top of this, BlitzPlus' command set features over 500 commands. This command set is highly streamlined meaning complete programs require very few lines of code indeed.

 

Apparently the original Worms was developed in BlitzBasic, as was the Eschalon RPG series.  I personally have never tried Blitz and don’t really intend to as I have never really been a fan of BASIC, but it is certainly worth checking out, especially for the price of 0$.

 

You can purchase it here.  I have no idea how long the offer is on for.

News

Month List

Popular Comments

Game From Scratch C++ Edition Part 3
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


Game From Scratch C++ Edition Part 3

 

 

So, now we have a functioning game loop and a screen to draw on, lets add some more functionality.  This time we are going to add a menu and a welcome splash screen.  We are going to take a consistent approach in that all “screens” are in charge of handling their own input.

 

Alright, lets start with adding a SplashScreen for when you start the game.  First off all, you are going to need an image to display as the splash screen.  Keep in mind the game is running at a fixed resolution of 1024x768, so ideally you want to make an image that size.  It is outside of the scope of this tutorial to create that image, but after playing around in Blender for a couple of minutes, I came up with this:

 

SplashScreen

Click here to download full size version of SplashScreen.png

 

… what can I say, I am a programmer.  You can use this image or create your own it really doesn’t matter, although to follow along with the code, name it SplashScreen.png if you do decide to create your own.  Now that we have our image, lets write some code.

 

First create a new header file in the Header Files folder named SplashScreen.h.  Now add the following code:

 

1 #pragma once 2 class SplashScreen 3 { 4 public: 5 void Show(sf::RenderWindow& window); 6 }; 7

Click here to download SplashScreen.h

 

Simple enough right?  After the last section, there should be nothing new here.  We are simply creating a class called SplashScreen with a single public function Show(), which takes a RenderWindow as a parameter.  Save your changes.

 

 

Now we want to create SplashScreen.cpp in the Source Files folder.  Once created, add the following code:

1 #include "StdAfx.h" 2 #include "SplashScreen.h" 3 4 5 void SplashScreen::Show(sf::RenderWindow & renderWindow) 6 { 7 sf::Image image; 8 if(image.LoadFromFile("images/SplashScreen.png") != true) 9 { 10 return; 11 } 12 13 sf::Sprite sprite(image); 14 15 renderWindow.Draw(sprite); 16 renderWindow.Display(); 17 18 sf::Event event; 19 while(true) 20 { 21 while(renderWindow.GetEvent(event)) 22 { 23 if(event.Type == sf::Event::EventType::KeyPressed 24 || event.Type == sf::Event::EventType::MouseButtonPressed 25 || event.Type == sf::Event::EventType::Closed ) 26 { 27 return; 28 } 29 } 30 } 31 }

Click here to download Splashscreen.cpp

 

This code is also pretty straight forward.  First thing we do is load the splashscreen image from disk and simply return if it doesn’t exist, meaning of course nothing will be shown.  With SFML an image is not seen on screen, that is the job of a sprite.  An image represents the actual pixel data from a file, but a sprite represents displaying that information on screen.  Why, you might wonder would you bother creating two different classes?  Mostly because you could have multiple sprites using the same image.  For example, our game is going to have at least two paddles, but we are going to use only a single image.  Also, in the case of a sprite sheet you often have multiple images in a single image file.

 

One the sprite is loaded, we simply draw it to the screen.  We don’t need to worry about coordinates because the sprite and the renderWindow are the same size.  Next we simply call RenderWindow.Display() which displays our image on screen.

 

As I said earlier, all windows are responsible for their own event handling, which exactly what happens starting on line 18.  On 19 we declare an infinite loop, then each pass through we check for available events and if the user presses a key, clicks a mouse or closes the window we exit the function, thus closing the splash screen window.

 

The main menu works very similarly but has a couple of key differences.  The menu is essentially just an image that is displayed similar to the splash screen.  Let’s take a look at it now.  Create a file called MainMenu.h ( note, you can use Add Class because MainMenu is a reserved class name in MFC… again, stupid bug. ) and add the following code:

 

1 #pragma once 2 #include "SFML/Window.hpp" 3 #include "SFML/Graphics.hpp" 4 #include <list> 5 6 class MainMenu 7 { 8 9 public: 10 enum MenuResult { Nothing, Exit, Play }; 11 12 struct MenuItem 13 { 14 public: 15 sf::Rect<int> rect; 16 MenuResult action; 17 }; 18 19 MenuResult Show(sf::RenderWindow& window); 20 21 private: 22 MenuResult GetMenuResponse(sf::RenderWindow& window); 23 MenuResult HandleClick(int x, int y); 24 std::list<MenuItem> _menuItems; 25 };

Click here to download MainMenu.h

 

First thing you may ask is “Why isn’t <list> declared in stdafx?”.  The answer is, you’re right, it should be.  As you know from earlier, any header file you include but aren’t actively being changed should be included in stdafx to accelerate the build process.  For sample code purposes though, it was better to show it included locally instead of having to show stdafx.h over and over.

 

MainMenu is a fairly straight forward class.  First off it defines an enum type that contains the various possible return values the menu could return.  Next it declares a struct called MenuItem that represents the individual menu items in the menu.  This struct is exceedingly simple, containing a sf::Rect<int> that represents the dimensions of the MenuItem. It also contains a MenuResult enum presenting the value to return if that MenuItem is clicked.

 

 

Optional information

 

What's with the <int> ???

You may have just encountered your first line of templated code. In MainMenu.h we declared:
sf::Rect<int> rect;
 
sf::Rect is a templated class.  In this case we are declaring an instance of sf::Rect using the type of int.  In place of int we could have used many other numeric data types, such as float or double or even your own class, as long as it supported all of the operators that sf::Rect requires.
 
In essence, templates allow a class such as sf::Rect to become more generic by removing the requirement of them to know about the datatype they are operating on.  So instead of having to for example, implement three Add() methods for eac int, float and double, they can simply write one.
 
This is an extremely simple and incomplete explanation of templates.  Templates are of extreme importance to C++ and are becoming more and more important with every revision, so it is a very good idea to familiarize yourself with how they work.  Such a discussion is well beyond the scope of this work, so you may wish to consult a site such as this or consult a book such as  C++ Templates The Complete Guide, an excellent book on the subject.
 
You should be able to make it through this tutorial with minimal knowledge of templates, but if you are going to become proficient in C++, it is an area you will need to know extremely well.

 

 

Next MainMenu declares a single public function Show() that returns a MenuResult enum type.  Finally are the private functions and data.  GetMenuResponse() is used internally and will be explained shortly, as is HandleClick().  The last line item is a list of type MenuItem, which will hold the various MenuItems that compose MainMenu.  std::list is a templated class from the Standard Template Library.  If you are unfamiliar with STL, you should rectify that as soon as you get the chance.  There are some good book and link suggestions for learning C++ in the C++ section of the Beginners Guide if you wish to learn more.

 

 

That’s about it for MainMenu.h.  Most of this will make more sense in a few minutes.  I thought I would take a moment to explain something about the design of MainMenu, the nested structs/enums.  You may be wondering why I nested the definition of MenuItem and MenuResult inside of MainMenu and the simple answer is because they belong to MainMenu, so we want to scope them within MainMenu.  Truth of the matter is, those items are of absolutely no use when not dealing with MainMenu, so there is no sense polluting the global namespace with a number of classes with no use to anything but a MainMenu object.  This is a key aspect of object oriented programming, encapsulation.

 

 

This leads to another conversation, the design of MainMenu itself.  Don’t menus share enough functionality they should derive from a common base class and a generic MenuItem class that isn’t specific to a specific type of menu?  The answer is very much yes!  In your own game, if you have multiple menus this is exactly what you would want to do.  In the case of Pang however, we are only going to have a single menu, so I went this route in order to keep the code smaller/easier to understand.  Don’t worry, later in the tutorial we will cover inheritance in more detail.

 

 

Optional information

 

Why a struct?

You may have noticed that MenuItem is a struct instead of a class and may wonder why that is.  The simple answer is, it just as easily could have been a class, but struct is a slightly better choice.
 
First off, the biggest difference between a class and a struct is that a class defaults to private while a struct defaults to public.  Since MenuItem contains entirely public members, choosing struct saves a bit of typing “public: “.
 
The second reason is more a convention thing, but is no less important, especially if you are dealing with other coders.  When dealing with fully publicly available POD types ( Plain Old Data ) that has no member functions, the norm is to use struct.  Finally it is common to use struct for functors but you can forget about that for now, we will cover it later.  There are some advantages to POD types ( like no vtables ) but they are well beyond the scope of what we are dealing with and are generally an example of premature optimization.
 
In short, you could have used class instead and been just as right, struct was just a slightly better fit.



 

Now let’s implement MainMenu.  Create a new file called MainMenu.cpp and add the following code:

 

1 #include "stdafx.h" 2 #include "MainMenu.h" 3 4 5 MainMenu::MenuResult MainMenu::Show(sf::RenderWindow& window) 6 { 7 8 //Load menu image from file 9 sf::Image image; 10 image.LoadFromFile("images/mainmenu.png"); 11 sf::Sprite sprite(image); 12 13 //Setup clickable regions 14 15 //Play menu item coordinates 16 MenuItem playButton; 17 playButton.rect.Top= 145; 18 playButton.rect.Bottom = 380; 19 playButton.rect.Left = 0; 20 playButton.rect.Right = 1023; 21 playButton.action = Play; 22 23 //Exit menu item coordinates 24 MenuItem exitButton; 25 exitButton.rect.Left = 0; 26 exitButton.rect.Right = 1023; 27 exitButton.rect.Top = 383; 28 exitButton.rect.Bottom = 560; 29 exitButton.action = Exit; 30 31 _menuItems.push_back(playButton); 32 _menuItems.push_back(exitButton); 33 34 window.Draw(sprite); 35 window.Display(); 36 37 return GetMenuResponse(window); 38 } 39 40 MainMenu::MenuResult MainMenu::HandleClick(int x, int y) 41 { 42 std::list<MenuItem>::iterator it; 43 44 for ( it = _menuItems.begin(); it != _menuItems.end(); it++) 45 { 46 sf::Rect<int> menuItemRect = (*it).rect; 47 if( menuItemRect.Bottom > y 48 && menuItemRect.Top < y 49 && menuItemRect.Left < x 50 && menuItemRect.Right > x) 51 { 52 return (*it).action; 53 } 54 } 55 56 return Nothing; 57 } 58 59 MainMenu::MenuResult MainMenu::GetMenuResponse(sf::RenderWindow& window) 60 { 61 sf::Event menuEvent; 62 63 while(true) 64 { 65 66 while(window.GetEvent(menuEvent)) 67 { 68 if(menuEvent.Type == sf::Event::MouseButtonPressed) 69 { 70 return HandleClick(menuEvent.MouseButton.X,menuEvent.MouseButton.Y); 71 } 72 if(menuEvent.Type == sf::Event::Closed) 73 { 74 return Exit; 75 } 76 } 77 } 78 }

Click here to download MainMenu.cpp

 

This code is fairly long, but not very complex.  First off we implement Show(), which is very similar to SplashScreen from before.  We load an image file “mainmenu.png” from the images folder and create a sprite to display it.  Next we create two MenuItem’s, which correspond with the location of their buttons physical locations within the mainmenu.png image file.  Lastly, each MenuItem has an action, which is represented by the MenuResult enum we described earlier.

 

MainMenu.png:

mainmenu

Click here to download MainMenu.png

 

After defining the location rects and action type of both MenuItems, we then add them to the _menuItems list using push_back(), which adds to an item to a list in the final position.  Next we draw our menu image to screen and tell the display to Display() just like we did in Splashscreen.  Finally, we call the function GetMenuResponse, returning it’s return value as Show’s return value.

 

GetMenuResponse() is the event loop for MainMenu.  It works just like our other two eventloops, except it only handles sf::Event::Closed and sf::Event::MouseButtonPressed.  In the event of close, it returns a value of MenuResult::Exit.  In the event of a button press, it passed the coordinates into HandleClick() returning it’s results.

 

HandleClick() is a very simple method that might look very confusing to you if you are new to STL datatypes.  First off, it declares an iterator, which is a datatype used for navigating through a collection of data.  In the for loop the iterator “it” is initially assigned a location of _menuItems.begin() which is the first element in the list.  Each pass through, the iterator’s ++ operator is called, which moves to the next item in the list, until the iterators location is equal to _menuItems.end().  One thing than can be a bit tricky is List.end() refers to a value past the end of the list, not to the last item in the list.  Think of .end() like you would a file’s EOF.  It does not represent a value, but instead the end of available values. 

 

Iterators also represent a pointer to the underlying datatype contained within the list<>.  Therefore when we dereference it ( using    (*it)  ) it contains a MenuItem type.  We then check to see if the click location is within the MenuItem’s rect.  If in fact the click was within MenuItem’s rect, we return the action (MenuResult). 

 

 

Lastly, we need to make a few changes to Game.h and Game.cpp, which will illustrate the power of using a state driven game structure. 

 

Change Game.h to contain the following:

1 #pragma once 2 #include "SFML\Window.hpp" 3 #include "SFML\Graphics.hpp" 4 5 6 class Game 7 { 8 public: 9 static void Start(); 10 11 private: 12 static bool IsExiting(); 13 static void GameLoop(); 14 15 static void ShowSplashScreen(); 16 static void ShowMenu(); 17 18 enum GameState { Uninitialized, ShowingSplash, Paused, 19 ShowingMenu, Playing, Exiting }; 20 21 static GameState _gameState; 22 static sf::RenderWindow _mainWindow; 23 };

Click here to download Game.h

 

The only changes we made here were the two next new functions on line 15 and 16, as well as the two new states on lines 18 and 19. The purpose of these changes will be explained in a moment.

 

In Game.cpp, we want to edit Game::Start() to look like:

1 void Game::Start(void) 2 { 3 if(_gameState != Uninitialized) 4 return; 5 6 _mainWindow.Create(sf::VideoMode(1024,768,32),"Pang!"); 7 8 _gameState= Game::ShowingSplash; 9 10 while(!IsExiting()) 11 { 12 GameLoop(); 13 } 14 15 _mainWindow.Close(); 16 }

 

The only real change here is line 8.  This simply sets the state to ShowingSplash when the game starts up.  Next up we just add two new states to Game::GameLoop, as follows:

1 void Game::GameLoop() 2 { 3 switch(_gameState) 4 { 5 case Game::ShowingMenu: 6 { 7 ShowMenu(); 8 break; 9 } 10 case Game::ShowingSplash: 11 { 12 ShowSplashScreen(); 13 break; 14 } 15 case Game::Playing: 16 { 17 sf::Event currentEvent; 18 while(_mainWindow.GetEvent(currentEvent)) 19 { 20 _mainWindow.Clear(sf::Color(sf::Color(0,0,0))); 21 _mainWindow.Display(); 22 23 if(currentEvent.Type == sf::Event::Closed) _gameState = 24 Game::Exiting; 25 26 if(currentEvent.Type == sf::Event::KeyPressed) 27 { 28 if(currentEvent.Key.Code == sf::Key::Escape) ShowMenu(); 29 } 30 } 31 break; 32 } 33 } 34 }

 

 

All that we add here are the Game::ShowingMenu and ShowingSplash case handlers, which call ShowMenu() and ShowSplash() respectively.  They are defined as:

 

 

1 void Game::ShowSplashScreen() 2 { 3 SplashScreen splashScreen; 4 splashScreen.Show(_mainWindow); 5 _gameState = Game::ShowingMenu; 6 } 7 8 void Game::ShowMenu() 9 { 10 MainMenu mainMenu; 11 MainMenu::MenuResult result = mainMenu.Show(_mainWindow); 12 switch(result) 13 { 14 case MainMenu::Exit: 15 _gameState = Game::Exiting; 16 break; 17 case MainMenu::Play: 18 _gameState = Game::Playing; 19 break; 20 } 21 }

Click here to download Game.cpp

 

Game::ShowSplashScreen() simply creates a SplashScreen object, calls its Show() method, then sets the game state to Showing Menu.  Game::ShowMenu() creates a MainMenu object and calls it’s Show() method.  In this case, it takes the returned MenuResults value and sets the game’s state accordingly.  This is how we handle the progression from state to state within our game. 

 

 

Pang running now:

imageimage

 

 

 

Click any key or mouse button to get past the splash screen, then in the menu click either “Exit Game” to um… exit.   That’s it for now.  In the next section we will work a bit more with graphics and delve a little deeper into object oriented programming.

 

You can download a completely updated project here.

 

 

Back to Part Two Forward to Part Four




blog comments powered by Disqus


Month List

Popular Comments