Learning IOS Game Programming

This book not only describes the components and technology needed to create a game on the iPhone, but it does so through the creation of a complete game.

Michael Daley

440 Pages

23945 Reads



PDF Format

7.92 MB

Game Development

Download PDF format

  • Michael Daley   
  • 440 Pages   
  • 19 Feb 2015
  • Page - 1

    read more..

  • Page - 2

    Praise for Learning iOS Game Programming “An excellent introduction into the world of game development explaining every aspect of game design and implementation for the iPad, iPhone, and iPod touch devices. A great way for anyone interested in writing games to get started.” —Tom Bradley, Software Architect, Designer of TBXML “A great developer and a great game.That’s read more..

  • Page - 3

    This page intentionally left blank read more..

  • Page - 4

    Learning iOS Game Programming read more..

  • Page - 5

    This page intentionally left blank read more..

  • Page - 6

    Learning iOS Game Programming Michael Daley Upper Saddle River, NJ • Boston • Indianapolis • San Francisco New York • Toronto • Montreal • London • Munich • Paris • Madrid Cape Town • Sydney • Tokyo • Singapore • Mexico City read more..

  • Page - 7

    Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and the publish- er was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals. The author and publisher have taken care in the preparation of this book, but read more..

  • Page - 8

    ❖ Dedicated to my mum, Jen ❖ read more..

  • Page - 9

    Contents at a Glance Preface xxi 1 Game Design 1 2 The Three Ts: Terminology, Technology, and Tools 13 3 The Journey Begins 39 4 The Game Loop 73 5 Image Rendering 97 6 Sprite Sheets 137 7 Animation 153 8 Bitmap Fonts 165 9 Tile Maps 183 10 The Particle Emitter 223 11 Sound 249 12 User Input 285 13 The Game Interface 299 14 Game Objects and Entities 325 15 Collision Detection 357 16 Putting read more..

  • Page - 10

    Table of Contents Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi 1 Game Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 The Game That Started It All (For Me) . . . . read more..

  • Page - 11

    Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 The iPhone SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Summary . . . . . . . . . . . . . read more..

  • Page - 12

    Creating the Game Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 The GameController Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Creating the Singleton . . . . . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 13

    PackedSpriteSheet Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Parsing the Control File . . . . . . . . . . . . . . . . . read more..

  • Page - 14

    Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 Exercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 9 Tile Maps . . . . . . . . . . . read more..

  • Page - 15

    Life Cycle of a Particle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 A Particle Is Born . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 A Particle Lives . . . . . . . . . . . . . . . . . read more..

  • Page - 16

    Processing Taps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 Accelerometer Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 Summary . . . . . . . . . . . . . . . . . . . . . read more..

  • Page - 17

    Detecting Collisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 Collision Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362 Entity-to-Map Collision Detection . . . . . . . . . . read more..

  • Page - 18

    Acknowledgments Writing this book has been an amazing journey, and it’s only through the efforts of many other people that you are reading this today.Without these people, I don’t believe the book would have even been published, let alone become the valuable resource I believe it to be. For this reason, I would like to acknowledge those people who have supported me on read more..

  • Page - 19

    projects, and more information about him and his work can be found at www.vincewebb.com.Vince is a real talent, and I’m pleased to have had the opportunity to work with him. n Games such as Sir Lamorak’s Quest need a lot of testing, and through my 71Squared.co.uk blog, I was able to get help from a great team of beta testers. These testers were all followers of read more..

  • Page - 20

    About the Author By day, Michael Daley works for the largest enterprise software company in the world supporting large corporate customers in communications. By night, Michael has taken on the task of learning how to build games for the iPhone. Michael started writing adventure games in BASIC on a Sinclair Spectrum 48k and progressed onto the Commodore 64 and the Amiga A500. read more..

  • Page - 21

    We Want to Hear from You! As the reader of this book, you are our most important critic and commentator.We value your opinion and want to know what we’re doing right, what we could do better, what areas you’d like to see us publish in, and any other words of wisdom you’re willing to pass our way. You can email or write me directly to let me know what read more..

  • Page - 22

    Preface Writing a game can be a daunting task. Even if you’re an experienced programmer, the design patterns, terminology, and thought processes can seem strange and unusual. Having spent most of my working life creating business applications, writing games has been a hobby that has seen me create many games my children have played and enjoyed over the years.With the read more..

  • Page - 23

    Each chapter describes in detail a specific component within the game, along with the technology required to support it, be it a tile map editor, or some effect we’re trying to create with OpenGL ES. Once an introduction to the functionality and technology is complete, the chapter then provides details on how the component has been implement- ed within Sir Lamorak’s read more..

  • Page - 24

    n Chapter 2, “The Three Ts:Terminology,Technology, and Tools”—Even experienced pr o- grammers can become confused by the three Ts used within game development. This chapter runs through the common technology, terminology, and tools used to create Sir Lamorak’s Quest and games in general.This chapter helps you understand the terms and technology covered throughout the book. n Chapter read more..

  • Page - 25

    n Chapter 9, “Tile Maps”—Tile maps allo w large game worlds to be created from reusing a small number of tile images.This common approach has been used in the past to create large game worlds (think of the original Super Mario Brothers game for Nintendo) when memory is limited, back in the early days of home game sys- tems.This technique is still popular today, and this read more..

  • Page - 26

    Audience for This Book This book has been written for people who are already programmers but who have never written computer games before. Although it assumes that you already have some experience with Objective-C, each chapter provides enough information on both Objective-C and other technologies so you can follow the concepts and implementations. By the time you complete this read more..

  • Page - 27

    n The iPhone Developer’s Cookbook, Second Edition, by Erica Sadun (Addison-Wesley, 2010). n Core Animation: Simplified Animation Techniques for Mac and iPhone Development,by Marcus Zarra and Matt Long (Addison-Wesley, 2010). n iPhone Programming:The Big Nerd Ranch Guide, by Aaron Hillegass and Joe Conway (Big Nerd Ranch, Inc., 2010). These books, along with other resources you’ll find on read more..

  • Page - 28

    1 Game Design I love games.That’s a fairly simple statement to make, but it really sums me up quite nicely. I’ve been playing games ever since I got my first computer back in 1982.That Sin- clair Spectrum 48k (see Figure 1.1) was something I nagged my parents about for months! And there, among the torn wrapping paper on Christmas morning of 1982, was my first read more..

  • Page - 29

    2 Chapter 1 Game Design It wasn’t long after getting that Spectrum that I started playing as many games as I could get. I wanted to know how the computer—and the games—actually worked. At the time, there were a number of magazines you could buy that gave you information on how to program in BASIC on the Sinclair.Those magazines, such as Sinclair User or ZX read more..

  • Page - 30

    3 The Game That Started It All (For Me) The Game That Started It All (For Me) At the time, I was mostly inspired by Matthew Smith, the 17-year-old who created the hit title Manic Miner. 1 Manic Miner (see Figure 1.2) was a platform game with 20 levels, and it even had an in-game soundtrack, which was a first back then. Matthew created Manic Miner in just six read more..

  • Page - 31

    4 Chapter 1 Game Design publisher and distributor. It wasn’t long before I was hunting the Internet high and low for information that would help me start to develop a game, and that journey has ulti- mately lead to you reading this book. So, What’s the Big Idea? Every game starts with a concept—an idea.When I started thinking about the game for this book, I went to read more..

  • Page - 32

    5 So, What’s the Big Idea? Note I toyed around with a lot of options for the game controls, and discuss those options and the decision-making process later in Chapter 12, “User Input.” Based on the casual nature of the game (and that there’s just no way I could build Halo 10), I ended up with a classic 2D game based in a haunted castle.The castle is inhabited read more..

  • Page - 33

    6 Chapter 1 Game Design You would not think that naming your game could cause problems, but you need to be aware of a couple of important issues when it comes to deploying your game to the App Store. At the time of writing, there are over 150,000 apps in the App Store.That’s a lot of apps and a lot of names that have already been used up, and that is the read more..

  • Page - 34

    7 Game Play Components their time.That meant that the parchment pieces for the Spell of Release would have to be placed around the castle randomly, so that each time the game is played, the player would need to hunt for the parchment all over again, rather than memorizing the locations. Game Play Components With the storyline and objective in place, it was time to think read more..

  • Page - 35

    8 Chapter 1 Game Design Note It may seem odd to make a statement like that last one. However, experience has shown me that although I can have many killer ideas at the start of a project, and I want to set some in stone as they are core to the game play, some of them just don’t end up in the game. They either were too complex to implement, they didn’t read more..

  • Page - 36

    9 Game Play Components Keys I decided that, to make things more challenging for the player, there are a couple of differ- ent door types.The first are normal doors that simply open and close randomly as the player is moving around the castle.The second type of door is a colored door.The idea is that these doors do not open unless the player is carrying the appropriately read more..

  • Page - 37

    10 Chapter 1 Game Design Weapons Many games have a collection of weapons the player can use. Being a knight in a haunted castle, I’ve decided to give the knight just one weapon, a mighty axe, which Sir Lamorak flings at the baddies with great skill. Only a single axe should be thrown at a time, and it will bounce off walls, killing all the baddies it touches, read more..

  • Page - 38

    11 Summary Player This may be the last in the list of game components, but it is one of the most important. The player is the central character within the game around which the story has been built, and there are specific actions the player will need to be able to do. From the story- line created earlier, we know that the player is a knight trapped in a castle read more..

  • Page - 39

    12 Chapter 1 Game Design There are areas we did not discuss in this chapter, such as In-App purchases. Although Sir Lamorak’s Quest isn’t making use of this capability, it is worth considering how In-App purchasing could be used within your game. Allowing the player to purchase new content (levels, weapons, energy, and such) extends the life span of the game and can read more..

  • Page - 40

    2 The Three Ts: Terminology, Technology, and Tools As you learned in the previous chapter, we covered the basic game design, storyline, and game components for Sir Lamorak’s Quest. Although this is all-important information to have at the moment, it’s no more than a story.What we now need to do is take a look at the three Ts: the terminology, technology, and tools we read more..

  • Page - 41

    14 Chapter 2 The Three Ts: Terminology, Technology, and Tools to some of the other tools I will use, such as Pixelmator (www.pixelmator.com).There is nothing to stop you from using your favorite graphics package. By the time you finish this chapter, you will have a good understanding of the termi- nology you will see throughout this book, as well as having a high-level view read more..

  • Page - 42

    15 Terminology The iPhone is many times more powerful than the home computers we had back in the 1980s. Its GPU, particularly in the iPhone 3GS, iPhone 4, and iPad, allows it to achieve some impressive visual effects, thanks to their support for OpenGL ES 2.0. What Is OpenGL ES? OpenGL ES is a subset of the OpenGL graphics language for mobile devices (ES stands for read more..

  • Page - 43

    16 Chapter 2 The Three Ts: Terminology, Technology, and Tools Sprite Sheet As described earlier, a sprite is a single image that is used (and reused) to represent an indi- vidual element onscreen, such as the player’s character, an enemy, and so on. As you can imagine, having many individual sprites within a game—and having a separate file for each sprite, which is then read more..

  • Page - 44

    17 Terminology These more complex sprite sheets mean you cannot perform a fixed calculation as seen already to work out where inside the sprite sheet a specific sprite may be. Instead, you need to include a control file, which does two things: n It defines the location of each sprite within the sprite sheet. n It defines a key for each sprite in the sprite sheet (for read more..

  • Page - 45

    18 Chapter 2 The Three Ts: Terminology, Technology, and Tools Just to make things interesting, you will likely see a different term used for sprite sheets when dealing with OpenGL ES as a sprite sheet is often referred to as a texture atlas. OpenGL ES and textures are covered later in this chapter, but for now, it is good to know that a texture is basically another read more..

  • Page - 46

    19 Terminology Figure 2.4 An animation sprite sheet. We all want the best graphics available, but unless you or someone you know has the nec- essary graphics skills, you will need to use whatever you can find—legally, of course—to keep your project moving along. If you know you will be stuck with developer art, try to come up with a game that suits your drawing read more..

  • Page - 47

    20 Chapter 2 The Three Ts: Terminology, Technology, and Tools luckily, tools such as Hiero 6 and bmfont 7 make the process of turning a font into a sprite sheet really easy. More detail on Hiero can be found in the section,“Tools.” AngelCode has created the bmfont tool, and it is this tool and its generated output that Hiero has been based. Although bmfont is much read more..

  • Page - 48

    21 Terminology In Sir Lamorak’s Quest, our hero will be walking around inside a castle. Although we could create the necessary tile maps manually, it’s much easier to draw the tile maps visu- ally, and that is exactly what we are going to do.We cover the creation of tile maps in Chapter 9,“Tile Maps.” Most large games, such as Doom 3 or Quake Arena, have some read more..

  • Page - 49

    22 Chapter 2 The Three Ts: Terminology, Technology, and Tools What Is a Particle? You may be wondering what we mean when we say particle. Don’t think of it in terms of atoms or quarks like you would in a physics class. When it comes to game development, what we really mean when we say “particle” is “image”. Each “particle” is in fact an image that is rendered to read more..

  • Page - 50

    23 Terminology There are many ways to detect collisions. Some are simple and involve checks to see if the box inside which our player’s sprite is drawn intersects the bounding box of another object, such as a ghost or wall. Other techniques are much more complex, especially when you start to work with physics engines, which is beyond the scope this book.These colli- sions read more..

  • Page - 51

    24 Chapter 2 The Three Ts: Terminology, Technology, and Tools Game Loop The last term I’m going to run through is the game loop.This is an important part of any game and is responsible for making sure that your game performs all the right functions at the right time and in the right order.There are a number of core activities that a game loop must do, such as the read more..

  • Page - 52

    25 Terminology updateIterations = ((currentTime - lastFrameTime) + cyclesLeftOver); if(updateIterations > (MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL)) updateIterations = (MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL); while (updateIterations >= UPDATE_INTERVAL) { updateIterations -= UPDATE_INTERVAL; // Update the game logic passing in the fixed update interval as the delta [sharedGameController read more..

  • Page - 53

    26 Chapter 2 The Three Ts: Terminology, Technology, and Tools This delta value is then passed to the functions that update the logic of the entities within the game and is used to calculate game elements, such as movement. For example, if you specify how far a ghost should move per millisecond, the ghost will only move that far regardless of the device’s speed. Sure, read more..

  • Page - 54

    27 Technology Cocoa Touch Cocoa Touch is a set of object-oriented frameworks that provide a runtime environment for applications running on iOS. Cocoa Touch is an iPhone-specific framework that en- ables you to create touch-based user interface elements as well as access hardware-specific features of the iPhone, iPod touch and iPad, such as the accelerometer, gyroscope, camera, and the read more..

  • Page - 55

    28 Chapter 2 The Three Ts: Terminology, Technology, and Tools color, texture, and transformations to these objects. Because OpenGL ES uses the GPU instead of the CPU, the graphics rendering is hardware accelerated, which means it’s really fast.The GPU is capable of performing floating-point operations over 100 times faster than the CPU. It is a real number-crunching monster. The read more..

  • Page - 56

    29 Technology Figure 2.6 A textured polygon in perspective. OpenGL ES 1.1 vs. 2.0 I’ve mentioned that there are two different versions of OpenGL ES currently, and it’s worth going through the key difference between them. OpenGL ES 1.1 has what is called a fixed pipeline architecture, which means that the operations available are fixed.You pro- vide data to OpenGL ES regarding read more..

  • Page - 57

    30 Chapter 2 The Three Ts: Terminology, Technology, and Tools to do because you have to create the functions you want to use. I expect to see more and more games taking advantage of OpenGL ES 2.0 now that it is supported on the iPhone 3GS, iPhone 4, and iPad, and over time, this will most likely be the way everyone goes. For our game and throughout this book, I read more..

  • Page - 58

    31 Tools shut in the distance along with spooky sounds positioned around the player can add a lot of depth to the game. There are many other items that can be configured within OpenAL, such as the dis- tance model, which defines how quickly sound drops off as the listener moves away from the sound source among other things. OpenAL enables us to play multiple sounds read more..

  • Page - 59

    32 Chapter 2 The Three Ts: Terminology, Technology, and Tools The iPhone development center provides a huge amount of information about devel- oping on the iPhone platform, including documents on getting started, a reference library, and other useful guides. It is also from this site that you can register as an iPhone devel- oper.This is important, as you need to be a read more..

  • Page - 60

    33 Tools Figure 2.8 The Xcode IDE. Although we will not be making much use of Interface Builder when building Sir Lamorak’s Quest, we will be using it to design items such as the settings screen, so it’s important to know that this tool exists. Figure 2.9 Using Interface Builder to create the Settings screen for Sir Lamorak’s Quest. read more..

  • Page - 61

    34 Chapter 2 The Three Ts: Terminology, Technology, and Tools The iPhone Simulator The iPhone Simulator (shown in Figure 2.10) is a small application within Xcode that lets you to test your application on your desktop, without installing the app on your iPhone. Although the iPhone Simulator is a great tool for most applications, there is no substitute for testing your games on read more..

  • Page - 62

    35 Tools end up with something that works great in the iPhone Simulator, but just crashes or runs slowly on the iPhone.All your real testing should be on the real device. n Different device capabilities— The iPhone and iPod Touch use technologies such as core location (a GPS/cellular location), Bluetooth, wireless, accelerometer, and with the iPhone 3GS, iPhone 4, and iPad, a read more..

  • Page - 63

    36 Chapter 2 The Three Ts: Terminology, Technology, and Tools Shark Shark is not some throwback to the Jaws movies, but it will attack your code in a good way. Shark is used to track down performance problems you may find in your code. Al- though you should always strive to get the best performance out of your applications, it is even more important with a game on a read more..

  • Page - 64

    37 Tools Figure 2.13 Hiero can be used to create sprite sheets for bitmap fonts you want to use in your game. Tiled This is a free open source tile map editor.Tiled (shown in Figure 2.14) enables you to load tile images and then graphically draw your map.You can have multiple layers of tiles and multiple tile sets, and you can even define parameters associated with read more..

  • Page - 65

    38 Chapter 2 The Three Ts: Terminology, Technology, and Tools Summary This chapter covered a lot of material, but it was important to provide you with some in- sight into the terminology, technology, and tools we are going to use to build Sir Lamorak’s Quest. Before going any further, make sure you download and install the following applica- tions on your system: n The read more..

  • Page - 66

    3 The Journey Begins We have covered a lot in the first two chapters, and you should be starting to feel a lit- tle more comfortable with the terminology, technology, and tools we are going to use to create Sir Lamorak’s Quest. Although the information we have covered has been impor- tant to understand before we start to dive into the code, diving into the read more..

  • Page - 67

    40 Chapter 3 The Journey Begins Figure 3.1 Xcode’s welcome screen. The next step is to create a new project. After closing the welcome window, go to File > New Project . A window appears, asking you to choose a template for your new project (see Figure 3.2). Figure 3.2 Xcode’s New Project window. read more..

  • Page - 68

    41 Creating the Project in Xcode Hint Make sure that Application is selected under the iPhone OS section on the left side of the window, or you will not see the OpenGL ES Application template. Once you have selected the OpenGL ES Application template and have made sure that the correct product is selected (that is, iPhone), click Choose.You will be presented with a panel read more..

  • Page - 69

    42 Chapter 3 The Journey Begins Note To be honest, this is not a view that I use very much. I prefer to see the files in the tree view outline on the left and have the editor pane open on the right. Clicking a file in the detail pane causes the editor pane to open. This is personal preference, so find what works for you and go with it. Running the Project read more..

  • Page - 70

    43 Application Delegate Although we have not done anything yet other than create the project and give it a name, the application already contains the key elements needed to render to the screen using OpenGL, which is all that’s needed to start working on the game. Under the Hood Now that we have our project created and running, let’s look at the code that has read more..

  • Page - 71

    44 Chapter 3 The Journey Begins In Xcode, expand the tree view for CH03_SLQTSOR and then the Classes group. In here are the main files that have been created within our project in which we are inter- ested. Select the CH03_SLQTSORAppDelegate.h file. Once selected, you see an editor panel appear on the right side, containing the file’s contents (also shown in Listing 3.1). read more..

  • Page - 72

    45 Application Delegate be importing it later. It’s good practice to use a forward declaration like this in the header files and then do the actual import in the implementation file. It reduces the chances of circular references, which can become a real headache when you have a lot of source files all referring to one another. Note If you are wondering what the EAGL read more..

  • Page - 73

    46 Chapter 3 The Journey Begins block, you don’t have to write any code—the compiler will do the coding for you. If you declare a property in this way and don’t use @synthesize in the implementation, you are still responsible for creating the getter and setter methods yourself. If you don’t create those methods, you will be given a compiler error. Examining the read more..

  • Page - 74

    47 Application Delegate } @end To start, we import the header file (CH03_SLQTSORAppDelegate.h), along with EAGLView.h: #import "CH03_SLQTSORAppDelegate.h" #import "EAGLView.h" These two lines notify the compiler to load the definition from the class’s header file along with the definition of the EAGLView class. If you recall, there was a forward declara- tion of EAGLView read more..

  • Page - 75

    48 Chapter 3 The Journey Begins Inside the preceding method, we are then sending a message to (calling a method on) the glView instance variable.You will remember from the header file that glView was de- clared with a type of EAGLView , so glView is a pointer to an instance of EAGLView .You may be wondering where we are actually creating the instance of EAGLView and read more..

  • Page - 76

    49 EAGLView the game, so for now it’s enough to know this file exists and can be seen in the Resource group in the project outline.The file that contains your app’s user interface is called MainWindow.xib. If you want to have a look at this file, simply double-click the MainWindow.xib file to open it in Interface Builder. Inside this file, a UIWindow object has been read more..

  • Page - 77

    50 Chapter 3 The Journey Begins id displayLink; NSTimer *animationTimer; Although we have already discussed the creation of ivars in an interface, it is worth run- ning through the id type used previously for the renderer ivar. The id type can point to any Objective-C object. It provides no information about an object other than it is an object.This allows Objective-C to support read more..

  • Page - 78

    51 EAGLView ES1Renderer and ES2Renderer are classes that have been created by the OpenGL ES template and are used to provide access to OpenGL rendering based on the version of OpenGL ES that the device supports.These classes will be covered later in more detail. Next is the declaration of a class method called layerClass .This method is overriding the layerClass method within read more..

  • Page - 79

    52 Chapter 3 The Journey Begins Note Allowing a CAEAGLLayer to be transparent requires a great deal of blending to the content behind the layer to show through. Blending is an expensive process that is likely to result in performance problems. eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, read more..

  • Page - 80

    53 EAGLView return nil; } } If renderer was not successfully created, an instance if ES1Renderer is created and again checked for success. If renderer is still nil , EAGLView is released and nil is returned to the calling class. If the creation of either an ES1Renderer or ES2Renderer instance was successful, the initialization continues. As mentioned in Chapter 2,“The Three read more..

  • Page - 81

    54 Chapter 3 The Journey Begins Note Because CADisplayLink was added to iPhone OS version 3.1, it won’t be available on iPhones that run an older version of the OS. Although it would be great if everyone could up- grade to the latest version of the iOS so we only had to worry about the latest version, that never happens. There will always be someone who is running read more..

  • Page - 82

    55 EAGLView This method overrides a method inside UIView.The default implementation of the method inside UIView does nothing.The method inside the EAGLView calls the resize- FromLayer method inside the renderer object passing in the CAEAGLLayer, which is used for this view.The resizeFromLayer method inside the renderer object then binds a render- Buffer to the EAGLContext and gets the read more..

  • Page - 83

    56 Chapter 3 The Journey Begins that are called when setting the animationFrameInterval ivar, and these are the next two methods in the class: - (void) startAnimation { if (!animating) { if (displayLinkSupported) { displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawView:)]; [displayLink setFrameInterval:animationFrameInterval]; [displayLink addToRunLoop:[NSRunLoop read more..

  • Page - 84

    57 EAGLView userInfo:nil repeats:TRUE]; animating = TRUE; } } This code shows an instance of NSTimer being created: animationTimer .This timer fires on a scheduled basis calculated by dividing 1.0 by 60.0 , which is the maximum number of frames the iPhone can display per second, and multiplying that by the animationFrameInterval . As with drawView , this causes the animationTimer to read more..

  • Page - 85

    58 Chapter 3 The Journey Begins from firing and also removes it from the run loop, and the displayLink ivar is set to nil . In Objective-C, it is valid to send messages to nil . Sending a message to nil simply has no effect at runtime. If displayLinkSupported is FALSE , the animationTimer is invalidated, which again stops it from firing and removes it from the run loop. read more..

  • Page - 86

    59 ES1Renderer Importing these headers enables us to use the OpenGL ES commands available as part of OpenGL ES 1.1—thus, the ES1 in the path of the header files. Next, the interface is declared that is inheriting from NSObject and implementing the ESRenderer protocol.This is important—it makes sure that the ES1Renderer class is go- ing to contain the methods defined in the read more..

  • Page - 87

    60 Chapter 3 The Journey Begins The first action of the initializer is to assign the value of [super init] to self and is a standard pattern when initializing a class. Now that self is correctly assigned to our instance of the class, we assign a new in- stance of the EAGLContext : the context : context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; As we saw read more..

  • Page - 88

    61 ES1Renderer where pixels are finally created. Renderbuffers are normally 2D images with a height, width, and color format. As part of the initialization of OpenGL ES, it is necessary to create the framebuffer and renderbuffer and assign the renderbuffer to the context we have as storage for the final image that is going to be rendered to the screen. Now that you know read more..

  • Page - 89

    62 Chapter 3 The Journey Begins That’s it for the initializer. All that is left is to return the object to the caller: return self; What we have just reviewed is the tip of the iceberg with regard to the initialization of OpenGL ES.To gain a deeper understanding of how to work with OpenGL ES on the iPhone, you should review Apple’s documentation, OpenGL ES read more..

  • Page - 90

    63 ES1Renderer The dimensions of the renderbuffer are placed in the backingWidth and backingHeight ivars ready for use later; then the framebuffer is checked to make sure all components have been set up correctly: if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); read more..

  • Page - 91

    64 Chapter 3 The Journey Begins Figure 3.5 shows how the x-, y-, and z-axis are arranged in OpenGL. By default, the origin (that is, the point at 0, 0, 0 ) in OpenGL ES on the iPhone is in the middle of the screen. OpenGL ES also uses it own units (that is, each unit in OpenGL does not represent a single pixel on the screen by default). It is up to you read more..

  • Page - 92

    65 ES1Renderer –1,1 0,1 1,1 –1,0 0,0 1,0 –1,–1 0,–1 1,–1 Figure 3.6 Mapping the iPhone’s default OpenGL coordinates. Now run the application by pressing Build and Run.The application should run and show a colored square moving up and down the screen as before, but this time, the rectan- gle will be the full size of the iPhone screen, as shown in Figure 3.7. Note The read more..

  • Page - 93

    66 Chapter 3 The Journey Begins Figure 3.7 Chap03 application with changed vertices. Defining the Color Values Now let’s look at the next array, which defines the colors used within the shape being drawn: static const GLubyte squareColors[] = { 255, 255, 0, 255, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 255, 255, }; By defining a separate color for each individual vertex, OpenGL will read more..

  • Page - 94

    67 ES1Renderer Positioning The next variable created is going to be used when calculating the position to render the square: static float transY = 0.0f; The following method makes sure that the current EAGLContext is the context that was created earlier: [EAGLContext setCurrentContext:context]; We have actually already set this in the init method, and because we only have one con- read more..

  • Page - 95

    68 Chapter 3 The Journey Begins Remember that the backingHeight and backingWidth were set from reading the dimen- sions of the renderbuffer associated with the context. Here, we are defining the Viewport to match the dimensions of the iPhone’s screen. Now that you have defined the viewport, you need to make sure that the matrices as- sociated with GL_PROJECTION and GL_MODELVIEW read more..

  • Page - 96

    69 How OpenGL Works Any OpenGL transformation we perform now will effect how the vertices (model) are represented in 2D space.There are many other state commands in OpenGL, and we will see a couple of them shortly. Applying Transformations on the Model Now that we know that the matrix mode is GL_MODELVIEW and the identity matrix has been loaded, we can start to perform read more..

  • Page - 97

    70 Chapter 3 The Journey Begins The glClear command takes a bitwise OR of masks that indicate the buffers that are to be cleared.The possible options are as follows: n GL_COLOR_BUFFER_BIT n GL_DEPTH_BUFFER_BIT These commands are used only for clearing the color buffer; however, if you wanted to clear both the color buffer and the depth buffer, you would structure the command as read more..

  • Page - 98

    71 How OpenGL Works Note All client-side capabilities are disabled by default, so you need to switch them on and off as necessary. To disable a client-side capability, use glDisableClientState . Having defined the vertices, we can now do the same for the colors array using almost identical commands, as follows: glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors); read more..

  • Page - 99

    72 Chapter 3 The Journey Begins Note Something we discuss in later chapters is performance. It’s worth noting that we should re- duce the number of these draw commands as much as possible throughout the code. There is CPU overhead when you call the OpenGL draw commands because data is moved to the GPU and so forth. If you have hundreds of draw commands per frame, read more..

  • Page - 100

    4 The Game Loop One of the most important elements of a game is the game loop. It is the heartbeat that keeps the game ticking. Every game has a series of tasks it must perform on a regular ba- sis, as follows: n Update the game state n Update the position of game entities n Update the AI of game entities n Process user input, such as touches or the accelerometer n read more..

  • Page - 101

    74 Chapter 4 The Game Loop This example game loop will continuously update the game and render to the screen un- til gameRunning is false . Although this code does work, it has a serious flaw: It does not take time into account. On slower hardware, the game runs slowly, and on fast hardware, the game runs faster. If a game runs too fast on fast hardware and too slow read more..

  • Page - 102

    75 The Game Loop Collision detection is normally done as part of the game’s update function. Each en- tity has their AI and position updated as play progresses.Those positions are checked to see if it has collided with anything. For example, Sir Lamorak could walk into (or collide with) a wall, or a ghost could collide with an axe. As you can imagine, the distance a read more..

  • Page - 103

    76 Chapter 4 The Game Loop when you start writing games, leaving the player open to a variable playing experience. Also remember that each of these frames is performing a single render and update cycle. A time-based variable interval loop is similar to the frame-based approach, but it also cal- culates the elapsed time.This calculation is used to work out the milliseconds read more..

  • Page - 104

    77 The Game Loop R = Render U = Update Collision detected R R R U U U U R Object delta Figure 4.2 Frames using a small delta value. R = Render U = Update R R U U U R R Object delta Figure 4.3 Frames using a large delta. Time-Based, Fixed Interval The key to this method is that the game’s state is updated a variable number of times per game cycle using a fixed read more..

  • Page - 105

    78 Chapter 4 The Game Loop shown in Figure 4.4.We are still passing a delta value to the game entities, but it’s a fixed value that is pre-calculated rather than the variable delta that was being used before (thus, the term fixed interval). This system causes the number of game updates to be fewer when the frame rate is high, but it also increases the number of read more..

  • Page - 106

    79 Getting Started need to use NSTimer rather than CADisplayLink . Using iPhone SDK 3.0 or less will also generate warnings, as shown in Figure 4.5. When you open the CH04_SLQTSOR project in Xcode, you see a number of new groups and classes in the Groups & Files pane on the left that have been added to the project since Chapter 3, including the following: n Group read more..

  • Page - 107

    80 Chapter 4 The Game Loop Because we are not using ES2Renderer , the ES2Renderer.h and .m files have been re- moved from the project.The Shaders group and its contents have also been removed. There is also an extra line that has been added to the end of the initWithCoder method, as shown here: sharedGameController = [GameController sharedGameController]; The next change is read more..

  • Page - 108

    81 Getting Started When the game loop is called from either CADisplayLink or NSTimer , it first obtains the current time using CACurrentMediaTime() .This should be used instead of CFAbsoluteTimeGetCurrent() because CACurrentMediaTime() is synced with the time on the mobile network if you are using an iPhone. Changes to the time on the network would cause hiccups in game play, so Apple read more..

  • Page - 109

    82 Chapter 4 The Game Loop The CADisplayLink or NSTimer now calls the game loop until the player quits or the bat- tery runs out (which it could do, given how much they will be enjoying the game!). This is not a complex game loop, although it may take a while to get your head around the calculations being done. I found that moving to this game loop reduced the read more..

  • Page - 110

    83 Getting Started You don’t have to worry if an instance has already been created or not because that is all taken care of inside the GameController class itself. The next change is within the render method, shown in Listing 4.3.This is where the template initially inserted drawing code for moving the colored square.We will see the code used to draw the square again, read more..

  • Page - 111

    84 Chapter 4 The Game Loop EAGLView ES1Renderer GameController GameScene SettingsScene GameScene MenuScene GameScene GameScene Figure 4.6 Class relationships. Now move to the bottom of the implementation and look at the initOpenGL method. This method sets up a number of key OpenGL ES states that we will be using throughout the game. If you move to the bottom of the implementation, you read more..

  • Page - 112

    85 Getting Started This command describes a transformation that produces an orthographic or parallel pro- jection.We have set the matrix mode to GL_PROJECTION , so this command will perform a transformation on the projection matrix.The previous function sets up an orthographic projection—in other words, a projection that does not involve perspective (it’s just a flat image). Note I read more..

  • Page - 113

    86 Chapter 4 The Game Loop Not using the depth buffer means that we have to manage z-indexing ourselves (that is, the scene needs to be rendered from back to front so objects at the back of the scene appear behind those at the front): glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glDisable(GL_DEPTH_TEST); We finish up the OpenGL ES configuration by enabling more OpenGL ES read more..

  • Page - 114

    87 Game Scenes and the Game Controller game elements.The game elements I’m talking about are the different scenes used in Sir Lamorak’s Quest, such as the following: n The main menu: This is where players are taken when they first launch Sir Lam- orak’s Quest.The main menu provides the player with options to change the game settings, view credits, or start the game. n read more..

  • Page - 115

    88 Chapter 4 The Game Loop SynthesizeSingleton macro created by Matt Gallagher. 2 Matt’s macro enables you to turn a class into a singleton class simply by adding a line of code to your header and another to your implementation. At the top of the GameController.h file, add the following import statement to bring in this macro: #import "SynthesizeSingleton.h" Note I read more..

  • Page - 116

    89 Game Scenes and the Game Controller This works well for our game scenes, as each scene will have its own logic and rendering code, but it will have ivars and methods, such as updateSceneWithDelta and renderScene , that all scenes need to have.We run through the AbstractScene class in a moment. After the interface declaration, the next step is to create a single property read more..

  • Page - 117

    90 Chapter 4 The Game Loop - (void)initGame; @end As you can see from this code, we are using initGame to initialize game scenes. Next is the implementation declaration for GameController .This is a standard declara- tion followed by a synthesize statement for currentScene , so the necessary getters and setters are created.The next line is added to turn this class into a read more..

  • Page - 118

    91 Game Scenes and the Game Controller This creates an entry in the dictionary that points to the scene instance and gives it a key of game . Notice that the next line releases scene : [scene release]; Adding scene to the dictionary increases its retain count by one, so releasing it now re- duces its retain count from two to one.When the dictionary is released or the read more..

  • Page - 119

    92 Chapter 4 The Game Loop AbstractScene Class AbstractScene was mentioned earlier, and as the name implies, it is an abstract class. All the game scenes we need to create will inherit from this class. Open AbstractScene.h in the Abstract Classes group, and we’ll take a look. The header starts off by importing the OpenGL ES header files.This allows any class that inherits read more..

  • Page - 120

    93 Game Scenes and the Game Controller - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event view:(UIView*)aView; - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event view:(UIView*)aView; - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event view:(UIView*)aView; The next method declared is similar to the touch methods. Just as touches are fed to each game scene, accelerometer events also read more..

  • Page - 121

    94 Chapter 4 The Game Loop the logic to move the box, and the box rendering code itself, were all held within the render method.This has now been split up inside GameScene . The updateSceneWithDelta method is called a variable number of times within the game loop.Within that method, we have defined the transY ivar, which increases within the updateSceneWithDelta method: - read more..

  • Page - 122

    95 Exercises Once the translation has finished, we point the OpenGL ES vertex pointer to the squareVertices array and the color pointer to the squareColors array: glVertexPointer(2, GL_FLOAT, 0, squareVertices); glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors); If you have a photographic memory, you may notice that there are a couple of lines missing from this section of code that read more..

  • Page - 123

    96 Chapter 4 The Game Loop 2. After you create your new class, initialize it in the GameController initGame method and add it to the dictionary with a key. Hint Don’t forget to make your new scene the current scene. If you get stuck, you can open the CH04_SLQTSOR_EXERCISE project file to see what you need to do. read more..

  • Page - 124

    5 Image Rendering One of the key elements of Sir Lamorak’s Quest—and, in fact, all games, unless you’re thinking about the old text-based adventures—is the ability to render images (sprites) to the screen.Without graphics, the game would be pretty dull. In this chapter, we run through the key concepts needed to render images to the screen using OpenGL ES.We cover the read more..

  • Page - 125

    98 Chapter 5 Image Rendering For Sir Lamorak’s Quest, we will be rendering a lot of images on the screen, including the following: n The player/character, Sir Lamorak himself. n The baddies (that is, ghosts, monsters, a bat, and so on) n Doors n Tiles for the tile map n Letters for fonts Each of these items requires us to define a quad and then fill it with the necessary read more..

  • Page - 126

    99 Rendering a Quad n GL_LINES n GL_TRIANGLE_FAN For our needs, we’ll work with GL_TRIANGLES and GL_TRIANGLE_STRIP . The difference between these is in how OpenGL ES uses the vertices we provide and how many vertices we actually need.We used the following command in Chapter 4’s ex- ample to render our quad (square): glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); The first parameter defines read more..

  • Page - 127

    100 Chapter 5 Image Rendering Triangle 2 2 1 4 3 Triangle 1 Figure 5.3 Result of using vertices in the order 1, 2, 4, and 3. Tip Having the vertices out of order is a common problem and certainly something I had to sort out a number of times. If you see an image such as that shown in Figure 5.3, there’s a good chance that your vertices aren’t in the correct read more..

  • Page - 128

    101 Texture Mapping Note Although I have said that you can use GL_TRIANGLES to render triangles in different loca- tions that are not linked, it is actually possible to achieve the same result using a GL_TRIANGLE_STRIP . If you define degenerate (zero-area) triangles in your vertex array, you can instruct OpenGL ES to move to a new vertex location without actually rendering the read more..

  • Page - 129

    102 Chapter 5 Image Rendering Figure 5.4 Texture coordinates and axis names. Although the axis used when defining a polygon is normally called (x, y), it is common for the same axis when defining texture coordinates to be referred to as (s, t), as shown in Figure 5.4. Just to make things even more confusing, it is also common to see the polygon axis referred to as (u, read more..

  • Page - 130

    103 Texture Mapping Vertex 1 = (0.0, 0.0) Vertex 2 = (1.0, 0.0) Vertex 3 = (0.0, 1.0) Vertex 4 = (1.0, 1.0) If you just wanted to map a portion of the full texture to the polygon, we can adjust the texture coordinates as necessary. Figure 5.6 shows the texture coordinates for mapping just a quarter of the texture to the polygon. This time, the mapping from the read more..

  • Page - 131

    104 Chapter 5 Image Rendering Interleaved Vertex Arrays Before we push into the ImageRenderManager class, it’s worth discussing Interleaved Vertex Arrays (IVA), which are used in the ImageRenderManager . We have seen the term vertex array already, but we have not talked about it in much de- tail. From the code we have already seen, you may remember that we have read more..

  • Page - 132

    105 Interleaved Vertex Arrays Although the commands are different, the parameters they take and their meaning are very similar.When using glColorPointer , the first parameter defines the number of com- ponents per color. Under OpenGL ES, this parameter must be 4 , as a color is made up of red, green, blue, and alpha.When using glVertexPointer or glTexCoordPointer , the first read more..

  • Page - 133

    106 Chapter 5 Image Rendering Note This example uses the &iva array to specify the start element in the array along with the structure element (for example, geometryVertex ). This tells OpenGL ES where to get the necessary data from within the array. This would have given OpenGL ES the same numbers we calculated manually, and you would not have had to worry about how read more..

  • Page - 134

    107 Image Rendering Classes Having a vertex on its own is not much use unless you are rendering points, so we need a structure that enables us to define a quad (that is, four TexturedColoredVertex structures).This structure, TexturedColoredQuad , is shown in Listing 5.2. Listing 5.2 The TexturedColoredQuad Structure typedef struct { TexturedColoredVertex vertex1; TexturedColoredVertex vertex2; read more..

  • Page - 135

    108 Chapter 5 Image Rendering reduce the number of OpenGL ES API calls when rendering a large number of images to the screen. We now run through the steps needed to create and render an image to the screen and, at the same time, take a look at the classes we use in Sir Lamorak’s Quest to carry out these functions. Although the steps needed to actually create read more..

  • Page - 136

    109 Image Rendering Classes The class then checks to make sure that image data has been found. If not, an error is raised. Using image , we can now retrieve information about the image’s alpha and color space. Because we now have access to the CGImage information using CGImageRef , we can easily get to the information we need using the following commands: read more..

  • Page - 137

    110 Chapter 5 Image Rendering Having obtained the image size, we now need to make sure that it’s power-of-two.There is no magic in this—just a couple of loops for width and height.The loops to calculate the width and height of the image, making sure they are a power-of-two, is shown in Listing 5.4. Listing 5.4 Setting the Image Size in Texture2D to a Power-of-Two width = read more..

  • Page - 138

    111 Image Rendering Classes We now have a width and height that contains the power-of-two dimensions of the im- age and that are no larger than the maximum texture size allowed. Generating Image Data Having calculated a width and height that are power-of-two and are large enough to en- compass our image, we need to get this data into OpenGL ES. Unfortunately, it’s not as read more..

  • Page - 139

    112 Chapter 5 Image Rendering Finally, we actually draw the bitmap image data we have loaded into the new context. Tip The coordinate system used in Core Animation and Quartz is different than that used in OpenGL ES. In OpenGL ES, the y-axis runs from 0 starting at the bottom of the screen and works its way up, but Core Animation is in reverse. Core Animation’s read more..

  • Page - 140

    113 Image Rendering Classes Now that we know that the name of a texture is actually a number, we can get OpenGL ES to generate a name for us using the following command: glGenTextures(1, &name); The name ivar has been defined in the header file as a GLUint and is then used within the glGenTextures command to request a new texture name from OpenGL ES.You may have read more..

  • Page - 141

    114 Chapter 5 Image Rendering The first parameter is the target, which is the same target that we used when binding our texture.The second parameter specifies the parameter name (that is, the parameter we want to configure), and the third parameter is the actual parameter value. The parameters we are configuring are used to define how OpenGL ES should handle images when read more..

  • Page - 142

    115 Image Rendering Classes glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); The parameters used in this command are as follows: n Target: The target texture. Must be GL_TEXTURE_2D. n Level: The level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image and must be greater than or equal to zero. n Internal read more..

  • Page - 143

    116 Chapter 5 Image Rendering Texture (0.0, 0.75) (0.875, 0.75) Image (0.0, 0.0) (0.875, 0.00) t s 1.0 1.0 Figure 5.9 Loaded image within the generated OpenGL ES texture. The last step is to release both the drawing context we created and also the bitmap data that was generated.This has been handed to OpenGL ES when we loaded the texture im- age data, so we can safely get read more..

  • Page - 144

    117 Image Rendering Classes The main class used when rendering images will be the Image class.When you create a new Image instance, the Image class handles the creation of the OpenGL ES texture using Texture2D . Because of the close relationship between an Image instance and Texture2D instance, there could be situations where many Image instances share the same texture. An easy way read more..

  • Page - 145

    118 Chapter 5 Image Rendering NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:filetype]; cachedTexture = [[Texture2D alloc] initWithImage:[UIImage imageWithContentsOfFile:path] filter:aFilter]; [cachedTextures setObject:cachedTexture forKey:aName]; return [cachedTexture autorelease]; } Once inside the method, the first check is to see if we can find a texture that has been created for read more..

  • Page - 146

    119 Image Rendering Classes ImageRenderManager Class So far, we have seen the classes that turn an image into an OpenGL ES texture and manage those textures to help reduce the amount of memory we are using.The next class we discuss is ImageRenderManager , which is responsible for actually rendering im- ages to the screen. I mentioned at the start of this chapter that we were read more..

  • Page - 147

    120 Chapter 5 Image Rendering Listing 5.11 ImageRenderManager init Method - (id)init { if(self = [super init]) { iva = malloc(kMax_Images * sizeof(TexturedColoredQuad)); ivaIndices = calloc(kMax_Images * 6, sizeof(GLushort)); ivaIndex = 0; renderTextureCount = 0; } return self; } Within the init method, we allocate the memory needed to store the IVA array we are going to use.The maximum read more..

  • Page - 148

    121 Image Rendering Classes Listing 5.12 ImageRenderManager addImageDetailsToRenderQueue: Method - (void)addImageDetailsToRenderQueue:(ImageDetails*)aImageDetails { [self copyImageDetails:aImageDetails]; [self addToTextureList:aImageDetails->textureName]; ivaIndex++; } First, the copyImageDetails method is called.This method copies the image’s TextureColoredQuad structure into the iva at the next available slot. It also read more..

  • Page - 149

    122 Chapter 5 Image Rendering Listing 5.13 ImageRenderManager addToTextureList: Method - (void)addToTextureList:(uint)aTextureName { BOOL textureFound = NO; for(int index=0; index<renderTextureCount; index++) { if(texturesToRender[index] == aTextureName) { textureFound = YES; break; } } if(!textureFound) texturesToRender[renderTextureCount++] = aTextureName; textureIndices[aTextureName][imageCountForTexture[aTextureName]] = ivaIndex; read more..

  • Page - 150

    123 Image Rendering Classes The textureIndices array holds all indices into the iva for images that share the same texture name.When rendering, we loop through the textureIndices array, retriev- ing the IVA index for each image using the current texture.These IVA indices will then be used to tell OpenGL ES which entry in the IVA should be used to render each image. This enables read more..

  • Page - 151

    124 Chapter 5 Image Rendering glDrawElements(GL_TRIANGLES, vertexCounter, GL_UNSIGNED_SHORT, ivaIndices); imageCountForTexture[texturesToRender[textureIndex]] = 0; } renderTextureCount = 0; ivaIndex = 0; } The first step in this method is to configure OpenGL ES to use the iva array for its data. These commands take a number of parameters.The first two parameters tell OpenGL ES the size of each read more..

  • Page - 152

    125 Image Rendering Classes Inside the loop, we bind to the current texture and set the vertexCount to zero. For each texture, the vertexCount is going to keep track of how many vertices we actually need OpenGL ES to render, which will be passed to the glDrawElements command. Next, we perform another loop.This loop iterates through all the images that have been added to the read more..

  • Page - 153

    126 Chapter 5 Image Rendering The Image Class We have covered a lot already in this chapter, but we have one final push before we are finished. Having built the underlying functions that enable us to create OpenGL ES tex- tures, manage them, and render them to the screen, we now come to a key class in render- ing within our game engine. The Image class provides read more..

  • Page - 154

    127 The Image Class Note Although Apple has done a lot of work to minimize the time needed to call a method or prop- erty, there is still a small performance hit. Reducing the class messaging as much as possi- ble in the core sections of your game will really pay off! One item we have not covered yet is the Color4fMake function. Inside the Global.h file found in read more..

  • Page - 155

    128 Chapter 5 Image Rendering The final stage of initializing the image is to call another private method, initializeImageDetails . If the name looks familiar, it’s because it is responsible for set- ting up the ImageDetails structure we covered in detail earlier in this chapter. It is shown in Listing 5.15. Listing 5.15 ImageRenderManager initializeImageDetails Method - read more..

  • Page - 156

    129 The Image Class Note You may remember from when we covered the Texture2D class that all images loaded into an OpenGL ES texture are upside down. While loading the texture coordinates into the ImageDetails structure in Listing 5.15, you can reverse the y-axis coordinates so the im- ages appear correctly onscreen. You can see from the code that we are using the image’s read more..

  • Page - 157

    130 Chapter 5 Image Rendering Listing 5.16 ImageRenderManager subImageInRect: Method - (Image*)subImageInRect:(CGRect)aRect { Image *subImage = [[Image alloc] initWithImageNamed:imageFileName filter:minMagFilter subTexture:aRect]; subImage.scale = scale; subImage.color = color; subImage.flipVertically = flipVertically; subImage.flipHorizontally = flipHorizontally; subImage.rotation = rotation; subImage.rotationPoint = read more..

  • Page - 158

    131 The Image Class n render n renderAtPoint: n renderAtPoint:scale:rotation: n renderCentered: n renderCenteredAtPoint: n renderCenteredAtPoint:scale:rotation: These are convenience methods, used to make the process of rendering an image to the screen easier.The majority of these methods are simply setting the properties of the image before it is rendered. Listing 5.18 shows the read more..

  • Page - 159

    132 Chapter 5 Image Rendering [sharedImageRenderManager addImageDetailsToRenderQueue:imageDetails]; if (dirty) { loadIdentityMatrix(matrix); translateMatrix(matrix, point); if(flipVertically) { scaleMatrix(matrix, Scale2fMake(1, -1)); translateMatrix(matrix, CGPointMake(0, (-imageSize.height * scale.y))); } if(flipHorizontally) { scaleMatrix(matrix, Scale2fMake(-1, 1)); translateMatrix(matrix, CGPointMake((-imageSize.width * scale.x), 0)); read more..

  • Page - 160

    133 The Image Class seen, when we covered the ImageRenderManager , we are rendering all the images for a texture using just a single glDrawElements command, so there is no possibility to call the OpenGL ES transforms between each image. The solution to this is to actually transform the vertices information for the image di- rectly, and it is for this reason that we have read more..

  • Page - 161

    134 Chapter 5 Image Rendering Getters and Setters The last few methods we need to cover in the Image class are some getters and setters.We could have just used those generated by @synthesize , but we need to not change only the value of the property but also set the dirty flag. Because we need to set this flag, we need to create our own getters and setters, as read more..

  • Page - 162

    135 Exercise spent. Putting in the time now to make your core classes functional and clean to use will save you plenty of time in the long run. This chapter is a milestone on our journey to creating Sir Lamorak’s Quest. Being able to load any image and render it to the screen, applying scale, rotation, and transparency, is the backbone of any game engine. Now that read more..

  • Page - 163

    This page intentionally left blank read more..

  • Page - 164

    6 Sprite Sheets Chapter 5,“Image Rendering,” was large and covered a number of complex concepts. Having done all that hard work, and with the classes in place for representing and render- ing images, we can move on to the other components needed in the game engine for Sir Lamorak’s Quest. As the title suggests, this chapter is all about sprite sheets. If you remember read more..

  • Page - 165

    138 Chapter 6 Sprite Sheets Figure 6.1 Sprite sheet with spacing between each sprite. Note I use the term packed because you can place smaller sprite sheets within this larger sprite sheet, thus reducing the number of separate sprite sheets used in the game. Another term for a sprite sheet is a texture atlas, but I will continue to use the old-school term of “sprite read more..

  • Page - 166

    139 Introduction to Sprite Sheets Figure 6.2 Sprite sheet grid with location {5, 1} highlighted. Figure 6.3 Complex sprite sheet from Sir Lamorak’s Quest. same size.This makes it easy to retrieve a sprite by providing its row and column number. Figure 6.2 shows a sprite sheet of twelve columns and three rows with the sprite at loca- tion {5, 1} highlighted. Complex Sprite read more..

  • Page - 167

    140 Chapter 6 Sprite Sheets Figure 6.4 The Flash-based Zwoptex tool, used for editing a complex sprite sheet. As you can see from Figure 6.3, a complex sprite sheet has many images that are all dif- ferent sizes and shapes—thus the need for a control file to make sense of it all. You could create your own control file for these files, providing the information on the read more..

  • Page - 168

    141 Using Zwoptex Figure 6.5 Import images into the sprite sheet. Figure 6.6 Zwoptex imports the images in the top-left corner of the canvas. matter), having a plist file makes things so much easier (and I like to take the easy route whenever possible). Now that you know what Zwoptex is, let’s show you how to use it. Using Zwoptex Using Zwoptex is really easy. Just point read more..

  • Page - 169

    142 Chapter 6 Sprite Sheets Figure 6.7 Sprite options menu and arranged sprites. Now that you’ve placed the images in Zwoptex, there are a number of ways to arrange the sprites on the canvas. Under the Arrange menu, you will find different options for laying out the sprites. Figure 6.7 shows the sprites having been laid out using the Complex By Width (no spacing) option. read more..

  • Page - 170

    143 The SpriteSheet Class Initialization Inside the SpriteSheet.m file, you find the following class methods: n spriteSheetForImageNamed:spriteSize:spacing:margin: imageFilter n spriteSheetForImage:sheetKey:spriteSize:spacing:margin: These methods are used to create new sprite sheets either from an image file or from an Image instance that has already been created. Notice that both of these are class read more..

  • Page - 171

    144 Chapter 6 Sprite Sheets The first line in Listing 6.1 defines a static NSMutableDictionary .This creates a single in- stance of NSMutableDictionary that the class methods use to cache the sprite sheets.This dictionary has been defined at the class level, which means that only a single copy of this dictionary will exist, regardless of how many SpriteSheet instances are created.This read more..

  • Page - 172

    145 The SpriteSheet Class We examine the cacheSprites method in a moment; first, there is another initializer method to look at, as shown in Listing 6.3. Listing 6.3 SpriteSheet initWithImage:spriteSize:spacing:margin Method - (id)initWithImage:(Image*)aImage spriteSize:(CGSize)aSpriteSize spacing:(NSUInteger)aSpacing margin:(NSUInteger)aMargin{ if (self = [super init]) { self.image = aImage; spriteSize = read more..

  • Page - 173

    146 Chapter 6 Sprite Sheets (spriteSize.width + spacing) + margin), (row * (spriteSize.height + spacing) + margin)); textureOffset.x = image.textureOffset.x * image.fullTextureSize.width + texturePoint.x; textureOffset.y = image.textureOffset.y * image.fullTextureSize.height + texturePoint.y; CGRect tileImageRect = CGRectMake(textureOffset.x, textureOffset.y, spriteSize.width, spriteSize.height); Image *tileImage = [[image read more..

  • Page - 174

    147 PackedSpriteSheet Class return nil; int index = (horizSpriteCount * aPoint.y) + aPoint.x; return [cachedSprites objectAtIndex:index]; } The first check we carry out in this class is on the coordinates that are being passed in. This method takes the coordinates for the sprite in a CGPoint variable. CGPoint has an x and y value that can be used to specify the grid coordinates read more..

  • Page - 175

    148 Chapter 6 Sprite Sheets [self parseControlFile:controlFile]; [controlFile release]; } return self; } Once inside the initializer, we create a new Image instance from the details passed in and allocate an NSMutableDictionary instance called sprites that will hold the details of the sprites in our packed sprite sheet. The last section of the initializer grabs the contents of the control read more..

  • Page - 176

    149 PackedSpriteSheet Class Figure 6.8 Sprite sheet plist control file. An example of the plist file inside the Plist Editor can be seen in Figure 6.8. The details we want for the sprites are therefore held in the frame’s objects. Now that we have a dictionary called frames , we loop through each of them, extract- ing the information we need. For each frame we read more..

  • Page - 177

    150 Chapter 6 Sprite Sheets NSLog(@"ERROR - PackedSpriteSheet: Sprite could not be found for key '%@'", aKey); return nil; } We pass an NSString into this method containing the key to the sprite’s dictionary that we created earlier. If you remember, the key is the filename of the image that was placed inside the packed sprite sheet. If an image is found for the key read more..

  • Page - 178

    151 Exercise Exercise The example project that is provided with this chapter, CH06_SLQTSOR, displays three different images that have been taken from a single sprite sheet.These images are scaled, rotated, and colored using the features of the Image class covered in Chapter 5 to show that the Image instance returned is an entirely separate image in its own right. The current read more..

  • Page - 179

    This page intentionally left blank read more..

  • Page - 180

    7 Animation We’re starting to add all the core classes to our game engine.We can now render an image using the Image class and apply different functions to it, such as scale, rotation, and color. In Chapter 6,“Sprite Sheets,” we looked at the SpriteSheet class that enables us to store multiple images that share the same dimensions in a single image and then retrieve read more..

  • Page - 181

    154 Chapter 7 Animation Figure 7.1 iPhone simulator running the CH07_SLQTSOR project. This chapter runs through the requirements for the Animation class and then reviews the implementation we are using for Sir Lamorak’s Quest. Introduction to Animation Let’s do some thinking about what it is our Animation class is going to need to do.There is no doubt that we could make the read more..

  • Page - 182

    155 Introduction to Animation delay value that is used for all frames of the animation, but that is too restrictive.We may have animation where we want certain frames to appear on the screen longer than others. Having a delay associated with each frame will allow us to do that. State As with most things inside a game, our animation will need to manage its state.We read more..

  • Page - 183

    156 Chapter 7 Animation this simple, the concept of a bounce frame was introduced.This is a simple property that defines a frame in the animation that should cause the animation to bounce, or run in the opposite direction without that frame being drawn. As we see later in Chapter 14,“Game Objects and Entities,” we will be able to have a single animation instance for read more..

  • Page - 184

    157 Animation Class By default, we are setting maxFrames to 5 .This causes the frames array to be allocated with enough space to store five frames of animation.You may be wondering why we are setting the maxFrames to five when we may need more frames than that.This is just the default value for the Aniamtion class.We will see in the next method that deals with read more..

  • Page - 185

    158 Chapter 7 Animation Listing 7.2 The addFrameWithImage:delay: Method #define FRAMES_TO_EXTEND 5 - (void)addFrameWithImage:(Image*)aImage delay:(float)aDelay { if(frameCount+1 > maxFrames) { maxFrames += FRAMES_TO_EXTEND; frames = realloc(frames, sizeof(AnimationFrame) * maxFrames); } frames[frameCount].image = [aImage retain]; frames[frameCount].delay = aDelay; frameCount++; } Once the check is complete and we read more..

  • Page - 186

    159 Animation Class Listing 7.3 The updateWithDelta: Method - (void)updateWithDelta:(float)aDelta { if(state != kAnimationState_Running) return; displayTime += aDelta; if(displayTime > frames[currentFrame].delay) { currentFrame += direction; displayTime -= frames[currentFrame].delay; if (type == kAnimationType_PingPong && (currentFrame == 0 || currentFrame == frameCount-1 || currentFrame == bounceFrame)) { read more..

  • Page - 187

    160 Chapter 7 Animation skipped.The direction variable stores either 1 for moving forward or -1 for moving backward through the frames. Having incremented the frame, we can update the animation based on its configured type. If the animation type is kAnimationType_PingPong and the currentFrame is either equal to 0, the number of frames in the animation, or to the configured bounceFrame , read more..

  • Page - 188

    161 Animation Class [frames[currentFrame].image renderCenteredAtPoint:aPoint scale:aScale rotation:aRotation]; } You can see that we are grabbing the current frame from the frames array using the currentFrame as the index.With that, we are then able to access the image property and from there call the necessary method on that image. As I’ve said before, we are just continuing to read more..

  • Page - 189

    162 Chapter 7 Animation - (Image*)imageForFrame:(NSUInteger)aIndex { if(aIndex > frameCount) { NSLog(@"WARNING - Animation: Invalid frame index"); return nil; } return frames[aIndex].image; } Organic Growth Not all the methods in the classes we have been through have existed from day one. I person- ally have found that as I develop a game, I come across handy methods that help to read more..

  • Page - 190

    163 Exercise As we added frames of animation, we were allocating memory for our AnimationFrame structure.To make sure we give this all back when the Animation in- stance is released, we need to loop through all the frames in our animation, freeing mem- ory as we go: - (void)dealloc { if (frames) { for(int i=0; i<frameCount; i++) { AnimationFrame *frame = &frames[i]; read more..

  • Page - 191

    164 Chapter 7 Animation class? Even if your sprite sheet is not animated, you could still cycle through the sprites to get the hang of how to use the Animation class. You could also search the Internet and try to find some animated sprites you could use. Once you have your own sprites in the project, try out the different animation types, as follows: n read more..

  • Page - 192

    8 Bitmap Fonts Most games provide the player with important information during game play using text. It’s important to be able to provide players with information such as their score, health, and time, as well as messages for the players. The iPhone SDK provides great features to render very attractive text to the screen. This is used by applications that use the UIKit read more..

  • Page - 193

    166 Chapter 8 Bitmap Fonts Figure 8.1 CH08_SLQTSOR project running on the iPhone simulator. Introduction to Bitmap Fonts As mentioned earlier, bitmap fonts enable you to render text to the screen using OpenGL ES. Even before OpenGL ES, developers were using the concept of bitmap fonts to ren- der text to the screen. Back in the 1980s, the 8-bit home computers and consoles were read more..

  • Page - 194

    167 Creating the Bitmap Font Sprite Sheet You may be wondering if we could use the PackedSpriteSheet class covered in Chapter 6,“Sprite Sheets”—unfortunately, the answer is no.The PackedSpriteSheet class was designed specifically to parse the sprite sheet control file generated by the Zwoptex appli- cation. Because the bitmap font image is also going to be a complex sprite read more..

  • Page - 195

    168 Chapter 8 Bitmap Fonts To make things easier, we are going to use a free Java application called Hiero (n4te. com/hiero/hiero.jnlp ).You may remember that we touched on this tool briefly in Chapter 2,“The Three Ts:Terminology,Technology, and Tools.” Note There is also a Windows-based application called BMFont (www.angelcode.com/products/ bmfont) that can create bitmap fonts from read more..

  • Page - 196

    169 Creating the Bitmap Font Sprite Sheet Note The maximum texture size that the iPhone 3G and all preceeding iPhone devices will handle is 1024 ×1024. It is important to make sure you do not exceed this size. If you do, the Texture2D class shrinks the texture by 50 percent to make it fit into the 1024 ×1024 lim- its. This causes the control file values that are also generated for the font read more..

  • Page - 197

    170 Chapter 8 Bitmap Fonts Tip You could load the PNG file produced by Hiero into a graphics application and make changes to the colors or shadows directly. This can be tricky, though—you need to make sure that each character does not move or change size. If the position or size changes, the control file that’s generated also needs to be updated. After you have read more..

  • Page - 198

    171 What’s with the C? This structure is going to be used to store information on each character in the font. Each character in the font has data that is associated with it, such as its ID, location within the font image, size, and offsets.The BitmapFontChar structure stores this information inside an array for each character in the font control file. What’s with the C? read more..

  • Page - 199

    172 Chapter 8 Bitmap Fonts The initializer first grabs a reference to the GameController and then creates an Image instance using the image details that were passed in. After the image has been created, the scale of the image is set along with the color. By default, all components of the color are set to 1.0 .This maximum intensity setting means that the actual colors of read more..

  • Page - 200

    173 What’s with the C? } else if([line hasPrefix:@"char id" ]) { [self parseCharacterDefinition:line]; } } [lines release]; } The first action of the method is to load the contents of the control file into a string. It is assumed that the control file will have a .fnt extension, as this is the default extension used by Hiero (described earlier). Having loaded the file read more..

  • Page - 201

    174 Chapter 8 Bitmap Fonts n char id : Provides the character definition information for each character in the font.This includes its location within the font’s image file, along with the size of the character. It also specifies how far we need to advance after rendering that character to correctly place the next character. If we find that the prefix is common , we call read more..

  • Page - 202

    175 What’s with the C? Parsing the char id Prefix If we come across a line in the control file that has the char id prefix, the parseCharacterDefinition: method is called.This method is basically the same as the parseCommon method. Listing 8.6 shows that the parseCharacterDefinition: method is the same as the parseCommon method, in which we separate the line sent in using = read more..

  • Page - 203

    176 Chapter 8 Bitmap Fonts We finally add the Image instance to the BitmapFontChar for the current character’s ID. Remember that the charsArray is made up of BitmapFontChar structures, and within that structure, there are variables to store the information we have just processed from the control file, along with an Image reference. It’s important to remember that this image needs read more..

  • Page - 204

    177 Rendering Text The core of this method is a loop that runs through all the characters in the text provided. The first line of code in the loop creates a variable called charID .This holds the ASCII code of the character.You’ll notice we are subtracting 32 from this value.This is to com- pensate for the fact that we are not using the first 32 ASCII character read more..

  • Page - 205

    178 Chapter 8 Bitmap Fonts Note Kerning information, if the font supports it, is also held within the control file produced by Hiero, making it possible to implement kerning as well. Because we aren’t using a great deal of text in Sir Lamorak’s Quest, we won’t worry about kerning the text. It’s good to know this information is available, though, if you need more read more..

  • Page - 206

    179 Rendering Text case BitmapFontJustification_MiddleCentered: point.x = aRect.origin.x + ((aRect.size.width - textWidth) / 2); point.y = aRect.origin.y + ((aRect.size.height - textHeight) / 2) – (commonHeight - textHeight); break; case BitmapFontJustification_BottomCentered: point.x = aRect.origin.x + ((aRect.size.width - textWidth) / 2); point.y = aRect.origin.y - (commonHeight - textHeight); break; case read more..

  • Page - 207

    180 Chapter 8 Bitmap Fonts n BitmapFontJustification_BottomRight n BitmapFontJustification_TopLeft n BitmapFontJustification_MiddleLeft n BitmapFontJustification_BottomLeft These values are used inside a switch statement to calculate the point at which to render the text onscreen. After the point has been calculated, the renderTextAtPoint: method is called to actually render the text. Text Width and Height read more..

  • Page - 208

    181 Summary if(charID == ' ') continue; stringHeight = MAX((charsArray[charID].height * image.scale.y) + (charsArray[charID].yOffset * image.scale.y), stringHeight); } return stringHeight; } The method in Listing 8.10 does almost the same thing as the one to calculate the width of text.The difference is that it ignores space characters, as they have no height the stringHeight variable only read more..

  • Page - 209

    182 Chapter 8 Bitmap Fonts In terms of the features, our game engine needs are almost finished.The next chapter covers the TiledMap class, which enables us to create large complex playing areas for our game, followed by Chapter 10,“The Particle Emitter,” where we will be able to start cre- ating explosions and other organic effects. Exercise This chapter should have given read more..

  • Page - 210

    9 Tile Maps Tile maps are used in computer games to both store and render a large playing area while using as little memory as possible.The technique isn’t as important today as it was 15 or 20 years ago, but there are still valid reasons for using a tile map in a game, espe- cially for things like collision detection. Knowing where an object is in relation to the read more..

  • Page - 211

    184 Chapter 9 Tile Maps Figure 9.1 iPhone Simulator running the CH09_SLQTSOR project. Introduction to Tile Maps Back in the early days of game development, managing memory efficiently was not just a nice optimization; it was a necessity.With limited memory and graphical performance, those early arcade games needed to store large playing areas and graphics in a way that would allow read more..

  • Page - 212

    185 Introduction to Tile Maps Figure 9.2 Example tile map. Areas of the map, such as the wooden floor, are all represented by a single image.This means we only have to store that one image in memory and just render it to the screen wherever the tile map identifies it should go. Now this is a very basic map.To make things more interesting, you could have more read more..

  • Page - 213

    186 Chapter 9 Tile Maps You can see that using many different tiles, you can create nice detailed maps.What is great is that as your map grows, your memory storage requirements do not. After you have all of your tiles images loaded, no matter how many times they are used in the tile map, you don’t need to store any additional image data. As your tile map grows, read more..

  • Page - 214

    187 Tile Map Editor Figure 9.4 Tiled GUI with a map being edited. Tiled has four key panels marked by red numbers in Figure 9.4.These panels are as follows: 1. Toolbar (at the top) 2. Main editor panel (in the middle) 3. Tile palette (at the bottom) 4. Layer palette (on the right) This gives us the perfect environment to build a tile map and see how it will look read more..

  • Page - 215

    188 Chapter 9 Tile Maps Note Tiled supports multiple tile sets within a single map. If you are creating a very large map that has more tiles that you can fit on a single 1024 ×1024 tile sheet, this is a handy feature. For our purposes, we will stick with a single tile sheet, supported by the TiledMap class. A tile sheet is basically the same as a simple sprite read more..

  • Page - 216

    189 Creating a Tile Map Figure 9.5 New Map dialog in the Tiled application. the data associated with each layer (that is, the layer’s name and tile data). It also imple- ments methods that enable you to query a layer’s data based on a tile’s coordinates. Creating a Tile Map After having a brief look at Tiled, let’s run through how you would create a tile map. read more..

  • Page - 217

    190 Chapter 9 Tile Maps Create a New Tile Set In the menu bar, select Map > New Tileset .This displays the New Tileset dialog, shown in Figure 9.6. As the name suggests, this dialog enables you to create a new tileset. Let’s quickly run through the New Tileset dialog’s options, as follows: n Name: This enables us to set a name for the tileset.This is most handy when read more..

  • Page - 218

    191 Creating a Tile Map Figure 9.7 Tileset palette containing the NewTiles.png tileset. If your tileset image had spacing between the tile images, the tile spacing and margin values should be changed to match the spacing in the image. After you finish configuring the settings, press OK.You see a palette of tile images ap- pear at the bottom of Tiled’s window, as shown in read more..

  • Page - 219

    192 Chapter 9 Tile Maps Now that we have the layers, save the map and call it tilemap.tmx. Drawing the Map Next, we can start drawing the map itself, so make sure the TileMap layer is selected in the layer panel.To draw a tile, simply select the tile you want to draw from the tileset palette and make sure that the brush tool is selected in the toolbar (along read more..

  • Page - 220

    193 Understanding the Tiled Configuration File Understanding the Tiled Configuration File When you create a map using Tiled, the output is a configuration file that describes the map you have created.This file is an XML file that contains the information necessary to recreate the map you have designed inside your game. At this point, it is worth taking a look at this file read more..

  • Page - 221

    194 Chapter 9 Tile Maps Listing 9.1 A Complete Tileset Element within a .tmx File <tileset name="Tiles" firstgid="1" tilewidth="40" tileheight="40"> <image source="NewTiles.png"/> <tile id="0"> <properties> <property name="reducePlayersHealth" value="10"/> </properties> </tile> </tileset> The tileset element shown read more..

  • Page - 222

    195 Understanding the Tiled Configuration File Attributes within the layer element define the layer name , width , and height . It is nor- mal for a layer ’s dimension to equal the map’s dimension, although nothing stops them from being different. As with the map and tileset elements, the layer element can have any number of properties defined for it.They follow the same read more..

  • Page - 223

    196 Chapter 9 Tile Maps The objectgroup element has attributes that define the name of the group along with the width and height .We won’t be using the width and height of the objectgroup in Sir Lamorak’s Quest, so there’s no need to concern yourself with those elements. A single objectgroup can contain any number of object elements.These define the name of the object along read more..

  • Page - 224

    197 Tile Map Classes n Layer data: Multi-dimensional array for storing the tile information within the layer. n Layer width: Width of the layer in tiles. n Layer height: Height of the layer in tiles. n Layer properties: Properties that have been created on the layer. n Tile images: Image information for each tile on the layer. We see how these properties are used as we move read more..

  • Page - 225

    198 Chapter 9 Tile Maps These are used to define the maximum width (kMax_Map_Width) and height (kMax_Map_Height) a layer can have.These constants are used further down the header file when defining the layerData array that holds the tile data, as shown here: int layerData[kMax_Map_Width][kMax_Map_Height][4]; The layerData array is a multi-dimensional array.The first two dimensions hold the x read more..

  • Page - 226

    199 Tile Map Classes screen does not support multiple tile sets.To increase performance, I wanted to keep the number of texture swaps to a minimum, and I’ve found that having a single tile set has not been a problem while writing Sir Lamorak’s Quest. The TileSetID starts at 0 for the first tile set and increments for each tile set used. Note Nothing is stopping you read more..

  • Page - 227

    200 Chapter 9 Tile Maps The method responsible for adding these tiles to a layer is called addTileImageAt: , and is shown in Listing 9.6. Listing 9.6 Layer addTileImageAt: Method -(void)addTileImageAt:(CGPoint)aPoint imageDetails:(ImageDetails*)aImageDetails { int index = (int)(layerWidth * aPoint.y) + (int)aPoint.x; memcpy(&tileImages[index], aImageDetails->texturedColoredQuad, sizeof(TexturedColoredQuad)); read more..

  • Page - 228

    201 Tile Map Classes Getting and Setting Tile Information Having created an instance of the Layer class and shown how to add tile information, we now look at the methods used to retrieve and set tile information within a layer. This is important, as we will want to query a layer and use the tile information re- turned within our game. It was mentioned earlier that we read more..

  • Page - 229

    202 Chapter 9 Tile Maps Listing 9.9 Layer tileImageAt: Method - (TexturedColoredQuad*)tileImageAt:(CGPoint)aPoint { int index = (int)(layerWidth * aPoint.y) + (int)aPoint.x; return &tileImages[index]; } This method is simple but important. It forms an important part of the rendering process when we come to render a layer’s tiles. TileSet Class Having looked at the Layer class and how read more..

  • Page - 230

    203 Tile Map Classes Listing 9.10 TileSet’s initWithImageNamed: Method - (id)initWithImageNamed:(NSString*)aImageFileName name:(NSString*)aTileSetName tileSetID:(int)tsID firstGID:(int)aFirstGlobalID tileSize:(CGSize)aTileSize spacing:(int)aSpacing margin:(int)aMargin { if (self = [super init]) { sharedTextureManager = [TextureManager sharedTextureManager]; tiles = [[SpriteSheet spriteSheetForImageNamed:aImageFileName spriteSize:aTileSize read more..

  • Page - 231

    204 Chapter 9 Tile Maps n getTileX : Given a TileID , this method returns the x component of where that tile is within the sprite sheet. n getTileY : Same as getTileX , but returns the y component of where a tile is within the sprite sheet. TiledMap Class The Layer and TileSet classes are helper classes that are used within the TiledMap class. When you want to use a Tiled read more..

  • Page - 232

    205 Tile Map Classes Note The version of TBXML used in Sir Lamorak’s Quest, and referenced throughout this book, is version 1.3. The NSDataAdditions class extends Apple’s NSData class, providing the ability to encode and decode base64 data and also inflate and deflate data using gzip. Information on the original authors of this class can be found in the NSDataAdditions.h file. The read more..

  • Page - 233

    206 Chapter 9 Tile Maps Listing 9.11 TiledMap initWithFileName:fileExtension Method (Part 1) - (id)initWithFileName:(NSString*)aTiledFile fileExtension:(NSString*)aFileExtension { self = [super init]; if (self != nil) { sharedGameController = [GameController sharedGameController]; sharedImageRenderManager = [ImageRenderManager sharedImageRenderManager]; tileSets = [[NSMutableArray alloc] init]; layers = [[NSMutableArray read more..

  • Page - 234

    207 Tile Map Classes Having created an instance of TBXML called tmxXML , we then need to parse the .tmx file that has been opened.This is handled by two private methods: parseMapFile: and parseMapObjects: (covered next).The TBXML instance is released when the file has been parsed.The next line of code uses memset to initialize the nullTCQ structure we have to zeros.This will be read more..

  • Page - 235

    208 Chapter 9 Tile Maps NSLog(@"INFO - TiledMap: Tilemap map dimensions are %dx%d", mapWidth, mapHeight); NSLog(@"INFO - TiledMap: Tilemap tile dimensions are %dx%d", tileWidth, tileHeight); The first step is to get the root object of the file being parsed. All the lookups we will do inside the document will use this root element as the parent. It’s then time to take the map read more..

  • Page - 236

    209 Tile Map Classes The last command in the while loop loads the property element with the next sibling that is found. If this is null , we have finished finding all the properties; otherwise, we process the next property as before.This continues until there are no more properties to process. Parsing the Tile Set Element After we finish dealing with the map element, we read more..

  • Page - 237

    210 Chapter 9 Tile Maps Once we have the image and source details for the tile set, we move onto processing any tile set properties.These properties are held at the tile image level (that is, each image in- side a tile set can have any number of properties associated with it).This can be useful if you want to assign information to a tile image that maybe read more..

  • Page - 238

    211 Tile Map Classes If we look at an example of the tile element and its properties, you see that we need a couple of loops: one that runs through all the tile elements that exist within a tileset , and another that processes the property details for each tile . Listing 9.17 is an excerpt from a .tmx file that shows a tile element with associated property elements. read more..

  • Page - 239

    212 Chapter 9 Tile Maps Having added the tile set to our array, we then release currentTileSet because its re- tain count would have been increased when adding it to the tileSets array. We finish off by incrementing the currentTileSetID counter and then looking for any other tileset elements. Parsing the Layer Element The layer element is processed in the same way as the read more..

  • Page - 240

    213 Tile Map Classes As each layer is processed, we create a new Layer instance.This is loaded with the infor- mation we parse from the .tmx file.We also parse any properties that have been defined for the layer and pass them to the Layer instance. Having parsed the layer element and created the Layer instance, next you’ll need to parse the tile information for that read more..

  • Page - 241

    214 Chapter 9 Tile Maps Listing 9.21 shows the loop we use to add the tiles to the layer we are currently pro- cessing. Listing 9.21 TiledMap parseMapFileTBXML: Method (Part 8) long y; for (tile_y=0, y=0;y<layerHeight*layerWidth;y+=layerWidth,tile_y++) { for (tile_x=0;tile_x<layerWidth;tile_x++) { int globalID = bytes[y+tile_x]; if(globalID == 0) { [currentLayer addTileAt:CGPointMake(tile_x, read more..

  • Page - 242

    215 Tile Map Classes If the data information was not base64 encoded, it means we need to process the tile data as plain XML. Note For large maps, this can create a significant performance problem, so base64 encoding should be used at all times. The preferences for saving a tile map can be changed from within Preferences . Listing 9.22 shows the code necessary to process read more..

  • Page - 243

    216 Chapter 9 Tile Maps Processing the plain XML tile information is almost identical to processing the other .tmx file elements.We loop through all the tile elements and use the attribute information to add tiles to the layer, just as we did when processing the compressed tile information. You will see that for both the compressed and plain loops, we are responsible for read more..

  • Page - 244

    217 Tile Map Classes Listing 9.23 TiledMap createLayerTileImages: Method - (void)createLayerTileImages { int x = 0; int y = 0; TileSet *tileSet = [tileSets objectAtIndex:0]; for(int layerIndex=0; layerIndex < [ layers count]; layerIndex++) { Layer *layer = [layers objectAtIndex:layerIndex]; for(int mapTileY=0; mapTileY < mapWidth; mapTileY++) { for(int mapTileX=0; mapTileX < mapHeight; mapTileX++) { int read more..

  • Page - 245

    218 Chapter 9 Tile Maps Rendering a Layer We’ve certainly covered a lot so far in this chapter.You’ll be glad to know that we are ap- proaching the end now as we look at how we render a layer. Having done all this hard work, we really want to start to see the results. For this, we need to be able to render our map layers to the screen.This is done read more..

  • Page - 246

    219 Tile Map Classes [sharedImageRenderManager renderImages]; if (!aUseBlending) glEnable(GL_BLEND); } When we render a tile map layer, we are actually rendering a small part of the map. It makes no sense to render the whole layer, which could be hundreds of tiles wide and high, when you are only going to actually see an 8x13 section of the map on the screen. I have read more..

  • Page - 247

    220 Chapter 9 Tile Maps Getting Tile Informaiton The final methods to discuss are those that let us query map information; for this, we’ll use the following methods: n tileSetWithGlobalID: : Returns the tile set that contains the global tile ID pro- vided. n layerIndexWithName: : Returns the index of a layer that has a name that matches the name provided. n mapPropertyForKey: : read more..

  • Page - 248

    221 Exercise Exercise The CH09_SLQTSOR project that accompanies this chapter moves over the top of a tile map, rendering two layers.The first layer is the map itself (that is, the floors and walls), and the second layer contains the objects, such as pictures, chairs, and so on. Remember that the actual layers in a tile map are always rendered at 0,0 , so movement inside read more..

  • Page - 249

    This page intentionally left blank read more..

  • Page - 250

    10 The Particle Emitter This chapter focuses on what has to be my favorite part of the game engine: the particle system. As mentioned in Chapter 2,“The Three Ts:Terminology,Technology, and Tools,” a particle system in the world of games does not involve expensive particle accelerators or the collision of exotic particles at the speed of light. Particle systems are actually read more..

  • Page - 251

    224 Chapter 10 The Particle Emitter Note To learn more about Cocos2D, look for Learning Cocos2D: A Hands-on Guide to Building iPhone & iP ad Games with Cocos2D, Box2d, and Chipmunk by Rod Strougo. This book is cur- rently in development and will be available in early 2011 from Addison-Wesley. Keep an eye on www.informit.com/learnmac for more news about upcoming Mac/iPhone read more..

  • Page - 252

    225 Particle Emitter Project the ParticleEmitter class we are using, and also learned how to configure the particle emitter using XML configuration files. Introduction to Particle Systems Particle systems have become more and more popular over the years. As both CPUs and GPUs have increased in speed, it has been possible for game designers and programmers to come up with more read more..

  • Page - 253

    226 Chapter 10 The Particle Emitter Comment out the three lines of code under the particle fountain configuration comment and then uncomment the three lines of code under the Appearing emitter configuration comment.When you then run the project again, you will see the particle emitter shown in Figure 10.2 in action. Although the particle fountain and appearing emitter look very read more..

  • Page - 254

    227 Life Cycle of a Particle n Max Radius Variance: Variance applied to a particle’s radius at creation. n Min Radius: Minimum radius a particle can be from the source position. n Radius Speed: Speed at which a particle moves from Max Radius to Min Radius. n Rotate Per Second: Number of degrees per second a particle will rotate around the source position. n Rotate Per Second read more..

  • Page - 255

    228 Chapter 10 The Particle Emitter 2.The next time that calculation is performed, we may get 6 as the answer if the macro returned 1. This technique is applied whenever there is a variance in our particle emitter, so that we can create randomness to the particle’s properties within bounds we have control over. That handles the situation where we want to randomly read more..

  • Page - 256

    229 Life Cycle of a Particle The update function will carry out a couple of functions.The first one creates new particles to be emitted based on an emission rate.The emission rate in the particle system is calculated when a particle emitter is created as follows: emissionRate = maxParticles / particleLifeSpan; This value is then used to work out how many particles are going read more..

  • Page - 257

    230 Chapter 10 The Particle Emitter particles (that is, those with a positive lifespan) are held together at the start of the array. We’ll see how this is done later in this chapter. Because of this, a particle never really dies; it is simply set to inactive.When we then need to emit a new particle, we simply grab an inactive particle from our array and set it read more..

  • Page - 258

    231 Particle Emitter Classes <maxRadius value="0.00"></maxRadius> <maxRadiusVariance value="0.00"></maxRadiusVariance> <minRadius value="0.00"></minRadius> <rotatePerSecond value="0.00"></rotatePerSecond> <rotatePerSecondVariance value="0.00"></rotatePerSecondVariance> </particleEmitterConfig> The root element for the file is called read more..

  • Page - 259

    232 Chapter 10 The Particle Emitter Listing 10.2 TBXMLParticleAdditions Header File #import "TBXML.h" #import "Global.h" @interface TBXML (TBXMLParticleAdditions) // Returns a float value from the processes element - (float) floatValueFromChildElementNamed:(NSString*)aName parentElement:(TBXMLElement*)aParentXMLElement; // Returns a bool value from the processes element - (BOOL) read more..

  • Page - 260

    233 Particle Emitter Classes parentElement:aParentXMLElement]; if (xmlElement) { float red = [[TBXML valueOfAttributeNamed:@"red" forElement:xmlElement] floatValue]; float green = [[TBXML valueOfAttributeNamed:@"green" forElement:xmlElement] floatValue]; float blue = [[TBXML valueOfAttributeNamed:@"blue" forElement:xmlElement] floatValue]; float alpha = [[TBXML valueOfAttributeNamed:@"alpha" read more..

  • Page - 261

    234 Chapter 10 The Particle Emitter The first structure is shown in Listing 10.4 and is called PointSprite . Listing 10.4 PointSprite Structure typedef struct { GLfloat x; GLfloat y; GLfloat size; Color4f color; } PointSprite; You may wonder why we have called the structure PointSprite .We are going to be using something called point sprites to render the particles for each particle read more..

  • Page - 262

    235 Particle Emitter Classes Listing 10.6 ParticleEmitter initParticleEmitterWithFile: Method - (id)initParticleEmitterWithFile:(NSString*)aFileName { self = [super init]; if (self != nil) { TBXML *particleXML = [[TBXML alloc] initWithXMLFile:aFileName]; [self parseParticleConfig:particleXML]; [self setupArrays]; [particleXML release]; } return self; } Inside our initializer, we first create a new instance of TBXML read more..

  • Page - 263

    236 Chapter 10 The Particle Emitter Having made sure that we at least have a configuration file with a valid root element, we then start to process the other elements we need. Listing 10.8 shows the texture element being processed, along with a number of other configuration elements. Listing 10.8 ParticleEmitter parseParticleConfig Method (Part 2) - read more..

  • Page - 264

    237 Particle Emitter Classes This method simply populates each property by using the appropriate method inside our TBXMLParticleAdditions class. Using methods such as vector2fFromChildElement saves us from repeating the code we have actually placed inside the TBXMLParticleAdditions category. The last line of this method is something we should also understand, as follows: emissionRate = read more..

  • Page - 265

    238 Chapter 10 The Particle Emitter Point Sprites I’ve already mentioned point sprites a couple of times in this chapter, so it would be helpful to run through what they are. Up until now, when we want to render something to the screen, we create a quad using four vertices and then map a texture into that quad. This works well, and we could easily use the same read more..

  • Page - 266

    239 Particle Emitter Classes Updating Particles With our particle configuration having been parsed and the storage setup, we can now deal with how to update the particles. Listing 10.10 shows the start of the ParticleEmitter updateWithDelta method. Listing 10.10 ParticleEmitter updateWithDelta Method (Part 1) - (void)updateWithDelta:(GLfloat)aDelta { if(active && emissionRate) { float rate = read more..

  • Page - 267

    240 Chapter 10 The Particle Emitter The code so far has made sure the particle emitter is active and within its defined dura- tion and also that particles have been emitted based on the emitter’s configuration.The next task is to run through all active particles and update their location, size, and color. Listing 10.11 shows the start of the while loop that updates read more..

  • Page - 268

    241 Particle Emitter Classes The while loop continues while the particleIndex ivar is less than the particleCount . particleCount is updated whenever a new particle is added to the particle emitter. Inside the while loop, the particle at particleIndex within the particle’s array is referenced, and we check to see if that particle’s timeToLive value is greater than 0. If this is read more..

  • Page - 269

    242 Chapter 10 The Particle Emitter The code to support this effect is specific to the needs of the portal, but it is still possible to generate effects that could be used in other situations by changing the configuration file of the emitter. If the emitter was not configured with a radius value, the emitter will be updated using the particle’s current position and read more..

  • Page - 270

    243 Particle Emitter Classes particleIndex++; } else { // As the particle is not alive anymore replace it with the // last active particle in the array and reduce the count of // particles by one. This causes all active particles to be // packed together at the start of the array so that a // particle which has run out of life will only drop into // this clause once read more..

  • Page - 271

    244 Chapter 10 The Particle Emitter Listing 10.13 ParticleEmitter addParticle Method Exert particle->position.x = sourcePosition.x + sourcePositionVariance.x * RANDOM_MINUS_1_TO_1(); particle->position.y = sourcePosition.y + sourcePositionVariance.y * RANDOM_MINUS_1_TO_1(); float newAngle = (GLfloat)DEGREES_TO_RADIANS(angle + angleVariance * RANDOM_MINUS_1_TO_1()); Vector2f vector = Vector2fMake(cosf(newAngle), read more..

  • Page - 272

    245 Particle Emitter Classes glBindBuffer(GL_ARRAY_BUFFER, verticesID); glBufferData(GL_ARRAY_BUFFER, sizeof(PointSprite) * maxParticles, vertices, GL_DYNAMIC_DRAW); glVertexPointer(2, GL_FLOAT, sizeof(PointSprite), 0); glColorPointer(4,GL_FLOAT,sizeof(PointSprite), (GLvoid*) (sizeof(GLfloat)*3)); GLint currentlyBoundTexture; GLint textureName = (GLuint)[[texture texture] name]; glGetIntegerv(GL_TEXTURE_BINDING_2D, &currentlyBoundTexture); if read more..

  • Page - 273

    246 Chapter 10 The Particle Emitter glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableClientState(GL_POINT_SIZE_ARRAY_OES); glDisable(GL_POINT_SPRITE_OES); if(blendAdditive) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); } You’ll see that we are using glDrawArrays to render the particles. Having loaded all the data into a VBO and not needing to jump around in the VBO read more..

  • Page - 274

    247 Have a Play This is certainly the most straightforward method in the ParticleEmitter class. It simply sets active to NO and resets the elapsedTime and emitCounter ivars.With this done, the particle emitter stops emitting or rendering particles and is ready to be started again if needed in the future. Have a Play In this book, the last section of a chapter is normally read more..

  • Page - 275

    248 Chapter 10 The Particle Emitter Figure 10.5 Particle Designer GUI. Summary As I said at the start of this chapter, particle systems are great fun to play with.The amaz- ing effects you can get by simply changing a few parameters are both a blessing and a curse. On the one hand, you can easily change settings to get the effect you are after without needing to change read more..

  • Page - 276

    11 Sound This is the final chapter that deals with the underlying technology we need to make Sir Lamorak’s Quest and most 2D games. Sound is one of the most important elements in a game. Although it’s possible to create a game that has no sound at all, sound really can take your game to a new level. Many of the games in the early 1980s didn’t have sound, read more..

  • Page - 277

    250 Chapter 11 Sound Introduction to Sound on the iPhone Sound on the iPhone can be a daunting subject.When I first looked at how to get sound on the iPhone, I found it to be confusing because a number of different approaches could be taken. The sound requirements for the iPhone are complicated.The device needs to handle different output routes—that is, internal speaker, read more..

  • Page - 278

    251 Introduction to Sound on the iPhone Note AVAudioSessionCategorySoloAmbient makes use of the iPhone’s hardware decoding capabilities. This is important if you are going to be playing a compressed sound or music file during your game, such as an MP3. Playing a compressed music file without using this category can cause very noticeable lag within your game. Understanding how to use read more..

  • Page - 279

    252 Chapter 11 Sound Playing Music When playing the game, it would be great to play some music.This is not mandatory and depends on the style of the game you are writing. For Sir Lamorak’s Quest, music can really add atmosphere to the game, so it is something we will want our sound manager handle. Luckily, there is a simple Objective-C API for playing back audio data read more..

  • Page - 280

    253 Introduction to Sound on the iPhone example, implemented using the iPhone I/O unit for playback.This results in the lowest latency, which is important when writing games. OpenAL is made up of three core objects that are used to generate a sound: n Listener n Source n Buffer There is only one listener object (per context 3), and all sound is rendered (generated) based on the read more..

  • Page - 281

    254 Chapter 11 Sound Source Source Source Listener Source Figure 11.1 Different sound source in relation to a single listener. Creating Sound Effects Knowing that we have APIs that can play music and sound effects for us is great, but we need to have music and sound effects that we can actually play. Putting sound into your game does not need to be expensive.There are read more..

  • Page - 282

    255 Introduction to Sound on the iPhone The AVAudioPlayer API will play any format of music that is supported by iOS. De- tails of the audio codecs supported up to iOS 4 are shown in Table 11.2. It’s important to understand how these formats are being handled (that is, are they being decoded using software or hardware? This will have a big impact on performance). read more..

  • Page - 283

    256 Chapter 11 Sound Note It is only possible to decode a single instance of one of the supported audio formats using hardware at any one time. If you play more than one MP3 sound, for example, the first sound will be decoded using hardware, but the second, third, and so forth will use software. For this reason, it is a good idea to use the hardware to decode your read more..

  • Page - 284

    257 Sound Manager Classes MyOpenALSupport is an example class provided by Apple. It takes audio data from an audio file and places it into a format that can be used with an OpenAL sound buffer. The MyOpenALSupport class takes care of identifying a number of important properties the sound file may have, including the following: n Sample Rate n Channels Per Frame n Format (for read more..

  • Page - 285

    258 Chapter 11 Sound Initialization The initialization of this class follows the singleton pattern that we covered in Chapter 4, “The Game Loop.” Although the creation of the singleton is the same, specific initializa- tion is being carried out within the init method. Listing 11.1 shows the first section of the init method. Listing 11.1 SoundManager init Method (Part 1) - read more..

  • Page - 286

    259 Sound Manager Classes error:&audioSessionError]; if (audioSessionError) NSLog(@"WARNING - SoundManager: Error setting the sound category to SoloAmbientSound"); } Just as the SoundManager class is a singleton, the AVAudioSession class is also a single- ton, so we grab a reference to its shared instance. After we have the reference to the audio session, we do a check to see if read more..

  • Page - 287

    260 Chapter 11 Sound stopMusicAfterFade = YES; usePlaylist = NO; loopLastPlaylistTrack = NO; } return self; } In this final section, you can see that we initialize OpenAL and check for the success of that initialization before moving on.We see what the initOpenAL method does next. Once OpenAL has been initialized, the sound manager’s ivars are given default values. Listing 11.5 read more..

  • Page - 288

    261 Sound Manager Classes The last command in Listing 11.5 sets up the distance model that we want to use. There are a number of different distance models available within OpenAL.They define how sound should be affected by the distance of the listener from the source. Details of all the different models are outside the scope of this book, but more infor- mation can be read more..

  • Page - 289

    262 Chapter 11 Sound Listing 11.7 SoundManager initOpenAL Method (Part 3) float listener_pos[] = {0, 0, 0}; float listener_ori[] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; float listener_vel[] = {0, 0, 0}; alListenerfv(AL_POSITION, listener_pos); alListenerfv(AL_ORIENTATION, listener_ori); alListenerfv(AL_VELOCITY, listener_vel); NSLog(@"INFO - Sound Manager: Finished initializing the sound manager"); return YES; } read more..

  • Page - 290

    263 Sound Manager Classes n resumeMusic n fadeMusicVolumeFrom:toVolume:duration:stop: n addToPlaylistNamed:track: n startPlaylistNamed: n removedFromPlaylistNamed:track: n removePlaylistNamed: n clearPlaylistNamed: n playNextTrack: n shutDownSoundManager: Loading Music We start by looking at the loadMusicWithKey:musicFile: method shown in Listing 11.8. Listing 11.8 SoundManager loadMusicWithKey:musicFile Method - read more..

  • Page - 291

    264 Chapter 11 Sound This method takes the key passed in and checks to see if an entry already exists within the musicLibrary dictionary for the key. If a match was found, a message is logged, explaining that the music has already been loaded. If no match is found, the path of the file is calculated within the main bundle of the application and an entry is added to read more..

  • Page - 292

    265 Sound Manager Classes return; } if(musicPlayer) [musicPlayer release]; musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; if(!musicPlayer) { NSLog(@"ERROR - SoundManager: Could not play music for key '%d'", error); return; } musicPlayer.delegate = self; [musicPlayer setNumberOfLoops:aRepeatCount]; [musicPlayer setVolume:currentMusicVolume]; [musicPlayer play]; read more..

  • Page - 293

    266 Chapter 11 Sound isMusicPlaying = NO; usePlaylist = NO; } - (void)pauseMusic { [musicPlayer pause]; isMusicPlaying = NO; } - (void)resumeMusic { [musicPlayer play]; isMusicPlaying = YES; } } - (void)setMusicVolume:(float)aVolume { if (aVolume > 1 ) aVolume = 1.0f; currentMusicVolume = aVolume; musicVolume = aVolume; [musicPlayer setVolume:currentMusicVolume]; } The AVAudioPlayer class provides methods read more..

  • Page - 294

    267 Sound Manager Classes Listing 11.12 SoundManager fadeMusicVolumeFrom: toVolume: duration: stop: Method - (void)fadeMusicVolumeFrom:(float)aFromVolume toVolume:(float)aToVolume duration:(float)aSeconds stop:(BOOL)aStop { if (timer) { [timer invalidate]; timer = NULL; } fadeAmount = (aToVolume - aFromVolume) / (aSeconds / kFadeInterval); currentMusicVolume = aFromVolume; fadeDuration = 0; targetFadeDuration = aSeconds; read more..

  • Page - 295

    268 Chapter 11 Sound isFading = NO; if (stopMusicAfterFade) { [musicPlayer stop]; isMusicPlaying = NO; } } else { currentMusicVolume += fadeAmount; } if(isMusicPlaying) { [musicPlayer setVolume:currentMusicVolume]; } } You can see that this method simply increments the fadeDuration ivar and checks to see if fadeDuration has reached or exceeded the target duration. If so, the timer is destroyed and read more..

  • Page - 296

    269 Sound Manager Classes NSMutableArray *playlistTracks = [musicPlaylists objectForKey:aPlaylistName]; BOOL newPlayList = NO; if (!playlistTracks) { newPlayList = YES; playlistTracks = [[NSMutableArray alloc] init]; } [playlistTracks addObject:aTrackName]; [musicPlaylists setObject:playlistTracks forKey:aPlaylistName]; if (newPlayList) [playlistTracks release]; } A playlist is basically an NSMutableArray that contains the read more..

  • Page - 297

    270 Chapter 11 Sound [self playMusicWithKey:[playlistTracks objectAtIndex:playlistIndex] timesToRepeat:0]; } Starting a playlist is very similar to creating one.The method in Listing 11.15 first searches for a playlist with the name provided. If nothing is found in the musicPlaylists dictionary, a message is logged. If an entry was found, the playlist ivars are set up.The key item here is read more..

  • Page - 298

    271 Sound Manager Classes Listing 11.17 SoundManager playNextTrack Method - (void)playNextTrack { if (playlistIndex + 1 == [currentPlaylistTracks count]-1 && loopLastPlaylistTrack) { playlistIndex += 1; [self playMusicWithKey:[currentPlaylistTracks objectAtIndex:playlistIndex] timesToRepeat:-1]; } else if (playlistIndex + 1 < [ currentPlaylistTracks count]) { playlistIndex += 1; [self read more..

  • Page - 299

    272 Chapter 11 Sound isEqualToString:aTrackName]) { indexToRemove = index; break; } } [playlistTracks removeObjectAtIndex:indexToRemove]; } } Removing a track from a playlist is pretty straightforward.The only trick to watch out for is that you cannot change the contents of an NSDictionary while you are looping through its contents.This is why the removeFromPlaylistName:track: method loops through the read more..

  • Page - 300

    273 Sound Effect Management Sound Effect Management So far, we have covered the features and technology needed to support music within the sound manager.We now look at the sound effect features. For high-performance, 3D sound, OpenAL is a perfect fit. If, however, you have just a few sound effects and no need for the positional nature of OpenAL, there is no reason you read more..

  • Page - 301

    274 Chapter 11 Sound Loading Sound Effects We follow the same order as the music features and look at how to load a sound. Listing 11.20 shows the first part of the loadSoundWithKey:soundFile: method. Listing 11.20 SoundManager loadSoundWithKey:soundFile: Method (Part 1) - (void)loadSoundWithKey:(NSString*)aSoundKey soundFile:(NSString*)aMusicFile { NSNumber *numVal = [soundLibrary read more..

  • Page - 302

    275 Sound Effect Management Having generated a buffer, we then check for any errors that may have occurred.The alError variable was set to AL_NO_ERROR at the start of the method to make sure that any previous OpenAL errors were reset. Note When you query OpenAL for any errors, it returns only the very last error. There may have been a number of errors generated over read more..

  • Page - 303

    276 Chapter 11 Sound buffer '%d'", aSoundKey, bufferID); } We check to make sure that a fileURL was returned and then deal with loading the sound data from the file.The MyGetOpenALAudioData function is used for this, which is part of the MyOpenALSupport.c file.This sample Apple function handles the identification of the data held within the supplied file, such as the size, read more..

  • Page - 304

    277 Sound Effect Management Listing 11.22 SoundManager playSoundWithKey:gain:pitch:location:shouldLoop: Method (Part 1) - (NSUInteger)playSoundWithKey:(NSString*)aSoundKey gain:(float)aGain pitch:(float)aPitch location:(CGPoint)aLocation shouldLoop:(BOOL)aLoop { alError = alGetError(); // Clear the error code NSNumber *numVal = [soundLibrary objectForKey:aSoundKey]; if(numVal == nil) return 0; NSUInteger bufferID = [numVal read more..

  • Page - 305

    278 Chapter 11 Sound for(NSNumber *sourceNumber in soundSources) { alGetSourcei([sourceNumber unsignedIntValue], AL_SOURCE_STATE, &sourceState); if(sourceState != AL_PLAYING) return [sourceNumber unsignedIntValue]; } } The nextAvailableSource method loops through all the sources that have been added to the soundSources dictionary, looking for a source that is not currently playing. As soon as a source read more..

  • Page - 306

    279 Sound Effect Management With the source ID found, the rest of the method deals with configuring that source to play the sound. First, the source is bound to buffer 0 , which ensures it is not bound to an- other sound source (this is similar to binding an OpenGL ES texture to texture ID 0 ).The source is then bound to the buffer, and the pitch and gain are read more..

  • Page - 307

    280 Chapter 11 Sound return; } NSUInteger bufferID = [numVal unsignedIntValue]; NSInteger bufferForSource; NSInteger sourceState; for(NSNumber *sourceID in soundSources) { NSUInteger currentSourceID = [sourceID unsignedIntValue]; alGetSourcei(currentSourceID, AL_BUFFER, &bufferForSource); if(bufferForSource == bufferID) { alSourceStop(currentSourceID); alSourcei(currentSourceID, AL_BUFFER, 0); } } if((alError = alGetError()) read more..

  • Page - 308

    281 Handling Sound Interruptions Setting Sound Effect and Listener Position The final two methods needed to manage sound effects are as follows: n setListenerLocation: n setOrientation: Listing 11.26 shows these two methods in use. Listing 11.26 SoundManager setListenerLocation and setOrientation Methods - (void)setListenerPosition:(CGPoint)aPosition { listenerPosition = aPosition; alListener3f(AL_POSITION, read more..

  • Page - 309

    282 Chapter 11 Sound It’s actually not that hard, but if you don’t manage the sound interruption, you will end up with no sound at all once the sound interruption has finished, leaving the player confused and in a cone of silence. As you saw earlier, the SoundManager class adopts the AVAudioSessionDelegate pro- tocol.This contains a number of optional methods that enable you read more..

  • Page - 310

    283 Handling Sound Interruptions if(aState) { NSLog(@"INFO - SoundManager: OpenAL Active"); [audioSession setCategory:soundCategory error:&audioSessionError]; if(audioSessionError) { NSLog(@"ERROR - SoundManager: Unable to set the audio session category"); return; } [audioSession setActive:YES error:&audioSessionError]; if (audioSessionError) { NSLog(@"ERROR - SoundManager: Unable to set the audio session state read more..

  • Page - 311

    284 Chapter 11 Sound Summary This has been another long chapter with a lot of information covered. Sound can appear to be a daunting subject on the iPhone when you first start to read through the docu- mentation. By reviewing the sound manager for Sir Lamorak’s Quest and having looked at some of the APIs available under iOS, you should now be more confident to tackle read more..

  • Page - 312

    12 User Input This chapter covers capturing user input for use in Sir Lamorak’s Quest. For any game to work, there needs to be some kind of input from the player.This could be simply mov- ing a game piece on a board game, selecting options, or moving a player around a 3D environment. Until the arrival of the iPhone, most handheld consoles had one or more joypad con- read more..

  • Page - 313

    286 Chapter 12 User Input Figure 12.1 iPhone Simulator running the CH12_SLQTSOR project. Note As mentioned earlier, the accelerometer is not used in Sir Lamorak’s Quest. However, this sample project does demonstrate how to read accelerometer data and use this to move the player. Also note that this project mixes OpenGL ES and UIKit controls in the same view. Mixing UIKit and read more..

  • Page - 314

    287 Introduction to User Input Introduction to User Input Handling user touches is fundamental to the iPhone.Without the ability to recognize one or more touches on the screen, you would not be able to interact with the iPhone, essen- tially making it an attractive paperweight. Because of this, Apple has provided a framework that enables you to capture and process touch events.We read more..

  • Page - 315

    288 Chapter 12 User Input Events can also contain multiple touches. Figure 12.3 shows how touch phases can be tracked on multiple touches at the same time. Touch Down Touch Moved Touch Ended Single touch Figure 12.2 Single-touch phases. Touch 1 Down Touch 1 Moved Touch 1 Ended Touch 2 Moved Touch 2 Down Touch 2 Ended Multiple touches Figure 12.3 Multi-touch phases. For each of the read more..

  • Page - 316

    289 Processing Touch Events By now, you’re probably wondering when the touchesCancelled method is called, as there is no obvious way to cancel a touch.This method is called if the system itself has to cancel a touch (for example, an event, such as an incoming phone call, occurs that causes the application to no longer be active or the view is removed). A view being read more..

  • Page - 317

    290 Chapter 12 User Input Listing 12.1 EAGLView Touch Methods - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { [[sharedGameController currentScene] touchesBegan:touches withEvent:event view:self]; } - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { [[sharedGameController currentScene] touchesMoved:touches withEvent:event view:self]; } - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { read more..

  • Page - 318

    291 Processing Touch Events Listing 12.2 GameScene touchesBegan:withEvent:view: Method - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event view:(UIView*)aView { for (UITouch *touch in touches) { CGPoint originalTouchLocation = [touch locationInView:aView]; CGPoint touchLocation = [sharedGameController adjustTouchOrientationForTouch:originalTouchLocation]; if (CGRectContainsPoint(joypadBounds, touchLocation) && read more..

  • Page - 319

    Tracking Touches Between Phases When implementing an onscreen joypad, it is necessary to track touches between phases (for example, once a touch has been registered on the joypad, we need to track where that touch moves to calculate the direction the player wants to move). The initial touch is handled by the touchesBegan method, and movement is handled by the touchesMoved method. read more..

  • Page - 320

    293 Processing Touch Events CGPoint touchLocation = [sharedGameController adjustTouchOrientationForTouch:originalTouchLocation]; float dx = (float)joypadCenter.x - (float)touchLocation.x; float dy = (float)joypadCenter.y - (float)touchLocation.y; // Manhattan Distance joypadDistance = abs(touchLocation.x - joypadCenter.x) + abs(touchLocation.y - joypadCenter.y); directionOfTravel = atan2(dy, dx); } } } This method works in read more..

  • Page - 321

    The directionOfTravel and joypadDistance values are used within the scenes updateSceneWithDelta: method.This is basically linking the joypad movement to the movement of the player. The touchesEnded Phase At some point, the player will either lift his finger from the screen, or slide it off.When this happens, the touchesEnded:withEvent method is triggered. Listing 12.4 shows the read more..

  • Page - 322

    for (UITouch *touch in touches) { CGPoint originalTouchLocation = [touch locationInView:aView]; CGPoint touchLocation = [sharedGameController adjustTouchOrientationForTouch:originalTouchLocation]; if (CGRectContainsPoint(joypadBounds, touchLocation) && !isJoypadTouchMoving) { isJoypadTouchMoving = YES; joypadTouchHash = [touch hash]; continue; } if (touch.tapCount == 2) { NSLog(@"Double Tap at X:%f Y:%f", read more..

  • Page - 323

    Accelerometer Events The accelerometer is a great feature on the iPhone, and many games use this as a mecha- nism for player control.This section briefly covers how you can get information from the accelerometer. Although not used in Sir Lamorak’s Quest, this book would not be com- plete without covering how to access the accelerometer. The first thing you’ll need to do read more..

  • Page - 324

    The sample project’s implementation employs a very basic low-pass filter on the data to remove sharp accelerations due to say the jostling of the device. Much more sophisti- cated filters are available, and some of these can be seen in the AccelerometerGraph project included within the iPhone SDK. Having captured the accelerometer data, we now have to use it. Listing read more..

  • Page - 325

    Having linked the switch and exposed it as a property in EAGLView , we can then use that property to check if the switch is on or off.This can be seen in the code in Listing 12.7, where we check the sharedGameController.eaglView.uiSwitch.on value. If the accelerometer is off, the joypad information is used to move the player; other- wise, the accelerometer information is read more..

  • Page - 326

    13 The Game Interface This chapter covers the interface elements of Sir Lamorak’s Quest, including how the different interfaces were built and implemented.There are two types of interface in Sir Lamorak’s Quest.The first type is those built using OpenGL ES, such as the main menu and main game interfaces.The second type is those built using UIKit controls, such as UISlider and read more..

  • Page - 327

    300 Chapter 13 The Game Interface Figure 13.1 iPhone Simulator running the SLQTSOR project. With one of these views visible, rotating the iPhone causes the views to rotate and main- tain the correct orientation to the player.You’ll also notice that the main menu in the background flips to maintain its orientation.This is also true when you are playing the game. As you look read more..

  • Page - 328

    301 OpenGL ES Interface This class would be able to take care of rendering and identifying if a touch landed within the buttons bounds using some kind of visual highlight on the button. What you implement is really down to the requirements for your game. It is amazing, though, what can be created using simple techniques. The following sections cover the three elements that read more..

  • Page - 329

    302 Chapter 13 The Game Interface Inside the sample project is a group called Game Scenes . Inside this group are two fur- ther groups: Menu and Game . Inside the Menu group is the class that implements the main menu called MenuScene.m. This class inherits from AbstractScene and contains all the logic and rendering code for the menu.The rendering code can be found in the read more..

  • Page - 330

    303 OpenGL ES Interface This is basic code, and you should recognize it from what has already been covered in the previous chapters.The core elements in this method deal with rendering the clouds that move in different directions.This is handled by the for loop at the start of the method. This method also checks the current state of the scene to decide on what needs to be read more..

  • Page - 331

    304 Chapter 13 The Game Interface Defining Button Bounds Inside the MenuScene.h file, a number of CGRect variables have been created.These are shown in Listing 13.3. Listing 13.3 CGRect Variables Defined in MenuScene.h CGRect startButtonBounds; CGRect resumeButtonBounds; CGRect scoreButtonBounds; CGRect instructionButtonBounds; CGRect logoButtonBounds; CGRect settingsButtonBounds; These variables hold the read more..

  • Page - 332

    305 OpenGL ES Interface This takes any touch from the set of touches that may exist and is therefore not an ap- proach to be used if you want to deal with multiple touches together. In this situation, you would need to loop through each touch, processing it as you go. From the touch, we then grab its location and adjust the coordinates based on the ori- entation of read more..

  • Page - 333

    306 Chapter 13 The Game Interface Handling touches is exactly the same for the other buttons on the main menu.The only difference is the code that is executed when a button is pressed. Visualizing Boundaries Setting up the boundaries for buttons and other elements does sound easy, but I found that identifying where boundaries were during testing was not so easy. I eventually read more..

  • Page - 334

    307 OpenGL ES Interface GLfloat vertices[8]; vertices[0] = aRect.origin.x; vertices[1] = aRect.origin.y; vertices[2] = aRect.origin.x + aRect.size.width; vertices[3] = aRect.origin.y; vertices[4] = aRect.origin.x + aRect.size.width; vertices[5] = aRect.origin.y + aRect.size.height; vertices[6] = aRect.origin.x; vertices[7] = aRect.origin.y + aRect.size.height; glDisableClientState(GL_COLOR_ARRAY); glDisable(GL_TEXTURE_2D); read more..

  • Page - 335

    308 Chapter 13 The Game Interface The code to render the boundaries was added to the AbstractEntity class inside the render method. Each entity in the game has two different boundaries: Movement bounds are checked against the map and stop the entity moving into a blocked tile, and collision bounds are checked against other entities and are used to see if one entity has read more..

  • Page - 336

    309 OpenGL ES Interface Manually Setting Orientation By default, Sir Lamorak’s Quest starts up in landscape mode.This has been defined in the sample project’s SLQTSOR-Info.plist file, located in the Resources group, as shown in Figure 13.4. In the property list, you see a line called Initial interface orientation that has a value of Landscape (right home button).This sets the read more..

  • Page - 337

    310 Chapter 13 The Game Interface This asks the iPhone to switch on the accelerometer and to start sending notifications when the orientation changes.The name of the notification that gets sent is the following: UIDeviceOrientationDidChangeNotification To capture those notifications, the ES1Renderer class, found in the Classes > Views group of the sample project, registers an observer read more..

  • Page - 338

    311 OpenGL ES Interface This method grabs the device’s orientation and then checks to see if it is equal to one of the two supported landscape modes (for example, UIDeviceOrientationLandscapeLeft or UIDeviceOrientationLandscapeRight ). When a match is found, the interfaceOrientation property of the GameController class is set, which will be used when orienting the UIKit views when they read more..

  • Page - 339

    312 Chapter 13 The Game Interface UIKit Interfaces Building and using the OpenGL ES-based interface builds on what we have reviewed so far in the book by making use of images as interface elements and tracking touches against defined bounds. Building interfaces with UIKit is different in that a lot of the work you need to do in OpenGL ES is done for you by the read more..

  • Page - 340

    313 UIKit Interfaces Figure 13.5 New File panel in Xcode. Figure 13.6 SettingsView.xib inside Interface Builder. read more..

  • Page - 341

    314 Chapter 13 The Game Interface Note If you open these .xib files from outside of Xcode, the images they use will not be found be- cause they are stored within the Xcode bundle. You see that this view was created from a number of different elements. A UIImageView was used for the background image of the wooden panel. On top of that, the labels and sliders were read more..

  • Page - 342

    315 UIKit Interfaces Tip When using images inside Interface Builder, they need to be part of the project or they will not be available to select in the Interface Builder GUI. Setting up your view really is just a case of dragging around controls and laying them out as you need. One item worth noting is that the background color of the view itself has been changed.When read more..

  • Page - 343

    316 Chapter 13 The Game Interface Figure 13.7 Linking an IBOutlet. Right-clicking the File’s Owner in the SettingsView.xib panel causes the File’s Owner panel to pop up.This is the black panel on the bottom right of Figure 13.7. Under the Outlets section, you see all the variables defined in the SettingsViewController.h file as IBOutlets . If you don’t see the outlets there, read more..

  • Page - 344

    317 UIKit Interfaces Figure 13.8 Linking an IBAction. Listing 13.11 Action Methods Defined in SettingeViewController.h - (IBAction)hide:(id)aSender; - (IBAction)moveToMenu:(id)sender; - (IBAction)musicValueChanged:(UISlider*)sender; - (IBAction)fxValueChanged:(UISlider*)sender; - (IBAction)joypadSideChanged:(UISegmentedControl*)sender; You can see that the IBAction keyword has been used when defining these methods. Again, this read more..

  • Page - 345

    318 Chapter 13 The Game Interface Listing 13.12 SettingsViewController IBAction Methods - (IBAction)musicValueChanged:(UISlider*)sender { sharedSoundManager.musicVolume = [sender value]; } - (IBAction)fxValueChanged:(UISlider*)sender { sharedSoundManager.fxVolume = [sender value]; } - (IBAction)joypadSideChanged:(UISegmentedControl*)sender { sharedGameController.joypadPosition = sender.selectedSegmentIndex; } These methods simply set read more..

  • Page - 346

    319 UIKit Interfaces return UIInterfaceOrientationIsLandscape(interfaceOrientation); } There really isn’t too much to this method. It simply returns YES if the orientation of the iPhone is landscape.The UIInterfaceOrientationIsLandscape macro is defined within the UIKit.h file and is a simple way to identify if the orientation passed in is landscape, regardless of it being landscape left or read more..

  • Page - 347

    320 Chapter 13 The Game Interface the values held in the GameController .This makes sure that the controls display the cor- rect values when the view appears. Next are the checks on the orientation of the iPhone.We check the value of interfaceOrientation in the GameController , which is updated when the iPhone is rotated inside ES1Renderer . Depending on the current orientation, the read more..

  • Page - 348

    321 UIKit Interfaces More on Core Animation Core animation is a complete topic in itself. If you’re looking for deeper coverage, I highly recommend reading Core Animation: Simplified Animation Techniques for Mac and iPhone Development by Marcus Zarra and Matt Long (Addison-Wesley, 2009). The first task this method carries out is to add this view as a subview to EAGLView .Re- read more..

  • Page - 349

    322 Chapter 13 The Game Interface hidingSettings notification that is observed by GameScene . Inside GameScene , this noti- fication causes the checkJoypadSettings method to be called, which is shown in Listing 13.17. Listing 13.17 GameScene checkJoypadSettings Method - (void)checkJoypadSettings { if (sharedGameController.joypadPosition == 0) { joypadCenter.x = 50; settingsButtonCenter.x = 465; read more..

  • Page - 350

    323 Summary Summary This chapter covered how interface elements are created using both OpenGL ES in com- bination with UIKit .We have seen the differences between the two and looked at how you build interface elements, such as buttons from scratch using OpenGL ES, and how tracking the player’s touches can activate them. For the UIKit interface elements, you saw how they were read more..

  • Page - 351

    This page intentionally left blank read more..

  • Page - 352

    14 Game Objects and Entities We are now at the point where we need to start thinking about how to populate our game world with game objects and entities. Game objects are items in the game, such as energy pickups, parchment pieces, and animated tile map game objects (such as lamps). Game entities include the player (Sir Lamorak), the baddies roaming around the castle, the read more..

  • Page - 353

    326 Chapter 14 Game Objects and Entities Game Objects Before we start looking at how game objects have been implemented, we take a look at the different game objects that are used within Sir Lamorak’s Quest, including the following: n Map: Implements the flickering lamps that can be seen on the walls and also the gravestone that appears when the player dies. n Key: Implements read more..

  • Page - 354

    327 Game Objects AbstractObject Class All game objects inherit from the AbstractObject class.This class contains all the prop- erties that are common between game objects and the methods that these game objects can override. It also implements the NSCoding protocol.This is useful when information about a game object needs to be saved and restored at a later stage. More information read more..

  • Page - 355

    328 Chapter 14 Game Objects and Entities // Game object subtypes enum { kObjectSubType_RedKey = 0, kObjectSubType_GreenKey = 1, kObjectSubType_BlueKey = 2, kObjectSubType_YellowKey = 3, kObjectSubType_Candy = 4, kObjectSubType_Cake = 5, kObjectSubType_Chicken = 6, kObjectSubType_Drink = 7, kObjectSubType_LolliPop = 8, kObjectSubType_Ham = 9, kObjectSubType_Grave = 10, kObjectSubType_BottomLamp = 11, read more..

  • Page - 356

    329 Game Objects Listing 14.3 AbstractObject Methods - (id)initWithTileLocation:(CGPoint)aTileLocation type:(int)aType subType:(int)aSubType; - (void)updateWithDelta:(float)aDelta scene:(AbstractScene*)aScene; - (void)render; - (void)checkForCollisionWithEntity:(AbstractEntity*)aEntity; - (CGRect)collisionBounds; - (id)initWithCoder:(NSCoder *)aDecoder; - (void)encodeWithCoder:(NSCoder *)aCoder; Each game object is responsible for its own read more..

  • Page - 357

    330 Chapter 14 Game Objects and Entities Listing 14.4 EnergyObject initWithTileLocation: Method - (id) initWithTileLocation:(CGPoint)aTileLocation type:(int)aType subType:(int)aSubType { self = [super init]; if (self != nil) { type = aType; subType = aSubType; tileLocation.x = aTileLocation.x + 0.5f; tileLocation.y = aTileLocation.y + 0.5f; pixelLocation = tileMapPositionToPixelPosition(tileLocation); read more..

  • Page - 358

    331 Game Objects case kGame objectSubType_Chicken: image = [[[pss imageForKey:@"item_chicken.png"] imageDuplicate] retain]; energy = 25; break; case kGame objectSubType_Ham: image = [[[pss imageForKey:@"item_ham.png"] imageDuplicate] retain]; energy = 20; break; case kGame objectSubType_LolliPop: image = [[[pss imageForKey:@"item_lollipop.png"] imageDuplicate] retain]; energy = 10; break; default: read more..

  • Page - 359

    332 Chapter 14 Game Objects and Entities The MapObject , KeyObject , and ParchmentObject classes also use this same process when they are initialized to identify what type of game object they are. Updating During the game scenes update method, all game objects that are within the visible screen have their update method called.The check to make sure that an object is visible or read more..

  • Page - 360

    333 Game Objects As you can see, it’s simple to place any logic required for a specific game object into these methods.The approach here is that all energy game objects are implemented in the same class, but there is nothing to stop you from creating separate classes for each of your game objects, with each implementing their own logic. My key reason for keeping the game read more..

  • Page - 361

    334 Chapter 14 Game Objects and Entities [sharedSoundManager playSoundWithKey:@"eatfood" location:CGPointMake(aEntity.pixelLocation.x, aEntity.pixelLocation.y)]; } } } The collision method checks to see if the entity that has possibly collided with it is an instance of the Player class. In Sir Lamorak’s Quest, the only entity that will ever be passed to this method is the Player .This read more..

  • Page - 362

    335 Game Objects By making use of an object layer, we can create and position game objects anywhere within the tile map.These objects are then parsed from within the tile map .tmx file dur- ing game initialization and loaded into the gameObjects array.We cover how the game objects are initialized in Chapter 16,“Pulling It All Together.” Figure 14.2 shows the Tiled editor read more..

  • Page - 363

    The location and dimensions for these object boxes are written to the tile map’s .tmx file. This allows object layers to be used for different purposes (for example, collision detection). The location of objects in the .tmx file are stored as pixel locations, not tile locations. When the objects are created, the pixel location of the bottom-left corner is converted to a tile read more..

  • Page - 364

    337 Game Objects Figure 14.5 Object Properties dialog box. The type field is used to store the object type value. Remember that an object can be one of three different types: n kObjectType_Key = 0 n kObjectType_Energy = 1 n kObjectType_General = 2 The item selected in Figure 14.5 is a lollipop, so the type should be 1 (that is, kObjectType_Energy ).To store the subtype , a read more..

  • Page - 365

    338 Chapter 14 Game Objects and Entities Defining Doors Each door in the castle is represented by an instance of the Door class. This class is re- sponsible for handling the different doors in the castle (that is, locked doors that you need a key to move through, and those that simply open and close randomly). Door locations and types are defined within the tile map. read more..

  • Page - 366

    339 Game Entities The Axe class is self-explanatory.This class represents the player’s axe that can be thrown. It handles the fact that an axe can bounce off walls and only exists for a defined period of time. The last two classes in the list are Door and Portal .These entities don’t move, but they perform an action. 1 Heisenberg’s Uncertainty Principle: read more..

  • Page - 367

    340 Chapter 14 Game Objects and Entities ParticleEmitter *dyingEmitter; ParticleEmitter *appearingEmitter; float offScreenTimer; float appearingTimer; float distanceFromPlayer; These common properties are used by a large number of the entities in Sir Lamorak’s Quest. Apart from the Player , Axe , Portal and Door classes, no other entity uses its own properties, just those defined in the read more..

  • Page - 368

    You’ll notice that the getTileCoordsForBoundingRect method is defined as a C func- tion, not Objective-C.This function gets called a lot, so making it a C function reduces the messaging overhead that Objective-C introduces when calling methods on a class. The getTileCoordsForBoundingRect method, along with the isEntityInTileAtCoords , initWithEncoder , and encodeWithEncoder are actually im- read more..

  • Page - 369

    Listing 14.12 Witch Chase Code in the updateWithDelta:scene: Method if (distanceFromPlayer <= 3 ) { entityAIState = kEntityAIState_Chasing; } else { entityAIState = kEntityAIState_Roaming; } if (entityAIState == kEntityAIState_Chasing) { speed = 1 * MOVEMENT_SPEED; float dx = tileLocation.x - scene.player.tileLocation.x; float dy = tileLocation.y - scene.player.tileLocation.y; angle = atan2(dy, dx) - read more..

  • Page - 370

    Most AI makes use of a state machine. By using a number of input parameters, a spe- cific state is set that causes the entity to exhibit specific behavior. In the Witch class, the entity’s AI state is held in the entityAIState variable, and an enum is used to define the current AI state.This can, of course, get much more complex when many more AI states and input read more..

  • Page - 371

    float blinkTimer; int lives; float stayDeadTime; CGPoint beamLocation; ///////////////// Inventory AbstractObject *inventory1, *inventory2, *inventory3; ///////////////// Flags BOOL renderSprite; BOOL hasParchmentTop, hasParchmentMiddle, hasParchmentBottom; The animation properties store the different animations used when Sir Lamorak is moving up, down, left, and right. currentAnimation simply points to one of the read more..

  • Page - 372

    blinkTimer += aDelta; if (blinkTimer >= 0.10) { renderSprite = (renderSprite == YES) ? NO : YES; blinkTimer = 0; } } [self updateLocationWithDelta:aDelta]; energyTimer += aDelta; if (energyTimer > 3) { energy -= 1; energyTimer = 0; } if (energy <= 0) { state = kEntityState_Dead; energy = 0; MapObject *grave = [[MapObject alloc] initWithTileLocation:tileLocation type:kObjectType_General read more..

  • Page - 373

    Listing 14.15 Player updateWithDelta: Method (Part 2) case kEntityState_Dead: deathTimer += aDelta; if (deathTimer >= stayDeadTime) { deathTimer = 0; state = kEntityState_Alive; energy = 100; } break; default: break; } } When the player dies, we don’t want him to immediately reappear. It would be good to give him some time to compose himself and carry on. For this reason, we read more..

  • Page - 374

    Listing 14.16 Player updateLocationWithDelta: Method (Part 1) - (void)updateLocationWithDelta:(float)aDelta { BoundingBoxTileQuad bbtq; CGPoint oldPosition = tileLocation; if (speedOfMovement != 0) { tileLocation.x -= (aDelta * (playerSpeed * speedOfMovement)) * cosf(angleOfMovement); CGRect bRect = [self movementBounds]; bbtq = getTileCoordsForBoundingRect(bRect, CGSizeMake(kTile_Width, kTile_Height)); if ([scene read more..

  • Page - 375

    A little math is used to work out the new position based on the angleOfMovement .With a new x location calculated, the player’s current movement bounds are retrieved and the getTileCoordsForBoundingRect is called.This method converts the four corners of the rectangle into tile coordinates.This enables you to verify whether the tile in which that corner is located is blocked or not. read more..

  • Page - 376

    Listing 14.17 Player updateLocationWithDelta: (Part 2) if (angleOfMovement > 0.785 && angleOfMovement < 2.355) { currentAnimation = downAnimation; } else if (angleOfMovement < - 0.785 && angleOfMovement > - 2.355) { currentAnimation = upAnimation; } else if (angleOfMovement < - 2.355 || angleOfMovement > 2.355) { currentAnimation = rightAnimation; } else { currentAnimation = read more..

  • Page - 377

    If the player was not moving, the current animation’s state is set to stopped and the anima- tion frame is set to 4, which is the standing pose. Inventory The Player class is also responsible for handling the player’s inventory.The following two classes are used to manage inventory: n placeInInventoryObject: n dropInventoryInSlot: When the player adds an inventory item, the read more..

  • Page - 378

    } else if (!self.inventory3) { aObject.state = kObjectState_Inventory; aObject.isCollectable = NO; aObject.pixelLocation = CGPointMake(300, 303); self.inventory3 = aObject; [self checkForParchment:aObject pickup:YES]; } } } First of all, the object being added has its state checked. If it is not marked as active, it’s not added. If it is active, each of the three slots is checked to see read more..

  • Page - 379

    352 Chapter 14 Game Objects and Entities if (aInventorySlot == 0) { self.inventory1 = nil; } else if (aInventorySlot == 1) { self.inventory2 = nil; } else if (aInventorySlot == 2) { self.inventory3 = nil; } [self checkForParchment:invObject pickup:NO]; } The slot number is passed into the method from GameScene .The object associated with the inventory slot passed in is selected, and it read more..

  • Page - 380

    353 Saving a Game Object or Entity Listing 14.20 GameScene saveGameState Method NSKeyedArchiver Creation Snippet NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *gameStatePath = [documentsDirectory stringByAppendingPathComponent:@"gameState.dat"]; NSKeyedArchiver *encoder; gameData = [NSMutableData data]; read more..

  • Page - 381

    Both the AbstractObject and AbstractEntity classes implement these methods.The encodeWithCoder: method from the AbstractEntity class is shown in Listing 14.21. Listing 14.21 AbstractEntity encodeWithCoder: Method - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeCGPoint:tileLocation forKey:@"position"]; [aCoder encodeFloat:speed forKey:@"speed"]; [aCoder encodeFloat:angle forKey:@"angle"]; read more..

  • Page - 382

    355 Summary When an object is asked to decode itself, the initWithCoder: method is called in- stead. Listing 14.22 shows this method from the AbstractEntity class. Listing 14.22 AbstractEntity encodeWithCoder: Method - (id)initWithCoder:(NSCoder *)aDecoder { [self initWithTileLocation:[aDecoder decodeCGPointForKey:@"position"]]; speed = [aDecoder decodeFloatForKey:@"speed"]; angle = [aDecoder read more..

  • Page - 383

    You should also not be afraid to make changes.Take something like the Ghost class and see if you can alter its behavior—maybe always chasing Sir Lamorak or altering how it roams around the castle. (Hint:Try making changes within the update method.) In Chapter 15,“Collision Detection,” we will review the collision detection strategy being used within Sir Lamorak’s Quest and read more..

  • Page - 384

    15 Collision Detection This chapter reviews how collision detection has been implemented within Sir Lam- orak’s Quest, as well as the common problems that need to be solved.Without collision detection, the player and game characters would be able to wander through walls, and we’d have no way of knowing when the player or entities hit each other. Although this chapter is read more..

  • Page - 385

    358 Chapter 15 Collision Detection Some games model the real world much more accurately using physics engines, but again, some physics engines still cheat when checking for collisions and responses and just do enough to give the illusion of a real-world interaction between objects. Luckily for us, Sir Lamorak’s Quest isn’t trying to be clever and uses just basic collision read more..

  • Page - 386

    isPlayerOverObject = NO; for(AbstractObject *gameObject in gameObjects) { if (gameObject.tileLocation.x >= minScreenTile_x && gameObject.tileLocation.x <= maxScreenTile_x && gameObject.tileLocation.y >= minScreenTile_y && gameObject.tileLocation.y <= maxScreenTile_y) { // Update the object [gameObject updateWithDelta:aDelta scene:self]; if (gameObject.state == kObjectState_Active) { [player read more..

  • Page - 387

    Instead, the game loop updates the game more than once per frame using this fixed delta.The render method is called only after the update has run enough times to meet the frame rate set.This means that the entities in the game move at a constant rate during each update. As more updates are performed per frame, fast-moving entities are updated and checked more frequently, read more..

  • Page - 388

    361 Detecting Collisions 2 The separating axis theorem: en.wikipedia.org/wiki/Separating_axis_theorem. Tip Although Sir Lamorak’s Quest uses boxes, it is possible to use other shapes as well. Bound- ing circles are another common approach to detecting if a collision has taken place. Some games also use multiple bounding boxes or circles for a single entity. This is useful if an en- read more..

  • Page - 389

    362 Chapter 15 Collision Detection if (testY < aRect.origin.y) testY = aRect.origin.y; if (testY > (aRect.origin.y + aRect.size.height)) testY = (aRect.origin.y + aRect.size.height); return ((aCircle.x - testX) * (aCircle.x - testX) + (aCircle.y - testY) * (aCircle.y - testY)) < aCircle.radius * aCircle.radius; } If you were using circles for all entities, you would need to also handle read more..

  • Page - 390

    Any tile that contains a red cross is blocked.This is a nice visual aid when editing the map. You’ll notice that in the tile sheet at the bottom of the screen, there is a tile that contains a simple red cross.This is what I paint in the Collision layer to mark a blocked tile. During game initialization, a collision map is built using a simple 2D array.This array read more..

  • Page - 391

    364 Chapter 15 Collision Detection if(globalTileID == kBlockedTileGloablID) { blocked[xx][yy] = YES; } else { if (!sharedGameController.shouldResumeGame) { if (globalTileID >= kFirstDoorTileGlobalID && globalTileID <= kLastDoorTileGlobalID) { int doorType = [[castleTileMap tilePropertyForGlobalTileID:globalTileID key:@"type" defaultValue:@"-1"] intValue]; if (doorType != -1) { door = [[Door read more..

  • Page - 392

    365 Entity-to-Map Collision Detection The same approach is used when parsing the doors.To identify that a tile is actually a door, I check the tiles globalTileID to see if it is within a set range. It does tie the tileset tightly to the code, but it really does improve performance. Inside the GameScene class is a method called isBlocked:y: , which is used to identify read more..

  • Page - 393

    Listing 15.6 Entity-to-Map Collision Check CGRect bRect = [self movementBounds]; BoundingBoxTileQuad bbtq = getTileCoordsForBoundingRect(bRect, CGSizeMake(kTile_Width, kTile_Height)); if([scene isBlocked:bbtq.x1 y:bbtq.y1] || [scene isBlocked:bbtq.x2 y:bbtq.y2] || [scene isBlocked:bbtq.x3 y:bbtq.y3] || [scene isBlocked:bbtq.x4 y:bbtq.y4]) { // Collision detected } First of all, an entity’s movement bounds are read more..

  • Page - 394

    367 Entity-to-Entity Collision Detection Entity-to-Entity Collision Detection This is the most straightforward collision detection you’ll find in Sir Lamorak’s Quest. Given the collision bounds for the entity and also details of the entity we could be collid- ing with, the entities checkForCollisionWithEntity: method is called. Listing 15.7 shows this method inside the Ghost class. Listing read more..

  • Page - 395

    if(([aEntity isKindOfClass:[Ghost class]] || [aEntity isKindOfClass:[Frank class]] || [aEntity isKindOfClass:[Witch class]] || [aEntity isKindOfClass:[Pumpkin class]] || [aEntity isKindOfClass:[Bat class]] || [aEntity isKindOfClass:[Vampire class]] || [aEntity isKindOfClass:[Zombie class]]) && state == kEntityState_Alive) { energy -= aEntity.energyDrain; } } } As you can see, how the Player deals with a read more..

  • Page - 396

    16 Pulling It All Together This chapter covers the areas needed to finish off Sir Lamorak’s Quest.The features dis- cussed include saving the game’s state, saving the player’s scores, performance tuning, and getting the game beta tested. We have come a long way since the start of this book, and a lot of detail has been cov- ered. From my own experience, and the read more..

  • Page - 397

    370 Chapter 16 Pulling It All Together After clearing the screen, the current model view matrix is pushed onto the stack, saving its contents.This is followed by a glTranslate command that takes half the width and height of the iPhone screen and subtracts the player’s pixel location. Remember that our tile map is 200 ×200 tiles.With each tile being 40×40 pixels, that gives us an read more..

  • Page - 398

    371 Saving the Game State and Settings Notice that we are actually subtracting 1 from the x and y tile location, and adding 2 to the width and height . As the player moves around, the tile map changes by a mini- mum of one pixel at a time if the player is moving slowly.This causes the map to move smoothly around the player. By adjusting the x and y tile map read more..

  • Page - 399

    372 Chapter 16 Pulling It All Together What we now need is the ability to save and restore those objects. Saving the games state is implemented in the GameScene class. All the information we want to save is in the GameScene , so it makes sense to place the method in that class.We also need to save the game settings, but this is done within the GameController read more..

  • Page - 400

    373 Saving the Game State and Settings [encoder encodeObject:savedScore forKey:@"score"]; [encoder encodeInt:locationName forKey:@"locationName"]; // Finish encoding and write the contents of gameData to file [encoder finishEncoding]; [gameData writeToFile:gameStatePath atomically:YES]; [encoder release]; // Tell the game controller that a resumed game is available read more..

  • Page - 401

    374 Chapter 16 Pulling It All Together Listing 16.4 GameScene loadGameState: Method - (void)loadGameState { [self initGameContent]; // Set up the file manager and documents path NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSMutableData *gameData; NSKeyedUnarchiver *decoder; // Check to see if the ghosts.dat read more..

  • Page - 402

    375 Saving the Game State and Settings SLQLOG(@"INGO - GameScene: Loading saved game score."); score = [[decoder decodeObjectForKey:@"score"] floatValue]; SLQLOG(@"INFO - GameScene: Loading game time data."); locationName = [decoder decodeIntForKey:@"locationName"]; SLQLOG(@"INFO - GameScene: Loading game time data."); [decoder release]; // Init the localDoors array [self initLocalDoors]; } read more..

  • Page - 403

    376 Chapter 16 Pulling It All Together The settings variable is configured in the initGameController method of the GameController class using the following: settings = [[NSUserDefaults standardUserDefaults] retain]; With settings initialized, we can use the methods available within NSUserDefaults to store the setting’s values.You’ll notice that we defined a key for each entry stored.This read more..

  • Page - 404

    377 Saving High Scores The method first checks to see if the NSUserDefaults entry with the key userDefaultsSet has a value of 1. If not, the games settings have never been saved, so de- fault values are used and the userDefaultsSet entry is updated to 1. If the userDefaultsSet preference does have a value of 1, the values for the games settings are read. Last of all, a read more..

  • Page - 405

    378 Chapter 16 Pulling It All Together If the user presses the Dismiss button, the score is thrown away and not recorded. If he enters a name, the current date and time, score, game time, and whether he won or lost is recorded. Listing 16.7 shows the alertView:clickedButtonAtIndex: method used to capture input from the player. Listing 16.7 GameScene alertView:clickedButtonAtIndex: read more..

  • Page - 406

    379 Saving High Scores Note I chose to use an arbitrary number for the tag value given to the UITextField . Feel free to use another number, if you’d like. This method is the delegate method for the UIAlertView .When the game is over or completed and the user touches the screen, a new UIAlertView is created in the touchesBegan:withEvent: method in GameScene .This creates an read more..

  • Page - 407

    380 Chapter 16 Pulling It All Together n Duration of the game n Score It also implements the NSCoding protocol so that it can encode and decode itself.This is how we are going to save the information to disk. The GameController class has an instance variable called unsortedHighScores .This NSMutableArray stores the instances of Score that have been loaded when the game started read more..

  • Page - 408

    381 Saving High Scores Listing 16.10 GameController saveHighScores Method - (void)saveHighScores { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *scoresPath = [documentsDirectory stringByAppendingPathComponent:@"highScores.dat"]; NSMutableData *scores; NSKeyedArchiver *encoder; scores = [NSMutableData data]; read more..

  • Page - 409

    382 Chapter 16 Pulling It All Together [decoder release]; } else { unsortedHighScores = [[NSMutableArray alloc] init]; } [self sortHighScores]; } When the GameController is first initialized, any high scores are loaded. From that point, the unsortedHighScores array is managed by GameController and then saved back to disk when new scores are added. Performance and Tuning When writing software read more..

  • Page - 410

    383 Performance and Tuning Optimizing your application, especially a game, is important, but it should be done on the basis of evidence (that is, profiling) and an obvious need, not just because a piece of code looks like it may be slow. There are areas in Sir Lamorak’s Quest that I believe can be optimized—making more use of C functions rather than Objective-C methods, read more..

  • Page - 411

    384 Chapter 16 Pulling It All Together Figure 16.4 Instruments running the Leaks template on SLQTSOR. Note The existing templates contain a number of different instruments already in place that you can immediately put to use . Leaks Instrument Selecting the Leaks instrument starts the Instruments application using that template. It also runs the current project in the iPhone Simulator read more..

  • Page - 412

    385 Performance and Tuning Notice that not all leaks come from your own application. If you look at the Responsible Library column, you see that none of them are SLQTSOR—they are all Apple frameworks. Even Apple’s code has leaks, and there is not much you can do about those. You’ll also find that you get different libraries reporting leaks on the iPhone Simulator as read more..

  • Page - 413

    386 Chapter 16 Pulling It All Together Make sure that the Leaks instrument is highlighted.This provides you with a list of leaked objects in the middle panel, as shown in Figure 16.5. Also, make sure that the ex- tended detail view is enabled. Figure 16.6 shows the options that should be enabled at the top of the Instruments GUI. The extended detail view is really useful read more..

  • Page - 414

    387 Performance and Tuning It should not be too hard to spot that we are allocating leakyString in the viewDidLoad: method and then again in the printAnotherMessage: method without releasing the already allocated string.This means the pointer to that first string is going to be lost—we can’t release the memory, therefore creating a leak. Add the following two lines of code in read more..

  • Page - 415

    388 Chapter 16 Pulling It All Together Figure 16.8 OpenGL ES instrument monitoring SLQTSOR running on an iPod 2G using iOS 4. Note The table lets you see the Implicit Scene Count, Renderer Utilization, Resource Bytes, Tiler Uti- lization and Core Animation Frames Per Second. It can take a while to get used to what you are looking at, but the ones I use most often are read more..

  • Page - 416

    389 Performance and Tuning If you double-click the first entry for the application in the stack trace, you will be taken to the code that was running, causing the high CPU usage. Figure 16.9 shows the code associated with a spike. The great thing about this view is that it provides you with information on the amount of time, as a percentage, spent on commands within the read more..

  • Page - 417

    390 Chapter 16 Pulling It All Together Given that most games perform a lot of float-point math, this is bad thing. Disabling the Compile for Thumb option in the build settings of your project normally provides a significant performance increase. Beta Testing With the finishing touches added to the game, leaks tracked down, and acceptable per- formance, it’s time to release your read more..

  • Page - 418

    391 Beta Testing The process for creating provisioning profiles and certificates can be very daunting at first, but working through the wizards and documents available on the iPhone Dev Cen- ter will get you up to speed. Multiple Device Types One of the key benefits of using beta testers is that you can get your game tested across a number of different devices.This is read more..

  • Page - 419

    392 Chapter 16 Pulling It All Together Feedback Beta testers can also provide great feedback around the actual game design itself. Sir Lam- orak’s Quest received great feedback on the look and style of the HUD in the game.The original, shown in Figure 16.10, was seen as being too big and taking up too much screen space. This can be a balance of personal preference. If a read more..

  • Page - 420

    393 Summary There are also commercial engines: n Torque, a 2D/3D Engine (www.torquepowered.com) n Bork3D, a 3D Engine (bork3d.com/engine) n ShiVa 3D, a 3D Engine (www.stonetrip.com) n Unity3D, a 3D Engine (www.unity3d.com) Having an understanding of what is going on “under the hood” helps make the best use of these game engines, especially the open source engines that you can read more..

  • Page - 421

    This page intentionally left blank read more..

  • Page - 422

    Index A A*, 343 AABB (Axis-Aligned Bounding Boxes), 360-361 abstract classes, 79 AbstractEntity class, 339 AbstractObject class, 327-329 AbstractObject Methods, 329 AbstractScene, 92-93 accelerometer, 285 accelerometer events, 296-298 adding frames, Animation class, 157-158 images to render queue, ImageRenderManager, 120-123 object layers to maps, 335 particles, ParticleEmitter class, 243-244 scores, to high read more..

  • Page - 423

    animation, 18-19 bounce frames, 155-156 direction, 155 frames, 154-155 projects, 153-154 rendering with Animation class, 160-161 states, 155 types, 155 updates, Animation class, 158-160 Animation class, 156 animation rendering, 160-161 updates, 158-160 finishing things off, 161-163 frames, adding, 157-158 initialization, 156-157 animationFrameInterval, 55 applicationWillTerminate, 43 application delegates, 43-44 header read more..

  • Page - 424

    checkJoypadSettings method, 322 @class, 45 clipping, 67 Cocoa Design Patterns, 312 Cocoa Touch, 27 Cocoa Touch Class, 312 codecs, 255 collision detection, 22-23, 357-358, 361-362 Axis-Aligned Bounding Boxes (AABB), 360-361 entity-to-entity collision detection, 367-368 entity-to-map collision detection, 365-366 frame-based versus time-based, 359-360 game loops, 74-75 collision maps, 362-365 collision method, 334 read more..

  • Page - 425

    EnergyObject class, 329 collisions, 333-334 initialization, 329-332 rendering, 333 updating, 332-333 entities, 10 entity-to-entity collision detection, 367-368 entity-to-map collision detection, 365-366 ES1Renderer, 58 color values, 66 positioning, 67-68 framebuffer, creating, 60-66 game loops, 82-85 render method, 63-66 renderbuffer, creating, 60-66 ES1Renderer.h, 58-59 ES1Renderer.m, 59-60 ES2Renderer, 52 examining read more..

  • Page - 426

    game scenes, 79, 86-87 AbstractScene, 92-93 game settings loading, 376-377 saving, 375-376 game state loading, 373-375 saving, 371-373 GameController class, 87-89, 308 GameController.m, 89-91 games for the iPhone, special considerations for, 4-5 Manic Miner, 3 naming, 5-6 objectives, 6-7 GameScene class, 93-95 generating image data,Texture2D, 111-112 texture names,Texture2D, 112-113 getters, 134 read more..

  • Page - 427

    ImageRenderManager. See ImageRenderManager Texture2D. See Texture2D TextureManager. See TextureManager ImageRenderManager, 119 images adding to render queue, 120-123 rendering, 123-126 initialization, 119-120 images adding to render queue, ImageRenderManager, 120-123 duplicating in Image class, 130 generating data in Texture2D, 111-112 loading, in Texture2D, 108-109 rendering with Image class, 130-133 read more..

  • Page - 428

    K keys, 9 keywords, IBAction, 317 kFadeInterval, 267 L Layer class, tile map classes, 196-197 adding tile images to layers, 199-200 adding tiles to layers, 198-199 getting and setting tile information, 201-202 initialization, 197-198 layer elements parsing, 212-216 tiled configuration file, 194-195 layer images, creating, 216-217 layerClass method, 51 layers rendering, 218-219 tile maps, 188-189 Leaks read more..

  • Page - 429

    Configure the Bitmap Context for Rendering the Texture, 111 EAGLView gameLoop: Method, 80 EAGLView render Method, 83 EAGLView Touch Methods, 290 EnergyGame object checkForCollisionWithEntity: Method, 333-334 EnergyObject collisionBounds Method, 334 EnergyObject initWithTileLocation: Method, 330-331 EnergyObject render Method, 333 EnergyObject updateWithDelta: Method, 332 Entity State enums Defined in Global.h, 340 read more..

  • Page - 430

    Getters and Setters, 134 The getWidthForString: Method, 180 Ghost checkforCollisionWithEntity: Method, 367 The ImageDetails Structure, 107 The imageDuplicate Method, 130 ImageRenderManager addImageDetailsToRenderQueue: Method, 121 ImageRenderManager addToTextureList: Method, 122 ImageRenderManager init Method, 120 ImageRenderManager initializeImageDetails Method, 128 ImageRenderManager renderImages Method, 123-124 read more..

  • Page - 431

    The render Method, 131-132 The Render Methods Within Animation.m, 160-161 The renderCenteredAtPoint:scale: rotation: Method, 131 Rendering the Texture Image, 111 Scene State as Defined in the Global.h File, 303 Setting the Image Size in Texture2D to a Power-of-Two, 110 SettingsViewController class, 318 SettingsViewController hide Method, 321 SettingsViewController shouldAutorotateToInterfaceOrientat ion: read more..

  • Page - 432

    SoundManager stopMusic, pauseMusic, resumeMusic, and setMusicVolume: Methods, 265-266 SoundManager stopSoundWithKey: Method, 279-280 SpriteSheet cacheSprites Method, 145-146 SpriteSheet InitWithImageNamed: spriteSize:spacing:margin:imageFilter Method, 144 SpriteSheet initWithImage:spriteSize: spacing:margin Method, 145 SpriteSheet spriteImageAtCoords: Method, 146-147 The spriteSheetForImageName: spriteSize:spacing:margin:image Filter: Method, read more..

  • Page - 433

    M managing playlists, 271-272 sound effects, 273 Manhattan distance, 293 Manic Miner, 3 map element, tile configuration file, 193 map elements parsing, 207-209 tiled configuration file, 193 map files parsing, 207 map elements, 207-209 map layers, creating, 191 maps collision maps, 362-365 drawing, 192 tile maps, 192 message nesting, 48 motion events, 287 multiple device types, beta testing, 391 read more..

  • Page - 434

    OpenGL, 68-69 applying transformations on models, 69-70 axis configuration, 64 rendering to screens, 70-72 OpenGL ES, 15, 27-29 XXXX1.1 versus 2.029-30 GL_TRIANGLE_STRIP, 99 instrument, 387-389 OpenGL ES interfaces, 300-301 defining button bounds, 304 handling touches, 304-308 rendering, 301-303 transitions, 308 OpenGL ES orientation, 308 manually setting, 309-311 orientation OpenGL ES, 308 manually setting, read more..

  • Page - 435

    particles, 21 adding in ParticleEmitter class, 243-244 life cycle of birth of particles, 227-228 death, 229 lives of, 228-229 rebirth, 229-230 rendering in ParticleEmitter class, 244-246 updating in ParticleEmitter class, 239-243 performance, Compiling for Thumb, 389-390 phases, tracking touches between, 292 pixelLocation, 327 placeholders, prototyping, 19 placeInInventory: method, 350-351 placing objects, tile read more..

  • Page - 436

    justified text, 178-180 layers, 218-219 OpenGL ES interfaces, 301-303 particles, ParticleEmitter class, 244-246 quads, 98-101 to screens, OpenGL, 70-72 text, 176-178 deallocation, 181 width and height, 180-181 renderLayer:mapx:mapy:width:height: useBlending: method, 218 renderScene method, 303, 369-370 retrieving sprites with PackedSpriteSheet class, 149-150 SpriteSheet class, 146-147 textures,TextureManager, 117-118 read more..

  • Page - 437

    soundLibrary dictionary, 258 SoundManager, 257 controlling music, 265-266 fading music, 266-268 initialization, 258-262 loading music, 263-264 managing playlists, 271-272 music playlists, 268-271 playing music, 264-265 removing music, 264 SoundManagerAVAudioPlayer, 257 special considerations, for iPhone games, 4-5 speed, update speed, 74 speedOfMovement, 347 sprite sheets, 16-18, 137-138 bitmap fonts, creating, read more..

  • Page - 438

    texture mapping, 101 texture coordinates, 101-103 texture names, generating in Texture2D, 112-113 texture parameters, binding with setting parameters, 113-114 Texture2D, 107, 108 binding texture and setting parame- ters, 113-114 generating texture names, 112-113 images generating data, 111-112 loading, 108-109 sizing, 109-111 initialization, 108 loading image data into OpenGL tex- ture, 114-116 read more..

  • Page - 439

    Tiled Qt, 186 TiledMap class tile map classes, 204-205 initialization, 205-207 XML parsing, 204 TileID, 199 tileImageAt: method, 201 tileLocation, 327 tiles, adding to layers, 198-199 TileSet class, tile map classes, 202 getting tile set information, 203-208 initialization, 202-203 tileset element, 193-194 TileSetID:Identifies, 199 time, 7 time maps, 20-21 time-based collision detection, versus frame- read more..

  • Page - 440

    updating EnergyObject class, 332-333 particles, ParticleEmitter class, 239-243 Player class, 344-346 user input, 287 accelerometer events, 296-298 projects, 285-286 taps, 294-295 touch events, 287-289 processing, 289-290 userDefaultsSet, 377 V vertex arrays, 104 vertical synchronization, 52 view ports, configuring, 85-86 Viewport function, 85 visualizing boundaries, 306-308 vsync, 52 W weapons, 10 width, text, read more..

Write Your Review