Mostrando entradas con la etiqueta software engineering. Mostrar todas las entradas
Mostrando entradas con la etiqueta software engineering. Mostrar todas las entradas

lunes, 29 de febrero de 2016

Breaking Fast: Menu Navigation

Hi all!

Breaking Fast is moving forward. This last week we worked on the menu navigation part, which includes the menu screens through which players navigate until the race begins. As for the technical side, I want to discuss the two main issues you have to consider when implementing this aspect of a game: how to manage the flow between screens, and how to pass information among screens. Let's get started!

Flow Management Schemes

There are two main "schemes" (I can't think of a better word) during menu navigation. In the first scheme, each screen is actually a different screen. This implies that, upon changing among screens, we swap the contents of one screen with the contents of the other screen. This can be implemented as a function in the screen manager:

 function changeScreen(newScreen)  
  currentScreen.unload()  
  currentScreen = newScreen  
  currentScreen.load()  
 end  

In order to manage transitions among screens (i.e. the implementation of the screen manager), it is useful to think of Finite State Machines. You can watch a series of two videos that I prepared for gaining insight on the matter.



 
In games it is also very common to use another scheme, in which the contents of different screens are all drawn, but only one of them has the focus at any moment. Think for example of a racing game in which you have to choose a scenario and then, the time of the race. You can implement this by using the aforementioned scheme, but it feels kind of overkill to unload one screen and to load another one just for the purpose of selecting the time. It seems more natural that the same screen presents both options, but that the player can only change one of them at any time. Actually, we can stop thinking of different screens in this situation. This "move the focus" approach can be implemented by means of screen phases or states

In particular, in Lua, we can hold a table of states, and we iterate over this table in order to draw and update the screen. We also have a variable that holds the value of the current state (the current focus), and we delegate the interaction of the player (be it with the keyboard or a gamepad) to the actual focused state. Some self-explanatory code is shown next:

 function load()  
  table.insert(states, state1)  
  table.insert(states, state2)  
  currentStateFocus = state1  
 end  
 function draw()  
  for _, v in ipairs(states) do   
   v.draw()  
  end  
 end  
 function update(dt)  
  for _, v in ipairs(states) do   
   v.update(dt)  
  end  
 end  
 function onKeyPressed(key)  
  currentStateFocus.onKeyPressed(key)  
 end  

Communication between Screens and States

Passing information among screens is essential. In particular for Breaking Fast, consider the following flow of actions:
  1. Players select the characters that will participate in the race.
  2. Players select the scenario in which the race will take place.
  3. Players select the duration of the race.

Consider the figure above, in which we mix the two menu navigation schemes explained before. Each transition among screens and states conveys both new information and the information carried by older transitions. In the end, when we prepare the race screen, we need to know all the options that have been chosen by the players through the different screens. Fortunately, implementing this in Lua is very simple thanks to a powerful feature of the language: function overriding of imported modules. Consider the following module, which models the Time Selection State:

 local timeSelectionState = {}  
   
 -- other functions  
   
 function timeSelectionState.toScenarioSelection()  
 end  
   
 function timeSelectionState.toGame(timeChosen)  
 end  
   
 return timeSelectionState  

As you can see, we are defining two empty functions. Any module that imports this module can re-define (i.e. override) these functions. So for example, consider the Scenario Selection Screen module, which contains the Time Selection State:

 local scenarioSelectionScreen = {}  
   
 -- other functions  
   
 function timeSelectionState.toScenarioSelection()  
      currentStateFocus = scenarioSelectionState  
 end  
   
 function timeSelectionState.toGame(timeChosen)  
      for _, v in ipairs(states) do  
           v.unloadResources()  
      end  
      scenarioSelectionScreen.toGame(numberOfPlayers, playersInfo, scenarioChosen, timeChosen)  
 end  
   
 function scenarioSelectionScreen.toGame(numberOfPlayers, playersInfo, scenarioChosen, timeChosen)  
 end  
   
 return scenarioSelectionScreen  

As you can observe, this module re-defines toScenarioSelction() and toGame() functions. In particular, toGame() unloads all the states of this screen, forwards the racing time that has been chosen by the player, and pads it to more information accumulated during previous phases. In turn, scenarioSelectionScreen defines an empty toGame() function that cam be re-defined by the module importing it. This latter module could therefore add some more information and pass it to the Race Screen.

And this is it! As always, I hope you enjoyed this tutorial, and if you have any question, don't hesitate to ask! Any feedback is also well appreciated.

See you!
FM

miércoles, 3 de junio de 2015

Correct Compositional Design in Cocos2d-x

Hi all!

Today I want to share with you an important caveat about composition in the context of Cocos2d-x. Composition is an object-oriented technique where a class contains (is composed of) another class to which it delegates functionality related to the latter. 

This technique is frequently suggested as an alternative to inheritance in complex hierarchies in order to avoid tangled structures, specially in those languages that do not support multiple inheritance (i.e. a class cannot have more than one parent class), such as Java. More information about the composition-inheritance binomial can be read here

In the context of Cocos2d-x, composition could be realized through a class that contains a Sprite object as part of its private members, for example:

 class Ball  
 {  
 public:  
   explicit Ball( const BallType &bt )  
   {  
      switch(bt)  
      {  
         case BallType::Hard:  
            ballSprite = Sprite::create("Balls/Hard.png");  
            break;  
         //more cases...  
      }  
   }  
   ~Ball()
   {
       //Clean-up by removing heap-allocated data
   }
   inline cocos2d::Sprite *getBallSprite() { return ballSprite; } 
 
 private:   
    cocos2d::Sprite *ballSprite;  
    //more data
 };  

In this case, the Ball constructor simply takes a scoped enum value and creates a sprite object depending on the type. We also provide a getter function to retrieve the pointer to the sprite object. The destructor, as always, should clean up the memory allocated by the object.

At this point, you may be tempted to place a delete ballSprite statement, but this would yield a compiler error, because Cocos2d-x uses its own reference counter for managing the memory of its objects. Therefore, when a Cocos2d-x object (such as a Sprite) is no longer referenced by any other object, the former is automatically deleted.

Now, a client class (e.g. a cocos2d::Layer ) could use the Ball class as follows:

 //A method in our layer class  
{  
   //start some loop
  {
    BallType bt = getRandomType();
    //balls is a member variable of type std::vector<std::unique_ptr<Ball>>
    std::unique_ptr newBall = std::make_unique<Ball>(bt); 
    layer -> addChild( newBall -> getSpriteBall() ); 
    balls.pushBack( std::move(newBall) );  
 
    //... process balls    
  }
  //All balls destroyed; all  
  Director::getInstance() -> replaceScene( AnotherScene::create() );
} //end of method


In a loop, this method creates balls of random types, adds the balls sprites to the layer to actually show the sprites on screen, and processes them (maybe it detects touches and so on). Upon termination of the loop, there is a change of Cocos2d-x scene, which means that all the children of the current layer (including the sprites of the balls) are safely deleted. Also, as the vector of balls goes out of scope, the destructor of the std::vector class is called, which in turns calls the destructor of the std::unique_ptr objects, which in turn calls the destructor of each Ball object. Everything perfect so far.

However, consider the following scenario. In this scenario, we want to show only on screen some balls of a specific type, whereas other types of balls should be stored and shown at a later time, for example upon termination of the loop. The code to perform this could be:

 //Method in our layer class  
{  
  //start a loop
  {
    BallType bt = getRandomType();
    std::unique_ptr newBall = std::make_unique<Ball>(bt); 

    if ( bt == BallType::Hard )
    {
      layer -> addChild( newBall -> getSpriteBall() );  
      balls.pushBack( std::move(newBall) );  
    } 
    else 
    {
      ballsToShowLater.pushBack( std::move(newBall) );
    }
    //... process balls      
  }
  //end of the loop
  //show hidden balls
  for (const auto& b : ballsToShowLater)
  { 
      layer -> addChild( b -> getSpriteBall() );  
  }   
  //..some more stuff with the new balls shown
  
  Director::getInstance() -> replaceScene( AnotherScene::create() );

} //end of the method

This code, which seems ok at a first glance, has an important flaw. The problem arises because of the automatic reference counting mechanism of Cocos2d-x, which we are not using properly. When we create a Sprite object in our Ball, the reference counter is still 0, because there is no object pointing at it. This means that if right after creating the Ball object we don't add the associated Sprite object to the layer hierarchy (via addChild() ), the next iteration of the framework will detect that the reference counter is 0 and will remove the Sprite object. However, if we add the Sprite to the layer hierarchy, we increase the reference counter by 1, which prevents the framework from deleting the Sprite.

In the first example, there was no problem because right after the creation of a Ball object, unconditionally, we added the Sprite to the layer hierarchy. However, in the following example, we are creating Ball objects and we are deferring the inclusion of their sprites in the hierarchy of the layer. Therefore, most likely, when we try to retrieve the Sprite object in the for loop, we simply retrieve garbage, because the pointer is dangling.

How to fix this? The solution is easy and fast. We simply need that Ball object reclaims (shared) ownership of its Sprite. Basically, we need that a Ball object is capable of expressing: "hey, I need the Sprite object, so don't remove it even if nobody else is using it". This is where the Cocos2d-x functions retain() and release() come into play, as shown next:

 class Ball  
 {  
 public:  
   explicit Ball( const BallType &bt )  
   {  
      switch(bt)  
      {  
         case BallType::Hard:  
            ballSprite = Sprite::create("Balls/Hard.png");  
            break;  
         //more cases...  
      }  
      ballSprite -> retain(); //This is my sprite, so don't mess up with it!
   }  
   ~Ball()
   {
       //Clean-up by removing heap-allocated data
       ballSprite -> release(); //I don't need this sprite object anymore
   }
   inline cocos2d::Sprite *getBallSprite() { return ballSprite; } 
 
 private:   
    cocos2d::Sprite *ballSprite;  
    //more data
 };  

So this is the main consideration when using composition with Cocos2d-x objects! Easy, right?

Hope you enjoyed it!
FM

Tweet: Don't miss this interesting read on #programming and #gamedev. Correct Compositional Design with #cocos2d-x (http://ctt.ec/hIFi9+)

martes, 3 de febrero de 2015

Integrating iAd in Cocos2d-x v3.x

Hi all!

First of all, Happy New Year! (better late than never, right?). Sorry for the delay, but I've really been busy this last month, and Christmas didn't help either... 

Today I want to share with you what I've been doing these last days. In the next game I'm working on, I wanted to include a free version with advertisements, but I had no experience on this task. The thing turned out to be quite simple (at least in iOS, which is the first target I have in mind), as the iAd Framework is intuitive. However, I had to face an additional challenge: integrating this framework with another framework I'm building my game upon, Cocos2d-x. The main contributions that helped me achieve this goal are this and this.

So, first of all, we need to understand the model that iAd Framework follows. In a nutshell, you need to create an interface that follows a protocol (which is the equivalent in Objective-C to a Java interface), that is, that should implement certain methods. The name of the protocol is AdBannerViewDelegate. So let us call our interface AdBanner and let us create a header file with it:

AdBanner.h
 #import <Foundation/Foundation.h>  
 #import <iAd/iAd.h>    
 @interface AdBanner : NSObject<ADBannerViewDelegate>  

The methods that we should implement are listed next, together with a brief description: 

- (void)bannerViewDidLoadAd:(ADBannerView *)banner

This method is called when a banner view has a new ad to display.

- (BOOL) bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL) willLeave

This method is called when the user taps the banner and should return YES if the banner action should execute. If willLeave=YES, then another app will be launched to execute the action, and no additional actions are required; NO if the action is going to be executed inside the game, so we should pause the activities that require interaction with the game.

- (void)bannerViewActionDidFinish: (ADBannerView *) banner


This method is called after the user has navigated the ad. It must resume activities if bannerViewActionShouldBegin: paused the gameplay.


- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error


This method is called if any error occurs. 

Note that the arguments refer to an ADBannerView object, which is the object that can contain and will show ads. The first thing therefore is to create an ADBannerView object and to include it in the hierarchy of views. Note that in a Cocos2d-x game, we typically have just one view, an EAGLView, which is a subclass of UIView that renders an OpenGL scene.  

In order to add the banner view, we need first to gain access to the RootViewController, that is, the object in charge of managing the different views. Also, we will need to access the size of the screen so as to place the banner, and therefore, we are going to obtain a UIWindow object that can provide that information. Finally, we want to add a boolean value to determine whether the banner view is currently visible or not. The resulting header and implementation files are presented next:

AdBanner.h
 #import <Foundation/Foundation.h>  
 #import <iAd/iAd.h>  
 @class RootViewController;   
 @interface AdBanner : NSObject<ADBannerViewDelegate>  
 {  
   UIWindow* window;  
   RootViewController* rootViewController;  
   ADBannerView* adBannerView;  
   bool adBannerViewIsVisible;  
 }  


AdBanner.mm (Note that the extension of Objective-C files are .m. However, as we will have to integrate with C++, we rename the file to .mm, which is an Objective-C++ file)
 -(id)init  
 {  
   if(self=[super init])  
   {  
     adBannerViewIsVisible = YES;  
     rootViewController =  
       (RootViewController*) [[[UIApplication sharedApplication] keyWindow] rootViewController];  
     window = [[UIApplication sharedApplication] keyWindow];  
     [self createAdBannerView];  
   }  
   return self;  
 }  
 - (void)createAdBannerView  
 {  
   adBannerView = [[ADBannerView alloc] initWithFrame:CGRectZero];  
   adBannerView.delegate = self;  
   [adBannerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];  
   CGRect adFrame = adBannerView.frame;  
   adFrame.origin.x = 0.0f;  
   adFrame.origin.y = window.bounds.size.height;  
   adBannerView.frame = adFrame;  
   [[rootViewController view] addSubview: adBannerView];  
 }  

In init, we state that the banner view should be visible and we retrieve the root view controller and the main window. Then, we call createAdBannerView, which creates and initializes the adBannerView object. The next step is very important: we state that the actual delegate of the adBannerView is the current object; this means that when the adBannerView object changes, it will notify our object by calling the methods of the protocol previously explained. The following method (setAutoresizingMask:) indicates that if the superview changes, the width of the banner view can be freely re-sized. This is important if you want to support changes in orientation for example. Then, we specify that the subview should be hidden, right after the bottom of the screen. Note that while the origin of the coordinates system in Cocos2d-x is in the bottom-left corner and the y component grows upwards, the origin of the UIView class is in the top-left corner, and the y component grows downwards. So, when we write:

adFrame.origin.y = window.bounds.size.height;

, we are placing the origin of the UIView on the bottom-left corner of the screen, and the banner would grow downwards. That's why it would be initially hidden. 

Finally, we add the banner view to the views hierarchy through the root view controller object. 

Now, we are going to add the protocol methods in the implementation file.

AdBanner.mm
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave  
 {  
   NSLog(@"Banner view is beginning an ad action");  
   if ( !willLeave )  
   {  
     //insert code here to suspend any services that might conflict with the advertisement  
   }  
   return YES;  
 }  

 - (void)bannerViewActionDidFinish: (ADBannerView *) banner  
 {  
   //if necessary, insert code here to resume services suspended by the previous method  
 }  
 - (void)bannerViewDidLoadAd:(ADBannerView *)banner  
 {  
   NSLog(@"New ad available");  
   [self layoutAnimated:YES]; //shows the banner with a pop-up animation 
 }  
 
 -(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error  
 {  
   NSLog( @"%@", error.description );  
   [self layoutAnimated: YES];  //hides the banner with an animation
 }  

Note that both bannerViewDidLoadAd: and bannerView: didFailToReceiveAdWithError: call a third instance method layoutAnimated:, which is not part of the protocol. This method is listed next:

AdBanner.mm
//... protocol methods above... 
-(void)layoutAnimated:(BOOL)animated  
 {  
   CGRect bannerFrame = adBannerView.frame;  
   //Has the banner an advestiment?  
   if ( adBannerView.bannerLoaded && adBannerViewIsVisible )  
   {  
     NSLog(@"Banner has advertisement");  
     bannerFrame.origin.y = window.bounds.size.height - bannerFrame.size.height;  
   } else  
   {  
     NSLog( @"Banner has NO advertisement" );  
     //if no advertisement loaded, move it offscreen  
     bannerFrame.origin.y = window.bounds.size.height;  
   }  
   [UIView animateWithDuration:animated ? 0.25 : 0.0 animations:^{  
     [rootViewController.view layoutIfNeeded];  
     adBannerView.frame = bannerFrame;  
   }];  
 }  

The code is more or less self-explanatory. We first check whether the banner view has actually an advertisement and whether it is visible. If it is, we place it on the bottom of the screen; otherwise, we place it offscreen (right after the bottom). We then call the static method animateWithDuration provided by UIView in order to show a simple pop-up animation.

Integrating with Cocos2d-x

Let's recap. Now, we have two files: AdBanner.h and AdBanner.mm, which encapsulates an AdBanner object capable of showing and hiding an ad banner view object. On the other hand, we have a Cocos2d-x scene onto which we would like to show the ad banner.

I'm going to show you a real example. In the new game I'm working on, I want to display the ad banner in the menu screen, which is a cocos2d:Layer, as depicted next:

MenuScreen.h
 #include "cocos2d.h"  
 class MenuScreen: public cocos2d::Layer  
 {  
 public:  
   static cocos2d::Scene* CreateScene();  
   virtual bool init();   
   CREATE_FUNC( MenuScreen );  
 private:  
   cocos2d::Size visibleSize;  
   cocos2d::Point origin;  
   cocos2d::Sprite *mBackground;  
   cocos2d::MenuItemImage *mPlayButton;  
   cocos2d::MenuItemImage *mSoundConfigButton;  
   cocos2d::MenuItemImage *mCreditsButton;  
   cocos2d::MenuItemImage *mGameCenterButton;  
   void ToNewGame();  
   void SoundConfig();  
   void ToCredits();  
   void ToGameCenter();  
 };  

It would be wonderful if I could do the following:

MenuScreen.h
#include "cocos2d.h"
#include "AdBanner.h" //THIS WON'T WORK!
 class MenuScreen: public cocos2d::Layer  
 {  
 public:  
   static cocos2d::Scene* CreateScene();  
   virtual bool init();   
   CREATE_FUNC( MenuScreen );  
 private:  
   cocos2d::Size visibleSize;  
   cocos2d::Point origin;  
   cocos2d::Sprite *mBackground;  
   cocos2d::MenuItemImage *mPlayButton;  
   cocos2d::MenuItemImage *mSoundConfigButton;  
   cocos2d::MenuItemImage *mCreditsButton;  
   cocos2d::MenuItemImage *mGameCenterButton;  
   void ToNewGame();  
   void SoundConfig();  
   void ToCredits();  
   void ToGameCenter();  
   AdBanner* adBanner; //THIS WON'T WORK!
 };  

That is, adding the header of AdBanner and defining a pointer to an AdBanner object in the class. However, as mentioned in the comments, this won't compile, because MenuScreen.h will be eventually included in its implementation, which is a .cpp file that would complain as soon as it finds Objective-C syntax (e.g. @interface).

The solution is to create an intermediate C++ object that mediates between C++ and Objective-C. For this purpose, let us create a class called AdBannerC, just like this:

AdBannerC.h
 #import "AdBanner.h";  
 class AdBannerC  
 {  
 public:  
   AdBannerC();  
   ~AdBannerC();  
 private:  
   AdBanner* impl;  
 };  

AdBannerC.mm
 #include "AdBannerC.h"  
 AdBannerC::AdBannerC()  
 {  
   impl = [[AdBanner alloc] init];  
 }    
 AdBannerC::~AdBannerC()  
 {  
   [impl removeView];  
 }   

Now, it would seem reasonable to include AdBanncerC.h in MenuScreen.h and write:

AdBannerC* adBanner = new AdBannerC();

However, THIS DOESN'T WORK! Why? Because we have said before that a .cpp file (well, to be more accurate, the C++ compiler) does not understand Objective-C syntax. If we include AdBannerC.h in MenuScreen.h, AdBanner.h is also being included, and AdBanner.h has Objective-C syntax!

The trick that we can apply here is commonly called the PIMPL idiom and it exploits the fact that a forward declaration of a type is enough to declare a pointer to that type. I'll explain myself. Consider this alternative definition of the AdBannerC class:

AdBannerC.h
 struct AdBannerImpl; //Forward declaration
 class AdBannerC  
 {  
 public:  
   AdBannerC();  
   ~AdBannerC();   
 private:  
   AdBannerImpl* impl;  
 };  

As you can see, now we don't have any imports, so any .cpp file can safely include this header file and won't find any strange Objective-C syntax. We have done a so-called forward declaration, meaning that we are telling the compiler that the type AdBannerImpl exists in some implementation file. This is enough for the compiler to let us define a pointer to this type. A struct in C++ is equivalent to a class, except that default values of its members are public.

The implementation file would be as follows:

AdBannerC.mm
 #include "AdBannerC.h"  
 #import "AdBanner.h"  
 struct AdBannerImpl  
 {  
   AdBanner* wrapped;  
 };  
 AdBannerC::AdBannerC()  
 {  
   impl = new AdBannerImpl();  
   impl -> wrapped = [[AdBanner alloc] init];  
 }  
 AdBannerC::~AdBannerC()  
 {  
   [impl -> wrapped removeView];  
   delete impl;  
 }  

Now, any scene in the game can create a banner view by just importing AdBannerC.h and doing:

adBanner = new AdBannerC();

Done!

However, as we mentioned earlier, sometimes it might be necessary to pause and resume the gameplay when the player interacts with the banner. How can we accomplish this? Easy: we just need to pass an instance of the scene to the banner object and let this banner object call the appropriate method of the scene. So, the first step is to create these methods:

MenuScreen.h
 class MenuScreen: public cocos2d::Layer  
 {  
 public:  
   // there's no 'id' in cpp, so we recommend returning the class instance pointer  
   static cocos2d::Scene* CreateScene();  
   // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone  
   virtual bool init();  
   void PauseGame();  //It pauses the current activities
   void ResumeGame(); //It resumes the activities
   //rest of class definition
}; 

MenuScreen.cpp
 void MenuScreen::PauseGame()  
 {  
   Director::getInstance() -> stopAnimation();  
 }  
 void MenuScreen::ResumeGame()  
 {  
   Director::getInstance() -> startAnimation();  
 }  

In order to pause and resume the game, we simply call the corresponding methods provided by the cocos2d::Director class.

Next step is passing the instance of the scene to the ad banner object. For this purpose, we need to modify slightly the AdBannerC class to make it accept an instance of MenuScreen:

AdBannerC.h
 class MenuScreen; 
 struct AdBannerImpl;
 class AdBannerC  
 {  
 public:  
   AdBannerC( MenuScreen& ms );  
   ~AdBannerC();   
 private:  
   AdBannerImpl* impl;  
 };  

AdBannerC.mm
 #include "AdBannerC.h"  
 #import "AdBanner.h"  
 struct AdBannerImpl  
 {  
   AdBanner* wrapped;  
 };  
 AdBannerC::AdBannerC( MenuScreen& ms )  
 {  
   impl = new AdBannerImpl();  
   impl -> wrapped = [[AdBanner alloc] initWithMenuInstance: ms];  
 }  
 AdBannerC::~AdBannerC()  
 {  
   [impl -> wrapped removeView];  
   delete impl;  
 }  

Thus, in MenuScreen.cpp, we would do the following:

AdBannerC *adBanner = new AdBannerC( *this );

Note that we have changed the initialization of impl->wrapped by using a new method called initWithMenuInstance:. Therefore, we need to define this method in AdBanner:

AdBanner.h
 #import <Foundation/Foundation.h>  
 #import <iAd/iAd.h>  
 @class RootViewController;  
 class MenuScreen;  
 @interface AdBanner : NSObject<ADBannerViewDelegate>  
 {  
   UIWindow* window;  
   RootViewController* rootViewController;  
   ADBannerView* adBannerView;  
   bool adBannerViewIsVisible;  
   MenuScreen* ms;   
   bool needToRestore;  
 }  
 -(id)initWithMenuInstance: (MenuScreen&) ms;   
 @end  

In addition to the new method, we have also added a new variable: needToRestore. This boolean value will tell us whether we need to resume the gameplay depending on whether our app was moved to the background or not.

AdBanner.mm
 #import "RootViewController.h"  
 #import "AdBanner.h"  
 #import "MenuScreen.h"  
 @implementation AdBanner  
 -(id)initWithMenuInstance: (MenuScreen &) msVar  
 {  
   ms = &msVar;  
   needToRestore = NO;  
   return [self init];  
 }    
 - (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave  
 {  
   NSLog(@"Banner view is beginning an ad action");  
   if ( !willLeave )  
   {  
     //Given that we are pausing the gameplay, we need to restore it later.
     needToRestore = YES;  
     // insert code here to suspend any services that might conflict with the advertisement  
     ms -> PauseGame();  
   }  
   return YES;  
 }  
 - (void)bannerViewActionDidFinish: (ADBannerView *) banner  
 {  
   if( needToRestore )  
   {  
     ms -> ResumeGame();  
   }  
   needToRestore = NO;  
 }  

//... rest of methods

And that's it! Wow! This post has been longer than I expected, but I hope that you found it interesting and useful for your own projects.

Some final thoughts:

  • In order to make sure that ad banner objects are actually deleted, activate Automatic Reference Counting (ARC) for the .mm files. Check here for how this is done. 
  • Always prefer smart pointers over raw pointers.
  • The solution I propose here is fine when you want to display an ad banner in just two or three scenes at most. If you will have lots of scene in your game showing ad banners, you should generalize all the scenes that may show ads into a superclass that implements the methods ResumeGame() and PlayGame(), and pass an instance of this superclass to the banner object. 

Thanks for your reading and don't hesitate to ask or correct if that's the case!
See you :)

jueves, 12 de septiembre de 2013

On Game Loops

Hi all!

Today I want to talk to you about something that is a must-know in the world of game programming: the game loop.

The game loop is the sequence of actions that are run by the machine during the execution of the game and that are repeated until the game finishes. In C++-style, the game loop looks something like this:

while (!finished()) {
      finished = getInput(&input);
      update(input);
      draw();
      clearScreen(); 
}

The first thing the game does is to check the input provided by the player: keyboard presses/releases, screen touches, etc. Then, it updates, probably according to the input, the world: player, enemies, platforms, score and other variables, collisions, etc. Then, it draws (or more technically, it renders) the scene onto the screen, and then it clears out the screen to allow the rendering of the next loop execution, also known as frame

I think that (almost) any game in the world can be organized by using this structure. How explicit this structure is from the viewpoint of the developer, is, however, another story, and it depends on the level of abstraction that the developer is using. 

For example, in the game I'm developing for PC/Mac (that famous platform game I mentioned in earlier posts), I began almost from scratch. Therefore, all my class hierarchy and methods are set so as to follow the game loop structure, and the actual code for my main method matches almost perfectly the previous one.

However, I've recently started developing a small, puzzle game for iOS (more in future posts), and for this, I'm using the Cocos2D framework. When you use high-level libraries or frameworks, many of the gory details are hidden in order to abstract away unnecessary complexities and let the developer focus on the gameplay. In the case of frameworks, furthermore, it is usual the so-called inversion of control. This means that the framework takes the role of the main routine, and is the framework that is in charge of calling certain components/classes developed by the programmer, taking a leading role.

I'll give you a very simple concrete example: Cocos2D uses the notion of Node (CCNode class) and Layer (CCNode layer). Layers can contain nodes, and nodes can be rendered. Therefore you can write something like [layer addChild: node], which adds a node to a layer. Once you've added the node to a layer, the framework itself ensures that the draw method of the node is called every frame, so you cannot see the explicit call to this method because it is hidden inside the framework implementation and it's not exposed as an API (actually, you can override the draw method, but this is an advanced feature for more experienced developers). 

The moral is this: even when you don't see the game loop, you must be aware that it's there, observing each of your movements... So be aware of it! Once you really understand the game loop and concept of frame, everything becomes nicer and easier.

See you!