Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Short Intro to iOS Game Development

Short Intro to iOS Game Development

Short Intro to iOS Game Development

Jussi Pohjolainen

October 25, 2016
Tweet

More Decks by Jussi Pohjolainen

Other Decks in Technology

Transcript

  1. Different iOS Approaches • SpriteKit • Makes it easier to

    build 2D Games • Uses graphics hardware on both Macs and iOS • SceneKit • Tools for creating 3D games • Physics Engine, Particle Generator • gravity, collisions, motion... • Possible to combine with SpriteKit • Metal • SpriteKit and SceneKit is for "casual games" • API that brings app code close to GPU to maximize performance • For games that require lot of processing power • Like OpenGL but should be easier and you get more performance on iOS devices
  2. SpriteKit – pros & cons • Pros • Built-in to

    iOS – no need for external libraries • Built-in tool for texture atlases and particles • Really easy to implement stuff, also features things like video- sprites and applying image effects and masks • Cons • Locked to iOS • Still rather new framework – some features may be missing compared to older frameworks • If you develop cross-platform, Unity is good choice • If you are a beginner in game development and/or solely focused on iOS, SpriteKit is a good choice
  3. Getting Started • UI iOS app • Storyboard holds view

    controller with one view (UIView) • The view is added to Window so that it's visible on the screen • SpriteKit • Exactly the same, but change UIView to SKView!
  4. SKView • SKView object is a view that displays SpriteKit

    – content. Content is provided by an SKScene object • SKView inherites UIView • SKScene represents a "level" or "screen" in the game • Handles the per-frame logic • Create your own class that extends SKScene • Composed with SKNodes (Base class): SKSpriteNode, SKLabelNode, SKShapeNode, SKLightNode, SKCameraNode, SKAudioNode
  5. Configure View Controller import UIKit import SpriteKit class ViewController: UIViewController

    { var spriteView : SKView! override func viewDidLoad() { super.viewDidLoad() // In Storyboard, change view controller's view type // from UIView to SKView! self.spriteView = self.view as? SKView; self.spriteView.showsDrawCount = true; self.spriteView.showsNodeCount = true; self.spriteView.showsFPS = true; }
  6. Open a Scene import UIKit import SpriteKit class ViewController: UIViewController

    { var spriteView : SKView! override func viewWillAppear(_ animated: Bool) { // Create StartScene - class let startScene = StartScene(size: self.spriteView.bounds.size); // Debugging to see what are the points // See: http://www.paintcodeapp.com/news/iphone-6-screens-demystified NSLog("Width = \(self.spriteView.bounds.width)"); NSLog("Height = \(self.spriteView.bounds.height)"); spriteView.presentScene(startScene); } }
  7. SKScene • SKScene is a "screen" in your game •

    Start screen, game screen, highscore screen • SKScene contains nodes, where the root node is SKScene itself • Different nodes available • Usually you subclass SKScene • Create initial content (nodes), implement the game logic, implement responder methods for touch events
  8. Scene class import Foundation import SpriteKit class StartScene : SKScene

    { let TITLE = "Game Title" // Called immediately after a scene is presented with a view override func didMove(to view: SKView) { self.backgroundColor = SKColor.blue // See doc: // Fill, AspectFill, AspectFit, ResizeFill // AspectFit => letterboxing // self.scaleMode = SKSceneScaleMode.aspectFit self.addChild(self.createTitle()); } func createTitle() -> SKLabelNode { .. } }
  9. Scene class import Foundation import SpriteKit class StartScene : SKScene

    { let TITLE = "Game Title" override func didMove(to view: SKView) { ... } func createTitle() -> SKLabelNode { let helloNode = SKLabelNode(fontNamed: "Chalkduster") // To be able to reference to the node later helloNode.name = self.TITLE helloNode.text = self.TITLE helloNode.fontSize = 50; // Center of the screen helloNode.position = CGPoint(x: self.frame.midX, y: self.frame.midY) return helloNode; }
  10. class StartScene : SKScene { let TITLE = "Game Title"

    override func didMove(to view: SKView) { ... } func createTitle() -> SKLabelNode { ... } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { let helloNode = self.childNode(withName: self.TITLE) // Unwrap optional from helloNode if let hello = helloNode { // Prevent multiple actions hello.name = ""; // Create actions let zoom = SKAction.scale(to: 2.0, duration: 0.5) let fadeAway = SKAction.fadeOut(withDuration: 0.5) let remove = SKAction.removeFromParent() // Create group of actions running in parallel let parallel = SKAction.group([zoom, fadeAway]) // Create group of actions running in sequence let sequence = SKAction.sequence([parallel, remove]); // Run the action // hello.run(sequence) hello.run(sequence, completion: { let gameScene = GameScene(size: self.size); let transition = SKTransition.doorsOpenVertical(withDuration: 0.5) self.view?.presentScene(gameScene, transition: transition) }) } } }
  11. import Foundation import SpriteKit class GameScene : SKScene { //

    Called immediately after a scene is presented with a view override func didMove(to view: SKView) { self.backgroundColor = SKColor.white self.addChild(self.createAlien()); self.addChild(self.createShootButton()); let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame) self.physicsBody = borderBody } ... }
  12. Creating Sprites func createAlien() -> SKSpriteNode { // Drage alien.png

    to your project alienSprite = SKSpriteNode(imageNamed: "alien") // Position the alien in the middle of the screen alienSprite.position = CGPoint(x: self.frame.midX, y: self.frame.midY) // Scale the texture down alienSprite.setScale(0.5) // Add physics! The physic boundaries are exactly the same than in the texture alienSprite.physicsBody = SKPhysicsBody(texture: alienSprite.texture!, size: alienSprite.size) // The mass in kg alienSprite.physicsBody!.mass = 0.2 // How bouncy alien alienSprite.physicsBody!.restitution = 0.5 // Frictional force when in contact alienSprite.physicsBody!.friction = 0.5 return alienSprite }
  13. SKPhysicsBody • Volume-based body • Rectangle, Radius, Texture.. • Edge-based

    body • Unaffected by forces or impulses, no mass or volume • Boundaries to the game (SKScene) // Boundaries let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame) self.physicsBody = borderBody
  14. Fire Ball func fireBall() -> Void { let ballSprite =

    SKSpriteNode(imageNamed: "ball") ballSprite.position.y = self.alienSprite.position.y + (alienSprite.frame.height / 2) + ballSprite.frame.height / 2 + 10 ballSprite.position.x = self.alienSprite.position.x ballSprite.physicsBody = SKPhysicsBody(texture: ballSprite.texture!, size: ballSprite.size) ballSprite.physicsBody!.mass = 0.1 ballSprite.physicsBody!.friction = 0.5 ballSprite.physicsBody!.restitution = 0.8 self.insertChild(ballSprite, at: 1) ballSprite.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 80)) }
  15. Button func createShootButton() -> SKSpriteNode { let shootSprite = SKSpriteNode(imageNamed:

    "shoot") shootSprite.position = CGPoint(x: self.frame.width - shootSprite.frame.width/2, y: shootSprite.frame.height/2) shootSprite.name = "fireButton" return shootSprite }
  16. Button override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touch = touches.first // Location in this node's coordinate system let location = touch?.location(in: self) let node = self.atPoint(location!) if(node.name == "fireButton") { fireBall() } else { jump() } }
  17. Collision vs Contacts • Collisions include all automatic physical interactions

    between bodies • By default, everything collides with each other • You can customize this: CollisionBitMask • Contacts • Contact event happens when two bodies touch. It's possible to implement custom logic when bodies in contact • By default, no events are send on collide • You can customize this
  18. CategoryBitMasks // Categories are defined as 32 - bit masks

    // When performing tests it uses AND between these let ALIEN_CATEGORY : UInt32 = 1 << 0 // 0000 0001 // 1 let EDGE_CATEGORY : UInt32 = 1 << 1 // 0000 0010 // 2 let BALL_CATEGORY : UInt32 = 1 << 2 // 0000 0100 // 4
  19. Adding CollisionBitMasks // Category bitmap mask for ball ballSprite.physicsBody!.categoryBitMask =

    BALL_CATEGORY // => Ball will collide with Alien and other balls ballSprite.physicsBody!.collisionBitMask = ALIEN_CATEGORY | BALL_CATEGORY /* BALL_CATEGORY = 0000 0100 ALIEN_CATEGORY = 0000 0001 collision mask = BALL_CATEGORY | ALIEN_CATEGORY = 0000 0101 AND EDGE_CATEGORY 0000 0010 0000 0000 => NO COLLISION! */
  20. Notifying about Collisions // Notify if contact has happened for

    custom code // // This body's contactTestBitMask is compared to others body's // category mask by performing a logical AND operation // // NOTIFY WHEN HITTING ALIEN ballSprite.physicsBody!.contactTestBitMask = ALIEN_CATEGORY
  21. ContactDelegate class GameScene : SKScene, SKPhysicsContactDelegate { // Called immediately

    after a scene is presented with a view override func didMoveToView(view: SKView) { self.physicsWorld.contactDelegate = self; } func didBegin(_ contact: SKPhysicsContact) { let bodyABitMask = contact.bodyA.categoryBitMask let bodyBBitMask = contact.bodyB.categoryBitMask // Do something } func didEnd(_ contact: SKPhysicsContact) { } }