Search code examples
swiftanimationsprite-kitskspritenodeskphysicsbody

How can I add a physics body to an SKAtlasTexture or create an animation through Images.xcassets?


I wanted to create a small animation of a car driving down the road, so I made an atlas of 9 different pictures. The car simply looks like its wheels are rotating and the car is bouncing a bit as it drives along. I already made an SKSpriteNode with an image and added a physics body on it so that it can jump and be affected by gravity.

So I was wondering how to add either a physics body to an SKAtlasTexture or create an animation through my image.xcassets folder. I tried to just change the SKSpriteNode to SKAtlasTexture, but that obviously didn't work as there are no physics bodies in SKAtlasTexture. So that's where I'm at. Any suggestions or solutions would be greatly appreciated.

Here some parts of my code:

class PlayScene: SKScene, SKPhysicsContactDelegate {

let road = SKSpriteNode(imageNamed: "road")
var origRoadPositionX = CGFloat(0)
var maxRoad = CGFloat(0)
var groundSpeed = 3
var carBaseLine = CGFloat(0)
let car = SKSpriteNode(imageNamed: "car")




enum ColliderType:UInt32{
    case car = 1
    case tower = 2
}



override func didMoveToView(view: SKView) {
    self.backgroundColor = UIColor(hex: 0x80E8FF)

    self.physicsWorld.contactDelegate = self
    //Car
    self.car.position = CGPointMake(CGRectGetMinX(self.frame)-20 + self.car.size.width, self.carBaseLine)
    self.car.physicsBody = SKPhysicsBody (rectangleOfSize: self.car.size)
    self.car.physicsBody?.allowsRotation = false
    self.car.physicsBody?.affectedByGravity = false
    self.car.physicsBody?.categoryBitMask = ColliderType.car.rawValue
    self.car.physicsBody?.contactTestBitMask = ColliderType.tower.rawValue
    self.car.physicsBody?.collisionBitMask = ColliderType.tower.rawValue
    self.addChild(car)

If more code is needed in order to find a solution, let me know and i can supply more of it.


Solution

  • You can use atlas folder for performing animation with images.

    Consider below example:

    import SpriteKit
    
    class GameScene: SKScene {
        
        var bombFrames : [SKTexture]!
        var bomb : SKSpriteNode!
        let NoneCategory   : UInt32 = 0x1 << 0
        let ProjectileCategory  : UInt32 = 0x1 << 2
        let bombCategory : UInt32 = 0x1 << 7
        
        override func didMoveToView(view: SKView) {
            /* Setup your scene here */
            runAction(SKAction.repeatActionForever(SKAction.sequence([SKAction.runBlock(addBomb), SKAction.waitForDuration(5.0)])))
        }
        
       
        override func update(currentTime: CFTimeInterval) {
            /* Called before each frame is rendered */
        }
        
        func addBomb() {
            
            let Name = "Bomb"
            let AnimatedAtlas = SKTextureAtlas(named: Name)
            var Framese = [SKTexture]()
            let numImages = AnimatedAtlas.textureNames.count
            for var i=1; i<=numImages; i++ {
                let TextureName = "\(i)"
                Framese.append(AnimatedAtlas.textureNamed(TextureName))
            }
            bombFrames = Framese
            
            let firstFrame = bombFrames[0]
            bomb = SKSpriteNode(texture: firstFrame)
            let actualY = random(min: bomb.size.height/2, max: size.height - bomb.size.height/2)
            bomb.position = CGPoint(x: size.width + bomb.size.width/2, y: actualY)
            bomb.physicsBody = SKPhysicsBody(texture: bomb.texture, size: bomb.texture!.size())
            bomb.physicsBody?.dynamic = true
            bomb.physicsBody?.categoryBitMask = bombCategory
            bomb.physicsBody?.contactTestBitMask = ProjectileCategory
            bomb.physicsBody?.collisionBitMask = NoneCategory
            bomb.physicsBody?.usesPreciseCollisionDetection = true
            addChild(bomb)
            
            let actualDuration = random(min: CGFloat(2.0), max: CGFloat(4.0))
            let actionMove = SKAction.moveTo(CGPoint(x: -bomb.size.width/2, y: actualY), duration: NSTimeInterval(actualDuration))
            let actionMoveDone = SKAction.removeFromParent()
            bomb.runAction(SKAction.sequence([actionMove, actionMoveDone]))
            playBombAnimation()
        }
        
        func random() -> CGFloat {
            return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
        }
        
        func random(#min: CGFloat, max: CGFloat) -> CGFloat {
            return random() * (max - min) + min
        }
        
        func playBombAnimation() {
            
            bomb.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(bombFrames, timePerFrame: 0.1, resize: false, restore: true)), withKey:"bombAnimation")
        }
    }
    

    And don't forget to add atlas folder into your project navigator like this:

    enter image description here

    As you can see in code you can add physics body to your sprite. and if you want you can try this way.

    Hope this will help.