0
Sprite Kit - Case Study
Michael Pan
For what
Storybook!
2D game
Storybook
https://www.youtube.com/watch?v=r_3TJtK1PjU
About Game
2D - Corona!
3D - Unity
What we will build
http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners
Create a Sprite Kit Project
Shooter
Make it landscape only
Run the project
Download the resource
http://cdn3.raywenderlich.com/wp-content/uploads/2015/01/
SpriteKitSimpleGameResources.zip
Drag resource into project
MyScene.m
#import "MyScene.h"!
!
@interface MyScene ()!
@property (nonatomic) SKSpriteNode * player;!
@end!
!
@implementat...
Run
Check the log
??
why
http://stackoverflow.com/questions/9539676/uiviewcontroller-returns-invalid-
frame
Modify the ViewController.m
- (void)viewDidLoad!
{!
[super viewDidLoad];!
!
// Configure the view.!
SKView * skView = (SKV...
viewDidAppear
-(void) viewDidAppear:(BOOL)animated{!
[super viewDidAppear:animated];!
SKView * skView = (SKView *)self.vie...
Good result
What we learned
SKScene
SKSpriteNode
self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];!
self.player.positio...
Class relationship
SKNode
SKEffectNode
SKScene
SKSpriteNode
- (void)addChild:(SKNode *)node;
Position
SKScene
(0,0)
(100,100)
Put SpriteNode on scene - right-down??
SKScene
(0,0)
(100,100)
Put SpriteNode on scene - left-up ??
SKScene
(0,0)
(100,100)
Put SpriteNode on scene - center ??
SKScene
(0,0)
(100,100)
Anchor point
(0,0) (1,0)
(0,1) (1,1)
(0.5,0.5) default
Test - position (0,0) with default Anchor Point
self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];!
self.pla...
Test - position (0,0) with default Anchor Point(0,0)
self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];!
sel...
Add enemy in MyScene.m (1)
- (void)addMonster {!
// Create sprite!
SKSpriteNode * monster = [SKSpriteNode
spriteNodeWithIm...
Add enemy in MyScene.m (2)
- (void)addMonster {!
 !
//…!
// Determine speed of the monster!
int minDuration = 2.0;!
int ma...
What we learned
SKAction!
moveTo:duration:!
removeFromParent!
sequence:
Class view
NSObject
SKNode
SKSpriteNode
SKAction
- (void)runAction:(SKAction *)action;
UIResponder
- (void)update:(NSTimeInterval)currentTime
every 1/60 second will be called automatically
Stabilise the time interval
@interface MyScene ()!
@property (nonatomic) SKSpriteNode * player;!
@property (nonatomic) NST...
Codes in update:
- (void)update:(NSTimeInterval)currentTime {!
CFTimeInterval timeSinceLast = currentTime -
self.lastUpdat...
Every second add a enemy
- (void)updateWithTimeSinceLastUpdate:
(CFTimeInterval)timeSinceLast {!
 !
self.lastSpawnTimeInte...
Run the app
Throw projectile
touch
Throw projectile - vector
(spriteX, spriteY)
offsetX
offsetY (touchX, touchY)
offsetX = touchX - spriteX
offsetY = touchY ...
Define helper function - offset
CGPoint subPoint(CGPoint a, CGPoint b ){!
CGPoint subPoint = CGPointMake(a.x - b.x, a.y - b....
Unit value of vector
offsetX = touchX - spriteX
offsetY = touchY - spriteY
unitValue = sqrt(offsetX^2 + offsetY^2)
Normali...
Define helper function - normalised offset
CGPoint normalisedPoint(CGPoint offset){!
CGFloat nValue = sqrtf(offset.x*offset....
Get touch event - add projectile
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{!
!
UITouch * touch = [t...
Multiply vector - helper function
CGPoint multiplyVector(CGPoint vector, CGFloat amount){!
CGPoint newVec = CGPointMake(ve...
Calculate projectile destination
(offsetX, offsetY)
(offsetX/unitValue, offsetY/unitValue)
newVec = multiplyVector(offset,...
Add point with offset
CGPoint addOffset(CGPoint a, CGPoint offset){!
CGPoint newVec = CGPointMake(a.x+offset.x, a.y+offset....
Get touch event - cal projectile destination
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{!
! // !
! C...
Run
Rotate the projectile
float velocity = 480.0/1.0;!
float realMoveDuration = self.size.width / velocity;!
SKAction * action...
Run
Collision Detection
Use the power of Physic Engine
Set gravity!
!
Set contact delegate
self.physicsWorld.gravity = CGVectorMake(0,0);
self.phy...
@interface MyScene ()<SKPhysicsContactDelegate>!
@property (nonatomic) SKSpriteNode * player;!
@property (nonatomic) NSTim...
physicsWorld
@interface SKScene : SKEffectNode!
!
@property (SK_NONATOMIC_IOSONLY, readonly) SKPhysicsWorld *physicsWorld;...
physicsBody
monster body!
!
projectile body
monster.physicsBody = [SKPhysicsBody
bodyWithRectangleOfSize:monster.size];
pr...
physics attributes
// movable!
monster.physicsBody.dynamic = YES;!
!
// like ID!
monster.physicsBody.categoryBitMask = mon...
Two category ids
static const uint32_t projectileCategory = 0x1 << 0;!
static const uint32_t monsterCategory = 0x1 << 1;
addMonster
- (void)addMonster { !
! // ignore …!
// physic!
monster.physicsBody = [SKPhysicsBody
bodyWithRectangleOfSize:m...
touchesBegan:withEvent:
projectile.physicsBody = [SKPhysicsBody
bodyWithCircleOfRadius:projectile.size.width/2];!
projecti...
SKPhysicsContactDelegate - impl
- (void)didBeginContact:(SKPhysicsContact *)contact!
{!
SKPhysicsBody *firstBody, *secondB...
SKPhysicsContactDelegate - impl(2)
- (void)didBeginContact:(SKPhysicsContact *)contact!
{!
if ((firstBody.categoryBitMask ...
Dismiss collided objects
- (void)projectile:(SKSpriteNode *)projectile
didCollideWithMonster:(SKSpriteNode *)monster {!
NS...
Run
About Music
Background Music - ViewController.m
#import <AVFoundation/AVFoundation.h>!
!
@interface ViewController ()!
@property (nona...
sound effect - touchesBegan:withEvent:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{!
! [self runAction...
Run
Change Scene
Create a new Scene
GameOverScene.h
#import <SpriteKit/SpriteKit.h>!
!
@interface GameOverScene : SKScene!
-(id)initWithSize:(CGSize)size won:...
GameOverScene.m
#import "GameOverScene.h"!
#import "MyScene.h"!
@implementation GameOverScene!
!
-(id)initWithSize:(CGSize...
GameOverScene.m - Label
-(id)initWithSize:(CGSize)size won:(BOOL)won {!
if (self = [super initWithSize:size]) {!
! ! // ig...
GameOverScene.m - Another Scene
-(id)initWithSize:(CGSize)size won:(BOOL)won {!
if (self = [super initWithSize:size]) {!
!...
Show GameOverScene - MyScene.m
#import "GameOverScene.h"!
!
- (void)addMonster {!
! SKAction * loseAction = [SKAction runB...
Show Win
@interface MyScene ()<SKPhysicsContactDelegate>!
@property (nonatomic) int monstersDestroyed;!
@end
- (void)proje...
Question ?
Upcoming SlideShare
Loading in...5
×

Shootting Game

511

Published on

Sprite Kit Case - Shooting Game

Published in: Entertainment & Humor
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
511
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
14
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "Shootting Game"

  1. 1. Sprite Kit - Case Study Michael Pan
  2. 2. For what Storybook! 2D game
  3. 3. Storybook https://www.youtube.com/watch?v=r_3TJtK1PjU
  4. 4. About Game 2D - Corona! 3D - Unity
  5. 5. What we will build http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners
  6. 6. Create a Sprite Kit Project Shooter
  7. 7. Make it landscape only
  8. 8. Run the project
  9. 9. Download the resource http://cdn3.raywenderlich.com/wp-content/uploads/2015/01/ SpriteKitSimpleGameResources.zip
  10. 10. Drag resource into project
  11. 11. MyScene.m #import "MyScene.h"! ! @interface MyScene ()! @property (nonatomic) SKSpriteNode * player;! @end! ! @implementation MyScene! ! -(id)initWithSize:(CGSize)size { ! if (self = [super initWithSize:size]) {! ! NSLog(@"Size: %@", NSStringFromCGSize(size));! ! self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];! self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];! self.player.position = CGPointMake(100, 100);! [self addChild:self.player];! }! return self;! }! @end
  12. 12. Run
  13. 13. Check the log ??
  14. 14. why http://stackoverflow.com/questions/9539676/uiviewcontroller-returns-invalid- frame
  15. 15. Modify the ViewController.m - (void)viewDidLoad! {! [super viewDidLoad];! ! // Configure the view.! SKView * skView = (SKView *)self.view;! skView.showsFPS = YES;! skView.showsNodeCount = YES;! ! // Create and configure the scene.! SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];! scene.scaleMode = SKSceneScaleModeAspectFill;! ! // Present the scene.! [skView presentScene:scene];! }
  16. 16. viewDidAppear -(void) viewDidAppear:(BOOL)animated{! [super viewDidAppear:animated];! SKView * skView = (SKView *)self.view;! ! skView.showsFPS = YES;! skView.showsNodeCount = YES;! ! // Create and configure the scene.! SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];! scene.scaleMode = SKSceneScaleModeAspectFill;! ! // Present the scene.! [skView presentScene:scene];! }
  17. 17. Good result
  18. 18. What we learned SKScene SKSpriteNode self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];! self.player.position = CGPointMake(100, 100);! [self addChild:self.player];
  19. 19. Class relationship SKNode SKEffectNode SKScene SKSpriteNode - (void)addChild:(SKNode *)node;
  20. 20. Position SKScene (0,0) (100,100)
  21. 21. Put SpriteNode on scene - right-down?? SKScene (0,0) (100,100)
  22. 22. Put SpriteNode on scene - left-up ?? SKScene (0,0) (100,100)
  23. 23. Put SpriteNode on scene - center ?? SKScene (0,0) (100,100)
  24. 24. Anchor point (0,0) (1,0) (0,1) (1,1) (0.5,0.5) default
  25. 25. Test - position (0,0) with default Anchor Point self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];! self.player.position = CGPointMake(0, 0);! [self addChild:self.player];
  26. 26. Test - position (0,0) with default Anchor Point(0,0) self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];! self.player.position = CGPointMake(0, 0);! self.player.anchorPoint = CGPointMake(0, 0);! [self addChild:self.player];
  27. 27. Add enemy in MyScene.m (1) - (void)addMonster {! // Create sprite! SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:@"monster"];!  ! // Determine where to spawn the monster along the Y axis! int minY = monster.size.height / 2;! int maxY = self.frame.size.height - monster.size.height / 2;! int rangeY = maxY - minY;! int actualY = (arc4random() % rangeY) + minY;! ! monster.position = CGPointMake(self.frame.size.width + monster.size.width/2, actualY);! [self addChild:monster];! }
  28. 28. Add enemy in MyScene.m (2) - (void)addMonster {!  ! //…! // Determine speed of the monster! int minDuration = 2.0;! int maxDuration = 4.0;! int rangeDuration = maxDuration - minDuration;! int actualDuration = (arc4random() % rangeDuration) + minDuration;!  ! // Create the actions! SKAction * actionMove = [SKAction moveTo:CGPointMake(-monster.size.width/2, actualY) duration:actualDuration];! SKAction * actionMoveDone = [SKAction removeFromParent];! [monster runAction:[SKAction sequence:@[actionMove, actionMoveDone]]];!  ! }
  29. 29. What we learned SKAction! moveTo:duration:! removeFromParent! sequence:
  30. 30. Class view NSObject SKNode SKSpriteNode SKAction - (void)runAction:(SKAction *)action; UIResponder
  31. 31. - (void)update:(NSTimeInterval)currentTime every 1/60 second will be called automatically
  32. 32. Stabilise the time interval @interface MyScene ()! @property (nonatomic) SKSpriteNode * player;! @property (nonatomic) NSTimeInterval lastSpawnTimeInterval;! @property (nonatomic) NSTimeInterval lastUpdateTimeInterval;! @end
  33. 33. Codes in update: - (void)update:(NSTimeInterval)currentTime {! CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;! self.lastUpdateTimeInterval = currentTime;! if (timeSinceLast > 1) {! timeSinceLast = 1.0 / 60.0;! self.lastUpdateTimeInterval = currentTime;! }! [self updateWithTimeSinceLastUpdate:timeSinceLast];! ! }
  34. 34. Every second add a enemy - (void)updateWithTimeSinceLastUpdate: (CFTimeInterval)timeSinceLast {!  ! self.lastSpawnTimeInterval += timeSinceLast;! if (self.lastSpawnTimeInterval > 1) {! self.lastSpawnTimeInterval = 0;! [self addMonster];! }! }!
  35. 35. Run the app
  36. 36. Throw projectile touch
  37. 37. Throw projectile - vector (spriteX, spriteY) offsetX offsetY (touchX, touchY) offsetX = touchX - spriteX offsetY = touchY - spriteY
  38. 38. Define helper function - offset CGPoint subPoint(CGPoint a, CGPoint b ){! CGPoint subPoint = CGPointMake(a.x - b.x, a.y - b.y);! return subPoint;! }
  39. 39. Unit value of vector offsetX = touchX - spriteX offsetY = touchY - spriteY unitValue = sqrt(offsetX^2 + offsetY^2) Normalised vector = (offsetX / unitValue , offsetY / unitValue) offsetX offsetY unitValue
  40. 40. Define helper function - normalised offset CGPoint normalisedPoint(CGPoint offset){! CGFloat nValue = sqrtf(offset.x*offset.x + offset.y*offset.y);! CGPoint nPoint = CGPointMake(offset.x/nValue, offset.y/nValue);! return nPoint;! }
  41. 41. Get touch event - add projectile -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{! ! UITouch * touch = [touches anyObject];! ! // get the location in the scene! CGPoint location = [touch locationInNode:self] ;! ! SKSpriteNode * projectile = [SKSpriteNode spriteNodeWithImageNamed:@"projectile"];! projectile.position = self.player.position;! ! CGPoint offset = subPoint(location, projectile.position);! ! if (offset.x <= 0) return;! ! [self addChild:projectile];! }
  42. 42. Multiply vector - helper function CGPoint multiplyVector(CGPoint vector, CGFloat amount){! CGPoint newVec = CGPointMake(vector.x*amount, vector.y*amount);! return newVec;! }
  43. 43. Calculate projectile destination (offsetX, offsetY) (offsetX/unitValue, offsetY/unitValue) newVec = multiplyVector(offset, 1000) (player.x+newVec.x, player.y+newVec.y)
  44. 44. Add point with offset CGPoint addOffset(CGPoint a, CGPoint offset){! CGPoint newVec = CGPointMake(a.x+offset.x, a.y+offset.y);! return newVec;! }
  45. 45. Get touch event - cal projectile destination -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{! ! // ! ! CGPoint direction = normalisedPoint(offset);! ! ! ! CGPoint shootOffset = multiplyVector(direction, 1000);! ! ! CGPoint realDest = addOffset(projectile.position, shootOffset);! ! ! float velocity = 480.0/1.0;! ! float realMoveDuration = self.size.width / velocity;! ! SKAction * actionMove = [SKAction moveTo:realDest duration:realMoveDuration];! ! SKAction * actionMoveDone = [SKAction removeFromParent];! ! [projectile runAction:[SKAction sequence:@[actionMove, actionMoveDone]]];! }
  46. 46. Run
  47. 47. Rotate the projectile float velocity = 480.0/1.0;! float realMoveDuration = self.size.width / velocity;! SKAction * actionMove = [SKAction moveTo:realDest duration:realMoveDuration];! SKAction * actionMoveDone = [SKAction removeFromParent];! SKAction * sequence = [SKAction sequence:@[actionMove, actionMoveDone]];! ! SKAction * rotate = [SKAction rotateByAngle:4*M_PI duration:0.5];! SKAction * forever = [SKAction repeatActionForever:rotate];! SKAction * group = [SKAction group:@[forever,sequence]];! [projectile runAction:group];
  48. 48. Run
  49. 49. Collision Detection
  50. 50. Use the power of Physic Engine Set gravity! ! Set contact delegate self.physicsWorld.gravity = CGVectorMake(0,0); self.physicsWorld.contactDelegate = self;
  51. 51. @interface MyScene ()<SKPhysicsContactDelegate>! @property (nonatomic) SKSpriteNode * player;! @property (nonatomic) NSTimeInterval lastSpawnTimeInterval;! @property (nonatomic) NSTimeInterval lastUpdateTimeInterval;! @end SKPhysicsContactDelegate
  52. 52. physicsWorld @interface SKScene : SKEffectNode! ! @property (SK_NONATOMIC_IOSONLY, readonly) SKPhysicsWorld *physicsWorld;! ! @end
  53. 53. physicsBody monster body! ! projectile body monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size]; projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2];
  54. 54. physics attributes // movable! monster.physicsBody.dynamic = YES;! ! // like ID! monster.physicsBody.categoryBitMask = monsterCategory;! ! // which ID will be contact! monster.physicsBody.contactTestBitMask = projectileCategory;! ! // can be contact or not! monster.physicsBody.collisionBitMask = 0
  55. 55. Two category ids static const uint32_t projectileCategory = 0x1 << 0;! static const uint32_t monsterCategory = 0x1 << 1;
  56. 56. addMonster - (void)addMonster { ! ! // ignore …! // physic! monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size]; // 1! monster.physicsBody.dynamic = YES; // 2! monster.physicsBody.categoryBitMask = monsterCategory; // 3! monster.physicsBody.contactTestBitMask = projectileCategory; // 4! monster.physicsBody.collisionBitMask = 0; // 5! }
  57. 57. touchesBegan:withEvent: projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2];! projectile.physicsBody.dynamic = YES;! projectile.physicsBody.categoryBitMask = projectileCategory;! projectile.physicsBody.contactTestBitMask = monsterCategory;! projectile.physicsBody.collisionBitMask = 0;
  58. 58. SKPhysicsContactDelegate - impl - (void)didBeginContact:(SKPhysicsContact *)contact! {! SKPhysicsBody *firstBody, *secondBody;! ! if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)! {! firstBody = contact.bodyA;! secondBody = contact.bodyB;! }! else! {! firstBody = contact.bodyB;! secondBody = contact.bodyA;! }! }
  59. 59. SKPhysicsContactDelegate - impl(2) - (void)didBeginContact:(SKPhysicsContact *)contact! {! if ((firstBody.categoryBitMask & projectileCategory) != 0 &&! (secondBody.categoryBitMask & monsterCategory) != 0){! ! [self projectile:(SKSpriteNode *) firstBody.node didCollideWithMonster:(SKSpriteNode *) secondBody.node];! }! }
  60. 60. Dismiss collided objects - (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster:(SKSpriteNode *)monster {! NSLog(@"Hit");! [projectile removeFromParent];! [monster removeFromParent];! }
  61. 61. Run
  62. 62. About Music
  63. 63. Background Music - ViewController.m #import <AVFoundation/AVFoundation.h>! ! @interface ViewController ()! @property (nonatomic) AVAudioPlayer * backgroundMusicPlayer;! @end! ! @implementation ViewController! -(void) viewDidAppear:(BOOL)animated{! ! NSError *error;! ! NSURL * backgroundMusicURL = [[NSBundle mainBundle] URLForResource:@"background- music-aac" withExtension:@"caf"];! ! self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];! ! self.backgroundMusicPlayer.numberOfLoops = -1;! ! [self.backgroundMusicPlayer prepareToPlay];! ! [self.backgroundMusicPlayer play];! }! @end
  64. 64. sound effect - touchesBegan:withEvent: -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{! ! [self runAction:[SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO]];! ! }
  65. 65. Run
  66. 66. Change Scene
  67. 67. Create a new Scene
  68. 68. GameOverScene.h #import <SpriteKit/SpriteKit.h>! ! @interface GameOverScene : SKScene! -(id)initWithSize:(CGSize)size won:(BOOL)won;! @end
  69. 69. GameOverScene.m #import "GameOverScene.h"! #import "MyScene.h"! @implementation GameOverScene! ! -(id)initWithSize:(CGSize)size won:(BOOL)won {! if (self = [super initWithSize:size]) {! ! // 1! self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];! ! // 2! NSString * message;! if (won) {! message = @"You Won!";! } else {! message = @"You Lose :[";! }! ! ! // ignore … ! ! }! ! return self;! }! @end
  70. 70. GameOverScene.m - Label -(id)initWithSize:(CGSize)size won:(BOOL)won {! if (self = [super initWithSize:size]) {! ! ! // ignored! ! ! SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];! label.text = message;! label.fontSize = 40;! label.fontColor = [SKColor blackColor];! label.position = CGPointMake(self.size.width/2, self.size.height/2);! [self addChild:label];! ! ! // ignored! ! }! ! return self;! }
  71. 71. GameOverScene.m - Another Scene -(id)initWithSize:(CGSize)size won:(BOOL)won {! if (self = [super initWithSize:size]) {! ! ! // ignored! ! ! [self runAction:! [SKAction sequence:@[! [SKAction waitForDuration:3.0],! [SKAction runBlock:^{! // 5! SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];! SKScene * myScene = [[MyScene alloc] initWithSize:self.size];! [self.view presentScene:myScene transition: reveal];! }]! ]]! ];! ! ! }! ! return self;! }
  72. 72. Show GameOverScene - MyScene.m #import "GameOverScene.h"! ! - (void)addMonster {! ! SKAction * loseAction = [SKAction runBlock:^{! ! ! SKTransition *reveal = [SKTransition flipHorizontalWithDuration: 0.5];! ! ! SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];! ! ! [self.view presentScene:gameOverScene transition: reveal];! ! }];! ! [monster runAction:[SKAction sequence:@[actionMove, loseAction, actionMoveDone]]];! }
  73. 73. Show Win @interface MyScene ()<SKPhysicsContactDelegate>! @property (nonatomic) int monstersDestroyed;! @end - (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster: (SKSpriteNode *)monster {! self.monstersDestroyed++;! if (self.monstersDestroyed > 5) {! SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];! SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES];! [self.view presentScene:gameOverScene transition: reveal];! }! }
  74. 74. Question ?
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×