Test Driven Cocos2d
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Test Driven Cocos2d

on

  • 397 views

Test Driven Game Development with Cocos2d. ...

Test Driven Game Development with Cocos2d.

This is the first part of my 8th Light University talk on how to effectively write unit tests for game development. We're using Cocos2d for the framework, but the principles apply to most game frameworks.

Statistics

Views

Total Views
397
Views on SlideShare
397
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Test Driven Cocos2d Presentation Transcript

  • 1. Saturday, October 26, 13
  • 2. Saturday, October 26, 13
  • 3. A game is a system in which players engage in an artificial conflict, defined by rules, that results in a quantifiable outcome. Rules of Play Saturday, October 26, 13
  • 4. Saturday, October 26, 13
  • 5. [Expect(game) toBe:Fun] TDD in Games with Cocos2D Saturday, October 26, 13
  • 6. Sprites and Sprite Sheets Scene Management Actions and Animations Effects Menus Tile Maps And more.... Saturday, October 26, 13
  • 7. Saturday, October 26, 13
  • 8. Saturday, October 26, 13
  • 9. Saturday, October 26, 13
  • 10. Saturday, October 26, 13
  • 11. Saturday, October 26, 13
  • 12. Saturday, October 26, 13
  • 13. Saturday, October 26, 13
  • 14. Saturday, October 26, 13
  • 15. The player starts the game and has three buckets.   They can move the buckets right and left. Saturday, October 26, 13
  • 16. Saturday, October 26, 13
  • 17. Saturday, October 26, 13
  • 18. Hello World Layer +(CCScene *) scene { !// 'scene' is an autorelease object. !CCScene *scene = [CCScene node]; ! !// 'layer' is an autorelease object. !HelloWorldLayer *layer = [HelloWorldLayer node]; ! !// add layer as a child to scene ![scene addChild: layer]; ! !// return the scene !return scene; } Saturday, October 26, 13
  • 19. Hello World Layer // on "init" you need to initialize your instance -(id) init { ! // always call "super" init ! // Apple recommends to re-assign "self" with the "super's" return value ! if( (self=[super init]) ) { !! ! ! // create and initialize a Label ! ! CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64]; !! !! ! !! !! !! !! !! // ask director for the window size CGSize size = [[CCDirector sharedDirector] winSize]; // position the label on the center of the screen label.position = ccp( size.width /2 , size.height/2 ); // add the label as a child to this Layer [self addChild: label]; Saturday, October 26, 13
  • 20. Buckets OCDSpec2Context(BucketsSpec) { Describe(@"moving", ^{ It(@"moves to the right", ^{ Buckets *buckets = [[Buckets alloc] initWithPosition:CGPointMake(10.0, 10.0)]; [buckets move:1]; [ExpectFloat(buckets.position.x) toBe:11.0 withPrecision:0.00001]; }); It(@"moves to the left", ^{ Buckets *buckets = [[Buckets alloc] initWithPosition:CGPointMake(10.0, 10.0)]; [buckets move:-1.0]; [ExpectFloat(buckets.position.x) toBe:9.0 withPrecision:0.00001]; }); }); } Saturday, October 26, 13
  • 21. Buckets @implementation Buckets -(id) initWithPosition:(CGPoint) position { if (self = [super init]) { self.position = position; } return self; } -(void) move:(float) movement { self.position = CGPointMake(self.position.x + movement, self.position.y); } @end Saturday, October 26, 13
  • 22. Saturday, October 26, 13
  • 23. Saturday, October 26, 13
  • 24. Bombing Layer -(id) init { if( (self=[super init]) ) { ! ! // ask director for the window size ! ! CGSize size = [[CCDirector sharedDirector] winSize]; Buckets *buckets = [[Buckets alloc] initWithPosition:CGPointMake(size.width / 2, size.height / 2)]; BucketsSprite *sprite = [BucketsSprite spriteWithBuckets:buckets]; ! ! // add the sprite as a child to this Layer ! ! [self addChild: sprite]; !} ! return self; } Saturday, October 26, 13
  • 25. Buckets Sprite @implementation BucketsSprite +(id) spriteWithBuckets:(Buckets *)buckets { BucketsSprite *sprite = [BucketsSprite spriteWithFile:@"buckets.png"]; sprite.buckets = buckets; [sprite scheduleUpdate]; return sprite; } -(void)update:(ccTime)delta { [self setPosition:self.buckets.position]; } @end Saturday, October 26, 13
  • 26. Saturday, October 26, 13
  • 27. Bombing Layer -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { CGPoint point = [touch locationInView:[touch view]]; CGSize size = [[CCDirector sharedDirector] winSize]; if (point.x > size.width / 2) { self.movement++; } else { self.movement--; } return YES; } Saturday, October 26, 13
  • 28. Bombing Layer -(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { CGPoint point = [touch locationInView:[touch view]]; CGSize size = [[CCDirector sharedDirector] winSize]; if (point.x > size.width / 2) { self.movement--; } else { self.movement++; } } Saturday, October 26, 13
  • 29. Bombing Layer -(void)update:(ccTime)delta { BucketsSprite *sprite = (BucketsSprite *)[self getChildByTag:kBucket]; [sprite move:self.movement]; } Saturday, October 26, 13
  • 30. Saturday, October 26, 13
  • 31. ? Saturday, October 26, 13
  • 32. Saturday, October 26, 13
  • 33. Bomber Spec OCDSpec2Context(BomberSpec) { Describe(@"moving back and forth", ^{ It(@"moves towards its next spot", ^{ RiggedLocations *locations = [RiggedLocations newWithValues:@[@0.0]]; Bomber *bomber = [[Bomber alloc] initWithPosition:CGPointMake(10, 40) speed:1.0 locationChooser:locations]; [bomber start]; [bomber update:1.0]; [ExpectFloat(bomber.position.x) toBe:9.0 withPrecision:0.0001]; }); Saturday, October 26, 13
  • 34. Rigged Locations @implementation RiggedLocations -(float) next { float value = [(NSNumber *) [self.values firstObject] floatValue]; if (self.values.count > 1) { [self.values removeObjectAtIndex:0]; } return value; } +(RiggedLocations *) newWithValues:(NSArray *)array { RiggedLocations *locations = [RiggedLocations new]; locations.values = [NSMutableArray arrayWithArray:array]; return locations; } @end Saturday, October 26, 13
  • 35. Random Locations Describe(@"using the random number generator", ^{ It(@"uses the random number generator for its next location", ^{ id rand = [OCMockObject mockForProtocol:@protocol(RandomNumberGenerator)]; NSRange range = NSMakeRange(0, 100); RandomLocationChooser *chooser = [RandomLocationChooser newChooserWithRange:range generator:rand]; float retVal = 0.0; [[[rand stub] andReturnValue:OCMOCK_VALUE(retVal)] generate]; [ExpectFloat([chooser next]) toBe:0.0 withPrecision:0.0001]; }); Saturday, October 26, 13
  • 36. Saturday, October 26, 13
  • 37. Bomber Spec It(@"stops at the location when coming from the left", ^{ RiggedLocations *locations = [RiggedLocations newWithValues:@[@19.0, @22.0]]; Bomber *bomber = [[Bomber alloc] initWithPosition:CGPointMake(17, 40) speed:2.0 locationChooser:locations]; [bomber start]; [bomber update:1.0]; [bomber update:1.0]; [ExpectFloat(bomber.position.x) toBe:21.0 withPrecision:0.0001]; }); It(@"doesn't move until it is started", ^{ RiggedLocations *locations = [RiggedLocations newWithValues:@[@19.0, @22.0]]; Bomber *bomber = [[Bomber alloc] initWithPosition:CGPointMake(17, 40) speed:2.0 locationChooser:locations]; [bomber update:1.0]; [ExpectFloat(bomber.position.x) toBe:17.0 withPrecision:0.0001]; }); Saturday, October 26, 13
  • 38. Bomber - (void)update:(float)deltaTime { if (self.started) { float moveDistance = self.speed * deltaTime; float distanceRemaining = abs(self.location - self.position.x); if (self.location > self.position.x) { self.position = CGPointMake(self.position.x + moveDistance, self.position.y); } else { self.position = CGPointMake(self.position.x - moveDistance, self.position.y); } if (moveDistance >= distanceRemaining) { self.location = [self.locations next]; } } Saturday, October 26, 13
  • 39. “Random” -(id) init { if (self = [super init]) { srand48(time(0)); } return self; } -(float) generate { return drand48(); } Saturday, October 26, 13
  • 40. Bombing Layer Bomber *bomber = [[Bomber alloc] initWithPosition:CGPointMake(size.width / 2, speed:60.0 locationChooser:chooser]; BomberSprite *bomberSprite = [BomberSprite newSpriteWithBomber:bomber]; [self addChild:bomberSprite z:0 tag:kBomber]; [bomber start]; Saturday, October 26, 13
  • 41. Bomber Sprite @implementation BomberSprite +(id) newSpriteWithBomber:(Bomber *)bomber { BomberSprite *sprite = [BomberSprite spriteWithFile:@"bomber.png"]; sprite.bomber = bomber; [sprite scheduleUpdate]; return sprite; } -(void)update:(ccTime)delta { [self.bomber update:delta]; [self setPosition:self.bomber.position]; } Saturday, October 26, 13
  • 42. Saturday, October 26, 13
  • 43. Bomber Spec It(@"drops a bomb when it changes direction", ^{ RiggedLocations *locations = [RiggedLocations newWithValues:@[@18.0]]; Bomber *bomber = [[Bomber alloc] initWithPosition:CGPointMake(17.0, speed:1.0 locationChooser:locations]; [bomber start]; [bomber update:1.0]; [ExpectInt(bomber.bombCount) toBe:1]; }); Saturday, October 26, 13
  • 44. Bomber Spec It(@"moves the bomb on each update", ^{ RiggedLocations *locations = [RiggedLocations newWithValues:@[@18.0]]; Bomber *bomber = [[Bomber alloc] initWithPosition:CGPointMake(17.0 speed:1.0 locationChooser:locations height:10 bombHeight:20]; [bomber start]; [bomber update:1.0]; [bomber update:1.0]; CGPoint bombPosition; [(NSValue *) bomber.bombs[0] getValue:&bombPosition]; [ExpectInt(bombPosition.x) toBe:18]; [ExpectInt(bombPosition.y) toBe:55 - kGravity]; }); Saturday, October 26, 13
  • 45. Bomber Sprite [self.bomber.bombs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [self.parent removeChildByTag:kBomb + idx]; NSValue *bombValue = (NSValue *)obj; CGPoint location; [bombValue getValue:&location]; CCSprite *bombSprite = [CCSprite spriteWithFile:@"bomb.png"]; bombSprite.position = location; [self.parent addChild:bombSprite z:0 tag:kBomb + idx]; }]; Saturday, October 26, 13
  • 46. SHOW ME Saturday, October 26, 13
  • 47. TDD and Games • Have a Plan • You Use the Framework • Keep Views dumb Bullets Suck - Hi Eric Saturday, October 26, 13
  • 48. Saturday, October 26, 13
  • 49. Saturday, October 26, 13
  • 50. Saturday, October 26, 13
  • 51. Saturday, October 26, 13
  • 52. Saturday, October 26, 13
  • 53. 5! Saturday, October 26, 13
  • 54. @paytonrules www.paytonrules.com www.8thlight.com www.github.com/paytonrules Saturday, October 26, 13