Problem with my simple 2D Game engine. Help!

Posts: 22
Joined: 2009.08
Post: #1
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!
Quote this message in a reply
Posts: 1,563
Joined: 2003.10
Post: #2
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.
Quote this message in a reply
Posts: 65
Joined: 2009.01
Post: #3
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.
Quote this message in a reply
Posts: 65
Joined: 2009.01
Post: #4
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.
Quote this message in a reply
Posts: 65
Joined: 2009.01
Post: #5
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];
Quote this message in a reply
Posts: 133
Joined: 2008.05
Post: #6
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)
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Best toolset/engine for iOS pixel art game? eXpiation 3 8,199 Oct 16, 2012 06:22 AM
Last Post: Skorche
  I wrote my engine and this is the 1st Game! papaonn 5 8,536 Mar 20, 2012 03:53 AM
Last Post: papaonn
  iPhone game engine Goliath 7 17,122 Jan 6, 2012 11:54 AM
Last Post: EqwanoX
  BetterLetter - The Perfectly SIMPLE Word Game for iOS wenbeen 1 4,035 Dec 29, 2011 09:08 AM
Last Post: AndyKorth
  [Game Engine]Orx coming to iPhone iarwain 6 13,597 May 17, 2011 02:31 PM
Last Post: iarwain