iDevGames Forums
Problem with my simple 2D Game engine. Help! - Printable Version

+- iDevGames Forums (
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: iPhone, iPad & iPod Game Development (/forum-11.html)
+--- Thread: Problem with my simple 2D Game engine. Help! (/thread-513.html)

Problem with my simple 2D Game engine. Help! - SamBaylus - Dec 15, 2009 01:05 AM

I'm building a 2D game engine for learning purposes. (I know OpenGL ES is the way to go, but baby steps first!)

So I've got a class called "GameObject". In the GameObject class, it's got a few instance variables including "float x", "float y", "float width", "float height" and "UIImage sprite". The "sprite" variable loads a .png file upon initializing, and all this works great. Now then, I've got a class that inherits from UIView that I called "GameView". This is where the trouble begins.

In GameView's "awakeFromNib" I've got this:

gameObjectArray = [[NSMutableArray arrayWithCapacity: NSNotFound] retain];
self.multipleTouchEnabled = YES;
gameLoopTimer = [NSTimer scheduledTimerWithTimeInterval: 0.002
                target: self
                selector: @selector(drawRect:)
                userInfo: nil
                repeats: YES];
GameObject *newObject = [[GameObject alloc]init];
[gameObjectArray addObject:newObject];


So what's happening here is I'm taking all the instances of GameObject that I'm making and I'm storing them into a mutable array, "gameObjectArray". From here, when I need to draw the GameObject's sprites, I pull out each GameObject and draw it's sprite on the screen with the GameObject's given x, y, width, and height. Here's the code for that method:

- (void)drawRect:(CGRect)rect {
GameObject *new = [gameObjectArray objectAtIndex:0];
[new.sprite drawInRect:(CGRectMake(new.x, new.y, new.width, new.height))];

And this all works fine. Since the x and y variables initialize to 0,0, the correct sprite is shown at the correct spot and all seems to be working great. However, a glimpse into the console window tells me otherwise. I get an error:
Tue Dec 15 00:01:10 samuel-bayluss-imac.local 2d Game Engine[9430] <Error>: CGContextRestoreGState: invalid context

I get this over and over and over and over and over for each repeat of the timer. Why is this? Everything is working correctly at the surface, but I'd like to nip this in the bud. Also, is there an easier way to do what I'm doing? Is the drawRect: method the only method I can put the drawing code?

Thanks in advance!

Problem with my simple 2D Game engine. Help! - ThemsAllTook - Dec 15, 2009 07:45 AM

Two things:
  • Why on earth are you creating an array with the capacity of NSNotFound? +arrayWithCapacity: takes an NSUInteger, and since NSNotFound is NSIntegerMax, which is LONG_MAX, which is 2147483647L on arm, you're requesting an array with a ridiculously large capacity. NSNotFound is a value that indicates that an item requested couldn’t be found or doesn’t exist, so it makes neither logical nor semantic sense to be passed as an array capacity.
  • Calling -drawRect: from your timer isn't what you want to be doing. -drawRect: is called by the UIView subsystem with some CGContext setup around it, and presumably you're confusing it by calling it yourself outside its expected CG state. What you want to do is have your timer method call [self setNeedsDisplay: YES] instead, and wait for -setNeedsDisplay: to call -drawRect: itself.

Problem with my simple 2D Game engine. Help! - johncmurphy - Dec 15, 2009 08:02 AM

I know I have encountered this problem before. I recall it had something to do with looping through an array that displayed an image, but I forget the details.
Can you post the code for the GameObject? I will try to reproduce the error.

Problem with my simple 2D Game engine. Help! - johncmurphy - Dec 15, 2009 08:25 AM

Well the array is not the problem.
I get the same error even without the array:
- (void)drawRect:(CGRect)rect {
    GameObject *newObject = [[GameObject alloc] init];
    [newObject.sprite drawInRect:(CGRectMake(100, 200, 128, 128))];

I will continue to look into it.

Problem with my simple 2D Game engine. Help! - johncmurphy - Dec 15, 2009 08:59 AM

I think the simplest answer to this problem is to make your GameObject a subclass of UIImageView, set its image property to your UIImage, and position it by moving its frame around.
Something like this:
GameObject *newObject = [[GameObject alloc] initWithFrame:CGRectMake(100, 200, 128, 128)];
newObject.image = [UIImage imageNamed:@"image1.png"];
[self addSubview:newObject];

Problem with my simple 2D Game engine. Help! - longjumper - Dec 15, 2009 10:06 AM

You should be using CALayer and sending it the setContents message with the image.

Then you should be positioning it by moving its position around.

In fact, this is exactly what CALayer is for.

Back to drawRect:, it is just a method. Writing drawing code in drawRect: doesn't just make it work, there are a lot of other things going on. When an iteration of the run loop is ending, the run loops checks to see if any views need to be redrawn. If they do, a context is prepared and activated. Then the view object is sent the message drawRect: where its drawing code acts on the current context.

You can't just send drawRect: to a view and expect drawing to happen.

(And by the way, drawRect: is invoked by the view's layer thru delegation on the iPhone)