skip to Main Content

I’m a fairly new app dev and very new to Sprite Kit. I am creating a game where I want a ball to always fall downward as if it were in gravity. This is just a 2d app so all I want is when the ball is falling, when you tilt the phone to the left, the ball travels down and left onscreen and if you tilt the phone to the right, the ball travels down and right onscreen. To give a better picture of what I want I made a quick diagram in photoshop:

Ball falling diagram

I would just like some opinions on which is the easiest and best way to do this. My first thought was record the yaw and use it to dictate how far the ball travels left or right. This would require some calculations to get the ball to fall perfectly at 90 degrees and although it sounds possible to me, I’m not sure if it is actually possible.

Does anybody think this is the way to do it or is there a better way to this?

A problem I came across when trying out my first idea was when I tilt the phone, the ball moved left and right (without any proper calculations, so it was entirely inaccurate), I would tilt the phone to the left (for example) and the further I tilted it, the less sensitive it became, so the ball would travel left less. This would prevent my idea from working and I’m not sure if there’s a way around it.

A bigger problem I encountered was when I swivelled around in my seat, the yaw would change too! I assume this has something to do with the compass since neither the roll or pitch changed as I did this. I’m sure something can be done to correct this because I never have this problem with games I play that use the gyroscope. If somebody could point me in the right direction with that, I’d be grateful, or I might just ask it in a separate new question. Below is another diagram I quickly drew up in photoshop to help with explaining the problem. Diagram 1 is the way I want to be able to tilt the phone but when you turn around (diagram 2) the ball moves left or right depending on how far you turn. (Yes, that is meant to be a person holding the phone in diagram 2)

phone tilt diagram

Help would be greatly appreciated!

3

Answers


  1. Here is some code I yanked from a demo project I built a while ago. It was a piece of rope created by connecting a bunch of views with UIKit Dynamics. Based on your description, I believe the behavior was the same as what you are looking for.

    A caveat is that this code follows the true direction of gravity, so if you set your phone down flat, the gravity will be 0 or close to 0 in the plane parallel to the screen, because its full magnitude will be along the z axis. You may want to normalize it so the direction changes but the magnitude remains constant.

    In this sample, self.gravity is a UIGravityBehavior, but you could use the same code to feed any kind of gravity simulation you want. Just log out the values inside the motion manager handler to see what kind of values you are likely to be getting.

    self.motionManager = [[CMMotionManager alloc] init];
    [self.motionManager startDeviceMotionUpdatesToQueue:self.motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error) {
        CMAcceleration gravity = motion.gravity;
        dispatch_async(dispatch_get_main_queue(), ^{
            self.gravity.gravityDirection = CGVectorMake(gravity.x, -gravity.y);
        });
    }];
    

    I hope this helps!

    Login or Signup to reply.
  2. Here’s a solution with SpriteKit:

    1.Create a new SpriteKit Project
    enter image description here

    2.Add the CoreMotion Framework

    enter image description here

    3.import the new framework in your ‘MyScene’ class:

    #import <CoreMotion/CoreMotion.h>
    

    4.Example is optimized for this orientation:

    enter image description here

    5.Add this code to the ‘touchesBegan’ method of the ‘MyScene’ class

        sprite.size = CGSizeMake(20, 20);
        sprite.physicsBody= [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
    

    6.Add this code to the ‘update’ method of the ‘MyScene’ class

    CMMotionManager *_motionManager;
    -(void)update:(CFTimeInterval)currentTime {
        /* Called before each frame is rendered */
        if (_motionManager== nil) {
            _motionManager=[[CMMotionManager alloc]init];
            _motionManager.deviceMotionUpdateInterval=0.025;
            [_motionManager startDeviceMotionUpdates];
        }
    
        CMAcceleration gravity=  _motionManager.deviceMotion.gravity;
        self.physicsWorld.gravity = CGVectorMake(gravity.y*4, -gravity.x/4);
    
    }
    

    You have to play around to find the optimal factors for the gravity.

    Hope that is usefull

    Login or Signup to reply.
  3. Swift Code:

     if motion.isDeviceMotionAvailable {
                self.motion.deviceMotionUpdateInterval = 1.0 / 60.0
                self.motion.showsDeviceMovementDisplay = true
                self.motion.startDeviceMotionUpdates(using: .xMagneticNorthZVertical)
                // Configure a timer to fetch the motion data.
                self.timer = Timer(fire: Date(), interval: (1.0/60.0), repeats: true,
                                   block: { (timer) in
                                    if let data = self.motion.deviceMotion {
                                      let gravityData = data.gravity
                                      scene.physicsWorld.gravity = CGVector(dx: 9.8 * (gravityData.x), dy: 9.8 * (gravityData.y))
                                    }
                })
                // Add the timer to the current run loop.
                RunLoop.current.add(self.timer, forMode: .defaultRunLoopMode)
              }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search