Title says it all. How do i use a sprite sheet in swift and sprite kit? I've searched google, stack exchange, and the apple documentation and I can't figure this one out.
In xcode 7, you can use Images.xcassets to create a sprite atlas.
Click on Images.xcassets
Click on the plus bottom in the bottom left
Select "new sprite atlas"
Then you can drag and drop all your images into the atlas
If you drag in all three image sizes with the proper suffix (#2x and #3x) it will automatically populate the images for you.
Then to use these assets in code simply write:
let atlas = SKTextureAtlas(named: "Sprites")
let texture = atlas.textureNamed("ball")
let sprite = SKSpriteNode(texture: texture)
you can be less specific and just specify a texture:
let texture = SKTexture(imageNamed: "ball")
let sprite = SKSpriteNode(texture: texture)
If you're looking to use an already created sprite sheet, check out this answer on SO: Using sprite sheets in xcode.
Related
So I am working on a game in SpriteKit. I have a function that generates a level for the player.
The function uses images placed in assets.xcassets to generate levels. The game has multiple themes , namely fire water and electricity. Each theme has its own set of images with the same names but each theme image set is in its separate folder/group. Is it possible for me to programmatically tell the function to use a specific folder so that I can generate levels for other themes without renaming images. Or is it possible for me to use multiple asset folders and change which one the function uses at runtime. I want to use a random theme every time the player restarts the level.
Sprite Atlas / Sprite Sheet
You can use a Sprite Atlas (also known as Sprite Sheet).
If you don't know what I'm talking about have a look at these 2 nice videos:
Sprite Sheets - The Movie Part 1
Sprite Sheets - The Movie Pt. 2 - Performance
How to use it
If you have watched the videos now you know that the main target of a Sprite Atlas is loading into the GPU all and only (as far as possible) the images needed for the current scene or level. This way drawing each frame becomes much faster because all the resources al already on the GPU and the CPU only needs to transmit the coordinates.
Namespace
Ok but how does it solve your problem?
Xcode allows you to create a namespace for each Sprite Atlas. So you can use the same name for resources in different Sprite Atlas.
How to create a Sprite Atlas.
This is pretty simple.
With Xcode open you Asset Catalog
Tap on the + button you see in the image below
Click on New Sprite Atlas
You'll se a new "Folder", that's your Sprite Atlas.
5. Now click on the Provides Namespacecheckbox on the right.
That's it. Now just drop your images into the Sprites folder in order to add them to your sprite atlas.
In this example I'm going to rename the Sprite Atlas as Sprites0 and will add a red circle named circle.
Then
will create another Sprite Atlas
will check again the Provides Namespacecheckbox
will name Sprites1
and finally will add a green circle names circle.
Here's the final result
Code
Let's see now how to use it.
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let textureAtlas0 = SKTextureAtlas(named: "Sprites0")
let texture0 = textureAtlas0.textureNamed("circle")
let sprite0 = SKSpriteNode(texture: texture0)
sprite0.position.y = 100
addChild(sprite0)
let textureAtlas1 = SKTextureAtlas(named: "Sprites1")
let texture1 = textureAtlas1.textureNamed("circle")
let sprite1 = SKSpriteNode(texture: texture1)
sprite1.position.y = -100
addChild(sprite1)
}
}
Result
How does it work
Step 1: you load the Sprite Atlas
let textureAtlas0 = SKTextureAtlas(named: "Sprites0")
Step 2: you load a specific texture from the texture atlas
let texture0 = textureAtlas0.textureNamed("circle")
Step 3: you use your texture as you want
let sprite0 = SKSpriteNode(texture: texture0)
sprite0.position.y = 100
addChild(sprite0)
I know that I can add sequences of individual images in Xcode, and let it create the Texture Atlas. This process is well-described in easily-searched venues. (Like this one.)
I am getting atlases from designers, created with Adobe Animate (v18.0) already combined into the full sheet, and moreover with the accompanying XML file describing the animation. (In which sub-images and display frames do not match 1:1, so it's hard to see how Xcode would figure that out.)
It's not clear to me from the SpriteKit docs whether/how to use these pre-defined Texture Atlases. Is this possible?
If you're getting pre-baked texture atlases, with externally-generated descriptions of where the sprites should get their textures, you'll probably have to create your sprites using SKTextures that you create using the init(rect:in:) initializer of a SKTexture.
You'll need to read the sprite's extents out of the XML file, and then create a texture out of the atlas. Then you can create a new SKTexture object that represents a part of the larger texture to act as your sprite's texture.
This is untested pseudocode, but it shows the process:
let spriteRect = (get the rect from the XML)
let atlas = SKTexture( imageNamed: "myTextureAtlas" )
let spriteTexture = SKTexture( rect:spriteRect, in:atlas )
let sprite = SKSpriteNode( texture:spriteTexture )
Once you have this process in place, you can animate the sprites using the usual methods, like setting up SKActions with a list of textures out of the texture atlas.
I am fairly new to programming and, as such, am still in the follow-the-tutorials stage of coding. Specifically, my most recent undertaking is "SpriteKit with Swift" (had to delete this link because I don't have 10 reputation)
Anyway, my issues lie with images. I have been doing everything else in accordance with the tutorial, but I wanted to use my own images for the SpriteNodes instead of the satellite and asteroid. Additionally, I want to set a specific image as my background, but every time I go about that I see that image alone in the Simulator. I just don't want to make the game verbatum; I want my own twist.
I am using Swift 2 in Xcode 7
Thanks in advance
this is what came up whilst I was putting in the background
this is what my GameScene looks like
Always try to post code when using stack overflow. I am not 100% sure this is what you are asking but Ill give it a shot.
By default SpriteKit optimises how it adds sprites.
skView.ignoresSiblingOrder = true // in gameViewController
This should stay true most likely because it optimises SpriteKits performance. It basically means sprites will not always get added to the SKScene in the order you are adding them to the scene.
You need to start using zPosition when layering multiple images in a scene with a defined order.
To add a background you would do this
let background = SKSpriteNode(imageNamed: "image name in asset catalogue"
background.zPosition = 1 // 1st layer
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
addChild(background)
To add sprites on top of the background you would do this
let sprite1 = SKSpriteNode(imageNamed: "image name in asset catalogue"
sprite1.zPosition = 2 // above background
sprite1.position = ...
addChild(sprite1)
let sprite2 = SKSpriteNode(imageNamed: "image name in asset catalogue"
sprite2.zPosition = 2 // if 3 also above sprite 1
sprite2.position = ...
addChild(sprite2)
I presume this is whats causing your problem, you are adding a background but the sprites after are not visible because they are below the background.
My SKScene uses the following code to add sprites to the screen at certain time intervals, but if there is already a sprite on the screen when the next one is added my application freezes. Is there a way to add the same sprite to the screen without the application freezing?
let timer = SKAction.waitForDuration(1.00)
let addSpriteNode = SKAction.runBlock{
self.addSprite()
}
let sequence = SKAction.sequence([timer, addSpriteNode])
self.runAction(SKAction.repeatActionForever(sequence), withKey: "Sprites")
Note: I am not currently at a computer that is capable of running Xcode, so I'm going off of memory.
Note 2: If I could comment, I would ask you to include the code located in the addSprite function. However, due to a lack of reputation, I am unable to do so. You could get a much faster and accurate answer by including that code, since that is the code that creates and adds the sprite.
Answer:
You mention that you are attempting to add the same sprite to the screen - possibly like this:
let sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake(50,50))
func addSprite() {
addChild(sprite)
}
You can not have the same sprite on the screen multiple times. Instead, each time you want a new sprite to be added to the screen, you have to create a new sprite. In your addSprite function, your code should create a new sprite, set it's properties, and then add it to the main view, as so:
fun addSprite() {
let sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake(50,50)) // Creates a new sprite. You can customize this as needed.
addChild(sprite) // Adds newly created sprite to screen.
}
I hope this helps. If you post your code, I could provide an answer more tuned to your question.
I'm working on a game in Xcode/Swift for iPad/iPhone.
What I need to do is to get the outline path of an image/silhouette, so that I can animate along the outline of the image/silhouette. This to create a laser cutting like effect, the one you see in movies when they break through a door/window with a lasercutter.
Just drawing it as a Beizer path won't work since I need to do this for a bunch of images/silhouettes. If possible I would prefer just to add images to my project and do the outlining in code, that way I can easily expand with more shapes and sizes.
In SpriteKit I've tried to use a SKPhysicsBody and then use the Alpha to create the outline. This gives me that outline but not as a path, so I can't animate along that line.
Actually when enabling ".showsPhysics" I get the line I need, but still not a line I can use for animations.
Is there a way to get to use/modify the ".showsPhysics" method or to reverse the PhysicsBody to a path?
I'm coding in Swift, and any advice would be appreciated.
This is an example of what I need, I need the blue line as a path for animation.
SpriteKit has a method to create a physics body from the contents of a texture. Read bodyWithTexture:size: for more information, especially the Discussion session. You should consider the balance between the performance and the accuracy.
Given an image below, here's a simple example to use bodyWithTexture:size:,
let texture = SKTexture(imageNamed: "rex")
let rex = SKSpriteNode(imageNamed: "rex")
rex.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
rex.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
rex.physicsBody?.dynamic = false // This line is just for demo
self.addChild(rex)
Image:
Result: