iPhone 游戏框架:第一阶段教程






4.70/5 (10投票s)
本教程的目标是建立一个基本的屏幕管理系统,并使其能够立即开始编写游戏代码。
- 导航到 ~library/Application Support/Developer/Shared/Xcode/ 并创建以下文件夹:Project Templates/iPhone Templates/ .. 您的最终目录结构应类似于 ~library/Application Support/Developer/Shared/Xcode/Project Templates/iPhone Templates/
- 将 OpenGL Screen Controller.zip 解压缩到您的 iPhone Templates 目录中。这将添加 OpenGL Screen Controller 文件夹和项目模板。您的新目录结构将如下所示:~library/Application Support/Developer/Shared/Xcode/Project Templates/iPhone Templates/OpenGL Screen Controller/(项目文件在此处)
- 打开 XCode,创建一个新项目,您会在左侧看到“User Templates”,其中有一个子类别“iPhone Templates”,单击它将显示您的 Screen Controller 模板。
查看代码,了解它是如何实现的。构建并运行它,如果您单击“Level Play”,它应该会过渡到一个新屏幕(游戏屏幕)。在游戏屏幕上,单击框架内的任何其他位置,它将从屏幕控制器中删除该屏幕并返回到标题屏幕。跟踪代码,了解它是如何实现的,并开始尝试。
各位,坐稳了,这将是一个相当大的教程。本教程的目标是建立一个基本的屏幕管理系统,并使其能够立即开始编写游戏代码。我想先说一句:这不是启动项目的唯一方法!在编程世界中,解决问题的方法有很多很多。有些人可能更喜欢使用 Cocos2D 来开发 iPhone,而另一些人则可能喜欢从头开始构建自己的引擎。我这样做更多是为了自己的学习过程,现在我已经学到了我能学到的东西,我想把知识分享给所有还在为我已解决的问题而挣扎的其他人。
另外,请记住,这个屏幕管理系统基本上是从 XNA 示例( http://creators.xna.com/ )中的 GameStateManagement 演示移植到 Objective-C 的,并进行了一些修改。目前使用 XNA 的任何人应该都能比较轻松地将其移植过来,因为其中很多代码对您来说应该很熟悉。
那么,现在我把这些说完了,让我们开始吧!您的第一步是前往 Jeff 的博客 iPhoneDevelopment 并获取 Updated OpenGL Xcode Project Template。
下一步是按照他的说明进行安装!安装完成后,使用他的模板加载一个新项目。您会发现一些地方有所不同,并且添加了很多内容。打开类子目录中的 GLView.m 文件,并添加以下四个方法
- (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];
}
这将实现,当您的 iPod touch 或 iPhone 被触摸时,一个消息将被发送到 GLView。我们将捕获该消息,并将其发送到 GLViewController
。好了,做完了吗?太棒了!现在进入有趣的部分。
打开您的 GLViewController.h 文件。您将要输入相当多的代码,我会在 .m 文件中解释所有内容,所以现在只需将您的 .h 文件调整为如下所示。您会发现 .m 文件被注释得非常详细,以显示每个内容是什么以及它的作用,我也会在这里添加一些额外的注释。这是 GLViewController.h 文件。
//
// 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
仔细查看 .h 文件,了解屏幕管理器可以做什么,这是一个好主意。显然,您可以处理触摸事件(还记得我们从 GLView 连接的那些吗?),而且,通过查看这些方法,您将能够向屏幕管理器添加和删除屏幕,更新和绘制,将后缓冲淡化为黑色,以及其他一些功能。让我们看看它是如何工作的!
//
// 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
正如您所看到的,这是一个相当大的类。之所以这么大,是因为我有一个糟糕的习惯,就是把所有东西都注释得一塌糊涂!我一直认为注释越多越好,因为如果您一年后回来想调整您的游戏,注释可以帮助您回忆起每个功能的作用。
GLViewController
(屏幕管理器)类中的注释解释了所有内容的作用,但如果您有任何疑问,请随时在此处发布。
现在我们需要一个或两个游戏屏幕!!请记住,以下代码永远不应直接用于创建游戏屏幕。我的意思是,将其用作超类,并用您的屏幕从中继承。例如,您的 TitleScreen 应该继承自 GameScreen。明白了吗?
这是 GameScreen.h 文件
//
// 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
这是 GameScreen.m 文件
//
// 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
好了,屏幕管理器和游戏屏幕类就完成了。但请记住——在 InputManager
构建完成之前,这不会成功编译。为什么不尝试自己弄一会儿,看看您能想出什么?我将在我的下一个更新中发布本教程的第二部分,详细介绍我如何实现我的输入管理器和两个屏幕(TitleScreen 和 PausedScreen)。
在我离开之前还有两件事:我真的很想找到一种方法将此变成一个模板供任何人使用,但我根本不知道怎么做。如果您知道如何做,请在下面的论坛上留言。
其次,如果您有任何问题、评论或俏皮话,请发布。我非常擅长阅读大家的评论,并在需要时给您回复。您可以发表评论或给我发送电子邮件,我会回复您。
编辑
我只是想让大家知道,这篇文章自从首次发布以来已经做了一些更改。我刚刚在 GLViewController 中的几个地方修改了代码。进行了以下更改
- 在 dealloc 方法的 for 循环中添加了
[self releaseScreen:screen];
。 - 在视图控制器顶部添加了 const bool
LANDSCAPE_MODE = NO;
,并在 setup view 方法中添加了一个 if / else 语句,以帮助设置横向视图而不是纵向视图。(第一个屏幕管理器是只为纵向视图编写的) - 在 loadContent 方法中添加了
input.isLandscape = LANDSCAPE_MODE;
。
再次感谢太多的人帮助我达到我目前的知识水平。我希望这对你们中的一些人有所帮助!祝大家编码愉快!
在此处 阅读原始博客文章。