Page 4 – Menu and State Manager

Step Eight: Adding a Menu

Step Eight Files

The next thing I did with iMarble was to fit it into the menu system I had set up for AdventureBall. This is kind of a beg leap in terms of how much code I have been adding per step up to now, but hopefully you will be able to follow along. The first thing I did was create stateManager.mm and stateManager.h. I am using the stateManager as the top level of my game. I removed gameShutdown, and made it stateManagerShutdown, and changed the callback in EAGLView.mm. I also changed the initial call in EAGLView.mm to stateManager instead of gameLoading.

stateManager

The state manager just has a couple of sections that will switch the state variable, then call the stateManager to direct the game to either the menu or game screens. The setPlay, and setMenu sections can be called from the rendering code in game.mm or menu.mm, where as I can not directly access the state variable.


#include "stateManager.h"
#include "game.h"
#include "menu.h"
#include "../src/sio2/sio2.h"

unsigned int STATE = 1;

void setPlay( void )
{
STATE = 0;
stateManager();
}
void setMenu( void )
{
STATE = 2;
stateManager();
}
void stateManager( void )
{
if( STATE==0 )
{ sio2->_SIO2window->_SIO2windowrender = gameLoading; }

if( STATE==1 )
{ sio2->_SIO2window->_SIO2windowrender = splashLoading; }

if( STATE==2 )
{ sio2->_SIO2window->_SIO2windowrender = menuLoading; }
}

void stateManagerShutdown( void )
{
sio2ResourceUnloadAll( sio2->_SIO2resource );
sio2ShutdownLUA();
sio2->_SIO2resource = sio2ResourceFree( sio2->_SIO2resource );
sio2->_SIO2window = sio2WindowFree( sio2->_SIO2window );
sio2 = sio2Shutdown();
printf("\nSIO2: shutdown...\n" );
}

You can get the code for the header files from the link above. The header files are really simple, so if you can’t figure them out from what game.h looks like, then just download the files.

menu.mm

The menu is pretty simple. It steals code directly from tutorial 17 for the splash loading. Then I load a full screen widget with material and an image for the background, and another smaller widget without material or image for a button. The graphic for the button is part of the background, so all I need is the button functionality. Rom says that the widget system got a pretty huge overhaul for SIO2 version 2.0, so hopefully it is easier to use and works better. One notable difference between AdventureBall and iMarble is that for some reason the xy coordinates for my widgets are reversed. The widget debug box was where it should be, but was responding to touches elsewhere. It took me hours to figure out that x and y were flipped, and that if I switched them in my code, the touches would be proper, just the debug box would be in the wrong spot. So I am a little reluctant to try and explain a lot of what I did here because I fear it may be a slightly futile effort. I will however provide code that any interested party could reverse engineer if they wished.

#include "menu.h"
#include "game.h"
#include "stateManager.h"
#include "../src/sio2/sio2.h"

////SPLASH LOADING VARIABLES
SIO2widget *splashWidget = NULL;
SIO2material *splashMaterial = NULL;
SIO2image *splashImage = NULL;

////MENU LOADING VARIABLES
SIO2widget *coverWidget = NULL;
SIO2material *coverMaterial = NULL;
SIO2image *coverImage = NULL;

SIO2widget *playWidget = NULL;
unsigned int MENU = 1;

////MENU RENDER VARIABLES
float splash_time = 3.0f;

void playWidgetTouch( void *, void *, vec2 *)
{
NSLog(@"PLAY");
MENU = 0;
}

void unloadMenu( void )
{
while( 0 != sio2->_SIO2resource->n_object )
{
SIO2object *_SIO2object = ( SIO2object * )sio2->_SIO2resource->_SIO2object[ 0 ];
if ( _SIO2object->_SIO2objectphysic )
{
sio2PhysicRemoveObject( sio2->_SIO2physic, _SIO2object );
}
sio2ObjectFree(_SIO2object);
}
sio2ResourceUnloadAll( sio2->_SIO2resource );
sio2->_SIO2resource = sio2ResourceFree( sio2->_SIO2resource );
sio2->_SIO2resource = sio2ResourceInit( "default" );
sio2->_SIO2window->_SIO2windowrender = setPlay;
}

void menuRender( void )
{
if( MENU )
{
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
sio2WindowEnter2D( sio2->_SIO2window, 0.0f, 100.0f );
{
sio2WindowEnterLandscape2D( sio2->_SIO2window );
{
if( splash_time )
{
if( splash_time _SIO2material->diffuse->w = splash_time; }
sio2WidgetRender( splashWidget, sio2->_SIO2window, SIO2_TRANSFORM_MATRIX_APPLY );
sio2MaterialReset();
splash_time -= sio2->_SIO2window->d_time;
if( splash_time _SIO2window, SIO2_TRANSFORM_MATRIX_APPLY );
sio2MaterialReset();
sio2WidgetReset();

sio2WidgetRender( playWidget, sio2->_SIO2window, SIO2_TRANSFORM_MATRIX_APPLY );
sio2MaterialReset();
sio2WidgetReset();
sio2WidgetDebug( playWidget );

sio2ResourceUpdateAllWidgetBoundaries( sio2->_SIO2resource, sio2->_SIO2window );
}
sio2WindowLeaveLandscape2D( sio2->_SIO2window );
}
sio2WindowLeave2D();
}
}
else
{
sio2DisableState( &playWidget->flags, SIO2_WIDGET_VISIBLE | SIO2_WIDGET_ENABLED | SIO2_WIDGET_CENTERED );
sio2->_SIO2window->_SIO2windowrender = unloadMenu;
}
}

void splashLoading( void )
{
////SPLASH LOADING
SIO2stream *_SIO2stream = sio2StreamOpen( "poweredby_l.jpg", 1 );
splashWidget = sio2WidgetInit ( "splash" );
splashMaterial = sio2MaterialInit( "splash" );
splashImage = sio2ImageInit ( "splash" );
sio2ImageLoad( splashImage, _SIO2stream );
sio2ImageGenId( splashImage, 0, 0.0f );
splashWidget->_SIO2material = splashMaterial;
splashMaterial->_SIO2image[ SIO2_MATERIAL_CHANNEL0 ] = splashImage;
splashMaterial->blend = SIO2_MATERIAL_COLOR;
splashWidget->_SIO2transform->scl->x = splashImage->width;
splashWidget->_SIO2transform->scl->y = splashImage->height;
_SIO2stream = sio2StreamClose( _SIO2stream );
sio2->_SIO2window->_SIO2windowrender = menuLoading;

}

void menuLoading( void )
{
sio2->tfilter = SIO2_IMAGE_BILINEAR;
sio2->afilter = SIO2_IMAGE_ISOTROPIC;

SIO2stream *_SIO2stream = sio2StreamOpen( "cover.tga", 1 );
coverWidget = sio2WidgetInit ( "cover" );
coverMaterial = sio2MaterialInit( "cover" );
coverImage = sio2ImageInit ( "cover" );
sio2ImageLoad( coverImage, _SIO2stream );
sio2ImageGenId( coverImage, 0, 0.0f );
coverWidget->_SIO2material = coverMaterial;
coverMaterial->_SIO2image[ SIO2_MATERIAL_CHANNEL0 ] = coverImage;
coverMaterial->blend = SIO2_MATERIAL_COLOR;
coverWidget->_SIO2transform->scl->x = coverImage->width;
coverWidget->_SIO2transform->scl->y = coverImage->height;
_SIO2stream = sio2StreamClose( _SIO2stream );

playWidget = sio2WidgetInit ( "play" );
playWidget->area->y = 140;
playWidget->area->x = 56;
playWidget->_SIO2transform->loc->y = 80;
playWidget->_SIO2transform->loc->x = 160;
playWidget->_SIO2widgettapdown = playWidgetTouch;
sio2EnableState( &playWidget->flags, SIO2_WIDGET_VISIBLE | SIO2_WIDGET_ENABLED | SIO2_WIDGET_CENTERED );

MENU = 1;

sio2->_SIO2window->_SIO2windowrender = menuRender;
}

game.mm

The biggest changes I made to game.mm this round were pretty simple. I changed the unloading code to call setMenu instead of gameLoading, so now when you fall off the edge it loads the menu again. In the end their will be a few different paths for unloading the game, either restarting the level, starting the next level, or returning to the menu. For now I set it like this to test the setMenu and setPlay. I changed the accelerometer code to test if we have a player object instead of the accelerometer data before working. It was giving errors in menu mode because the player hadn’t been loaded, but it was trying to assign accelerometer data to it any way. Now, while in the menu the player sio2object is found NULL, and therefore does not attempt to assign forces to the player object.
void gameUnloading( void )
{
sio2ResourceUnload(sio2->_SIO2resource, SIO2_OBJECT);
while( 0 != sio2->_SIO2resource->n_object )
{
SIO2object *_SIO2object = ( SIO2object * )sio2->_SIO2resource->_SIO2object[ 0 ];
if ( _SIO2object->_SIO2objectphysic )
{
sio2PhysicRemoveObject( sio2->_SIO2physic, _SIO2object );
}
sio2ObjectFree(_SIO2object);
}
sio2ResourceUnloadAll( sio2->_SIO2resource );
sio2->_SIO2resource = sio2ResourceFree( sio2->_SIO2resource );
sio2->_SIO2resource = sio2ResourceInit( "default" );

sio2->_SIO2window->_SIO2windowrender = setMenu;
}

...
...

void gameScreenAccelerometer( void *_ptr )
{
player = ( SIO2object * )sio2ResourceGetObject( sio2->_SIO2resource, "object/player" );

if( x )
{
if( player )
{
player->_SIO2objectphysic->_btRigidBody->setActivationState( ACTIVE_TAG );
player->_SIO2objectphysic->_btRigidBody->applyCentralForce( btVector3( sio2->_SIO2window->accel->y*(-20.0),
(sio2->_SIO2window->accel->x*20.0), 0));
}
}
}

I imagine their were a couple other changes, I just can’t think of them at the moment. Check out the files, they are working, so anything I am missing here is definitely in there.
~KeithK

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s