Video Update 2
Hi all and welcome to Video Update 2. This is a quick 8 min video just to show you what I’m working on for Tutorial 10. Things are hectic at the moment, but progress is being made.
I hope you enjoy the video update and as always, it would be great to get feedback and comments.
Mike
69 Comments
MFerron on June 21st, 2009
Hey Mike,
Can’t wait for Tutorial 10. Really looking forward to it.
As far as your organization and other updates/fixes from the previous tutorials, I noticed you mentioned you wouldn’t be able to cover every single change. Will this mean that if we follow Tutorial 10 from where we left off in Tutorial 9 our game will not work?
Thanks again,
-MFerron
bob on June 21st, 2009
Hi Mike, great update I noticed in the code in one part of the video the word JoyPad ( that brings back memories )
Tony on June 22nd, 2009
Excellent Mike. You’re making quite some progress. I’ve had to split up my files similar to the way you did, simply for the sake of clarity.
You really spoil your viewers with your tutorials. I’ve seen quite a few tutorials in the past few weeks. None of them measure up to yours.
I’ve come across an interesting survey on iPhone apps development which I thought might interest you and your readers. It’s located at http://t-machine.org/index.php...../#more-576. It’s quite sobering actually.
Thanks for the great work.
Cheers!
Tony
Jamie Hill on June 22nd, 2009
Looking very interesting.
Do you mind me asking what you updated to get things running on 3.0 as I’ve just installed the SDK and just get a black screen (on my own version that I’ve been putting together based on your tutorials).
MFerron on June 22nd, 2009
@jamie
I don’t remember exactly where it was, but he did answer this question earlier(I had the same question). Not positive, but it should be in the comments of tutorial 4. Sorry I couldn’t be more specific, but its on the site somewhere.
It was a simple 1-liner if I believe.
Jeff on June 22nd, 2009
@jamie
Inside
applicationDidFinishLaunching
, you probably have something similar to this in your code:
[self mainGameLoop];
To work in 3.0, that will have to replaced with this:
[self performSelectorOnMainThread:@selector(mainGameLoop) withObject:nil waitUntilDone:NO];
I think the problem is that the
applicationDidFinishLaunching
thread has to finish.
Cheers.
mike on June 22nd, 2009
Hi guys and thanks for the feedback :o)
@MFerron, Whilst there are changes to the structure and classes which have already been created up to Tutorial 9, I am expecting that your code should just be able to plug in with maybe just a couple of changes. I’ve tried hard to keep the API to the classes the same unless I’ve really needed to change it. One example would be that the Image class does not take a UIImage anymore, you just pass in the name of the Image you want to use and it creates an image itself etc. This was so I could get it working with my ResourceManager. That should just be a simple change though to replace the Image class inits from a UIImage to an NSString for the image name. I will be checking, but apart from that and the actual layout of the code changing it should work as before, I hope :o) but I’ll help people if things break too much.
@Jamie, I didn’t even type a letter and you got the answer. I love how people who read this blog help each other out. I was hoping that the blog would become a location for people to share with and help each other apart from the tutorials and that has certainly happened :o)
If you have any other questions just let me know.
Thanks
Mike
Jamie Hill on June 22nd, 2009
Thanks guys for the quick response, that’s great. I don’t even pretend to understand what is happening there (threads make my head hurt!).
MFerron on June 22nd, 2009
@Mike
That doesn’t sound too bad! Since I’m sure there are very good reasons, both technically and aesthetically, for your changes… it may end up being best that I just take your tutorial 10 and add my personal stuff to it. Instead of the other way around.
On a different note, I’m not sure what your plans are for AI in your game, but I’ve come across some very good tutorials in the past that illustrate the math concepts behind a number of basic AI interactions that can really go a long way into making a game feel just a little more real.
Things like chasing, evading, wandering, turning-towards, and way points (which you have already implemented). When implemented these actions/reactions can do cool stuff like homing missiles, bad guys fleeing when their health is low, roaming animals, chasing zombies, etc.
They’re written in C#, not Objective-C, but the concepts and math will hold true no matter what language (I found them when I did a little Xbox 360 programming). If you’re interested let me know and I’ll send you or whoever else the links.
-MFerron
mike on June 22nd, 2009
Hi MFerron. I’m hoping the changes will not be too bad, but it may well be easier in the long run if you like the changes of course :o) to go with adding your code to the project to reduce the amount of time chasing issues.
I am definitely going to be needing AI, and as you said, I’ve got some basic steering behavior in place already. What you have got sounds really interesting, so if you have stuff you could send to mike@71squared.co.uk that would be great :o)
I’ve not played with the Xbox at all in terms of writing stuff, although my kids love the console.
Mike
mike on June 22nd, 2009
@bob, yes, joypad :o)
I’ve been playing with having an onscreen joypad which you should be able to move your finger over to control your character. This has proved harder than I thought so I’m still using the accelerometer for the moment. Also found that the touch events were flooding the game and causing it to slow down as well. So a number of problems to sort out, but as I’ve seen a number of other games doing this, I think it would be cool to get it working :o)
Mike
bob on June 22nd, 2009
@Mike
I emailed you a pretty large file 8M its a full book with examples for Game AI.. hope you can receive it
MFerron on June 22nd, 2009
@Mike
Did my email make it through the wires as well?
mike on June 22nd, 2009
@MFerron, yep, that it did and I’ve started to compare my steering code with the waypoint code in the examples.
I like how they are actually kept simple which I like :o) and I also spotted some collision detection ones which I’m going to check out as well. Thanks for the link :o)
Mike
MFerron on June 22nd, 2009
Hey Bob,
I’d be interested in seeing that book as well if you don’t mind. ferr0234@umn.edu
Thanks
Jamie Hill on June 22nd, 2009
@Mike, I’ve noticed that you have gone back to using NSTimer for doing the frame delay. Is there a reason for this?
mike on June 22nd, 2009
@Jamie, that is most likely some old code floating around :o)
I’ve kept playing with all sorts of different game loops, but at the moment I’m still using the one that’s been in from almost day one. There are pros and cons to this method, such as it links game logic update with the frame rate. There are instances where this may not be a good idea such as when tracking very fast moving objects and the game scene cannot be drawn at 60fps, but I’ve not yet run into too many of those, so I’m keeping it as simple as I can for as long as I can :o)
Mike
Jamie Hill on June 22nd, 2009
@Mike, I’m looking at the code in Tutorial 8 and 9 inside the mainGameLoop where the while is commented out.
mike on June 22nd, 2009
Ah, my bad, I had that in because it was the only way I could get the app to work on 3.0 until I found out about running the method on the main thread, as posted above :o)
Now I’ve got that working I’m back to the good old game loop.
Sorry about that :o)
Mike
Jamie Hill on June 22nd, 2009
@Mike, aha, I see, however I can’t see the tread stuff in your latest code i.e. in the AppDeligate you have:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES]; [glView startAnimation];
…which is working in 3.0 for me.
mike on June 22nd, 2009
Ah, yes, I didn’t put the change in until recently so the last two tutorials were still using the NSTimer. I’ll be back to normal in the next tutorial :o)
Mike
Jamie Hill on June 22nd, 2009
@Mike, that’s cool, thanks for the info.
Jamie Hill on June 22nd, 2009
@mike, I’m wondering if you can help me with something else (slightly off topic). I am doing something similar to what you are doing in you font class i.e. using glDrawElements to output a bunch of renders in one hit (it’s a render buffer class I’m working on). When I dump it out to the screen anything else that has been drawn is lost, even if it is not in the same area of the screen. I was wondering if you’d come across this?
Jamie Hill on June 22nd, 2009
@mike, sorry for the triple post you can ignore it, I wasn’t re-enabling GL_VERTEX_ARRAY. Can you see any performance reason for not using glDrawElements all the time over glDrawArrays as I’ve come up with quite a nice buffering system and I’m thinking of using it for one-off renders too.
mike on June 22nd, 2009
No problem Jamie, I’m glad you found the problem.
From the tests I’ve run, there is not much difference in glDrawElements and glDrawArrays. The key really is if you want to draw the contents in your arrays out of order, in which case glDrawElements is the way to go.
I’ve not actually done any work on putting individual renders together. Apart from the tilemap class and font class which do batch the renders up, the Image class just does immediate rendering, which when you have a number of images you want to render can be a performance bottleneck.
If you have anything you can share re your render routine I’d be really interested to see it. I know others have been working on batching their rendering up as well such as Tom from the blog.
When I had sat and had a think about it, there are always the issues of holding the vertices, texture coords and colour info for each quad, ordering of the renders to the screen as well as switching between textures. So far, I’ve not come up with a system which would be handle all those things at the moment.
Mike
kp3406 on June 22nd, 2009
Hi all, I have been following the tutorials from the beginning, but this is my first post here. Just to comment on what Mike just said,
I have my game setup using as few glDraw___ calls as possible. Bassically I have two different sizes of monsters, and a overall MonsterGroup class for each containing a single spriteSheet with all monsters. That MonsterGroup controls creating, destroying, updating, and rendering all monsters it contains.
I also modified the particle emitter and created a particle emitter Manager singleton class, which handles creating, destroying, updating, and drawing all particle emitters. I found this really useful for being able to trigger particle effects from my other objects. I.E my homing missiles have a particle emitter for a smoke trail, and for their explosion. My plans for the future are to change this into a generic point sprite manager to handle all effects using point sprites
I also added a primitive drawing manager singleton class, that handles the creating, destroying, updating, and rendering of all primitive openGL drawing (using lines for me). For me this is used for drawing healthbars over all monsters, and any other effects that require drawing lines.
I have five main things update each frame: the two monster groups, the bullet emitter, the primitive drawing manager, and the particle emitter manager. I am planning to add two – a background tilemap update, and a text manager update to that as well. These main objects also render once each frame, so you only need to change the texture that is bound 5-6 times each frame to draw everything.
I have recently done some Stress tests of my engine, and I found that the bottleneck was in the particle emitter – having about 32 particle emitters with 200 particles each slowed down my ipod touch 1st gen to about 20 fps. That said, i reduced the number of particles per generator to 100, and made some other optimizations and I can have about 120 monsters on screen attacking, lots of bullets and missiles, and around 50 particle emitters on screen while keeping the framerate at 50+fps. Keep in mind, each monster has a lot of logic in its update loop, finding and tracking its target and moving, stuff like that. To me, this is totally adequate for my game, and It looks really crazy on screen. I have not seen many other iphone games that do this much action on the screen at once, so I think that I have my engine working pretty well.
If anyone has any comments on if I am doing anything wrong, or suggestions in how i set things up please let me know. This is the first game I have attempted, so I dont know if my methodology of grouping things is typical. I couldn’t figure out where to start in making a game until seeing these tutorials, so I owe you alot of thanks!
kp3406 on June 22nd, 2009
Sorry for that enormous post! I didn’t realize how long it was until I submitted it. It seems it would have been better suited for an email, so feel free to get rid of it if it takes up too much space!
Joey on June 23rd, 2009
@kp3406
Your post was only a few minute read, and all of it was good to know. I was going to try implementing similar modifications to increase performance because I, too, was going to have the screen covered with bullets and objects flying every which way, but I really haven’t had time to try everything out yet. Objective-C is still quite awkward coming from a C++, VB6, AS3, and PL/SQL background, and the time restraint doesn’t help much either.
But to add to your performance issues, I had similar troubles in other languages. What I used to do to increase performance was to skip some code every few frames or more if it allowed. This really was not a fix but it did help among other things.
@Mike or anyone else who might know the answer
Obviously, in practice there might not be a difference to the human eye but in theory, is displaying a background of 420 by 340 pixels using a tilemap class versus using a single image more efficient in terms of performance when using Open GL? I haven’t used Open GL before.
Thanks,
Joey
mike on June 23rd, 2009
@kp3406 that’s a great post and don’t worry about how much space it takes up :o) having people share this kind of information is exactly what I wanted to happen on the site, so I appreciate your time in providing that comment.
It sounds like you have really been taking the code and layout to the next level which is great. The crazy thing is that I’ve done all this code and I only now starting to actually use it in anger with a game as you can see from the Update Video, so I’m just starting to find areas which are not performing well or need changing. So you are well ahead of me in that respect. Fro what you describe it sounds like you are going the right way with the design of your code. Grouping things together and reducing the OpenGL draw calls really is the way to go I believe and the only area which could do with some work when the games get hectic is the game loop. Not having the logic update linked to the frame rate i.e. having maybe 2 or 3 logic updates per frame, can help to keep the game running smoothly when screen renders are taking a while as well as help with problems with collision detection for fast moving objects i.e. you can check their position more frequently and not have a missile move straight through a ship.
I think keeping 50+fps with all that going on is a real achievement so I would certainly say that your going in the right direction :o)
@Joey, I’ve not tested to see if there is a benefit between just drawing a large image or a tilemap. I would expect the tilemap to be a little slower than a single image as there is more work to do in crunching through the vertices and texture coordinates. If you are going to have a static image as a background I would go with a single image. If you have a large background that you want to scroll around etc then a tilemap is the way to go. It means you are only rendering what is visible to the player and not wasting memory and time rendering a huge image which is only partially visible. Hope that helps.
Mike
kp3406 on June 23rd, 2009
@Mike – are you saying to update the logic more frequently than rendering to the screen? In my game at least, the logic updating seems to be the limiting factor so I think I have been doing the opposite, rendering to the screen more frequently than updating the logic (by limiting the logic update rate)
I just tried implementing the TouchesMoved method to scroll my background (right now a static image, 960×320 and scrolled width-wise in landscape mode). I am finding that I cant seem to get the touchesMoved events handled quick enough with the game updates, I.E. the background scrolling is jerky and irregular. TouchesBegan events work fine, so I believe the problem lies in the TouchesMoved.
I am using the run loop you used earlier in tutorials, with
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, TRUE) == kCFRunLoopRunHandledSource);
Using larger values than .002 actually seems to make the scrolling worse. It seems like touches from TouchesMoved are only registered every 1-5 pixels of movement, which is making the scrolling jerky, and making it appear unresponsive to the movement of your finger. Have you come across this issue in your game? I think my run loop needs modifying to handle touches more frequently or at a regular interval…but I’m not really sure what modifications are needed
Greg on June 23rd, 2009
A general coding question, but related to what’s being discussed… How do you do stress tests to determine bottlenecks? Besides the obvious – turning certain things off and seeing if what’s left on runs faster. Sometimes you can’t turn off what you want to test because something else is relying on it. NSLogging doesn’t work as it just slows everything down.
mike on June 23rd, 2009
Hi Greg, great question. At the moment I’m using a combination of Instruments and Shark to see what is taking the time. I can’t say that I fully understand everything that things like Shark are telling me :o) but at least it points me in the general direction of things which are taking up a lot of time.
Instruments is also a good place to start and does give clearer information, but its not as detailed as Shark.
Mike
MFerron on June 23rd, 2009
@greg
My knowledge of optimizing graphical processes is limited, but I do know a little about general code optimization and performance debugging, so I’ll share it and hopefully it can offer some help.
Its going to sound really trivial when I say this, but make sure you aren’t doing the same thing twice, or computing more than you need to. Optimizing your algorithms can ramp up your speed greatly, and sometimes its really hard to see that your code is repeating itself.
For example, last year I needed to write a program to take an image (as a grid of pixels) and do some color blending. I did this by averaging color values for each pixel based on its neighboring pixels.
Now, a pixel in the middle of the image would have 8 neighbors, right? But a pixel on the corner would only have 3, and an edge pixel with only 5. I shouldn’t be using the same function for every pixel in the grid, should I? No. When I realized this, and adjusted my code, the performance gains were actually somewhat significant.
Did that example make sense? Sorry if it didn’t! The moral of the story is that you should try to find places where you may be doing something you don’t really need to.
A few other pointers on optimizing:
- The less local variables, the better. And when you use them, put them as far inside as you can. Don’t have them sitting outside a for loop when you only need them inside.
- That brings me to for loops. If you can avoid nesting them, do so! Nested for loops can murder performance.
- Initialize variables at the time they’re declared.
- A lot of times high readability in code can mean worse performance. This isn’t always the case but its something to think about. If your code doesn’t need much commenting for a human to understand easily, the computer may end up spending more time on it.
- Try rearranging things if you can. In my experience, that ends up helping, for who knows what reason. Unfortunately in the environment of game programming, there is a fairly strict order to your function calls, so this may not apply.
- Put the most common cases in your switch statements first.
- Addition is faster than multiplication, and multiplication is faster than division.
Hopefully this can help you. Its more general coding based, but it may apply for you.
-MFerron
Jamie Hill on June 23rd, 2009
@mike, I sent you an email on the buffer stuff, did you get it ok?
mike on June 23rd, 2009
Hi Jamie, I did indeed get your email. I checked it out at lunch time and its pushed me into getting a RenderManager written. I’ve kept putting it off and working on other things, but I really should get it sorted out. Your code has given me some great ideas of how to approach it and also get colour, transformation and layers going as well.
We shall have to see how much of this I actually achieve :o) but I appreciate the inspiration, just what I needed. All that I create will of course become available through tutorials etc.
Thanks Jamie
Mike
Jamie Hill on June 23rd, 2009
@mike, sounds good. One thing you may find which I have come across, is that it’s hard to do this without a slowdown. Currently it’s running slower than I would like, however I can’t see an obvious way of optimising it as I think what is causing the slowdown is simply the method call to the render buffer that logs the renders. Obviously you don’t get this problem currently in the font class as you never leave the current method while rendering the characters.
Any ideas on how to speed this up?
mike on June 23rd, 2009
Hmm, there is certainly some overhead in calling methods in Objective-C. I’m not sure of a way off the top of my head to sort that out without using C++ or something instead of an Objective-C class.
Maybe something can be done using inline functions or something, but I’d need to play with that to see what happens.
I’ll let you know how I get on :o) and thanks for the heads up.
Mike
Jamie Hill on June 23rd, 2009
@mike, Something you might find useful when speed testing (put this just before setting lastTime in the main game loop):
// Calculate the FPS framesPerSecond = (1.0f / (time - lastTime));
I then output this using the font class.
bob on June 23rd, 2009
Thanks for that bit of code Jamie.
mrspeaker on June 24th, 2009
Can’t wait! The scene manager looks like a cool idea too. I’ve been hunting and hunting for nice ways to lay this stuff out, so I’m looking forward to seeing this one in action!
kp3406 on June 24th, 2009
In case anyone has the same issues, I figured out why I thought my TouchesMoved was being unresponsive. I am using the ipod in landscape mode, and I temporarily forgot that the x/y coordinates from touches are not converted when you are in landscape mode…Using touch.y for touch.x solved the problem and the touchesMoved method now seems to work pretty well for background scrolling
A Person on June 24th, 2009
@mike ,Hey mike are you doing all the collision detection with the tile map or just the tile map collisions themselves
mike on June 24th, 2009
Hi A Person
At the moment I am building a simple [x][y] array which holds BOOLs for each tile on the map. When I’ve loaded the map I move through all the tiles checking for a property called blocked. If I find it and its true then the array for that location is maked as true. Once I have that I can then check to see if any corners of the players bounding box have entered into a tile which in the array is marked as blocked. If so I then deal with a collision situation.
I’m using the same approach for actor in the game that move around but need to collide with walls etc.
When it comes to checking of an actor has hit the player, I will do this is two phases. The broad phase will identify actors which are in the same tile as the player, or in any of the 8 tiles around the player. Once I’ve done that the narrow phase will then check to see if any of the actors bounds intersects the bounds of the player. If they do then they have collided and I’ll deal with that.
That is a real quick explanation of what I am doing and plan to do :o) and I hope it makes some sense.
Mike
MFerron on June 24th, 2009
@Mike
Does your collision system handle non-rectangular collision? So if there is a spherical enemy/object, it doesn’t appear to be intersecting with the square that bounds it, but instead the nontransparent parts of the texture.
My current plans for my game will involve spheres, or sphere-like shapes, so I’m curious as to what the best way of going about this is.
I figure you could do it a mathematical way, but that would only be completely accurate for plain old circles. Then I would imagine you could do it by pixel values, i.e. alpha > 0 –> collision, but that seems very taxing on the system. Ideas?
-MFerron
A Person on June 24th, 2009
@mike is there an advantage to looking at the tiles two sprites are in and then checking bounding boxes or why not just use bounding boxes right off the bat?
A Person on June 24th, 2009
@MFerron if you want to look at some rect-rect and circle-circle collision detection code google cocos2d iphone collision detection and you should see something like circle-circle cocos2d collision detection. This works great and am currently using it.
Jeff on June 25th, 2009
@A Person,
Circle-circle collision checks do work well. One modification I would make to the code at http://kwigbo.com/wp/2009/03/0.....detection/ (assuming that is the site you were referring to) would be to compare the squared distances rather than the acutual distance between points.
That should save you a square root operation, which adds up when it is done many times each frame.
Cheers.
A Person on June 25th, 2009
@mike, quick question mike, how are you getting the x and y coordinates in that map array if the tile map constantly moves?
A Person on June 25th, 2009
@Mike
I think i might have found a bug with the layer class with the methods that get ID’s for the tiles. In my collision detection class i am trying to detect collisions for layers of the tile map, so i noticed in you tile map class you have set a blank tile with a global id of 0 and tile id of -1 so i check to see if my sprite is about to collide with a tile with a global id of something not 0 if it does its solid and we stop. I get the layer fine its not that and the tile position of the sprite is fine too i think it is this global id and i have yet to try using map properties, so just thought i let you know.
Thomas on June 25th, 2009
I have a somewhat techinal question. In the update method i get a delta time, how do i save this value so i can keep track of how long the game have been running, or use it to make sure there is a delay between i call a method in the update section?
mike on June 25th, 2009
@A Person, I’m tracking the player and the actors/objects on the map using map coordinates i.e., the X and Y coordinates of a player are floats which hold tile coordinates e.g. an actor may have an X of 5.4 and a Y of 3.2. To get the real screen coordinates for this location I multiply these values by the tile size of the map so 5.4*50 = 270 and 3.2*50=160. That is then where they are rendered. To get a tile location I do the opposite and divide the pixel location by the tile size i.e. 270/50=5.4.
I hope that makes sense :o)
I have also been using the tiled map class to check for blocked tiles. First time around I had a layer that did nothing by hold collision data, i.e. if there was an image in a tile location it was blocked. I did that by checking to see if the tileset id was not -1. That worked fine but I’ve not tried using the tileid or global id. I’ll check that out.
To remove the need to have a layer for collisions as I have a large map, I am not setting a property for tiles which are blocked. I just call the property blocked and set its value to true. I then use the following code when I’ve loaded the map to set up the collision array:
// Build a map of blocked locations within the tilemap. This information is held on layer 1
// of the tilemap which has been read in
for(int layer=0; layer < 2; layer++) {
for(int yy=0; yy < tileMap.mapHeight; yy++) {
for(int xx=0; xx < tileMap.mapWidth; xx++) {
int _globalTileID = [[[tileMap layers] objectAtIndex:layer] getGlobalTileIDAtX:xx y:yy];
NSString *_value = [tileMap getTilePropertyForGlobalTileID:_globalTileID key:@"blocked" defaultValue:@"false"];
if([_value isEqualToString:@"true"]) {
_blocked[xx][yy] = YES;
}
}
}
}
I then have a simple class selector which returns a BOOL which is the value of a supplied tile location:
- (BOOL)blocked:(float)x y:(float)y {
return _blocked[(int)x][(int)y];
}
Mike
Jamie Hill on June 25th, 2009
Hi,
I’ve just come across and solved a massive bottleneck in my code and thought I’d share it as it’s a quick fix for huge performance gains.
I was running around 35 frames per second on the iPhone and couldn’t find any obvious way of speeding things up. I thought it could be to do with the kerning dictionary so disabled it in the font class. It turns out that I was also using kerning the the method that gets the width for the text and this was slowing things down drastically.
The solution has been to implement a lookup table in straight C, it takes up around 64k for each font but I think it’s a small price to pay for the increase in speed. I am not up to a full 60 frames per second in my 1st gen iPhone.
I define, in place of the kerning dictionary the following (apologies if the code isn’t formatted properly):
// In the header file
char kerning[256][256];
// When looping through the kerning read from file
char firstCharID = [[properties objectForKey:@"first"] intValue];
char secondCharID = [[properties objectForKey:@"second"] intValue];
char kerningAmount = [[properties objectForKey:@"amount"] intValue];
NSLog(@"Kerning for first: %d, second: %d = %d", firstCharID, secondCharID, kerningAmount);
kerning[firstCharID][secondCharID] = kerningAmount;
// The method that gets the kerning value
- (int)kerningForFirst:(unichar)first second:(unichar)second {
return kerning[(int)first][(int)second];
}
Jamie Hill on June 25th, 2009
@mike, sorry for the mess I put this in pre tags but the codes gone haywire.
Jamie Hill on June 25th, 2009
Correction, I am now up to a full 60 frames per second in my 1st gen iPhone.
mike on June 25th, 2009
@Jamie, no problem. I’ve added the pre tags now :o)
That is a great change by the way and something I’m going to drop into my code if that’s ok.
I’m also impressed at the performance you are getting out of your game. Can I ask how many triangles you are rendering per frame. I’m doing around 100-150 at 55-60 fps and then things start to slow down, which looks to be an issue with the rendering not being batched plus message overhead. I’d be interested to see what what you are able to render.
Mike
Jamie Hill on June 25th, 2009
@mike, by all means drop that into your code.
With regards fps with lots of triangles I have not completed my tile class yet so I’m not really sure on how it will perform with that too although I have slapped masses of scrolling text around the screen and there appears to be no drop in frame rate.
I will let you know when I get some solid figures but I am putting the performance gain down to the Buffer class I mentioned. I have changed the buffer stuff quite a bit and will post any further possible optimisations I come across.
One thing I am trying to do is use is to use triangle strips for the tile class as they have common vertices what with being butted together. I have also tried interleaving the vertex and texture data for extra performance but haven’t found it to make all that much difference. More info on interleaving here: http://iphonedevelopment.blogs.....art-8.html
Cheers,
Jamie
A Person on June 28th, 2009
Hey mike sorry i’m asking many questions about this stuff and i must be becoming a pest but i still don’t get how you know where the tiles are on the map because you can use mapX and mapY and position it, also the map renders from the origin of the top left tile which doesn’t make playerPosition.y / tileHeight work (and it doesn’t account for the map position and mapY) so just wondering how you got around this.
kp3406 on June 28th, 2009
@mike – I’m not exactly sure what you count as number of triangles per frame, but I am getting very good fps drawing about 3300 images, about 3000 of which are point sprite particle effects. So I think that translates to about 4200 triangles being rendered each frame? I am counting 1 triangle per point sprite and 4 per texture being rendered. With only about 500-1000 triangles per frame I am getting around 300-400fps except when handling touches on the screen, which seems to slow the framerate to 45-55 for a split second (not even noticable though).
I know that using any NSLog statements in your update/render loop will cause a VERY significant slowdown, and quickly reduce your framerate to a halt. Also, I havent yet experimented with how many draw__ calls you can have before causing a slowdown, but I have 7 now in my render loop and it seems to be fine. Numbers I’ve seen thrown around on the internet are draw__ calls in the late tens to twenties can start to cause slowdown, don’t know if this is accurate though.
mike on June 28th, 2009
@A Person. Don’t worry about asking questions. That was the reason for doing the blog :o)
I’m going to create a diagram which will hopefully explain what I’m doing. I think a picture will be easier than words, I hope :o)
I will also be releasing Tutorial 10 soon which will contain all my code for moving around the tilemap. Hopefully that will help as well.
As soon as I have my diagram done I’ll post a comment.
@kp3406, thanks for the info on your frame rates etc. You mentioned your getting 300-400fps. Are you running on the Sim? iPhone and iPod hardware has a max frame rate of 60fps which is why I ask.
I’ve been running some experiments with Tom who comments on the blog and its been really interesting seeing what has an impact. Calling glDraw___ too many times does up CPU usage a lot as all the API calls have overhead, so having all your geometry, texture and colour information in a single interleaved array seems to be the way to go. This is what the Anglecodefont class and Particle emitter classes do. I’m working on a design at the moment to create a RenderManager which will be able to provide that ability for all drawing, including what is draw from within the Image class.
There have been some great posts on the blog on this subject and I’m grateful to all those who have joined in. Its given me many more ideas on how to approach that problem and I’ll be posting info on the RenderManager once Tutorial 10 is done and I’ve got it coded up.
Mike
A Person on June 28th, 2009
@mike do you plan to leave the NSLogs in the code as I’ve noticed they drop speed
mike on June 28th, 2009
@A Person, in the project I’m using for Tutorial 10 I’ve placed a check on each NSLog, and only if you have set a debug flag will the NSLog entries be produced, so they are there is you need them for debug, but you can stop them showing really easily.
Mike
A Person on June 28th, 2009
I found a some great little methods from cocos2d to rotate the device and the images. I decided to put them in the Singleton class and then add a sharedGameInstance to the app delegate so it can rotate your view from the begining. So this goes in the Singleton header file:
creating a shared game instance in the delegate is pretty straight forward.
so here is the code in the Singleton.m
And that will rotate your device while keeping the images the same.
A Person on June 28th, 2009
it seems my pre tags hid my code so i’ll just re post it.
found a some great little methods from cocos2d to rotate the device and the images. I decided to put them in the Singleton class and then add a sharedGameInstance to the app delegate so it can rotate your view from the begining. So this goes in the Singleton header file:
#define LANDSCAPE_LEFT 0 // 1 is left 0 is right // Landscape mode BOOL landscape; - (void) applyLandscape; - (void) setLandscape: (BOOL) on; - (BOOL) landscape;
make sure you put that in the right spots
creating a shared game instance in the delegate is pretty straight forward.
so here is the code in the Singleton.m:
- (BOOL) landscape
{
return landscape;
}
- (void) setLandscape: (BOOL) on
{
if( on != landscape ) {
landscape = on;
if( landscape )
#ifdef LANDSCAPE_LEFT
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated:NO];
#else
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeLeft animated:NO];
#endif
else
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortrait animated:NO];
}
return;
}
- (void) applyLandscape
{
if( landscape ) {
glTranslatef(160,240,0);
#ifdef LANDSCAPE_LEFT
glRotatef(-90,0,0,1);
glTranslatef(-240,-160,0);
#else
// rotate left
glRotatef(90,0,0,1);
glTranslatef(-240,-160,0);
#endif // LANDSCAPE_LEFT
}
}
And that will rotate your device while keeping the images the same.
kp3406 on June 28th, 2009
@mike – Thanks for letting me know – I was doing a bogus calculation for fps before! I am using the actual device (ipod touch first gen), the simulator actually runs slower for me, probably because the computer is bad. My actual framerate is 59-60 fps consistantly drawing what I said earlier.
For your renderManager, how are you going to handle drawing objects from different textures? Or are you just going to have all assets on one giant texture? I am not sure what the best way to do this is
A Person on June 29th, 2009
@mike i think a good idea for your tutorials would be too release the source with no examples of using the new features for example you played a sound in your last tutorial, if you don’t include this in the source then we can use it as a template and won’t have to worry about the changes (i do it this way and it is easy to start a new project with your engine and easy to add to it).
@anyone if you want to do this you can google making project templates in xcode (very simple to do)
MFerron on June 29th, 2009
Hey Mike,
After you posted this video update, I started to try to mimic your director/actor setup and see if I could get my own up and running before you posted tutorial 10.
I’m not sure I’m going about it the right way, though. Could you offer up a little detail on your implementation? Unless of course you’re releasing the next video soon. Then I’ll just reference that.
Thanks,
MFerron
A Person on June 30th, 2009
I noticed mike your site was busy one day and I thought you uploaded tutorial10 to the videos directory. Are you just making the blog post now?




A Person on June 21st, 2009
Thanks mike that was great is it possible to give us the source