what’s new in spritekit - apple developer · framework features what is spritekit? 2d graphics...
TRANSCRIPT
© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.
Graphics and Games #WWDC16
Session 610
What’s New in SpriteKit
Ross Dexter Games Technologies EngineerClément Boissière Games Technologies Engineer
What Is SpriteKit?
Framework featuresWhat Is SpriteKit?
2D graphics framework for gamesFlexible, easy to use, high-performanceSupported on iOS, macOS, tvOS & watchOS Automatic access to the latest updatesNatural integration with Swift
Xcode-integrated live editorWhat Is SpriteKit?
Visually lay out your game scenesTimeline-based animationParticle editorAsset Catalog integrationTile map editingGameplayKit integration
Built-in Metal supportWhat Is SpriteKit?
Automatically Metal-backedZero action required for developers
Scene Outline View
Scene hierarchy at-a-glanceScene Outline View
The Jump Bar contains the scene hierarchy• Only allows for selection• Shows one branch at a time
Scene hierarchy at-a-glanceScene Outline View
Scene Outline View shows the entire hierarchy• Select, rename, remove• Drag to parent/unparent• Can lock and/or hide nodes
NEW
GameplayKit Integration
Entities and componentsGameplayKit Integration
Design pattern focused on modularityComponents encapsulate behavior• Health• Collision• Player input
Write it once, assign to multiple objects
Entities and componentsGameplayKit Integration NEW
Assign components directly from the editorProperties can be tweaked via the inspectorWe take care of the hard stuff for you
PathfindingGameplayKit Integration
Pathfinding uses navigation graphsGraphs are collections of nodesNodes are joined by connectionsDescribes how to move through scene
Navigation graph editorGameplayKit Integration
Create and edit navigation graphs• Add and remove nodes• Create or adjust connections
NEW
FPS Performance Gauge
Real-time performance breakdownFPS Performance Gauge
Real-time performance breakdownFPS Performance Gauge
Frame rate
Real-time performance breakdownFPS Performance Gauge
Frame rateGPU utilization
Real-time performance breakdownFPS Performance Gauge
Frame rateGPU utilizationCPU/GPU frame time
Real-time performance breakdownFPS Performance Gauge
Frame rateGPU utilizationCPU/GPU frame time
Real-time performance breakdownFPS Performance Gauge
Breakdown of update loop• Render• Client update• Actions• Physics
Easy to identify bottlenecksAvailable on iOS and watchOS
NEW
Real-time performance breakdownFPS Performance Gauge
Breakdown of update loop• Render• Client update• Actions• Physics
Easy to identify bottlenecksAvailable on iOS and watchOS
NEW
Real-time performance breakdownFPS Performance Gauge
Breakdown of update loop• Render• Client update• Actions• Physics
Easy to identify bottlenecksAvailable on iOS and watchOS
NEW
Tile Maps
NEW
What are tile maps?Tile Maps
Tile maps are a grid of evenly spaced imagesUsed to build scenes from repeating imagesQuickly create large, detailed scenes
NEW
What are tile maps?Tile Maps
Tile maps are a grid of evenly spaced imagesUsed to build scenes from repeating imagesQuickly create large, detailed scenes
NEW
What are tile maps?Tile Maps
Tile maps are a grid of evenly spaced imagesUsed to build scenes from repeating imagesQuickly create large, detailed scenes
Why use tile maps?Tile Maps
Could place individual images by handPros• Small images help keep overhead low• Can be rearranged
Cons• Tedious and time consuming• Clutters the scene with lots of nodes• Quickly becomes difficult to manage
Why use tile maps?Tile Maps
Could place individual images by handPros• Small images help keep overhead low• Can be rearranged
Cons• Tedious and time consuming• Clutters the scene with lots of nodes• Quickly becomes difficult to manage
Why use tile maps?Tile Maps
Could use static images for your scenesPros• Easy to place and manage• Doesn’t clutter the scene
Cons• Tweaks require changing your assets• Large images require more memory• Variety requires additional large assets
Why use tile maps?Tile Maps
Tile maps get you the best of both solutions• Easy to manage• Can be quickly modified• Large scenes with low overhead
NEW
Why use tile maps?Tile Maps
Tile maps get you the best of both solutions• Easy to manage• Can be quickly modified• Large scenes with low overhead
NEW
Why use tile maps?Tile Maps
Great for lots of different games and art styles
NEW
Why use tile maps?Tile Maps
Great for lots of different games and art styles• Top-down RPGs
NEW
Why use tile maps?Tile Maps
Great for lots of different games and art styles• Top-down RPGs• Side-scrolling platformers
NEW
Why use tile maps?Tile Maps
Great for lots of different games and art styles• Top-down RPGs• Side-scrolling platformers• Isometric city builders
NEW
Why use tile maps?Tile Maps
Great for lots of different games and art styles• Top-down RPGs• Side-scrolling platformers• Isometric city builders• Hex-based board games
NEW
DemoTile maps in action
Class overviewTile Maps
SKTileMapNode
SKTileSet
SKTileGroup
SKTileGroupRule
SKTileDefinition
NEW
SKTileMapNode is the tile mapDerived from SKNodeContains all of the placed tiles Needs a tile set to be able to place tiles
Class overviewTile Maps NEW
SKTileSet contains all placeable tile groupsAlso defines the type of tiles it contains• Grid• Isometric• Hexagonal
SKTileMapNode
SKTileSet
SKTileGroup
SKTileGroupRule
SKTileDefinition
Class overviewTile Maps
SKTileGroup contains a set of related tiles• Grass• Water• Stone
Has rules that govern tile placement
NEW
SKTileMapNode
SKTileSet
SKTileGroup
SKTileGroupRule
SKTileDefinition
Class overviewTile Maps NEW
SKTileMapNode
SKTileSet
SKTileGroup
SKTileGroupRule
SKTileDefinition
SKTileGroupRule controls how to interactContains tile variants
Class overviewTile Maps
SKTileMapNode
SKTileSet
SKTileGroup
SKTileGroupRule
SKTileDefinition
NEW
SKTileDefinition defines tile appearanceAllows for animationImages can be flipped and/or rotated
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Creating Tile Maps and Setting Tiles
// Get the tile set
guard let tileSet = SKTileSet(named: ”MyTileSet”) else { return }
// Create a tile map
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileMap = SKTileMapNode(tileSet: tileSet, columns: 16, rows: 16, tileSize: tileSize)
// Get a tile group from the tile set
let tileGroup = tileSet.tileGroups.first
// Set tile group for a specific tile
tileMap.setTileGroup(tileGroup, forColumn: 4, row: 7)
// Fill the entire map with a tile group
tileMap.fill(with: tileGroup)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
// Check user data in the tile under the player’s sprite
// Convert the player’s position into the tile map’s frame of reference
let position = tileMap.convert(playerSprite.position, from: playerSprite)
// Get the column and row of the tile that contains the position
let column = tileMap.tileColumnIndex(fromPosition: position)
let row = tileMap.tileRowIndex(fromPosition: position)
// Get the tile definition in the tile the player’s sprite is over
guard let definition = tileMap.tileDefinition(atColumn: column, row: row) else { return }
// Access custom user data on the tile definition
let customUserData = definition.userData?.value(forKey: “MyKey”)
Framework feature recapTile Maps
Tile maps get more out of your art budget• Fewer assets needed• Reduced memory overhead
Supports animation
NEW
Framework feature recapTile Maps
Designed to be layered• Increased asset versatility• Enables effects
Great for different art styles and games
NEW
Framework feature recapTile Maps NEW
Automatic subdivision• Only visible chunks are drawn
Batch renderingMultiple tile types• Grid• Isometric• Hexagonal
Editor feature recapTile Maps
Editing tile maps is simple and easyAutomapping does the hard work for youCreate new tile sets visually
NEW
Warp Transformation
Clément Boissière Games Technologies Engineer
IntroductionWarp Transformation
IntroductionWarp Transformation
Available transforms in SpriteKit
IntroductionWarp Transformation
Available transforms in SpriteKit• Scale
IntroductionWarp Transformation
Available transforms in SpriteKit• Scale• Rotation
IntroductionWarp Transformation
Available transforms in SpriteKit• Scale• Rotation• Custom shader
IntroductionWarp Transformation
SKWarpGeometry• Two grids of points defining the distortion• Source positions• Destination positions
NEW
IntroductionWarp Transformation
SKWarpGeometry• Two grids of points defining the distortion• Source positions• Destination positions
NEW
IntroductionWarp Transformation
SKWarpGeometry• Two grids of points defining the distortion• Source positions• Destination positions
NEW
IntroductionWarp Transformation
SKWarpGeometry• Two grids of points defining the distortion• Source positions• Destination positions
NEW
ExamplesWarp Transformation NEW
ExamplesWarp Transformation
A few examples
NEW
ExamplesWarp Transformation
A few examples• Squash
NEW
ExamplesWarp Transformation
A few examples• Squash• Stretch
NEW
ExamplesWarp Transformation
A few examples• Squash• Stretch• Keyframe-based animations
NEW
How it worksWarp Transformation NEW
How it worksWarp Transformation
Concept• A grid is an indexed set of points
NEW
0 1 2
3 4 5
6 7 8
How it worksWarp Transformation
Concept• A grid is an indexed set of points• Each cell is a quad
NEW
0 1 2
3 4 5
6 7 8
How it worksWarp Transformation
Concept• A grid is an indexed set of points• Each cell is a quad• Vertices change to create distortion
NEW
0 1 2
3 4 5
6 7 8
How it worksWarp Transformation
Concept• A grid is an indexed set of points• Each cell is a quad• Vertices change to create distortion• Keep the same texture coordinates
NEW
0 1 2
3 4 5
6 7 8
How it worksWarp Transformation
Concept• A grid is an indexed set of points• Each cell is a quad• Vertices change to create distortion• Keep the same texture coordinates• GPU interpolation
NEW
0 1 2
3 4 5
6 7 8
How it worksWarp Transformation
Concept• A grid is an indexed set of points• Each cell is a quad• Vertices change to create distortion• Keep the same texture coordinates• GPU interpolation
NEW
Warp Transformation NEW
Warp Transformation NEW
How it worksWarp Transformation
Higher level of details• More cells?
NEW
How it worksWarp Transformation
Higher level of details• More cells?
NEW
How it worksWarp Transformation NEW
How it worksWarp Transformation
End result• Automatic quad subdivisions• High level of detail• Minimal quad count
NEW
How it worksWarp Transformation
You can specify the max subdivision level• Adjust details level• Performance tuning
NEW
sd = 1 sd = 4
// SKWarpGeometryGrid - 2x2 grid example.
// [0]---[1]---[2]
// | | |
// [3]---[4]---[5]
// | | |
// [6]---[7]---[8]
var src = [float2]()
var dst = [float2]()
let warpGrid = SKWarpGeometryGrid(columns: 2,
rows: 2,
sourcePositions: src,
destPositions: dst)
sprite.warpGeometry = warpGrid
sprite.subdivisionLevels = 3 // Optional, defaults to 2
NEW
// SKWarpGeometryGrid - 2x2 grid example.
// [0]---[1]---[2]
// | | |
// [3]---[4]---[5]
// | | |
// [6]---[7]---[8]
var src = [float2]()
var dst = [float2]()
let warpGrid = SKWarpGeometryGrid(columns: 2,
rows: 2,
sourcePositions: src,
destPositions: dst)
sprite.warpGeometry = warpGrid
sprite.subdivisionLevels = 3 // Optional, defaults to 2
NEW
// SKWarpGeometryGrid - 2x2 grid example.
// [0]---[1]---[2]
// | | |
// [3]---[4]---[5]
// | | |
// [6]---[7]---[8]
var src = [float2]()
var dst = [float2]()
let warpGrid = SKWarpGeometryGrid(columns: 2,
rows: 2,
sourcePositions: src,
destPositions: dst)
sprite.warpGeometry = warpGrid
sprite.subdivisionLevels = 3 // Optional, defaults to 2
NEW
// SKWarpGeometryGrid - 2x2 grid example.
// [0]---[1]---[2]
// | | |
// [3]---[4]---[5]
// | | |
// [6]---[7]---[8]
var src = [float2]()
var dst = [float2]()
let warpGrid = SKWarpGeometryGrid(columns: 2,
rows: 2,
sourcePositions: src,
destPositions: dst)
sprite.warpGeometry = warpGrid
sprite.subdivisionLevels = 3 // Optional, defaults to 2
NEW
// SKWarpGeometryGrid - 2x2 grid example.
// [0]---[1]---[2]
// | | |
// [3]---[4]---[5]
// | | |
// [6]---[7]---[8]
var src = [float2]()
var dst = [float2]()
let warpGrid = SKWarpGeometryGrid(columns: 2,
rows: 2,
sourcePositions: src,
destPositions: dst)
sprite.warpGeometry = warpGrid
sprite.subdivisionLevels = 3 // Optional, defaults to 2
NEW
// New SKAction
let a1 = SKAction.warp(to: grid,
duration: 5.0)
let a2 = SKAction.animate(withWarps: [grid1, grid2, grid3],
times: [t1, t2, t3])
let a3 = SKAction.animate(withWarps: [grid1, grid2, grid3],
times: [t1, t2, t3],
restore: true)
NEW
// New SKAction
let a1 = SKAction.warp(to: grid,
duration: 5.0)
let a2 = SKAction.animate(withWarps: [grid1, grid2, grid3],
times: [t1, t2, t3])
let a3 = SKAction.animate(withWarps: [grid1, grid2, grid3],
times: [t1, t2, t3],
restore: true)
NEW
// New SKAction
let a1 = SKAction.warp(to: grid,
duration: 5.0)
let a2 = SKAction.animate(withWarps: [grid1, grid2, grid3],
times: [t1, t2, t3])
let a3 = SKAction.animate(withWarps: [grid1, grid2, grid3],
times: [t1, t2, t3],
restore: true)
NEW
DemoWarp transformation
Per-Node Attributes for Custom Shaders
IntroductionPer-Node Attributes for Custom Shaders
Custom shaders in SpriteKit• SKShader (fragment shader)• Built-in shader symbols• SKUniform
Game ideaPer-Node Attributes for Custom Shaders
Game ideaPer-Node Attributes for Custom Shaders
Game ideaPer-Node Attributes for Custom Shaders
Game ideaPer-Node Attributes for Custom Shaders
Game ideaPer-Node Attributes for Custom Shaders
ExamplePer-Node Attributes for Custom Shaders
Shader UniformSprite
u_health
ExamplePer-Node Attributes for Custom Shaders
u_health : float
low
0.2
half
0.5
full
1.0
ExamplePer-Node Attributes for Custom Shaders
Shader1Sprite1 Uniform0.5
u_health
ExamplePer-Node Attributes for Custom Shaders
Shader1Sprite1 Uniform0.50.5
u_health
u_health
u_health
ExamplePer-Node Attributes for Custom Shaders
Shader2 UniformSprite20.2
Shader3 UniformSprite31.0
Shader1Sprite1 Uniform0.50.5
u_health
u_health
u_health
ExamplePer-Node Attributes for Custom Shaders
Shader2 UniformSprite20.2
Shader3 UniformSprite31.0
Shader1Sprite1 Uniform0.50.5
u_health
ExamplePer-Node Attributes for Custom Shaders
Shader
Sprite1
Sprite2
Sprite3
a_health
a_health
a_health
a_health
Attribute
ExamplePer-Node Attributes for Custom Shaders
Shader
NEW
Sprite1
Sprite2
Sprite3
0.5
0.2
1.0
// SKAttribute for Per-Node Customization
// 1) Create your attributes:
let attribute = SKAttribute(name: "a_health", type: .float)
// 2) Attach to a shader:
shader.attributes = [attribute]
// 3) Set attributes directly on compatible nodes:
sprite1.setValue(SKAttributeValue(float: 0.2), forAttributeNamed: "a_health")
sprite2.setValue(SKAttributeValue(float: 0.5), forAttributeNamed: "a_health")
sprite3.setValue(SKAttributeValue(float: 1.0), forAttributeNamed: "a_health")
// SKAttribute for Per-Node Customization
// 1) Create your attributes:
let attribute = SKAttribute(name: "a_health", type: .float)
// 2) Attach to a shader:
shader.attributes = [attribute]
// 3) Set attributes directly on compatible nodes:
sprite1.setValue(SKAttributeValue(float: 0.2), forAttributeNamed: "a_health")
sprite2.setValue(SKAttributeValue(float: 0.5), forAttributeNamed: "a_health")
sprite3.setValue(SKAttributeValue(float: 1.0), forAttributeNamed: "a_health")
NEW
// SKAttribute for Per-Node Customization
// 1) Create your attributes:
let attribute = SKAttribute(name: "a_health", type: .float)
// 2) Attach to a shader:
shader.attributes = [attribute]
// 3) Set attributes directly on compatible nodes:
sprite1.setValue(SKAttributeValue(float: 0.2), forAttributeNamed: "a_health")
sprite2.setValue(SKAttributeValue(float: 0.5), forAttributeNamed: "a_health")
sprite3.setValue(SKAttributeValue(float: 1.0), forAttributeNamed: "a_health")
NEW
// SKAttribute for Per-Node Customization
// 1) Create your attributes:
let attribute = SKAttribute(name: "a_health", type: .float)
// 2) Attach to a shader:
shader.attributes = [attribute]
// 3) Set attributes directly on compatible nodes:
sprite1.setValue(SKAttributeValue(float: 0.2), forAttributeNamed: "a_health")
sprite2.setValue(SKAttributeValue(float: 0.5), forAttributeNamed: "a_health")
sprite3.setValue(SKAttributeValue(float: 1.0), forAttributeNamed: "a_health")
NEW
Focus Interaction on Apple TV
IntroductionFocus Interaction on Apple TV
IntroductionFocus Interaction on Apple TV
Interaction on tvOS• Integrated with UIKit• Simple to use• Consistent user experience• Support a wide range of controllers
SpriteKit integrationFocus Interaction on Apple TV
Now also integrated with SpriteKit!Use cases• Game menus• Entire game interaction• Less code!
NEW
// Focus extended support for non-view items
public protocol UIFocusItem : UIFocusEnvironment NEW
// Focus extended support for non-view items
public protocol UIFocusItem : UIFocusEnvironment
// SKNode now conforms to the UIFocusItem protocol
public class SKNode : UIResponder, NSCopying, NSCoding,
NEW
UIFocusItem
// 1) Create a subclass
class MenuElementNode : SKSpriteNode {
// 2) Override canBecomeFocused
override func canBecomeFocused() -> Bool {
return true
}
}
NEW
// 1) Create a subclass
class MenuElementNode : SKSpriteNode {
// 2) Override canBecomeFocused
override func canBecomeFocused() -> Bool {
return true
}
}
NEW
// 1) Create a subclass
class MenuElementNode : SKSpriteNode {
// 2) Override canBecomeFocused
override func canBecomeFocused() -> Bool {
return true
}
}
NEW
NEWclass GameScene : SKScene {
let menuItem = MenuElementNode()
override func sceneDidLoad() { // 3) Opt-in the node for focus interaction self.menuItem.isUserInteractionEnabled = true; }
// 4) Track focus updates on your SKView, SKScene // or any SKNode that would make sense for your app logic. override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { let prevItem = context.previouslyFocusedItem let nextItem = context.nextFocusedItem
if nextItem is MenuElementNode { // Run some SKAction } } }
NEWclass GameScene : SKScene {
let menuItem = MenuElementNode()
override func sceneDidLoad() { // 3) Opt-in the node for focus interaction self.menuItem.isUserInteractionEnabled = true; }
// 4) Track focus updates on your SKView, SKScene // or any SKNode that would make sense for your app logic. override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { let prevItem = context.previouslyFocusedItem let nextItem = context.nextFocusedItem
if nextItem is MenuElementNode { // Run some SKAction } } }
NEWclass GameScene : SKScene {
let menuItem = MenuElementNode()
override func sceneDidLoad() { // 3) Opt-in the node for focus interaction self.menuItem.isUserInteractionEnabled = true; }
// 4) Track focus updates on your SKView, SKScene // or any SKNode that would make sense for your app logic. override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { let prevItem = context.previouslyFocusedItem let nextItem = context.nextFocusedItem
if nextItem is MenuElementNode { // Run some SKAction } } }
SpriteKit integrationFocus Interaction on Apple TV NEW
SpriteKit on Apple Watch
IntroductionSpriteKit on Apple Watch
SpriteKit now available for Apple Watch!• High-performance 2D graphics framework• Particles, actions, physics, animations• Scene and Particle Editors• Debugging tools
NEW
IntroductionSpriteKit on Apple Watch
SpriteKit now available for Apple Watch!• High-performance 2D graphics framework• Particles, actions, physics, animations• Scene and Particle Editors• Debugging tools
NEW
Getting startedSpriteKit on Apple Watch
SKView
Getting startedSpriteKit on Apple Watch
SKView
SKScene
Getting startedSpriteKit on Apple Watch
SKSpriteNode
SKLabelNode
SKEmitterNode
SKCropNode
SKShapeNode
SKTileMapNode
SKFieldNode
SKCameraNode
SKLightNode
SKView
SKScene
Getting startedSpriteKit on Apple Watch
SKSpriteNode
SKLabelNode
SKEmitterNode
SKCropNode
SKShapeNode
SKTileMapNode
SKFieldNode
SKCameraNode
SKLightNode
SKScene
WKInterfaceSKScene
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
CompatibilitySpriteKit on Apple Watch
Audio playback SKAudioNode not supported SKAction playSoundFileNamed
Video playback SKVideoNode not supported WKInterfaceMovie
Visual effectsSKEffectNode using CoreImage Filter SKEffectNode using SKShader
NEW
SpriteKit Best Practices
Asset CatalogSpriteKit Tips & Tricks
Asset CatalogSpriteKit Tips & Tricks
SpriteKit is fully integrated with Asset Catalog
Asset CatalogSpriteKit Tips & Tricks
SpriteKit is fully integrated with Asset Catalog• Use sprite atlas for minimal draw calls
Asset CatalogSpriteKit Tips & Tricks
SpriteKit is fully integrated with Asset Catalog• Use sprite atlas for minimal draw calls• Support assets of multiple size (1x, 2x, 3x)
Asset CatalogSpriteKit Tips & Tricks
SpriteKit is fully integrated with Asset Catalog• Use sprite atlas for minimal draw calls• Support assets of multiple size (1x, 2x, 3x)• Support for On-Demand Resources (iOS, tvOS)
Asset CatalogSpriteKit Tips & Tricks
SpriteKit is fully integrated with Asset Catalog• Use sprite atlas for minimal draw calls• Support assets of multiple size (1x, 2x, 3x)• Support for On-Demand Resources (iOS, tvOS)• Compiles necessary assets into runtime binary
PerformanceSpriteKit Tips & Tricks NEW
PerformanceSpriteKit Tips & Tricks
Performance tuning and battery life improvements
NEW
PerformanceSpriteKit Tips & Tricks
Performance tuning and battery life improvements• SpriteKit now only renders when necessary
NEW
PerformanceSpriteKit Tips & Tricks
Performance tuning and battery life improvements• SpriteKit now only renders when necessary• Additional ways to control the frame rate
NEW
PerformanceSpriteKit Tips & Tricks
Performance tuning and battery life improvements• SpriteKit now only renders when necessary• Additional ways to control the frame rate
NEW
// Specify the desired FPS.
skView.preferredFramesPerSecond = 30
@objc public protocol SKViewDelegate : NSObjectProtocol {
// Dynamically control the render rate.
// - return YES to initiate an update and render for the target time.
// - return NO to skip update and render for this target time.
@objc public func view(_ view: SKView, shouldRenderAtTime time: TimeInterval) -> Bool
}
PerformanceSpriteKit Tips & Tricks
Performance tuning and battery life improvements• SpriteKit now only renders when necessary• Additional ways to control the frame rate
NEW
// Specify the desired FPS.
skView.preferredFramesPerSecond = 30
@objc public protocol SKViewDelegate : NSObjectProtocol {
// Dynamically control the render rate.
// - return YES to initiate an update and render for the target time.
// - return NO to skip update and render for this target time.
@objc public func view(_ view: SKView, shouldRenderAtTime time: TimeInterval) -> Bool
}
Summary
Summary
What's New in SpriteKit
Summary
What's New in SpriteKit• Scene Outline View
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration• FPS Performance Gauge
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration• FPS Performance Gauge• Tile Maps
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration• FPS Performance Gauge• Tile Maps• Warp Transformation
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration• FPS Performance Gauge• Tile Maps• Warp Transformation• Per-Node Attributes for Custom Shaders
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration• FPS Performance Gauge• Tile Maps• Warp Transformation• Per-Node Attributes for Custom Shaders• Focus Interaction on Apple TV
Summary
What's New in SpriteKit• Scene Outline View• GameplayKit Integration• FPS Performance Gauge• Tile Maps• Warp Transformation• Per-Node Attributes for Custom Shaders• Focus Interaction on Apple TV• SpriteKit on Apple Watch
More Information
https://developer.apple.com/wwdc16/610
Related Sessions
Go Live with ReplayKit Mission Tuesday 10:00AM
Focus Interaction on tvOS Mission Wednesday 4:00PM
Visual Debugging with Xcode Presidio Wednesday 4:00PM
Controlling Game Input for Apple TV Mission Wednesday 5:00PM
What’s New in GameplayKit Pacific Heights Thursday 9:00AM
Advances in SceneKit Rendering Mission Thursday 11:00AM
Related Sessions
What’s New in Game Center Mission Friday 10:00AM
Game Technologies for Apple Watch Mission Friday 3:00PM
Labs
Game Center Lab Graphics, Games, and Media Lab A Friday 12:00PM
SpriteKit Lab Graphics, Games, and Media Lab B Friday 12:00PM
watchOS Graphics and Games Lab Graphics, Games, and Media Lab B Friday 4:00PM