A Question about keydown event and Object setter?

Discussion in 'Mac Programming' started by rachelNexus6, Feb 13, 2011.

  1. rachelNexus6 macrumors newbie

    Joined:
    Feb 13, 2011
    #1
    Hello everyone... I know this is probably too much to ask, but there is probably and expert Objective-C programmer here lurking about that can spot my mistake instantly.

    I am working on writing a 2d game engine in Objective C and using "CocoaQuest" the template for doing this. I am finding that this thingy is filled with bugs. So, in the code below... it draws a little map, and I am able to move around with the 'w', 'a', 'd', 'x' keys. When you press Shift and these keys it fires a bullet.

    The problem is two fold:
    1.)
    The [super keyDown: theEvent]; is getting in the way. When this is in there the bullets don't work. When it is taken out, another problem happens.

    2.)
    The bullets ONLY fire up (eUp)

    I have tracked down the offender somewhat... in the '-moveBullets' method right before the switch, 'direction' is not being set. It just blows through the switch statement. So I am thinking the logic of the keydown method is written incorrectly and not transferring the direction into the object.

    the Bizarro thing is that this code is straight out of a book I paid good money for. Anywho, if there is someone here that can spot the mistake, I would be very grateful.

    I am a total newbie by the way if your wondering. :)

    Code:
    #import "GameView.h"
    
    #define kMapHeight 20
    #define kMapWidth 20
    
    
    
    char gMapData[kMapWidth][kMapHeight] = {
    	"XXXXXXXXXXXXXXXXXXXX",
    	"XPPPP....MMM.......X",
    	"X.............T....X",
    	"X....T.............X",
    	"X..................X",
    	"X..........T.......X",
    	"X......T...........X",
    	"X...........X......X",
    	"X...........X......X",
    	"X.XXXXXXXXXXXXXXXX.X",
    	"X...........X......X",
    	"X...X.XXX...X......X",
    	"X...X...X..........X",
    	"X...XXXXX..........X",
    	"X...........TTTTTT.X",
    	"X...XXXXXXX........X",
    	"X...X.....X........X",
    	"X...X..X.XX........X",
    	"X...X..X...........X",
    	"XXXXXXXXXXXXXXXXXXXX" };
    
    
    #define kBulletColumnKey    @"bullet column"
    #define kBulletRowKey       @"bullet row"
    #define kBulletDirectionKey @"bullet direction"
    
    enum { eUp, eDown, eRight, eLeft };
    
    
    
    char mapDataAtLocation ( int column, int row )
    {
    	return gMapData[ kMapHeight - 1 - row][column];
    }
    
    void setMapDataAtLocation ( char newData, int column, int row )
    {
    	gMapData[ kMapHeight - 1 - row][column] = newData;
    }
    
    BOOL isMapLocationPassableForPlayer ( int column, int row )
    {
    	char locationData = mapDataAtLocation( column, row );
    	
    	return locationData != 'X' && locationData != 'T';
    }
    
    @implementation GameView
    
    - (id)initWithFrame:(NSRect)frameRect
    {
    	if ((self = [super initWithFrame:frameRect]) != nil)
    	{
    		// Add initialization code here
    		playerColumn_ = 1;
    		playerRow_ = 1;
    		playerHealth_ = 10;
    		playerScore_ = 0;
    		
    		bullets_ = [[NSMutableArray alloc] init];
    	}
    	return self;
    }
    
    
    - (NSRect) rectForMapCellAtColumn: (int) col row: (int) row
    {
    	return NSMakeRect( col * cellWidth_,
    					  row * cellHeight_,
    					  cellWidth_, cellHeight_ );
    }
    
    
    - (void) drawBullseyeInRect: (NSRect) rect
    {
    	float width = NSWidth( rect );
    	float height = NSHeight( rect );
    	
    	NSBezierPath* path = [[NSBezierPath alloc] init];
    	
    	while ( width > 0 && height > 0 )
    	{
    		[path appendBezierPathWithOvalInRect: rect];
    		
    		rect = NSInsetRect( rect, 3, 3 );
    		
    		width -= 3;
    		height -= 3;
    	}
    	
    	[[NSColor redColor] set];
    	[path stroke];
    	[path release];
    }
    
    
    - (void)drawRect:(NSRect)rect
    {
    	NSRect bounds = [self bounds];
    	float viewWidth = NSWidth( bounds );
    	float viewHeight = NSHeight( bounds );
    	cellWidth_ = viewWidth / kMapWidth;
    	cellHeight_ = viewHeight / kMapHeight;
    	
    	int row, col;
    	
    	//  draw the map
    	for ( row = 0; row < kMapHeight; row++ )
    	{
    		for ( col = 0; col < kMapWidth; col++ )
    		{
    			char cellData = mapDataAtLocation( col, row );
    			NSRect cellRect = [self rectForMapCellAtColumn: col row: row];
    			if ( cellData == 'X' )
    			{
    				[[NSColor blackColor] set];
    				[NSBezierPath fillRect: cellRect];
    			}
    			else if ( cellData == 'P' )
    			{
    				cellRect = NSInsetRect( cellRect, NSWidth( cellRect ) / 4, NSHeight( cellRect ) / 4 );
    				
    				[[NSColor purpleColor] set];
    				NSBezierPath* potionPath = [[NSBezierPath alloc] init];
    				[potionPath appendBezierPathWithOvalInRect: cellRect];
    				[potionPath fill];
    				[potionPath release];
    			}
    			else if ( cellData == 'T' )
    			{
    				[self drawBullseyeInRect: cellRect ];
    			}
    			else if ( cellData == 'M' )
    			{
    				[[NSColor brownColor] set];
    				[NSBezierPath fillRect: cellRect];
    			}
    		}
    	}
    	
    	//  draw the player
    	NSRect playerRect = [self rectForMapCellAtColumn: playerColumn_ row: playerRow_];
    	
    	NSBezierPath* playerPath = [[NSBezierPath alloc] init];
    	[playerPath appendBezierPathWithOvalInRect: playerRect];
    	[playerPath stroke];
    	[playerPath release];
    	
    	//  draw the bullets
    	[[NSColor redColor] set];
    	NSEnumerator* bulletEnumerator = [bullets_ objectEnumerator];
    	NSMutableDictionary* bulletDictionary = [bulletEnumerator nextObject];
    	
    	while ( bulletDictionary )
    	{
    		int column = [[bulletDictionary objectForKey: kBulletColumnKey] intValue];
    		int row = [[bulletDictionary objectForKey: kBulletRowKey] intValue];
    		
    		// NSLog(@"column = %i", column);
    		// NSLog(@"row= %i", row);
    		
    		NSRect bulletRect = [self rectForMapCellAtColumn: column row: row];
    		bulletRect = NSInsetRect( bulletRect, NSWidth( bulletRect ) / 3.0, NSHeight( bulletRect ) / 3.0 );
    		
    		NSBezierPath* bulletPath = [[NSBezierPath alloc] init];
    		[bulletPath appendBezierPathWithOvalInRect: bulletRect];
    		[bulletPath fill];
    		[bulletPath release];
    		
    		bulletDictionary = [bulletEnumerator nextObject];
    	}
    	
    }
    
    
    - (void) keyDown: (NSEvent*) theEvent
    {
    	int newPlayerCol = playerColumn_;
    	int newPlayerRow = playerRow_;
    	int direction = eUp;
    	
    	NSString* eventChars = [theEvent charactersIgnoringModifiers];
    	
    	if ( [eventChars isEqualTo: @"w"] )
    	{
    		//  move the player up
    		newPlayerRow++;
    		direction = eUp;
    	}
    	else if ( [eventChars isEqualTo: @"x"] )
    	{
    		//  move the player down
    		newPlayerRow--;
    		direction = eDown;
    	}
    	else if ( [eventChars isEqualTo: @"a"] )
    	{
    		//  move the player left
    		newPlayerCol--;
    		direction = eLeft;
    	}
    	else if ( [eventChars isEqualTo: @"d"] )
    	{
    		//  move the player right
    		newPlayerCol++;
    		direction = eRight;
    	}
    	else
    	{
    		[super keyDown: theEvent];
    		return;
    	}
    	
    	//  handle a player shot
    	if ( [theEvent modifierFlags] & NSShiftKeyMask )
    	{
    		//  the player moved while holding the SHIFT key
    		//  fire a bullet in the appropriate direction
    		
    		[self fireBulletAtColumn: newPlayerCol row: newPlayerRow inDirection: direction];
    		[self setNeedsDisplay: YES];
    	}
    	else
    	{
    		//  validate player movement
    		if ( newPlayerCol >= 0 && newPlayerCol < kMapWidth && newPlayerRow >= 0 && newPlayerRow < kMapHeight )
    		{
    			if ( isMapLocationPassableForPlayer( newPlayerCol, newPlayerRow ) )
    			{
    				//  valid move
    				playerColumn_ = newPlayerCol;
    				playerRow_ = newPlayerRow;
    				
    				if ( mapDataAtLocation( newPlayerCol, newPlayerRow ) == 'P' )
    				{
    					//  we've stepped on a potion
    					playerHealth_ += 5;
    					setMapDataAtLocation( '.', newPlayerCol, newPlayerRow );
    					
    					[self showPlayerStatus];
    				}
    				
    				[self setNeedsDisplay: YES];
    			}
    		}
    	}
    }
    
    
    
    
    - (BOOL) acceptsFirstResponder
    {
    	return YES;
    }
    
    
    - (void) fireBulletTimer: (NSTimer*) timer
    {
    	[self moveBullets];
    	[self moveMonsters];
    	[self setNeedsDisplay: YES];
    }
    
    - (void) awakeFromNib
    {
    	[self showPlayerStatus];
    	
    	bulletTimer_ = [NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: @selector(fireBulletTimer:) userInfo: nil repeats: YES];
    }
    
    
    - (void) showPlayerStatus
    {
    	//  show the player's status
    	NSString* titleString = [NSString stringWithFormat: @"Cocoa Quest: Health = %d, Score = %d", playerHealth_, playerScore_];
    	[[self window] setTitle: titleString];
    }
    
    
    - (void) fireBulletAtColumn: (int) column row: (int) row inDirection: (int) direction
    {
    	NSMutableDictionary* newBullet = [[NSMutableDictionary alloc] init];
    	
    	[newBullet setObject: [NSNumber numberWithInt: column] forKey: kBulletColumnKey];
    	[newBullet setObject: [NSNumber numberWithInt: row] forKey: kBulletRowKey];
    	[newBullet setObject: [NSNumber numberWithInt: direction] forKey: kBulletDirectionKey];
    	
    	[bullets_ addObject: newBullet];
    	[newBullet release];
    }
    
    
    - (BOOL) validBulletColumn: (int) column row: (int) row
    {
    	BOOL validPosition = YES;
    	
    	if ( column < 0 || column >= kMapWidth )
    	{
    		validPosition = NO;
    	}
    	
    	if ( row < 0 || row >= kMapHeight )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'X' )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'T' )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'M' )
    	{
    		validPosition = NO;
    	}
    	
    	return validPosition;
    }
    
    
    - (void) moveBullets
    {
    	NSMutableArray* bulletsToRemove = [[NSMutableArray alloc] init];
    	
    	NSEnumerator* bulletEnumerator = [bullets_ objectEnumerator];
    	NSMutableDictionary* bulletDictionary = [bulletEnumerator nextObject];
    	
    	while ( bulletDictionary )
    	{
    		
    		
    		int column = [[bulletDictionary objectForKey: kBulletColumnKey] intValue];
    		int row = [[bulletDictionary objectForKey: kBulletRowKey] intValue];
    		int direction = [[bulletDictionary objectForKey: kBulletDirectionKey] intValue];
    		
    		// this works here also  int direction = eRight;
    		// direction is not getting set here...
    		
    		
    		switch ( direction )
    		{
    			case eUp:
    				row++;
    				break;
    			case eDown:
    				row--;
    				break;
    			case eRight:
    				column++;
    				break;
    			case eLeft:
    				column--;
    				break;
    			default:
    				NSLog( @"Invalid bullet direction" );
    		}
    		
    		//  update the bullet's position
    		[bulletDictionary setObject: [NSNumber numberWithInt: column] forKey: kBulletColumnKey];
    		[bulletDictionary setObject: [NSNumber numberWithInt: row] forKey: kBulletRowKey];
    		
    		if ( ![self validBulletColumn: column row: row] )
    		{
    			//  check to see if the bullet hits a target
    			if ( mapDataAtLocation( column, row ) == 'T' )
    			{
    				//  remove the target and replace with floor ('.')
    				setMapDataAtLocation( '.', column, row );
    				
    				//  give the player a few points
    				playerScore_ += 4;
    				[self showPlayerStatus];
    			}
    			else if ( mapDataAtLocation( column, row ) == 'M' )
    			{
    				//  remove the target and replace with floor ('.')
    				setMapDataAtLocation( '.', column, row );
    				
    				//  give the player a few points
    				playerScore_ += 25;
    				[self showPlayerStatus];
    			}
    			
    			//  remove the bullet from the list
    			[bulletsToRemove addObject: bulletDictionary];
    		}
    		
    		bulletDictionary = [bulletEnumerator nextObject];
    	}
    	
    	//  clean up after any bullets that need to be removed
    	[bullets_ removeObjectsInArray: bulletsToRemove];
    	[bulletsToRemove release];
    }
    
    
    - (BOOL) validMonsterColumn: (int) column row: (int) row
    {
    	BOOL validPosition = YES;
    	
    	if ( column < 0 || column >= kMapWidth )
    	{
    		validPosition = NO;
    	}
    	
    	if ( row < 0 || row >= kMapHeight )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'X' )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'T' )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'P' )
    	{
    		validPosition = NO;
    	}
    	
    	if ( mapDataAtLocation( column, row ) == 'M' )
    	{
    		validPosition = NO;
    	}
    	
    	if ( column == playerColumn_ && row == playerRow_ )
    	{
    		validPosition = NO;
    	}
    	
    	return validPosition;
    }
    
    
    - (void) moveMonsters
    {
    	int column, row, newColumn, newRow;
    	
    	for ( row = 0; row < kMapHeight; row++ )
    	{
    		for ( column = 0; column < kMapWidth; column++ )
    		{
    			char mapData = mapDataAtLocation( column, row );
    			
    			if ( mapData == 'M' )
    			{
    				//  found a monster
    				//  try to move in a random direction
    				newColumn = column + (random() % 3) - 1;
    				newRow = row + (random() % 3) - 1;
    				
    				if ( [self validMonsterColumn: newColumn row: newRow] )
    				{
    					//  move the monster
    					setMapDataAtLocation( '.', column, row );
    					setMapDataAtLocation( 'M', newColumn, newRow );
    				}
    				else
    				{
    					//  we ran into something
    					//  if it was the player,
    					//  damage both of us
    					if  ( newColumn == playerColumn_ && newRow == playerRow_ )
    					{
    						playerHealth_ -= 3;
    						[self showPlayerStatus];
    						
    						//  monsters currently don't have health
    						//  they're just alive or dead
    						//  so remove the monster
    						//  from the map
    						setMapDataAtLocation( '.', column, row );
    					}
    				}
    			}
    		}
    	}
    }
    
    @end
    
    
    
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    What is the book, exactly? Title, author, edition.

    Does the book have a website? (Most do) If so, have you looked on the website for errors in whatever edition of the book you have?
     
  3. rachelNexus6 thread starter macrumors newbie

    Joined:
    Feb 13, 2011
    #3

    It's the Spiderworks book, "Cocoa Game Programming Workshop" It's an eBook I got a while ago, and of course the publishing is out of business, the author has no contact information and is writing a new book for aPress. Dave Hill I think his name is.

    This is actually making me a better programmer, and I wonder if the bugs are in the book on purpose. It is a glaring mistake for a published book. I don't see of any way of contacting him
     
  4. PatrickCocoa macrumors 6502a

    Joined:
    Dec 2, 2008
    #4
    The old days

    I remember playing around with this book (Cocoa Quest) several years ago. I do not remember any problem with the bullets - the guy (or dot) could move around the screen and fire bullets at various blocks.

    My guess is that something else is wrong in your code that is causing the problem with the bullets.
     
  5. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #5
    So basically it's a dead book. That doesn't seem like a good thing to try learning from, especially if you're a complete noob to programming. No publisher, no contact, no fixes, no updates. You're throwing good money (today's time and effort) after bad (the purchase of a dead book).

    If you can't interact with the author, then you need to give us enough information to try to duplicate the problem. That means a complete set of compilable source, nibs/xibs, etc. It also means identifying what your OS and Xcode version are, and what the program itself expects as OS and Xcode versions (those should be in the book).

    Right now, there's not enough context to do anything useful with the posted code. It's incomplete without a header file, and without knowing what its intended OS is, we're only guessing what it should do.
     
  6. rachelNexus6, Feb 14, 2011
    Last edited by a moderator: Feb 15, 2011

    rachelNexus6 thread starter macrumors newbie

    Joined:
    Feb 13, 2011
    #6

    Thank you guys for all your help. You guys are right about it being a dead book. It is circa 2005, and I think herein is where the problem is. I think it's XCode. I don't think it's a problem in the code because i have checked it like 10,000 times. Even typing it back in from SCRATCH. Same thing. The game files originally had an .xcode extension instead of .xcodeproj, so that tells you it's like back in tiger days.

    A big culprit is the super key down part. It seems to just shut down everything in the logic.

    The reason I like the book so much though is that it shows you how to make a 2D scrolling game almost just like my favorite from the arcade GAUNTLET! and it does it from a very bare bones approach.

    I hear that he is writing a new book at the moment for Apress that is going to be out March 31st. It looks nice and beefy and has more to it. I hope he does something like this in the book.

    But yeah, I am going to abandon it and look for something else. Just too far back and like I said, I think Xcode has something to do with it, and frankly if I can complain here. I am getting really tired of Apple turning Xcode upside down every 6 months. They really need to stabilize that IDE and it's SDK's or at least make them way more backward compatible.

    Having said that, I am drooling over Xcode 4. FINALLY everything integrated. All those little windows and Interface builder makes me want to kick the screen out. But, yes you probably guessed it, as soon as my new game programming book comes out, XCode 4 will come out, and my new book is obsolete.

    I am not upgrading to Xcode 4 till I get though my book :)

    I know! I know! I remember back building it way back when and it worked good. I thought I was a G-d when I typed that in and made that little round circle move around and fire that bullet. So now I finally have some time to learn game programming more, and I go back to my tried and true buddy and he let me down.
     

Share This Page