SlideShare a Scribd company logo
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!
!
@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
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 = (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];!
}
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];!
}
Good result
What we learned
SKScene
SKSpriteNode
self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];!
self.player.position = CGPointMake(100, 100);!
[self addChild:self.player];
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.player.position = CGPointMake(0, 0);!
[self addChild:self.player];
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];
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];!
}
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]]];!
 !
}
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) NSTimeInterval lastSpawnTimeInterval;!
@property (nonatomic) NSTimeInterval lastUpdateTimeInterval;!
@end
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];!
!
}
Every second add a enemy
- (void)updateWithTimeSinceLastUpdate:
(CFTimeInterval)timeSinceLast {!
 !
self.lastSpawnTimeInterval += timeSinceLast;!
if (self.lastSpawnTimeInterval > 1) {!
self.lastSpawnTimeInterval = 0;!
[self addMonster];!
}!
}!
Run the app
Throw projectile
touch
Throw projectile - vector
(spriteX, spriteY)
offsetX
offsetY (touchX, touchY)
offsetX = touchX - spriteX
offsetY = touchY - spriteY
Define helper function - offset
CGPoint subPoint(CGPoint a, CGPoint b ){!
CGPoint subPoint = CGPointMake(a.x - b.x, a.y - b.y);!
return subPoint;!
}
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
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;!
}
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];!
}
Multiply vector - helper function
CGPoint multiplyVector(CGPoint vector, CGFloat amount){!
CGPoint newVec = CGPointMake(vector.x*amount, vector.y*amount);!
return newVec;!
}
Calculate projectile destination
(offsetX, offsetY)
(offsetX/unitValue, offsetY/unitValue)
newVec = multiplyVector(offset, 1000)
(player.x+newVec.x, player.y+newVec.y)
Add point with offset
CGPoint addOffset(CGPoint a, CGPoint offset){!
CGPoint newVec = CGPointMake(a.x+offset.x, a.y+offset.y);!
return newVec;!
}
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]]];!
}
Run
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];
Run
Collision Detection
Use the power of Physic Engine
Set gravity!
!
Set contact delegate
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
@interface MyScene ()<SKPhysicsContactDelegate>!
@property (nonatomic) SKSpriteNode * player;!
@property (nonatomic) NSTimeInterval lastSpawnTimeInterval;!
@property (nonatomic) NSTimeInterval lastUpdateTimeInterval;!
@end
SKPhysicsContactDelegate
physicsWorld
@interface SKScene : SKEffectNode!
!
@property (SK_NONATOMIC_IOSONLY, readonly) SKPhysicsWorld *physicsWorld;!
!
@end
physicsBody
monster body!
!
projectile body
monster.physicsBody = [SKPhysicsBody
bodyWithRectangleOfSize:monster.size];
projectile.physicsBody = [SKPhysicsBody
bodyWithCircleOfRadius:projectile.size.width/2];
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
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:monster.size]; // 1!
monster.physicsBody.dynamic = YES; // 2!
monster.physicsBody.categoryBitMask = monsterCategory; // 3!
monster.physicsBody.contactTestBitMask = projectileCategory; // 4!
monster.physicsBody.collisionBitMask = 0; // 5!
}
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;
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;!
}!
}
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];!
}!
}
Dismiss collided objects
- (void)projectile:(SKSpriteNode *)projectile
didCollideWithMonster:(SKSpriteNode *)monster {!
NSLog(@"Hit");!
[projectile removeFromParent];!
[monster removeFromParent];!
}
Run
About Music
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
sound effect - touchesBegan:withEvent:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{!
! [self runAction:[SKAction playSoundFileNamed:@"pew-pew-lei.caf"
waitForCompletion:NO]];!
!
}
Run
Change Scene
Create a new Scene
GameOverScene.h
#import <SpriteKit/SpriteKit.h>!
!
@interface GameOverScene : SKScene!
-(id)initWithSize:(CGSize)size won:(BOOL)won;!
@end
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
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;!
}
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;!
}
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]]];!
}
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];!
}!
}
Question ?

More Related Content

What's hot

Implement angular calendar component how to drag &amp; create events
Implement angular calendar component how to drag &amp; create eventsImplement angular calendar component how to drag &amp; create events
Implement angular calendar component how to drag &amp; create events
Katy Slemon
 
Box2D and libGDX
Box2D and libGDXBox2D and libGDX
Box2D and libGDX
Jussi Pohjolainen
 
Макс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложенияхМакс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложениях
CocoaHeads
 
libGDX: Tiled Maps
libGDX: Tiled MapslibGDX: Tiled Maps
libGDX: Tiled Maps
Jussi Pohjolainen
 
Using Android Things to Detect & Exterminate Reptilians
Using Android Things to Detect & Exterminate ReptiliansUsing Android Things to Detect & Exterminate Reptilians
Using Android Things to Detect & Exterminate Reptilians
Nilhcem
 
Project presentation(View calender)
Project presentation(View calender)Project presentation(View calender)
Project presentation(View calender)
Ikhtiar Khan Sohan
 
WebXR if X = how?
WebXR if X = how?WebXR if X = how?
The Ring programming language version 1.3 book - Part 49 of 88
The Ring programming language version 1.3 book - Part 49 of 88The Ring programming language version 1.3 book - Part 49 of 88
The Ring programming language version 1.3 book - Part 49 of 88
Mahmoud Samir Fayed
 
Introduction to Immersive Web
Introduction to Immersive WebIntroduction to Immersive Web
Introduction to Immersive Web
Hirokazu Egashira
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
Nilhcem
 
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VRHow to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
GeilDanke
 
iOS Training Session-3
iOS Training Session-3iOS Training Session-3
iOS Training Session-3
Hussain Behestee
 
HoloLens Programming Tutorial: AirTap & Spatial Mapping
HoloLens Programming Tutorial: AirTap & Spatial MappingHoloLens Programming Tutorial: AirTap & Spatial Mapping
HoloLens Programming Tutorial: AirTap & Spatial Mapping
Takashi Yoshinaga
 
Implementing a Simple Game using libGDX
Implementing a Simple Game using libGDXImplementing a Simple Game using libGDX
Implementing a Simple Game using libGDX
Jussi Pohjolainen
 
The Ring programming language version 1.5.1 book - Part 64 of 180
The Ring programming language version 1.5.1 book - Part 64 of 180The Ring programming language version 1.5.1 book - Part 64 of 180
The Ring programming language version 1.5.1 book - Part 64 of 180
Mahmoud Samir Fayed
 
Standford 2015 week3: Objective-C Compatibility, Property List, Views
Standford 2015 week3: Objective-C Compatibility, Property List, ViewsStandford 2015 week3: Objective-C Compatibility, Property List, Views
Standford 2015 week3: Objective-C Compatibility, Property List, Views
彼得潘 Pan
 
The Ring programming language version 1.5.2 book - Part 52 of 181
The Ring programming language version 1.5.2 book - Part 52 of 181The Ring programming language version 1.5.2 book - Part 52 of 181
The Ring programming language version 1.5.2 book - Part 52 of 181
Mahmoud Samir Fayed
 
Augmented Reality in JavaScript
Augmented Reality in JavaScriptAugmented Reality in JavaScript
Augmented Reality in JavaScript
Zeno Rocha
 
Home Automation with Android Things and the Google Assistant
Home Automation with Android Things and the Google AssistantHome Automation with Android Things and the Google Assistant
Home Automation with Android Things and the Google Assistant
Nilhcem
 
Android Wear Essentials
Android Wear EssentialsAndroid Wear Essentials
Android Wear Essentials
Nilhcem
 

What's hot (20)

Implement angular calendar component how to drag &amp; create events
Implement angular calendar component how to drag &amp; create eventsImplement angular calendar component how to drag &amp; create events
Implement angular calendar component how to drag &amp; create events
 
Box2D and libGDX
Box2D and libGDXBox2D and libGDX
Box2D and libGDX
 
Макс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложенияхМакс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложениях
 
libGDX: Tiled Maps
libGDX: Tiled MapslibGDX: Tiled Maps
libGDX: Tiled Maps
 
Using Android Things to Detect & Exterminate Reptilians
Using Android Things to Detect & Exterminate ReptiliansUsing Android Things to Detect & Exterminate Reptilians
Using Android Things to Detect & Exterminate Reptilians
 
Project presentation(View calender)
Project presentation(View calender)Project presentation(View calender)
Project presentation(View calender)
 
WebXR if X = how?
WebXR if X = how?WebXR if X = how?
WebXR if X = how?
 
The Ring programming language version 1.3 book - Part 49 of 88
The Ring programming language version 1.3 book - Part 49 of 88The Ring programming language version 1.3 book - Part 49 of 88
The Ring programming language version 1.3 book - Part 49 of 88
 
Introduction to Immersive Web
Introduction to Immersive WebIntroduction to Immersive Web
Introduction to Immersive Web
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
 
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VRHow to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
 
iOS Training Session-3
iOS Training Session-3iOS Training Session-3
iOS Training Session-3
 
HoloLens Programming Tutorial: AirTap & Spatial Mapping
HoloLens Programming Tutorial: AirTap & Spatial MappingHoloLens Programming Tutorial: AirTap & Spatial Mapping
HoloLens Programming Tutorial: AirTap & Spatial Mapping
 
Implementing a Simple Game using libGDX
Implementing a Simple Game using libGDXImplementing a Simple Game using libGDX
Implementing a Simple Game using libGDX
 
The Ring programming language version 1.5.1 book - Part 64 of 180
The Ring programming language version 1.5.1 book - Part 64 of 180The Ring programming language version 1.5.1 book - Part 64 of 180
The Ring programming language version 1.5.1 book - Part 64 of 180
 
Standford 2015 week3: Objective-C Compatibility, Property List, Views
Standford 2015 week3: Objective-C Compatibility, Property List, ViewsStandford 2015 week3: Objective-C Compatibility, Property List, Views
Standford 2015 week3: Objective-C Compatibility, Property List, Views
 
The Ring programming language version 1.5.2 book - Part 52 of 181
The Ring programming language version 1.5.2 book - Part 52 of 181The Ring programming language version 1.5.2 book - Part 52 of 181
The Ring programming language version 1.5.2 book - Part 52 of 181
 
Augmented Reality in JavaScript
Augmented Reality in JavaScriptAugmented Reality in JavaScript
Augmented Reality in JavaScript
 
Home Automation with Android Things and the Google Assistant
Home Automation with Android Things and the Google AssistantHome Automation with Android Things and the Google Assistant
Home Automation with Android Things and the Google Assistant
 
Android Wear Essentials
Android Wear EssentialsAndroid Wear Essentials
Android Wear Essentials
 

Similar to Shootting Game

Intro to Game Programming
Intro to Game ProgrammingIntro to Game Programming
Intro to Game Programming
Richard Jones
 
Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)
Korhan Bircan
 
Leaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGLLeaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGL
gerbille
 
Useful Tools for Making Video Games - Irrlicht (2008)
Useful Tools for Making Video Games - Irrlicht (2008)Useful Tools for Making Video Games - Irrlicht (2008)
Useful Tools for Making Video Games - Irrlicht (2008)
Korhan Bircan
 
Game development with Cocos2d
Game development with Cocos2dGame development with Cocos2d
Game development with Cocos2d
Vinsol
 
Making Games in JavaScript
Making Games in JavaScriptMaking Games in JavaScript
Making Games in JavaScript
Sam Cartwright
 
HTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymoreHTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymore
Remy Sharp
 
cocos2d for i Phoneの紹介
cocos2d for i Phoneの紹介cocos2d for i Phoneの紹介
cocos2d for i Phoneの紹介
Jun-ichi Shinde
 
Synchronizing without internet - Multipeer Connectivity (iOS)
Synchronizing without internet - Multipeer Connectivity (iOS)Synchronizing without internet - Multipeer Connectivity (iOS)
Synchronizing without internet - Multipeer Connectivity (iOS)
Jorge Maroto
 
Browsers with Wings
Browsers with WingsBrowsers with Wings
Browsers with Wings
Remy Sharp
 
I wanted to change the cloudsrectangles into an actuall image it do.pdf
I wanted to change the cloudsrectangles into an actuall image it do.pdfI wanted to change the cloudsrectangles into an actuall image it do.pdf
I wanted to change the cloudsrectangles into an actuall image it do.pdf
feelinggifts
 
WebVR - MobileTechCon Berlin 2016
WebVR - MobileTechCon Berlin 2016WebVR - MobileTechCon Berlin 2016
WebVR - MobileTechCon Berlin 2016
Carsten Sandtner
 
303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code
jonmarimba
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
DroidConTLV
 
14709302.ppt
14709302.ppt14709302.ppt
14709302.ppt
SunilChaluvaiah
 
Oxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resourcesOxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resources
corehard_by
 
JavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your codeJavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your code
Laurence Svekis ✔
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 

Similar to Shootting Game (20)

Intro to Game Programming
Intro to Game ProgrammingIntro to Game Programming
Intro to Game Programming
 
Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)
 
Leaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGLLeaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGL
 
Useful Tools for Making Video Games - Irrlicht (2008)
Useful Tools for Making Video Games - Irrlicht (2008)Useful Tools for Making Video Games - Irrlicht (2008)
Useful Tools for Making Video Games - Irrlicht (2008)
 
Game development with Cocos2d
Game development with Cocos2dGame development with Cocos2d
Game development with Cocos2d
 
Making Games in JavaScript
Making Games in JavaScriptMaking Games in JavaScript
Making Games in JavaScript
 
HTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymoreHTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymore
 
cocos2d for i Phoneの紹介
cocos2d for i Phoneの紹介cocos2d for i Phoneの紹介
cocos2d for i Phoneの紹介
 
Synchronizing without internet - Multipeer Connectivity (iOS)
Synchronizing without internet - Multipeer Connectivity (iOS)Synchronizing without internet - Multipeer Connectivity (iOS)
Synchronizing without internet - Multipeer Connectivity (iOS)
 
Intro to HTML5
Intro to HTML5Intro to HTML5
Intro to HTML5
 
Browsers with Wings
Browsers with WingsBrowsers with Wings
Browsers with Wings
 
I wanted to change the cloudsrectangles into an actuall image it do.pdf
I wanted to change the cloudsrectangles into an actuall image it do.pdfI wanted to change the cloudsrectangles into an actuall image it do.pdf
I wanted to change the cloudsrectangles into an actuall image it do.pdf
 
WebVR - MobileTechCon Berlin 2016
WebVR - MobileTechCon Berlin 2016WebVR - MobileTechCon Berlin 2016
WebVR - MobileTechCon Berlin 2016
 
Sbaw091117
Sbaw091117Sbaw091117
Sbaw091117
 
303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
 
14709302.ppt
14709302.ppt14709302.ppt
14709302.ppt
 
Oxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resourcesOxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resources
 
JavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your codeJavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your code
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 

More from Michael Pan

Activity
ActivityActivity
Activity
Michael Pan
 
Introduction to Android Studio
Introduction to Android StudioIntroduction to Android Studio
Introduction to Android Studio
Michael Pan
 
Eclipse and Genymotion
Eclipse and GenymotionEclipse and Genymotion
Eclipse and Genymotion
Michael Pan
 
Strategy Pattern for Objective-C
Strategy Pattern for Objective-CStrategy Pattern for Objective-C
Strategy Pattern for Objective-C
Michael Pan
 
Core data lightweight_migration
Core data lightweight_migrationCore data lightweight_migration
Core data lightweight_migration
Michael Pan
 
Google maps SDK for iOS 1.4
Google maps SDK for iOS 1.4Google maps SDK for iOS 1.4
Google maps SDK for iOS 1.4Michael Pan
 
Homework2 play cards
Homework2 play cardsHomework2 play cards
Homework2 play cards
Michael Pan
 
Autorelease pool
Autorelease poolAutorelease pool
Autorelease poolMichael Pan
 
Objc under the_hood_2013
Objc under the_hood_2013Objc under the_hood_2013
Objc under the_hood_2013Michael Pan
 
Prototype by Xcode
Prototype by XcodePrototype by Xcode
Prototype by Xcode
Michael Pan
 
Nimbus
NimbusNimbus
Nimbus
Michael Pan
 
Superstar dj pdf
Superstar dj pdfSuperstar dj pdf
Superstar dj pdf
Michael Pan
 
比價撿便宜 Steven
比價撿便宜 Steven比價撿便宜 Steven
比價撿便宜 StevenMichael Pan
 
Appsgaga - iOS Game Developer
Appsgaga - iOS Game DeveloperAppsgaga - iOS Game Developer
Appsgaga - iOS Game DeveloperMichael Pan
 
GZFox Inc. Jacky
GZFox Inc. JackyGZFox Inc. Jacky
GZFox Inc. JackyMichael Pan
 
創投公司 hoku_20121017
創投公司 hoku_20121017創投公司 hoku_20121017
創投公司 hoku_20121017Michael Pan
 
Opening iOS App 開發者交流會
Opening iOS App 開發者交流會Opening iOS App 開發者交流會
Opening iOS App 開發者交流會
Michael Pan
 

More from Michael Pan (20)

Activity
ActivityActivity
Activity
 
Introduction to Android Studio
Introduction to Android StudioIntroduction to Android Studio
Introduction to Android Studio
 
Eclipse and Genymotion
Eclipse and GenymotionEclipse and Genymotion
Eclipse and Genymotion
 
Note something
Note somethingNote something
Note something
 
Strategy Pattern for Objective-C
Strategy Pattern for Objective-CStrategy Pattern for Objective-C
Strategy Pattern for Objective-C
 
Core data lightweight_migration
Core data lightweight_migrationCore data lightweight_migration
Core data lightweight_migration
 
Google maps SDK for iOS 1.4
Google maps SDK for iOS 1.4Google maps SDK for iOS 1.4
Google maps SDK for iOS 1.4
 
Homework2 play cards
Homework2 play cardsHomework2 play cards
Homework2 play cards
 
Autorelease pool
Autorelease poolAutorelease pool
Autorelease pool
 
Objc under the_hood_2013
Objc under the_hood_2013Objc under the_hood_2013
Objc under the_hood_2013
 
Prototype by Xcode
Prototype by XcodePrototype by Xcode
Prototype by Xcode
 
Dropbox sync
Dropbox syncDropbox sync
Dropbox sync
 
Nimbus
NimbusNimbus
Nimbus
 
Superstar dj pdf
Superstar dj pdfSuperstar dj pdf
Superstar dj pdf
 
ADB - Arthur
ADB - ArthurADB - Arthur
ADB - Arthur
 
比價撿便宜 Steven
比價撿便宜 Steven比價撿便宜 Steven
比價撿便宜 Steven
 
Appsgaga - iOS Game Developer
Appsgaga - iOS Game DeveloperAppsgaga - iOS Game Developer
Appsgaga - iOS Game Developer
 
GZFox Inc. Jacky
GZFox Inc. JackyGZFox Inc. Jacky
GZFox Inc. Jacky
 
創投公司 hoku_20121017
創投公司 hoku_20121017創投公司 hoku_20121017
創投公司 hoku_20121017
 
Opening iOS App 開發者交流會
Opening iOS App 開發者交流會Opening iOS App 開發者交流會
Opening iOS App 開發者交流會
 

Recently uploaded

Scandal! Teasers June 2024 on etv Forum.co.za
Scandal! Teasers June 2024 on etv Forum.co.zaScandal! Teasers June 2024 on etv Forum.co.za
Scandal! Teasers June 2024 on etv Forum.co.za
Isaac More
 
Treasure Hunt Puzzles, Treasure Hunt Puzzles online
Treasure Hunt Puzzles, Treasure Hunt Puzzles onlineTreasure Hunt Puzzles, Treasure Hunt Puzzles online
Treasure Hunt Puzzles, Treasure Hunt Puzzles online
Hidden Treasure Hunts
 
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and LoveMeet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
get joys
 
Tom Selleck Net Worth: A Comprehensive Analysis
Tom Selleck Net Worth: A Comprehensive AnalysisTom Selleck Net Worth: A Comprehensive Analysis
Tom Selleck Net Worth: A Comprehensive Analysis
greendigital
 
A TO Z INDIA Monthly Magazine - JUNE 2024
A TO Z INDIA Monthly Magazine - JUNE 2024A TO Z INDIA Monthly Magazine - JUNE 2024
A TO Z INDIA Monthly Magazine - JUNE 2024
Indira Srivatsa
 
Panchayat Season 3 - Official Trailer.pdf
Panchayat Season 3 - Official Trailer.pdfPanchayat Season 3 - Official Trailer.pdf
Panchayat Season 3 - Official Trailer.pdf
Suleman Rana
 
Meet Crazyjamjam - A TikTok Sensation | Blog Eternal
Meet Crazyjamjam - A TikTok Sensation | Blog EternalMeet Crazyjamjam - A TikTok Sensation | Blog Eternal
Meet Crazyjamjam - A TikTok Sensation | Blog Eternal
Blog Eternal
 
240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf
Madhura TBRC
 
This Is The First All Category Quiz That I Made
This Is The First All Category Quiz That I MadeThis Is The First All Category Quiz That I Made
This Is The First All Category Quiz That I Made
Aarush Ghate
 
The Evolution of Animation in Film - Mark Murphy Director
The Evolution of Animation in Film - Mark Murphy DirectorThe Evolution of Animation in Film - Mark Murphy Director
The Evolution of Animation in Film - Mark Murphy Director
Mark Murphy Director
 
Create a Seamless Viewing Experience with Your Own Custom OTT Player.pdf
Create a Seamless Viewing Experience with Your Own Custom OTT Player.pdfCreate a Seamless Viewing Experience with Your Own Custom OTT Player.pdf
Create a Seamless Viewing Experience with Your Own Custom OTT Player.pdf
Genny Knight
 
Reimagining Classics - What Makes a Remake a Success
Reimagining Classics - What Makes a Remake a SuccessReimagining Classics - What Makes a Remake a Success
Reimagining Classics - What Makes a Remake a Success
Mark Murphy Director
 
From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...
From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...
From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...
Rodney Thomas Jr
 
I Know Dino Trivia: Part 3. Test your dino knowledge
I Know Dino Trivia: Part 3. Test your dino knowledgeI Know Dino Trivia: Part 3. Test your dino knowledge
I Know Dino Trivia: Part 3. Test your dino knowledge
Sabrina Ricci
 
Young Tom Selleck: A Journey Through His Early Years and Rise to Stardom
Young Tom Selleck: A Journey Through His Early Years and Rise to StardomYoung Tom Selleck: A Journey Through His Early Years and Rise to Stardom
Young Tom Selleck: A Journey Through His Early Years and Rise to Stardom
greendigital
 
Christina's Baby Shower Game June 2024.pptx
Christina's Baby Shower Game June 2024.pptxChristina's Baby Shower Game June 2024.pptx
Christina's Baby Shower Game June 2024.pptx
madeline604788
 
Hollywood Actress - The 250 hottest gallery
Hollywood Actress - The 250 hottest galleryHollywood Actress - The 250 hottest gallery
Hollywood Actress - The 250 hottest gallery
Zsolt Nemeth
 
Maximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdf
Maximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdfMaximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdf
Maximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdf
Xtreame HDTV
 
Skeem Saam in June 2024 available on Forum
Skeem Saam in June 2024 available on ForumSkeem Saam in June 2024 available on Forum
Skeem Saam in June 2024 available on Forum
Isaac More
 

Recently uploaded (19)

Scandal! Teasers June 2024 on etv Forum.co.za
Scandal! Teasers June 2024 on etv Forum.co.zaScandal! Teasers June 2024 on etv Forum.co.za
Scandal! Teasers June 2024 on etv Forum.co.za
 
Treasure Hunt Puzzles, Treasure Hunt Puzzles online
Treasure Hunt Puzzles, Treasure Hunt Puzzles onlineTreasure Hunt Puzzles, Treasure Hunt Puzzles online
Treasure Hunt Puzzles, Treasure Hunt Puzzles online
 
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and LoveMeet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
 
Tom Selleck Net Worth: A Comprehensive Analysis
Tom Selleck Net Worth: A Comprehensive AnalysisTom Selleck Net Worth: A Comprehensive Analysis
Tom Selleck Net Worth: A Comprehensive Analysis
 
A TO Z INDIA Monthly Magazine - JUNE 2024
A TO Z INDIA Monthly Magazine - JUNE 2024A TO Z INDIA Monthly Magazine - JUNE 2024
A TO Z INDIA Monthly Magazine - JUNE 2024
 
Panchayat Season 3 - Official Trailer.pdf
Panchayat Season 3 - Official Trailer.pdfPanchayat Season 3 - Official Trailer.pdf
Panchayat Season 3 - Official Trailer.pdf
 
Meet Crazyjamjam - A TikTok Sensation | Blog Eternal
Meet Crazyjamjam - A TikTok Sensation | Blog EternalMeet Crazyjamjam - A TikTok Sensation | Blog Eternal
Meet Crazyjamjam - A TikTok Sensation | Blog Eternal
 
240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf
 
This Is The First All Category Quiz That I Made
This Is The First All Category Quiz That I MadeThis Is The First All Category Quiz That I Made
This Is The First All Category Quiz That I Made
 
The Evolution of Animation in Film - Mark Murphy Director
The Evolution of Animation in Film - Mark Murphy DirectorThe Evolution of Animation in Film - Mark Murphy Director
The Evolution of Animation in Film - Mark Murphy Director
 
Create a Seamless Viewing Experience with Your Own Custom OTT Player.pdf
Create a Seamless Viewing Experience with Your Own Custom OTT Player.pdfCreate a Seamless Viewing Experience with Your Own Custom OTT Player.pdf
Create a Seamless Viewing Experience with Your Own Custom OTT Player.pdf
 
Reimagining Classics - What Makes a Remake a Success
Reimagining Classics - What Makes a Remake a SuccessReimagining Classics - What Makes a Remake a Success
Reimagining Classics - What Makes a Remake a Success
 
From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...
From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...
From Slave to Scourge: The Existential Choice of Django Unchained. The Philos...
 
I Know Dino Trivia: Part 3. Test your dino knowledge
I Know Dino Trivia: Part 3. Test your dino knowledgeI Know Dino Trivia: Part 3. Test your dino knowledge
I Know Dino Trivia: Part 3. Test your dino knowledge
 
Young Tom Selleck: A Journey Through His Early Years and Rise to Stardom
Young Tom Selleck: A Journey Through His Early Years and Rise to StardomYoung Tom Selleck: A Journey Through His Early Years and Rise to Stardom
Young Tom Selleck: A Journey Through His Early Years and Rise to Stardom
 
Christina's Baby Shower Game June 2024.pptx
Christina's Baby Shower Game June 2024.pptxChristina's Baby Shower Game June 2024.pptx
Christina's Baby Shower Game June 2024.pptx
 
Hollywood Actress - The 250 hottest gallery
Hollywood Actress - The 250 hottest galleryHollywood Actress - The 250 hottest gallery
Hollywood Actress - The 250 hottest gallery
 
Maximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdf
Maximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdfMaximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdf
Maximizing Your Streaming Experience with XCIPTV- Tips for 2024.pdf
 
Skeem Saam in June 2024 available on Forum
Skeem Saam in June 2024 available on ForumSkeem Saam in June 2024 available on Forum
Skeem Saam in June 2024 available on Forum
 

Shootting Game

  • 1. Sprite Kit - Case Study Michael Pan
  • 4. About Game 2D - Corona! 3D - Unity
  • 5. What we will build http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners
  • 6. Create a Sprite Kit Project Shooter
  • 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. Run
  • 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. 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];! }
  • 18. What we learned SKScene SKSpriteNode self.player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];! self.player.position = CGPointMake(100, 100);! [self addChild:self.player];
  • 21. Put SpriteNode on scene - right-down?? SKScene (0,0) (100,100)
  • 22. Put SpriteNode on scene - left-up ?? SKScene (0,0) (100,100)
  • 23. Put SpriteNode on scene - center ?? SKScene (0,0) (100,100)
  • 24. Anchor point (0,0) (1,0) (0,1) (1,1) (0.5,0.5) default
  • 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. 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. 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. 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]]];!  ! }
  • 31. - (void)update:(NSTimeInterval)currentTime every 1/60 second will be called automatically
  • 32. Stabilise the time interval @interface MyScene ()! @property (nonatomic) SKSpriteNode * player;! @property (nonatomic) NSTimeInterval lastSpawnTimeInterval;! @property (nonatomic) NSTimeInterval lastUpdateTimeInterval;! @end
  • 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. Every second add a enemy - (void)updateWithTimeSinceLastUpdate: (CFTimeInterval)timeSinceLast {!  ! self.lastSpawnTimeInterval += timeSinceLast;! if (self.lastSpawnTimeInterval > 1) {! self.lastSpawnTimeInterval = 0;! [self addMonster];! }! }!
  • 37. Throw projectile - vector (spriteX, spriteY) offsetX offsetY (touchX, touchY) offsetX = touchX - spriteX offsetY = touchY - spriteY
  • 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. 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. 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. 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. Multiply vector - helper function CGPoint multiplyVector(CGPoint vector, CGFloat amount){! CGPoint newVec = CGPointMake(vector.x*amount, vector.y*amount);! return newVec;! }
  • 43. Calculate projectile destination (offsetX, offsetY) (offsetX/unitValue, offsetY/unitValue) newVec = multiplyVector(offset, 1000) (player.x+newVec.x, player.y+newVec.y)
  • 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. 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. Run
  • 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. Run
  • 50. Use the power of Physic Engine Set gravity! ! Set contact delegate self.physicsWorld.gravity = CGVectorMake(0,0); self.physicsWorld.contactDelegate = self;
  • 51. @interface MyScene ()<SKPhysicsContactDelegate>! @property (nonatomic) SKSpriteNode * player;! @property (nonatomic) NSTimeInterval lastSpawnTimeInterval;! @property (nonatomic) NSTimeInterval lastUpdateTimeInterval;! @end SKPhysicsContactDelegate
  • 52. physicsWorld @interface SKScene : SKEffectNode! ! @property (SK_NONATOMIC_IOSONLY, readonly) SKPhysicsWorld *physicsWorld;! ! @end
  • 53. physicsBody monster body! ! projectile body monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size]; projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2];
  • 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. Two category ids static const uint32_t projectileCategory = 0x1 << 0;! static const uint32_t monsterCategory = 0x1 << 1;
  • 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. 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. 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. 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. Dismiss collided objects - (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster:(SKSpriteNode *)monster {! NSLog(@"Hit");! [projectile removeFromParent];! [monster removeFromParent];! }
  • 61. Run
  • 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. sound effect - touchesBegan:withEvent: -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{! ! [self runAction:[SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO]];! ! }
  • 65. Run
  • 67. Create a new Scene
  • 68. GameOverScene.h #import <SpriteKit/SpriteKit.h>! ! @interface GameOverScene : SKScene! -(id)initWithSize:(CGSize)size won:(BOOL)won;! @end
  • 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. 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. 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. 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. 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];! }! }