6
votes

enter image description here

I'm new with sprite kit. I have tried simple ball bouncing game with 2 player, another is tracking the ball slowly. But I have discovered a problem. When I move the line to ball (with edge) ball disappearing from the screen. Another times not a problem, ball bouncing. What is the problem?

I have one GameScene, sks and ViewController. My sprite nodes coming from sks. If someone explain this case. It would be better. I have attached what I did below.

My GameScene:

class GameScene: SKScene {

var ball = SKSpriteNode()
var enemy = SKSpriteNode()
var main = SKSpriteNode()

override func didMove(to view: SKView) {

    ball = self.childNode(withName: "ball") as! SKSpriteNode
    enemy = self.childNode(withName: "enemy") as! SKSpriteNode
    main = self.childNode(withName: "main") as! SKSpriteNode

    ball.physicsBody?.applyImpulse(CGVector(dx: -20, dy: -20))
    ball.physicsBody?.linearDamping = 0
    ball.physicsBody?.angularDamping = 0

    let border = SKPhysicsBody(edgeLoopFrom: self.frame)
    border.friction = 0
    border.restitution = 1

    self.physicsBody = border

}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    for touch in touches {

        let location = touch.location(in: self)
        main.run(SKAction.moveTo(x: location.x, duration: 0.2))
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    for touch in touches {

        let location = touch.location(in: self)
        main.run(SKAction.moveTo(x: location.x, duration: 0.2))
    }

}

override func update(_ currentTime: TimeInterval) {
    // Called before each frame is rendered

    enemy.run(SKAction.moveTo(x: ball.position.x, duration: 0.5))
}

View controller:

class GameViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    if let view = self.view as! SKView? {
        // Load the SKScene from 'GameScene.sks'
        if let scene = SKScene(fileNamed: "GameScene") {
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFill

            // Present the scene
            view.presentScene(scene)
        }

        view.ignoresSiblingOrder = true


    }
}

override var prefersStatusBarHidden: Bool {
    return true
}

Pad settings:

pad

Ball settings:

ball

Some updates

I have tried some messages in update function, then encountered with same case ball goes outside from left side of the device (using iPhone 6S)

enter image description here

enter image description here

2016-12-08 14:27:54.436485 Pong[14261:3102941] fatal error: ball out of left bounds: file

enter image description here

3
what is -474.846...? Is this an x or y position? Does every error message have this same number or did they start about 0? Is this on a device or in the simulator?Steve Ives
@SteveIves My anchor point 0.5 so -474 for that size is not mean ball goes outside of the left side screen?iamburak

3 Answers

3
votes

You're pinching the ball against the wall, with the enemy. This means that the force is eventually enough to create enough speed of ball movement/force to overcome the physics system, so it pops through the wall. If you make your enemy stop before it pinces the ball against the wall, you should be fine.

This 'pincing' is occurring because of this line of code:

enemy.run(SKAction.moveTo(x: ball.position.x, duration: 0.5))

This is making the enemy chase the ball, which is a good idea for a ball game, but for the way it's being moved is wrong. Using an Action means the enemy has infinite force applied to it, and is aiming for the middle of the ball.

So when the ball gets to the wall, it's stopped against a physics object with infinite static force, then this enemy comes along and applies infinite force from the other side... and the ball either pops inside the bounds of the enemy, or over the other side of the wall, because it's being crushed by infinite forces.

So you either need to take very good care of how you control the enemy with Actions, or use forces to control the enemy, as these won't be infinite, and the physics system will be able to push back on the enemy.

2
votes

How easy is it to reproduce the problem? In update(), print the ball's position to see where it is when it has 'disappeared'. (this will produce a lot of output, so be warned).

From what you've posted, it doesn't look like the ball is set to collide with the border, meaning the ball will not react (i.e. bounce off) the border and the border itself is immobile (as it's an edge-based physics body). This, combined with a high ball velocity (from a hard hit) might make it possible that you have hit the ball so hard with the 'main' sprite that it's gone through the border - using preciseCollisionDetection=true might resolve this but give the border a category first and add this to the ball's collisionBitMask.

2
votes

here is an example of what Steve is saying (in your .update())

if ball.position.x > frame.maxX { fatalError(" ball out of right bounds") }
if ball.position.x < frame.minX { fatalError(" ball out of left bounds") }
if ball.position.y > frame.maxY { fatalError(" ball out of top bounds") }
if ball.position.y < frame.minY { fatalError(" ball out of bottom bounds) }

you could also just spam your debug window:

print(ball.position)

This will help you to find out what is going on--if your ball is flying through the boundary, or if it's getting destroyed somewhere, or some other possible bug.

As a workaround (for now) I would just replace the above "fatalError" with "ball.position = CGPoint(x: 0, y: 0)" or some other position to "reset" the ball in case of it getting lost.

You could even store it's last position in a variable, then restore it to that should the above if-statements trigger.

var lastBallLocation = CGPoint(x: 0, y: 0) // Just to initialize
override func update( prams ) {
  if ball.position.x > frame.maxX { ball.position = lastBallLocation }
  // .. copy the other three cases
  lastBallLocation = ball.position // update only on successful position

Or, you could try making the walls thicker (use a shape node or spritenode and lay them on the outside of the frame such as the walls of a house, and your view on screen is the "room")

make sure to give SKSpriteNode a physics body so will bounce off the red blocks

each wall also has a physics body for bouncing:

enter image description here