Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Set velocity for distance

I'm trying to make a moving platform on Swift and, in order to make the player move together with the platform, I needed to change the self.moveByX(), which was much simpler, to the physicsBody?.velocity (and add some friction to both platform and player).

So, I made a function like this:

self.runAction(
    SKAction.repeatActionForever(
        SKAction.sequence([
            SKAction.runBlock({
                print(self.position.x)
                self.physicsBody?.velocity = CGVectorMake(20, 0.0)
            }),
            SKAction.waitForDuration(3),
            SKAction.runBlock({
                print(self.position.x)
                self.physicsBody?.velocity = CGVectorMake(-20, 0.0)
            }),
            SKAction.waitForDuration(3)
        ])
    )
)

The problem is that I expected the difference between the positions to be exactly 60 (20 * 3s), but I'm receiving logs of the platform x position like this:

596.042907714844
544.228393554688
596.048950195312
544.234008789062
596.054565429688
544.116333007812
595.936584472656
544.121887207031
595.942199707031
544.127685546875
595.824584960938
544.009704589844

So, the difference between the positions is something between 51~52

How do I make the platform move in a specific and exact distance by changing the velocity?

Edit: I don't know if this is relevant, but I've set the platform's physics body like this:

self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
self.physicsBody?.categoryBitMask = PhysicsCategory.Ground
self.physicsBody?.contactTestBitMask = PhysicsCategory.Player
self.physicsBody?.collisionBitMask = PhysicsCategory.Player
self.physicsBody?.allowsRotation = false
self.physicsBody?.affectedByGravity = false
self.physicsBody?.dynamic = true
self.physicsBody?.friction = 1.0
self.physicsBody?.restitution = 0.0
self.physicsBody?.mass = 99999999999
like image 712
Sergio Toledo Piza Avatar asked Mar 02 '16 16:03

Sergio Toledo Piza


1 Answers

I haven't worked with Sprite Kit before but I think your problem is that the linearDamping property of an SKPhysicsBody is set by default to 0.1, with a quick calculation (20*3-20*3*0.1 = 54) this sounds about right if the velocity if being damped every frame.

Here is the documentation for the property:

https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/index.html#//apple_ref/occ/instp/SKPhysicsBody/linearDamping

Edit: I thought I should check my answer at least so I wrote a quick (rough) program:

var dampingOccurancesPerSecond = 60.0 //Corresponds to frame rate
var numberOfSeconds = 3.0
var time = 0.0

@IBAction func test(sender: UIButton) {
    let result = checkDistanceForVelocity(20, damping: 0.1, distanceTraveled: 0.0)
    print(result)
}

 func checkDistanceForVelocity(velocity: Double, damping: Double, distanceTraveled: Double) -> Double {

    if time < numberOfSeconds {

        time += 1/dampingOccurancesPerSecond

        let newVelocity = velocity - (velocity * damping/dampingOccurancesPerSecond)

        let newDistance = (distanceTraveled + velocity/dampingOccurancesPerSecond)

        return checkDistanceForVelocity(newVelocity, damping: damping, distanceTraveled: newDistance)

    }

    return distanceTraveled

}

The small variations on your traveled distance is also likely due to small changes in your frame rate. When the dampingOccurancesPerSecond changes from 60 -> 50 the total distance traveled changes from 52.1203109538336 -> 51.8808576268828

Hope this helped!!

like image 156
Olivier Wilkinson Avatar answered Oct 06 '22 18:10

Olivier Wilkinson