Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / iPhone

iPhone Gaming Framework: Stage 1 Tutorial

4.70/5 (11 votes)
2 Jun 2009CPOL5 min read 57.2K   412  
The goal for this tutorial is to get a basic screen management system up and running, ready to start writing game code.
  1. Navigate to ~library/Application Support/Developer/Shared/Xcode/ and create the following folders: Project Templates/iPhone Templates/ .. Your final directory structure should look like ~library/Application Support/Developer/Shared/Xcode/Project Templates/iPhone Templates/
  2. Unzip the OpenGL Screen Controller.zip into your iPhone Templates directory. This will add the OpenGL Screen Controller folder and project template. Your new directory structure will look like: ~library/Application Support/Developer/Shared/Xcode/Project Templates/iPhone Templates/OpenGL Screen Controller/(project files here)
  3. Open up XCode, create new project, and you’ll see on the left side “User Templates” with a sub-category “iPhone Templates,” clicking on that will bring up your Screen Controller template.

Look at the code, see how its done. Build and run it, and if you click “Level Play” it should transition to a new screen (the gameplay screen) .. click anywhere else in the frame while on the gameplay screen, and it will remove that screen from the screen controller and go back to the title screen. Trace the code, see how it does it, and start playing around.

Buckle in guys, this is going to be a rather large tutorial. The goal for this tutorial is to get a basic screen management system up and running, ready to start writing game code. I would like to start off by saying the following: This is not the only way to get a project up and running! There are many many many ways of solving problems in the programming world. Some people might prefer to use Cocos2D for the iPhone, while others might prefer to roll their own engine from scratch. I did this more as a learning process for myself, and now that I’ve learned what I could, I thought I should share the knowledge to everyone else who is struggling with the problems that I’ve solved.

Also, keep in mind that this screen management system is basically a port of the GameStateManagement demo from the XNA sample ( http://creators.xna.com/ ) from C# to Objective-C with some modifications. Anyone currently using XNA should have a fairly easy time porting this over, as a lot of the code should be recognizable to you.

So, now that I’ve got that out of the way, lets begin! Your first step is going to head over to Jeff’s blog iPhoneDevelopment and pick up the Updated OpenGL Xcode Project Template.

Next step, is to follow his directions and install it! Once you have it installed, load a new project using his template. You will find that a few things are different, and a whole lot is added. Open up the GLView.m in the classes subdirectory, and add the following four methods:

C++
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	[controller touchesBegan:touches withEvent:event InView:self  WithTimer:animationTimer];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
	[controller touchesMoved:touches withEvent:event InView:self  WithTimer:animationTimer];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	[controller touchesEnded:touches withEvent:event InView:self  WithTimer:animationTimer];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	[controller touchesCancelled:touches withEvent:event InView:self  WithTimer:animationTimer];
}

What this is going to do, is when your iPod touch or iPhone is touched, a message is sent to the GLView. We are going to capture that message, and send it to the GLViewController. Okay, got that done? GREAT! Now comes the fun stuff.

Open up your GLViewController.h file. You are going to be putting in quite a bit of code, and I’ll explain everything when we do the .m file, so for right now just adjust your .h file to look like the following. You’ll see the .m file is HEAVILY commented to show what everything is and what it does, and I’ll make some additional notes here as well. Here is the GLViewController.h file.

C++
//
//	The View Controller is a service which mananges one or more GameScreen
//	instances. It maintains a stack of screens, calls their Update and Draw
//	methods at the appropriate times, and automatically routes the input to
//	the topmost active screen.
//
//	Created by XNA Development Team ( http://creators.xna.com/ ) as a
//	ScreenManager.cs GameComponent.
//
//  Adapted for iPhone Game Development by Craig Giles on 1/1/09.
//

//
//	Import statements
//
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>

#import "Texture2D.h"
#import "InputManager.h"
#import "GameScreen.h"
#import "TitleScreen.h"

@class GLView;
@interface GLViewController : UIViewController
{
	NSMutableArray *screens;
	NSMutableArray *screensToUpdate;
	InputManager *input;
	Texture2D *blankTexture;

	bool isInitialized;
	bool traceEnabled;	

	UIView *gameView;
	CGRect viewport;
}

//
//	Properties
//
@property (nonatomic, retain) NSMutableArray *screens;
@property (nonatomic, retain) NSMutableArray *screensToUpdate;
@property (nonatomic, retain) InputManager *input;
@property (nonatomic, retain) Texture2D *blankTexture;

@property (nonatomic, readwrite) bool isInitialized;
@property (nonatomic, readwrite) bool traceEnabled;

@property (nonatomic, retain) UIView *gameView;
@property (nonatomic, readwrite) CGRect viewport;

//
//	Methods
//
- (void) setupView:(GLView*)view;
- (void) loadContent;
- (void) addScreen:(GameScreen *)screen;
- (void) removeScreen:(GameScreen *)screen;
- (void) releaseScreen:(GameScreen *)screen;
- (void) updateView:(GLView *)view WithTime:(float)deltaTime;
- (void) drawView:(GLView *)view WithTime:(float)deltaTime;
- (void) traceScreens;
- (void) fadeBackBufferToBlack:(double)alpha;

//
//	Touches events
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;

@end

Its a good idea to look through the .h file to see what you can do with the screen manager. Obviously you can do the touch events (remember we connected those from the GLView?) but also, looking at the methods you will be able to add and remove screens from the screen manager, update and draw, fade back buffer to black, and a few other things. Let's see how it all works!

C++
//
//	The View Controller is a service which mananges one or more GameScreen
//	instances. It maintains a stack of screens, calls their Update and Draw
//	methods at the appropriate times, and automatically routes the input to
//	the topmost active screen.
//
//	Created by XNA Development Team ( http://creators.xna.com/ ) as a
//	ScreenManager.cs GameComponent.
//
//  Adapted for iPhone Game Development by Craig Giles on 1/1/09.
//

//
//	Import commands from Jeff's template
//
#import "GLViewController.h"
#import "GLView.h"
#import "OpenGLCommon.h"
#import "ConstantsAndMacros.h"

//
//	This indicates weather or not the game will be played in
//	landscape or portrait mode. While in landscape mode, the
//	screen will be rotated, but also the input will be off.
//	Touch coordinates for the screen will have to be converted
//	before it reaches the input manager class.
//
const bool LANDSCAPE_MODE = NO;

//
//	The time it takes for a game screen to transition
//	These can be over written in the game screen init.
//	If there is no values in the game screen itself, these
//	will be used as the default values.
//
const float TRANSITION_ON_TIME = .70f;
const float TRANSITION_OFF_TIME = .20f;

//
//	Implementation of the Screen Manager class
//
@implementation GLViewController

//
//	Getters / Setters
//
@synthesize screens;
@synthesize screensToUpdate;
@synthesize input;
@synthesize blankTexture;

@synthesize isInitialized;
@synthesize traceEnabled;

@synthesize gameView;
@synthesize viewport;

//
//	Setup View handles setting up OpenGL's Projection Matrix and
//	enables all states needed for rendering the game to screen.
//
-(void)setupView:(GLView*)view
{
	//	Set the view to the gameView
	gameView = view;

	//	Modify the Projection matrix
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	//
	//	Orthof projection is used for 2d games. This sets the coordinates to
	//	(0, 0) at the top left corner of the screen, and as you move downward
	//	your y value will increase. As you move to the right, your x value will
	//	increase.
	//	(left, right, bottom, top, near, far)
	//
	//	If the game is going to be played in landscape mode, enable
	//	it via the bool switch at the top of the GLViewController.m file.
	if ( LANDSCAPE_MODE )
	{
		viewport = CGRectMake(0, 0, 480, 320);
		glViewport(0, 0, viewport.size.height, viewport.size.width);
		glRotatef(-90, 0, 0, 1);
        glOrthof(0, viewport.size.width, viewport.size.height, 0, -10.0, 10.0);  

	}
	else	//	Game is to be played in portrait
	{
		viewport = CGRectMake(0, 0, 320, 480);
		glViewport(0, 0, viewport.size.width, viewport.size.height);
		glOrthof(0.0, viewport.size.width, viewport.size.height, 0.0, -1.0, 1.0);	

	}

	//
	//	Setup Model view matrix
	//	Load graphics settings
	//
	glMatrixMode(GL_MODELVIEW);

	glDisable(GL_DEPTH_TEST);
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);	

	//	needed to draw textures using Texture2D
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);

	//	enables alpha for transparent textures
	//	I forget where I got these commands, iDevGames.net I think
	glAlphaFunc(GL_GREATER, 0.1f);
	glEnable(GL_ALPHA_TEST);

	//
	//	Setup clear color (cornflower blue'ish)
	//	Call me crazy, but I got so used to this color developing
	//	for XNA. This is a little nod to the Microsoft Development
	//	Team :)
	//
	glLoadIdentity();
	glClearColor(.39f, 0.58f, 0.920f, 1.0f); 

	//
	//	Call the view controllers loadContent method
	//
	[self loadContent];

}

//
//	Loads all content needed to run the screen manager. This is seperated
//	from the setupView method in order to seperate what is needed from OpenGL
//	to setup the screen, and what is needed from the screen manager to set
//	up the game structure.
//
- (void)loadContent
{
	//
	//	Allocate memory for your arrays to hold the Screens "stacks."
	//	All game screens will be housed in this array for easy manipulation.
	//
	screens = [[NSMutableArray alloc] init];
	screensToUpdate = [[NSMutableArray alloc] init];

	//
	//	Allocate memory for the input manager and the blankTexture used
	//	to fade the screen in / out.
	//
	input = [[InputManager alloc] init];
	input.isLandscape = LANDSCAPE_MODE;
	blankTexture = [[Texture2D alloc] initWithImage:[UIImage imageNamed:@"blankTexture.png"]];

	for (GameScreen *screen in screens)
		[screen loadContent];

	//
	//	Once we are initialized, set the bool values to appropriate values.
	//
	isInitialized = YES;
	traceEnabled = NO;

	//
	//	Adds a title screen to the game stack. This will be taken out
	//	later, and right now is only used for debugging purposes. It
	//	will be replaced with your splash screen or game introduction
	//	screen.
	//
	TitleScreen *newScreen = [[TitleScreen alloc] init];
	[self addScreen:newScreen];
	[newScreen release];
}

//
//	When the view controller exits, we will need to clean up any memory used.
//
- (void)dealloc
{
	//
	//	setup a delete screens array and add all of the current game screens
	//	to this array. We will then cycle through all game screens, unloading
	//	their content, and releasing them from the view controller. After all
	//	is said and done, we will then remove the deleteScreens array, and
	//	continue on releasing any other memory allocated for the view controller.
	//
	NSMutableArray *deleteScreens = [[NSMutableArray alloc] initWithArray:screens];

	for (GameScreen *screen in deleteScreens)
	{
		[self removeScreen:screen];
		[self releaseScreen:screen];
	}

	[deleteScreens release];
	[screens release];
	[screensToUpdate release];
	[input release];
	[blankTexture release];

    [super dealloc];
}

//
//	If the game is going over memory, this method will be called by the device
//	warning that we are running low on memory and should release any un needed
//	items.
//
- (void)didReceiveMemoryWarning
{
	//	<<TODO: Unload any un-needed game content here>>
    [super didReceiveMemoryWarning];
}

//
//	Add a screen to the view controller
//
- (void) addScreen:(GameScreen *)screen
{
	//
	//	When adding a screen to the view controller, we will be
	//	setting some default values for the screen, and then call
	//	the screens "loadContent" method. Once everything is loaded,
	//	the view controller will retain the screen and add it to the
	//	screens array.
	//
	screen.controller = self;
	screen.viewport = self.viewport;
	screen.transitionOnTime = TRANSITION_ON_TIME;
	screen.transitionOffTime = TRANSITION_OFF_TIME;
	screen.currentScreenState = TransitionOn;
	screen.transitionPosition = 1;
	[screen loadContent];

	[screen retain];
	[screens addObject:screen];
}

//
//	Unload all game content from the screen. This in turn
//	sets a flag within the screen itself, that the content has
//	been unloaded, and in the controllers Update method, all game
//	screens that have been unloaded will be released from memory.
//
- (void) removeScreen:(GameScreen *)screen
{
	//unload any content it has stored
	[screen unloadContent];
}

//
//	Release all game screens from memory, that have had their content
//	unloaded. This will release all screens themselves, as well as remove
//	them from the screens arrays.
//
- (void) releaseScreen:(GameScreen *)screen
{
	//	remove the screen from all screen arrays
	[screens removeObject:screen];
	[screensToUpdate removeObject:screen];

	//	deallocate any memory used for the screen
	[screen release];
}

//
//	Update every screen in the screens stack, keeping track
//	of which screens are covered and which are fully active.
//	if a screen is fully active and "on top" of the stack, it
//	should receive any input.
//
- (void) updateView:(GLView *)view WithTime:(float)deltaTime
{
	//	Read the touch input
	[input update:deltaTime];

	//	make a copy of hte master screen list, to avoid confusion if
	//	the process of updating one screens adds or removes others.
	[screensToUpdate removeAllObjects];

	for(GameScreen *screen in screens)
		[screensToUpdate addObject:screen];

	bool otherScreenHasFocus = NO;
	bool coveredByOtherScreen = NO;

	//	loop as long as there are screens waiting to be updated
	while ([screensToUpdate count] > 0)
	{
		//	pop the topmost screen off the waiting list
		GameScreen *screen = [screensToUpdate objectAtIndex:([screensToUpdate count] - 1)];

		[screensToUpdate removeObjectAtIndex:[screensToUpdate count] - 1];

		//	update the screen
		[screen update:deltaTime OtherScreenHasFocus:otherScreenHasFocus
								CoveredByOtherScreen:coveredByOtherScreen];

		if ([screen currentScreenState] == TransitionOn ||
			[screen currentScreenState] == Active)
		{
			//	if this is the first active screen we came across,
			//	give it a chance to handle input.
			if (!otherScreenHasFocus)
			{
				[screen handleInput:input];
				otherScreenHasFocus = YES;
			}

			//	if this is an active non-popup, inform any subsequent
			//	screens that they are covered by it
			if (![screen isPopup])
				coveredByOtherScreen = YES;

		}
	}

	//	do we need to print the debug trace?
	if (traceEnabled)
		[self traceScreens];

	//
	//	For every screen that had their content unloaded.. release
	//	the memory used for that screen here. We do this up front
	//	to ensure that any released screen doesn't get their update
	//	or draw methods called, when there is nothing to update or draw.
	//
	for (GameScreen *screen in screens)
	{
		if (screen.hasBeenUnloaded)
		{
			[self releaseScreen:screen];
		}
	}
}

//
//	Draw the game screens from "Bottom to Top." This is done
//	in order to ensure that any pop'up screens are drawn on top
//	of the full screen below it.
//
- (void) drawView:(GLView *)view WithTime:(float)deltaTime
{
	//	Clear the screen to preset color before drawing
	glClear(GL_COLOR_BUFFER_BIT);

	//	Draw every screen in the screens array
	for (GameScreen *screen in screens)
	{
		//if the screens content has been unloaded, don't draw
		if (screen.hasBeenUnloaded)
			continue;

		[screen draw:deltaTime];
	}
}

//
//	Helper method designed to draw the screen names currently
//	in the game stack in order to see if they are being added
//	and removed correctly.
//
- (void) traceScreens
{
	//	<<TODO: Input code to draw the screen names>>
}

//
//	Helper method to draw a translecent black fullscreen sprite, used
//	for fading screens in and out, and for darkening the background
//	behind pop up screens.
//
- (void) fadeBackBufferToBlack:(double)alpha
{
	glColor4f(alpha,alpha,alpha,alpha);
	[blankTexture drawInRect:self.viewport];
	glColor4f(1, 1, 1, 1);
}

//
//	When the screen is touched by the user, the GLView will pass along a message
//	to the view controller that the screen has been touched. The view controller
//	will take the message, and pass it along to the input manager where the
//	necessary information will be stored and filtered to the game screen that
//	will handle the user input.
//
//	In order for this to work, in your GLView, you need to write the following
//	4 methods:
//	- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//	- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
//	- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
//	- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
//
//	Those methods will call the methods below.
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
	[input touchesBegan:touches withEvent:event InView:touchView  WithTimer:timer];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
	[input touchesMoved:touches withEvent:event InView:touchView  WithTimer:timer];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
	[input touchesEnded:touches withEvent:event InView:touchView  WithTimer:timer];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
	[input touchesCancelled:touches withEvent:event InView:touchView  WithTimer:timer];
}

@end

As you can see, this is a pretty good sized class. What makes it bigger is I have a nasty habit of commenting everything to hell! I always believe it is best to comment heavily, because if you come back a year later and want to adjust your game, comments make it very helpful for remembering what does what.

The comments in the GLViewController (screen manager) class explains what everything does, but if you have any questions feel free to post them here.

So now we need a game screen or two!! Remember, the following code should never be used to make a game screen directly. What I mean is, use this as a super class and inherit from it with your screens. For example, your TitleScreen should inherit from GameScreen. Make sense?

Here is the GameScreen.h file

C++
//
//	A screen is a single layer that has update and draw logic, and which
//	can be combined with other layers to build up a complex screen system
//	or menu system, or even dialog system.
//
//	Developed by XNA Development Studio ( http://creators.xna.com/ )
//	Modified for the iPhone Gameing Framework by Craig Giles on 1/1/09.
//

#import <Foundation/Foundation.h>

#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>

#import "InputManager.h"
#import "Texture2D.h"

//
//	Enum to describe the screens transition state
//
enum ScreenState {
	TransitionOn = 0,
	Active,
	TransitionOff,
	Hidden
};

//
//	Forward Declarations
//
@class GLViewController;

@interface GameScreen : NSObject
{
@private
	GLViewController *controller;
	CGRect viewport;

	bool hasBeenUnloaded;
	bool isPopup;

	float transitionOnTime;
	float transitionOffTime;
	float transitionPosition;
	float transitionAlpha;
	enum ScreenState currentScreenState;

	bool isExiting;
	bool isActive;
	bool otherScreenHasFocus;
}

@property (nonatomic, retain) GLViewController *controller;
@property (readwrite) CGRect viewport;

@property (readwrite) bool hasBeenUnloaded;
@property (readwrite) bool isPopup;

@property (readwrite) float transitionOnTime;
@property (readwrite) float transitionOffTime;
@property (readwrite) float transitionPosition;
@property (readwrite) float transitionAlpha;

@property (readwrite) enum ScreenState currentScreenState;

@property (readwrite) bool isExiting;
@property (readwrite) bool isActive;
@property (readwrite) bool otherScreenHasFocus;

- (void) loadContent;
- (void) unloadContent;

- (void) handleInput:(InputManager *)input;
- (void) update:(float)deltaTime	OtherScreenHasFocus:(bool)otherFocus	CoveredByOtherScreen:(bool)coveredByOtherScreen;
- (bool) updateTransition:(float)deltaTime	TransitionTime:(float)transition	Direction:(int)direction;
- (void) draw:(float)deltaTime;

- (void) exitScreen;

@end

and the GameScreen.m file

C++
//
//	A screen is a single layer that has update and draw logic, and which
//	can be combined with other layers to build up a complex screen system
//	or menu system, or even dialog system.
//
//	Developed by XNA Development Studio ( http://creators.xna.com/ )
//	Modified for the iPhone Gameing Framework by Craig Giles on 1/1/09.
//

#import "GameScreen.h"

@implementation GameScreen

//
// Properties
//
@synthesize controller;
@synthesize viewport;

@synthesize hasBeenUnloaded;
@synthesize isPopup;

@synthesize transitionOnTime;
@synthesize transitionOffTime;
@synthesize transitionPosition;
@synthesize transitionAlpha;

@synthesize currentScreenState;

@synthesize isExiting;
@synthesize otherScreenHasFocus;

@dynamic isActive;
- (bool) isActive
{
	return !otherScreenHasFocus &&
	(currentScreenState == TransitionOn ||
	 currentScreenState == Active);
}

//
// Constructor(s) / destructors
//
- (id) init
{
	self = [super init];
	if (self != nil)
	{
		//initializations go here
		isExiting = NO;
	}
	return self;
}

- (void) dealloc
{
	//Deallocations go here
	[super dealloc];
}

//
// Loads all content associated with the current screen
//
- (void) loadContent
{

}

//
// Unloads all content associated with the current screen
//
- (void) unloadContent
{
	//	Release the screen manager
	[controller release];

	//	inidicate that the screens content has been unloaded
	hasBeenUnloaded = YES;
}

//
// Allows the screen to perform its update logic.
//
- (void) handleInput:(InputManager *)input
{
}

//
//	Updates the base screen. Since any game screen
//	wil be inheriting from this class, the game screen will
//	call this update method. This update just helps with the
//	transition between two screens, and if a screen is
//	transitioning on and off.
//
- (void) update:(float)deltaTime	OtherScreenHasFocus:(bool)otherFocus	CoveredByOtherScreen:(bool)coveredByOtherScreen
{
	otherScreenHasFocus = otherFocus;

	if (isExiting)
	{
		//if the screen is going to die, it should transition off
		currentScreenState = TransitionOff;

		if (![self updateTransition:deltaTime TransitionTime:transitionOffTime Direction: 1])
		{
			//when transition finishes, remove the screen
			[controller removeScreen:self];
		}
	}
	else if (coveredByOtherScreen)
	{
		//if the screen is covered by another, it should transition off
		if ([self updateTransition:deltaTime TransitionTime:transitionOffTime Direction: 1])
		{
			//scren is still transitioning
			currentScreenState = TransitionOff;
		}
		else
		{
			//transition has finished
			currentScreenState = Hidden;
		}
	}
	else
	{
		if ([self updateTransition:deltaTime TransitionTime:transitionOnTime Direction: -1])
		{
			//still busy transitioning
			currentScreenState = TransitionOn;
		}
		else
		{
			//transition finished
			currentScreenState = Active;
		}
	}
}

//
//	Helper method for updating the screen transition position
//	(how much the screen has faded in / out)
//
- (bool) updateTransition:(float)deltaTime TransitionTime:(
    float)time Direction:(int)direction
{
	//	how much should we move by?
	float transitionDelta;

	if (time <= 0)
		transitionDelta = 1;
	else
		transitionDelta = deltaTime / time;

	//update the transition position
	transitionPosition += transitionDelta * direction;

	//did we reach the end of the transition?
	if (direction < 0 && transitionPosition <= 0 ||
		direction > 0 && transitionPosition >= 1)
	{
		//clamp transition position to 0, 1, or value;
		if (transitionPosition >= 1)
			transitionPosition = 1;
		else if (transitionPosition <= 0)
			transitionPosition = 0;

		return NO;
	}//end "end of transition"

	//otherwise, we are still busy transitioning
	return YES;
}

//
//	Each screen will have their own draw method. EVERY SCREEN
//	should call [super draw:deltaTime] in order to draw
//	the fade correctly when the screen manager wishes to fade
//	the screen in or out.
//
- (void) draw:(float)deltaTime
{
	[self.controller fadeBackBufferToBlack:self.transitionPosition];
}

//
// Tells the screen to go away. Unlike [controller removeScreen] which
// instantly kills the screen, this method respects the transition timings
// and will give the scren a chance to gradually transition off.
//
- (void) exitScreen
{
	if (transitionOffTime == 0)
	{
		//if the screen has zero transition time, kill it
		[controller removeScreen:self];
	}
	else
	{
		//otherwise flag that it should transition off and exit
		isExiting = YES;
	}
}

@end

Well that does it for the screen manager and the game screen classes. But keep in mind — this will NOT build until the InputManager is built. Why don’t you try to fiddle with that for a while, see what you can come up with? I’ll post Part 2 of this tutorial detailing how I did my input manager and two screens (TitleScreen and PausedScreen) in my next update.

Two thing before I go: I would really like to find a way to turn this into a template for anyone wishing to use it, but I simply do not know how. If you know how to do so, please leave a message on the forum below.

Secondly, if you have any questions, comments, sly remarks, please post them. I am very good at reading everyones comments, and getting back to you if needed. You can either post a comment or send me an email and I’ll get back to you.

EDIT:
I just wanted to let everyone know that there have been a few changes to this article since first posting. I just modified the code within the GLViewController in several places. The following changes were made:

  • Added [self releaseScreen:screen]; in the dealloc method inside the for loop.
  • added const bool LANDSCAPE_MODE = NO; at the top of the view controller, and an if / else statement in the setup view method to help with setting up a landscape view rather than a portrait view. (The first screen manager was written for only portrait view)
  • added input.isLandscape = LANDSCAPE_MODE; to the loadContent method.

Again, there are too many people to thank for helping me to get to where I am with my current knowledge. I hope this was informational to a few of you! Happy coding everyone!

Read the original blog post here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)