250 likes | 435 Views
Write the Code. Change the World. They Already Have Changed the World. Facebook Twitter Pandora Candy Crush Instagram Snapchat. How to Do It. Terminology Platforms Tools Let’s Make an App. Terminology. Code App Development Environment Build, Run, Crash, Debug Compile Simulator
E N D
Write the Code Change the World
They Already Have Changed the World • Facebook • Twitter • Pandora • Candy Crush • Instagram • Snapchat
How to Do It • Terminology • Platforms • Tools • Let’s Make an App
Terminology • Code • App • Development Environment • Build, Run, Crash, Debug • Compile • Simulator • xCode
Platforms • Microsoft – Windows (Computers and Phones) • Internet Browsers – Safari, Chrome, Firefox, Internet Explorer • Apple – OSX (Computers) • Apple – iOS (iPhone, iPad, Apple Watch) • Google – Android
Tools • xCode • Simulator • Google • Stack Exchange • Tutorials
Let’s Make an App • Go to App Store, Download and Install xCode • Launch xCode • File, New, Project, Application, Game • Run • Hello World • Now, Change the World • Run Again
Get the Resources • http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners • http://cdn3.raywenderlich.com/wp-content/uploads/2015/01/SpriteKitSimpleGameResources.zip
Start CodingGameScene.m #import “GameScene.h” // 1 @interface GameScene() @property (nonatomic) SKSpriteNode * player; @end @implementation GameScene -(id)initWithSize:(CGSize)size { if (self = [super initWithSize:size]) { //2 NSLog(@”Size: %@”, NSStringFromCGSize(size)); // 3 self.backgroundColor = [SKColor colorWithRed:1.0 green: 1.0 blue: 1.0 alpha:1.0]; // 4 self.player = [SKSpriteNodespriteNodeWithImageNamed:@”player”]; self.player.position = CGPointMake(100,100); [self addChold:self.player]; } return self; }
Add Player to Screen • Open ViewController.m • Replace ViewDidLoad with viewWillLayoutSubviews
GameViewContoller.mviewWillLayoutSubviews -(void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; // Configure the View SKView * skView = (SKView *)self.view; if (!skView.scene) { skView.showFPS = YES; skView.showNodeCount = YES; // Create and configure the Screen SKScene * scene = [ GameScenesceneWithSize:skView.bounds.size]; scene.scaleMode = SKSceneScaleModeAspectFill; // Present the Scene [skViewpresentScene:scene]; } }
Move the Player • Open GameScene.m self.player.position = CGPointMake(self.player.size.width/2, self.frame.size.height/2);
Add the Bad Guys • Implement AddMonster • Make the Monsters Move
AddMonsterGameScene.m - (void)addMonster { // Create sprite SKSpriteNode * monster = [SKSpriteNodespriteNodeWithImageNamed:@"monster"]; // Determine where to spawn the monster along the Y axis intminY = monster.size.height / 2; intmaxY = self.frame.size.height - monster.size.height / 2; intrangeY = maxY - minY; intactualY = (arc4random() % rangeY) + minY; // Create the monster slightly off-screen along the right edge, // and along a random position along the Y axis as calculated above monster.position = CGPointMake(self.frame.size.width + monster.size.width/2, actualY); [self addChild:monster]; // Determine speed of the monster intminDuration = 2.0; intmaxDuration = 4.0; intrangeDuration = maxDuration - minDuration; intactualDuration = (arc4random() % rangeDuration) + minDuration; // Create the actions SKAction * actionMove = [SKActionmoveTo:CGPointMake(-monster.size.width/2, actualY) duration:actualDuration]; SKAction * actionMoveDone = [SKActionremoveFromParent]; [monster runAction:[SKAction sequence:@[actionMove, actionMoveDone]]]; }
Shoot ‘em UpGameScene.m static inline CGPointrwAdd(CGPoint a, CGPoint b) { return CGPointMake(a.x + b.x, a.y + b.y); } static inline CGPointrwSub(CGPoint a, CGPoint b) { return CGPointMake(a.x - b.x, a.y - b.y); } static inline CGPointrwMult(CGPoint a, float b) { return CGPointMake(a.x * b, a.y * b); } static inline float rwLength(CGPoint a) { returnsqrtf(a.x * a.x + a.y * a.y); } // Makes a vector have a lengthof 1 staticinlineCGPointrwNormalize(CGPoint a) { floatlength = rwLength(a); returnCGPointMake(a.x / length, a.y / length); }
Shoot ‘em UpHandling Touches -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // 1 - Choose one of the touches to work with UITouch * touch = [touches anyObject]; CGPoint location = [touch locationInNode:self]; // 2 - Set up initial location of projectile SKSpriteNode * projectile = [SKSpriteNodespriteNodeWithImageNamed:@"projectile"]; projectile.position = self.player.position; // 3- Determine offset of location to projectile CGPoint offset = rwSub(location, projectile.position); // 4 - Bail out if you are shooting down or backwards if (offset.x <= 0) return; // 5 - OK to add now - we've double checked position [self addChild:projectile]; // 6 - Get the direction of where to shoot CGPoint direction = rwNormalize(offset); // 7 - Make it shoot far enough to be guaranteed off screen CGPointshootAmount = rwMult(direction, 1000); // 8 - Add the shoot amount to the current position CGPointrealDest = rwAdd(shootAmount, projectile.position); // 9 - Create the actions float velocity = 480.0/1.0; float realMoveDuration = self.size.width / velocity; SKAction * actionMove = [SKActionmoveTo:realDestduration:realMoveDuration]; SKAction * actionMoveDone = [SKActionremoveFromParent]; [projectile runAction:[SKAction sequence:@[actionMove, actionMoveDone]]]; }
Shoot ‘em UpCollision Detection GameScene.m static const uint32_t projectileCategory = 0x1 << 0; static const uint32_t monsterCategory = 0x1 << 1; GameScene.m / initWithSize self.physicsWorld.gravity = CGVectorMake(0,0); self.physicsWorld.contactDelegate = self; GameScene.m / addMonster / afterCreating Monster monster.physicsBody = [SKPhysicsBodybodyWithRectangleOfSize:monster.size]; // 1 monster.physicsBody.dynamic = YES; // 2 monster.physicsBody.categoryBitMask = monsterCategory; // 3 monster.physicsBody.contactTestBitMask = projectileCategory; // 4 monster.physicsBody.collisionBitMask = 0; // 5 GameScene.m / TouchesEnded / after setting projectile position projectile.physicsBody = [SKPhysicsBodybodyWithCircleOfRadius:projectile.size.width/2]; projectile.physicsBody.dynamic = YES; projectile.physicsBody.categoryBitMask = projectileCategory; projectile.physicsBody.contactTestBitMask = monsterCategory; projectile.physicsBody.collisionBitMask = 0; projectile.physicsBody.usesPreciseCollisionDetection = YES;
Shoot ‘em UpCollision Detection GameScene.m - (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster:(SKSpriteNode *)monster { NSLog(@"Hit"); [projectile removeFromParent]; [monster removeFromParent]; } - (void)didBeginContact:(SKPhysicsContact *)contact { // 1 SKPhysicsBody *firstBody, *secondBody; if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) { firstBody = contact.bodyA; secondBody = contact.bodyB; } else { firstBody = contact.bodyB; secondBody = contact.bodyA; } // 2 if ((firstBody.categoryBitMask & projectileCategory) != 0 && (secondBody.categoryBitMask & monsterCategory) != 0) { [self projectile:(SKSpriteNode *) firstBody.nodedidCollideWithMonster:(SKSpriteNode *) secondBody.node]; } }
Shoot ‘em UpCollision Detection GameScene.h / Implement Delegate @interface GameScene() <SKPhysicsContactDelegate>
Sound Check GameViewController.m @import AVFoundation; @interface GameViewController() @property (nonatomic) AVAudioPlayer * backgroundMusicPlayer; @end GameViewController.m / viewWillLayoutSubviews / after [super viewWillLayoutSubviews] NSError *error; NSURL * backgroundMusicURL = [[NSBundle mainBundle] URLForResource:@"background-music-aac" withExtension:@"caf"]; self.backgroundMusicPlayer = [[AVAudioPlayeralloc] initWithContentsOfURL:backgroundMusicURL error:&error]; self.backgroundMusicPlayer.numberOfLoops = -1; [self.backgroundMusicPlayerprepareToPlay]; [self.backgroundMusicPlayer play]; GameScene.m / TouchesEnded / at the top [self runAction:[SKActionplaySoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO]];
Winners and Losers • Now, let’s create a new scene and layer that will serve as your “You Win” or “You Lose” indicator. • Create a new file with the iOS\Cocoa Touch\Objective-C class template, name the class GameOverScene, make it a subclass of SKScene, and click Next and then Create. • GameOverScene.h • #import <SpriteKit/SpriteKit.h> • @interface GameOverScene : SKScene • -(id)initWithSize:(CGSize)size won:(BOOL)won; • @end
Winners and LosersGameOverScene.m #import "GameOverScene.h" #import “GameScene.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 :["; } // 3 SKLabelNode *label = [SKLabelNodelabelNodeWithFontNamed:@"Chalkduster"]; label.text = message; label.fontSize = 40; label.fontColor = [SKColorblackColor]; label.position = CGPointMake(self.size.width/2, self.size.height/2); [self addChild:label]; // 4 [self runAction: [SKAction sequence:@[ [SKAction waitForDuration:3.0], [SKActionrunBlock:^{ // 5 SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5]; SKScene * myScene = [[GameScenealloc] initWithSize:self.size]; [self.viewpresentScene:myScene transition: reveal]; }] ]] ]; } return self; } @end
Winners and LosersFinishing Up GameScene.m #import "GameOverScene.h" GameScene.m / addMonster / replace Last Line SKAction * loseAction = [SKActionrunBlock:^{ SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5]; SKScene * gameOverScene = [[GameOverScenealloc] initWithSize:self.sizewon:NO]; [self.viewpresentScene:gameOverScene transition: reveal]; }]; [monster runAction:[SKAction sequence:@[actionMove, loseAction, actionMoveDone]]]; GameScene.m / addToInterface @property (nonatomic) intmonstersDestroyed; gameScene.m / projectile:didCollideWithMonster / bottom self.monstersDestroyed++; if (self.monstersDestroyed > 30) { SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5]; SKScene * gameOverScene = [[GameOverScenealloc] initWithSize:self.sizewon:YES]; [self.viewpresentScene:gameOverScene transition: reveal]; }