ApplyImpulse has an exponential effect on how much it pushes the object

131 views Asked by At

In this simple physics simulation there is a bit of odd behaviour. The applyImpulse is applied every 5 seconds, but each time this happens the box shoots up even higher, even though the same value is used for the applyImpulse. After about 20 seconds, the box is shooting up very high.

The box has a small red box attached to it, which is where the impulse is applied.

PHOTOS CAPTURED:

THIS IS THE CODE:

import SpriteKit

enum collisionType: UInt32 {
    case obj = 0b1 //1
    case bottom = 0b10 //2
}

var cam: SKCameraNode?
var screenSize = CGSize()

class GameScene: SKScene, SKPhysicsContactDelegate {

    let obj = SKSpriteNode(color: .white, size: CGSize(width: 50, height: 50))
    var camBottom = SKSpriteNode()
    let block = SKSpriteNode(color: .red, size: CGSize(width: 25, height: 25))

Then in override func didMove(to view: SKView):

    screenSize = self.size
    camBottom = SKSpriteNode(color: .gray, size: CGSize(width: ((3/2) * screenSize.width), height: 200))
    physicsWorld.contactDelegate = self

    cam = SKCameraNode()
    self.camera = cam
    addChild(cam!)

    camBottom.position.y = -screenSize.height/2 + camBottom.size.height/2
    camBottom.zPosition = -1
    addChild(camBottom)
    camBottom.addPhysicsBody(category: .bottom, collision: nil, contact: .obj, isDynamic: false, gravity: false, rotation: false)
    camBottom.physicsBody?.restitution = 0.0
    camBottom.physicsBody?.isResting = true
    camBottom.physicsBody?.friction = 1.0

    addChild(obj)
    block.position = CGPoint(x: -30, y: -obj.size.height/2)
    obj.addChild(block)

    obj.physicsBody = SKPhysicsBody(bodies: [SKPhysicsBody(rectangleOf: obj.size, center: obj.position), SKPhysicsBody(rectangleOf: block.size, center: block.position)])
    obj.physicsBody?.categoryBitMask = collisionType.obj.rawValue
    obj.physicsBody?.collisionBitMask = collisionType.bottom.rawValue
    obj.physicsBody?.contactTestBitMask = collisionType.bottom.rawValue
    obj.physicsBody?.affectedByGravity = true
    obj.physicsBody?.allowsRotation = true

    runAutomation()

    let wait = SKAction.wait(forDuration: 0.01)
    let act = SKAction.run {
        self.updateCam()
    }
    run(SKAction.repeatForever(SKAction.sequence([wait, act])))

.addPhysicsBody is an extension defined in a new Swift file, it is this:

extension SKSpriteNode {
func addPhysicsBody(category: collisionType, collision: collisionType?, contact: collisionType?, isDynamic: Bool, gravity: Bool, rotation: Bool) {
    self.physicsBody = SKPhysicsBody(rectangleOf: self.size)
    self.physicsBody?.categoryBitMask = category.rawValue
    if collision != nil {
        self.physicsBody?.collisionBitMask = (collision?.rawValue)!
    } else {
        self.physicsBody?.collisionBitMask = 0
    }
    if contact != nil {
        self.physicsBody?.contactTestBitMask = (contact?.rawValue)!
    } else {
        self.physicsBody?.contactTestBitMask = 0
    }
    self.physicsBody?.isDynamic = isDynamic
    self.physicsBody?.affectedByGravity = gravity
    self.physicsBody?.allowsRotation = rotation
}
}

Then the functions defined in the GameScene:

func updateCam() {
    let val: CGFloat = 15
    let xDist = (obj.position.x - (camera?.position.x)!)/val
    let yDist = (obj.position.y - (camera?.position.y)!)/val
    camera?.position.x += xDist
    camera?.position.y += yDist
}

func runAutomation() {
    let wait = SKAction.wait(forDuration: 5.0)
    let act = SKAction.run {
        print("Before", self.obj.physicsBody?.velocity)
        self.obj.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 30), at: self.block.position)
        print("After", self.obj.physicsBody?.velocity)
    }
    run(SKAction.repeatForever(SKAction.sequence([wait, act])))
}

override func update(_ currentTime: TimeInterval) {
    // Called before each frame is rendered
    camBottom.position.x = (camera?.position.x)!
}

It is very odd, I'm not sure if it is intentional. Nevertheless, how can I make it so that each time the impulse is applied, the box flies up about the same distance? What is the correct method?

Thank you

1

There are 1 answers

2
Retterdesdialogs On

It looks like you are applying the impulse from the self.block.position with

self.obj.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 30), at: self.block.position)

At some point your object is not on the same position like before. So it will apply the same impulse but from another position. Maybe you want self.obj.position instead of self.block.position or just use

self.obj.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 30))

To let it jump higher you have set the dy to a higher value.