Search code examples
iosswiftsprite-kitskspritenodecore-motion

How to move sprite just left or right using CoreMotion?


For this game I am creating, I want the Sprite "Character" to either move left or right by me tilting the device either left or right.

I have looked into it and changed the code, but it seems like that it does not work.

When I run it, the "Character" moves in only one direction and still goes either up or down.

I would just like the "Character" to move only left or right, not up or down.

Any help on this?

Here is a look at the GameScene.swift file:

import SpriteKit

import CoreMotion

class GameScene: SKScene {

let motionManager = CMMotionManager()

var Ground = SKSpriteNode()

var Character = SKSpriteNode()

override func didMoveToView(view: SKView) {
    /* Setup your scene here */

    Character = SKSpriteNode(imageNamed: "NinjaGhost")
    Character.physicsBody = SKPhysicsBody(circleOfRadius:    Character.size.height)
    Character.size = CGSize(width: 200, height: 200)
    Character.physicsBody?.allowsRotation = false
    Character.zPosition = 2
    Character.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
    self.addChild(Character)

    Ground = SKSpriteNode(imageNamed: "Dirt Background")
    Ground.size = CGSize(width: 1920, height: 1080)
    Ground.zPosition = 1
    Ground.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
    self.addChild(Ground)

    motionManager.startAccelerometerUpdates()
    motionManager.accelerometerUpdateInterval = 0.1
    motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue() ) {
        (data, error) in

self.physicsWorld.gravity = CGVectorMake(CGFloat((data?.acceleration.x)!) * 1, 0)
}
}







override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
   /* Called when a touch begins */

}

override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */



}







}

Solution

  • You should follow the swift guidelines, your properties should not start with capital letters, only classes, structs, enums and protocols should. It makes code harder to read on stack overflow (code is marked blue but shouldn't) and in general its not good practice.

    Change your code to this because there was a few errors.

     character = SKSpriteNode(imageNamed: "NinjaGhost")
     character.size = CGSize(width: 200, height: 200) // Better to call this before positioning
     character.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2) // Give pos before physics body
     character.physicsBody = SKPhysicsBody(circleOfRadius: character.size.width / 2) // You have to divide by 2 when using circleOfRadius to get proper size in relation to the sprite
     character.physicsBody?.allowsRotation = false
     character.physicsBody?.affectedByGravity = false // Stop falling
     character.zPosition = 2
     self.addChild(character)
    

    In your motion queue code you are manipulating the scene itself, so that will not work.

    Try this code instead which uses the physics body to move the sprite. This is my preferred way of doing it because it gives the sprite more natural movement, especially when changing direction, compared to directly manipulating the sprites position property (If you want to manipulate the sprite position property directly than read this article. http://www.ioscreator.com/tutorials/move-sprites-accelerometer-spritekit-swift)

       if let error = error { // Might as well handle the optional error as well
              print(error.localizedDescription)
              return
       }
    
       guard let data = motionManager.accelerometerData else { return }
       if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft {
            character.physicsBody?.applyForce(CGVectorMake(-100 * CGFloat(data.acceleration.y), 0))
        } else {
            character.physicsBody?.applyForce(CGVectorMake(100 * CGFloat(data.acceleration.y), 0))
        }
    

    This will make the sprite move on the x axis. I am using data.acceleration.y because in this example the game is in landscape so you have to use the Y data to move it on the x axis.

    I am also checking in which landscape orientation the device is so that the motion works in both orientations.

    Adjust the 100 here to get the desired force depending on the size of the sprite (higher is more force). Big sprites properly need a few 1000s to move.