Hi guys, I have gone through most of the Hillegass Book "Cocoa Programming for Mac OS X" and now looking to work on some of my own projects. For one of my university courses, I made a simple game in java using the basic graphics and image icon classes. I am trying to implement this as a Cocoa application now.
The java game was made up of "Bodies", which was an abstract class that represented objects in the game (eg, for space invaders, bodies included missles, bullets, aliens and the spaceship). Bodies would have a step (movement, change in state etc) and a draw method. A "game" was an object made up of bodies and also included draw and step methods, which applied the draw and step methods to all the bodies in the game. The main class had a timer that constantly stepped and redrew the game.
For the cocoa version, I have a GameView, which is kinda like the game class and the main class in one. I also have a body class which is near identical to the java version. I also have (for now) a person class, which just draws a black rectangle that I move around the screen with the arrow keys. My main menu xib simply has a gameview in it.
Here is the code so far:
The main trouble I am having at the moment is how to use key presses to control game type commands. The Hillegass book doesn't go into it very well, and it is hard to find things on the internet about this. The java version of the game used a similar bool system for controls with key presses, but I am having trouble implementing it in cocoa. Is there a better way. Also, I'm not sure if I have implemented the person and body classes correctly, as they seem to be causing errors such as "no -step method found" and others (I might post the errors later, I just realised I have typed up way more than what I expected to). I'm thinking that the errors in the code are pretty basic and that if I can sort these ones out, I should be able to have a good grasp of the basics and be able to continue work at my own pace without needing too much help.
Am I taking the right approach to implementing a game in Cocoa, or should I be doing this much differently? Any advice would be very helpful.
The java game was made up of "Bodies", which was an abstract class that represented objects in the game (eg, for space invaders, bodies included missles, bullets, aliens and the spaceship). Bodies would have a step (movement, change in state etc) and a draw method. A "game" was an object made up of bodies and also included draw and step methods, which applied the draw and step methods to all the bodies in the game. The main class had a timer that constantly stepped and redrew the game.
For the cocoa version, I have a GameView, which is kinda like the game class and the main class in one. I also have a body class which is near identical to the java version. I also have (for now) a person class, which just draws a black rectangle that I move around the screen with the arrow keys. My main menu xib simply has a gameview in it.
Here is the code so far:
Code:
GameView.h
#import <Cocoa/Cocoa.h>
@class Person;
@interface GameView : NSView {
BOOL upPressed, downPressed, rightPressed, leftPressed;
Person *person;
NSTimer *timer;
}
@property (readwrite) BOOL upPressed;
@property (readwrite) BOOL downPressed;
@property (readwrite) BOOL leftPressed;
@property (readwrite) BOOL rightPressed;
- (void)runGame:(NSTimer *)aTimer;
@end
-----------------------------------------------------------------
GameView.m
#import "GameView.h"
@implementation GameView
@synthesize upPressed, downPressed, leftPressed, rightPressed;
#pragma mark Events
- (void)keyDown:(NSEvent *)event
{
//Look for key presses and assign BOOL value
switch ([event keyCode]) {
case 126: //up arrow
upPressed = YES;
break;
case 125: //down arrow
downPressed = YES;
break;
case 124: // right arrow
rightPressed = YES;
break;
case 123:
leftPressed = YES;
break;
}
}
- (void)keyUp:(NSEvent *)event
{
switch ([event keyCode]) {
case 126: //up arrow
upPressed = NO;
break;
case 125: //down arrow
downPressed = NO;
break;
case 124: // right arrow
rightPressed = NO;
NSLog(@"right arrow");
break;
case 123:
leftPressed = NO;
break;
}
}
#pragma mark View Methods
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
person = [[Person alloc] initWithX:400 Y:250];
[person retain];
if (timer == nil) {
timer = [[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(runGame:)
userInfo:nil
repeats:YES] retain];
}
}
return self;
}
- (void)runGame:(NSTimer *)aTimer
{
[person step:self];
[self setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds = [self bounds];
[[NSColor whiteColor] set];
[NSBezierPath fillRect:bounds];
[person draw];
}
@end
----------------------------------------------------------------------------------
Body.h
#import <Cocoa/Cocoa.h>
@class GameView;
@interface Body : NSObject {
float x, y, width, height, xVel, yVel, acc;
}
@property (readwrite) float x;
@property (readwrite) float y;
@property (readwrite) float width;
@property (readwrite) float height;
@property (readwrite) float xVel;
@property (readwrite) float yVel;
@property (readwrite) float acc;
- (double)distanceFrom:(Body *)b;
- (BOOL)collidesWith:(Body *)b;
- (BOOL)pointInsidePointX:(float)xp Y:(float)yp;
- (void)draw;
- (void)step:(GameView *)game;
- (void)stayInScreen;
@end
-----------------------------------------------------------------------------------
Body.m
#import "Body.h"
@implementation Body
@synthesize x, y, width, height, xVel, yVel, acc;
- (BOOL)pointInsidePointX:(float)xp Y:(float)yp
{
// This determines if a point is within this body.
return x < xp && xp < x + [self width] && y < yp && yp < y + [self height];
}
- (double)distanceFrom:(Body *)b
{
// This calculates the distance between centers.
double xd = ([b x] + [b width] / 2) - (x + [self width] / 2);
double yd = ([b y] + [b height] / 2) - (y + [self height] / 2);
return sqrt(xd * xd + yd * yd);
}
- (BOOL)collidesWith:(Body *)b
{
// This determines if two bodies have collided.
return [self pointInsidePointX:b.x Y:b.y]
|| [self pointInsidePointX:b.x + b.width Y:b.y]
|| [self pointInsidePointX:b.x Y:b.y + b.height]
|| [self pointInsidePointX:b.x + b.width Y:b.y + b.height]
|| [b pointInsidePointX:[self x] Y:[self y]];
}
- (void)step:(GameView *)game
{
//Abstract
}
- (void)draw
{
//Abstract
}
- (void)stayInScreen
{
if (x < 0.0) { //left wall
x = 0.0;
}if (x + width > 500) {// right wall
x = (float) 500 - [self width];
}if (y + height < 0.0) {//floor
acc = 0;
yVel = 0;
y = height;
}if (y > 300) { //roof
y = (double) 300 - height;
yVel = 0.0;
}
}
@end
----------------------------------------------------------------------------------
Person.h
#import <Cocoa/Cocoa.h>
#import "Body.h"
@interface Person : Body {
}
- (id)initWithX:(float)xp Y:(float)yp;
@end
----------------------------------------------------------------------------------
Person.m
#import "Person.h"
@implementation Person
- (id)initWithX:(float)xp Y:(float)yp
{
[super init];
xVel = 0.0;
yVel = 0.0;
acc = 0.0;
x = xp;
y = yp;
return self;
}
- (void)draw
{
NSRect person = NSMakeRect(x, y, 10.0, 30.0);
[[NSColor blackColor] set];
[NSBezierPath fillRect:person];
}
- (void)step:(GameView *)game
{
if ([game upPressed])
y += 10;
if (game.leftPressed)
x -= 10;
if (game.rightPressed)
x += 10;
}
@end
The main trouble I am having at the moment is how to use key presses to control game type commands. The Hillegass book doesn't go into it very well, and it is hard to find things on the internet about this. The java version of the game used a similar bool system for controls with key presses, but I am having trouble implementing it in cocoa. Is there a better way. Also, I'm not sure if I have implemented the person and body classes correctly, as they seem to be causing errors such as "no -step method found" and others (I might post the errors later, I just realised I have typed up way more than what I expected to). I'm thinking that the errors in the code are pretty basic and that if I can sort these ones out, I should be able to have a good grasp of the basics and be able to continue work at my own pace without needing too much help.
Am I taking the right approach to implementing a game in Cocoa, or should I be doing this much differently? Any advice would be very helpful.