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 :)

miércoles, 17 de diciembre de 2014

Saturday at Granada Gaming

Hi all!

As I promised, here is my story and impressions at Granada Gaming, the first edition of this series of events where videogames professionals and small indie studios come together to celebrate their passion for games. 

I arrived by 10:30 a.m (doors opened half an hour earlier) and after lining up for half an hour, I got into the Congress Palace of Granada, where the event was held. 


Figure 1. A long line of people waiting to get into the Congress Palace

As soon as you passed through the doorstep, you could see gift shops populated with game-related stuff, stands where companies showed their last products, and long tables filled with laptops where the audience could play games developed by small studios. 

I headed directly (well, after a quick snack at the cafeteria) to the second talk of the day: Once Upon a Time: The Development of Videogames, where Mario García, from Mercury Steam (responsible for Castlevania Lord of Shadows, among others), discussed the process of creating games. In particular, the speaker is involved in the creation of game mechanics and gameplay experience in general. After his talk, I asked him whether they, at Mercury Steam, used some scripting language for this task. He answered that the most sensitive part of the code (the code that must run fast) is hard-coded in the game itself, whereas the rest is outsourced to Lua. The answer did not surprise given the increasing trend of using this scripting language in the industry.


Figure 2. A bunch of people around DriveClub.

Then, I took some time off the conference room to have a walk around. I could play several games, including Street Fighter x Tekken, which was actually pretty fun. There was also a retro area where you could enjoy jewels of old times, such as Alex Kidd. I also took the opportunity to hand out some Chubby Buddy flyers :).

But in my deepest heart, what I really wanted was trying the so-much wanted Oculus glasses. So I lined up again, and after other thirty minutes, the long-awaited moment arrived. A member of the staff was helping me wearing the glasses, and I could feel how I was transported into a miniaturized  roller-coaster. Moving your head around the room provided an impressive immersive feeling, since you could feel as if you were really there: the movement and turns of the head were really accurate and there were no lags at all. 


Figure 3. The line to try Oculus.

But the weirdest thing happened when the coach started to move. At that point, I felt something strange, neither too bad nor too good, but strange. I could feel what was actually happening: my brain was interpreting that I was moving, but my body was still, sitting and even aware of the noise that the headphones tried to vanish. However, a tickling sensation emerged from my stomach as the coach was moving faster and faster, and especially during the first descent. I even grabbed my chair because for a moment I thought that I could fall off. However, this sensation only lasted for some small fraction of time, and I really enjoyed the trip. 

I think it is not easy to envision the acceptance of this device in the near future by the games community. I'd really like to try them in a more interactive scenario before judging. But the immersive experience is out of discussion. The question is: would many people be able to wear the glasses in a horror game like Silent Hill P.T.? Mmm... I'm not sure I could play for more than 5 minutes... :) See below (after the end of this post) for opinions about the Oculus experience made by two persons that came with me.


Video: me looking through the Oculus... And yes, I really grabbed the chair.

The next talk I attended was about games marketing, which is a hot topic given the high saturation of the market. Basically, one of the main takeaways was that marketing should start long before the release of the game, and that Youtubers are playing an ever-increasing role in promoting the success of many independent games. 

In the next talk, the people behind the development of Randals Monday (one of the big lures of the event) described their experience while designing a graphic adventure. The designers wanted, from the very first moment, to pay tribute to old graphic adventures that are considered masterpieces today, such as Day of the Tentacle or Fate of Atlantis. The game, which is implemented around Unity, faced several technical challenges given that the engine is mainly designed for 3d games. However,  after seeing the game by myself, I can attest that developers made a great job at faking 2d. I asked the speaker personally for advices on designing the puzzles, and he answered that lots of paper-made drafts are required to make sure that the player cannot miss an important object for continuing the game, likely the biggest challenge in this type of games.


Figure 4. The conference room during the last talk I attended.

The last talk I could turn up was about marketing again. The speaker discussed the importance of making your game different from others, and of selling this difference. I asked about the impact of prices in the App Store in the selling opportunities. In particular, I wanted to know the speaker's opinion on my personal observation that a lower price does not guarantee more sales, or more benefits, since once the potential buyer is willing to pay, he or she would not mind to pay more. The speaker agreed with this observation and concluded that prices around 5 € are more than reasonable for well-designed mobile games.

And that's all. The festival continued on Sunday, but I could not be there. However, I'm delighted with the increasing number of games conferences initiatives in Spain (see more about Gamepolis in Malaga). Let's hope this is just the starting point for a 2015 full with videogames events.

See you!
FM

Oliver's experience with Oculus

While I was lining up, I was facing the traditional dilemma of those who are going to test something for the first time: enjoy or analyze? I chose the analysis, trusting that if the experience was worth it, I wouldn't forsake the emotions. And so it was.

When it was my turn, another question arose: should I take my glasses off? Fortunately, the staff member in charge told me that I could keep them on. The first thing that came to my attention was the possibility to look all around me; the immersive feeling was awesome, above all considering that graphics were a bit poor. Next thing I noticed was that my body really reacted as if I was in a real roller-coaster, especially during the descents. However, I got the knack in the end: in order to get the tickling sensation during descents, you need to look downwards. Otherwise (if you look up), you won't feel anything. In my opinion, a complete immersion experience requires further elements, such as a moving chair, but of course that would make the product more expensive. Another drawback of the demo was the poor quality headphones. As a musician and sound technician, I really advocate the use of good quality, closed design headphones to provide a real 3d experience. To sum up, although Oculus glasses are an innovative and interesting product, the provided experience is still limited. We'll have to wait until more polished designs and cheaper components, but I encourage companies and people to bet on this kind of technology, which will surely shape the future of interactive media.

Just as a side note, even when the obvious application of Oculus are videogames, I think it would be worthy exploring its application to other scenarios, such as immersive cinema, where you can walk around a scene as if you were a ghost.

Manuela's experience with Oculus

I have little to add to Oliver's comprehensive review, with which I mostly agree. First, I think that graphics were poor, which is a pity because the immersive feeling (which was really high) could have been absolutely staggering with a better design. Second, moving your head around the room gave the real impression of being in that room. Finally, the feeling of the brain being tricked was fantastic at first, although later you get used to the feeling. In general, I think it was a good experience, and I'm looking forward to seeing what developers achieve with this device.

martes, 9 de diciembre de 2014

To Granada Gaming Festival!

Hi all!

This weekend will take place the Granada Gaming Festival, and I've just bought the tickets to be there. Among other activities and interesting lectures, the organizers promise to let the audience test Oculus Rift. Let's see if I'm luckier than in the last edition of Gamepolis. As I did in the latter festival, I'll try to cover my impressions, so stay tuned.

See you!
FM