6

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

iamburak
  • 3,508
  • 4
  • 34
  • 65
  • 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 Dec 08 '16 at 11:03
  • @SteveIves My anchor point 0.5 so -474 for that size is not mean ball goes outside of the left side screen? – iamburak Dec 08 '16 at 11:16

3 Answers3

3

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.

Confused
  • 6,048
  • 6
  • 34
  • 75
  • is this an overflow? Also, perhaps simpler may be to set a cap limit on the ball's velocity... checking in update if it's over a threshold, then resetting it / capping it. This would seem like something Apple should have already implemented... – Fluidity Dec 08 '16 at 16:06
  • 1
    @Fluidity added a bit to answer to explain what I mean by pincing – Confused Dec 08 '16 at 18:08
  • 1
    This is an issue a lot of first time physics users come up against, not realising that they need to commit to using physics, or using algorithmic motion controls. The two don't mix very well... the physics system often suffers at the hands of the infinite force that algorithmically motivated objects have. All puns intended. – Confused Dec 08 '16 at 18:11
  • So there is a difference between .move and .applyForce? Ok. Oh! That makes sense, because .move doesn't need a pb. So it would be best to just use one or the other.. rght? – Fluidity Dec 08 '16 at 18:17
  • 1
    If using physics, best to use physics for everything... less problems, but there will be times when traditional "go here, do this" animation is required. Elevators and lifts are one example where it's often best to use "moveTo" etc. @Fluidity – Confused Dec 08 '16 at 18:37
2

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.

Steve Ives
  • 7,894
  • 3
  • 24
  • 55
  • He could set up a quick check in `update` to spit out an error message if the ball goes outside of the border. I don't see how the ball could go through the wall if they are at the same zposition and collision... Other than a glitch. – Fluidity Dec 08 '16 at 10:33
  • @Fluidity, yea - I did think of that but if something else is happening and the sprite it getting removed from the scene, the the check may not fire. But my way will produce LOADS of log messages and if it take a while to reproduce the problem, it may not be practical. Maybe do a check to see if ball.frame 'intersects' self.frame and if not, then print the ball's position. – Steve Ives Dec 08 '16 at 10:41
  • 1
    @Fluidity I've definitely seen fast-moving objects move through a boundary physicsBody in the simulator (but yes, a glitch) - not sure if I've seen if on a device. But if the ball doesn't collide with the boundary, then it won't move, so it's possible for the ball and the boundary to overlap, and then the physics engine will try to make then NOT overlap and it might move the ball to the wrong side of the border. – Steve Ives Dec 08 '16 at 10:43
  • 1
    Worth bearing in mind that if bodyA is set to contact bodyB, there is no need to have bodyB contact bodyA. However, for collisions, things are different if a collision set up is not reciprocated (i.e. bodyA collides with bodyB but the results of the collision will be different depending upon if bodyB collides with bodyA or not). – Steve Ives Dec 08 '16 at 10:48
  • Can you elaborate that last comment? – Fluidity Dec 08 '16 at 10:53
  • 1
    I have attached some updates, ball goes outside from left side of the device using 6S. @Fluidity I will try your prompt now. – iamburak Dec 08 '16 at 10:54
  • @Fluidity For contacts (ie..e you want didBegin(contact: ) to be called when 2 sprites touch, you just need a correct contact setup (contactTestBitMask etc) for one sprite with the other - there is no need to have the other sprite to also contact the first one. However, for collisions, imagine 2 balls that collide with each other. Each ball that is set to collide with the other will 'bounce off' the ball it is set to collide with. If they collide with each other, both bounce off. If one does and the other doesn't, one bounces off and the other goes straight on as though it hit nothing. – Steve Ives Dec 08 '16 at 10:58
  • @SteveIves It's `ball.position.x` in update function. – iamburak Dec 08 '16 at 11:03
  • @tobeiosdev It does look like the ball is going through the border. Try setting the ball to collide with the border (create a new category, assign this to border's categoryBitMask and add this to ball's collisionBitMask). – Steve Ives Dec 08 '16 at 11:05
  • @tobeiosdev i just updated my code with position.x and position.y, my bad – Fluidity Dec 08 '16 at 11:05
  • @SteveIves thanks, that makes a bit more sense now. I've mostly been working with RPG and text games so I haven't got the collision down 100% yet. – Fluidity Dec 08 '16 at 11:07
  • @Fluidity I have a sample project on SO for playing with contacts and collisions - see this answer http://stackoverflow.com/a/40424041/1430420 – Steve Ives Dec 08 '16 at 11:10
  • @Fluidity Check my last attachment, I caught fatal error. – iamburak Dec 08 '16 at 11:30
2

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

Fluidity
  • 3,985
  • 1
  • 13
  • 34
  • @tobeiosdev ok. So your ball is definitely going through the wall. Did you try replacing the `fatalError` with the reset ball code I suggested? You could also try making the walls thicker (put another node as a wall on each border) – Fluidity Dec 08 '16 at 11:39
  • As you can see my game GameScene, How Can I thicken the wall in this case? please detail more . – iamburak Dec 08 '16 at 11:51
  • yes this fatal error coming from your latest editing advice. – iamburak Dec 08 '16 at 11:52
  • @tobeiosdev see my last code block.. .replace the `fatalError` with `ball.position = lastBallLocation`.. .also, I added a picture showing the border walls I made in the scene editor – Fluidity Dec 08 '16 at 12:01
  • self.frame is bigger than the screen. I think the ball is stuck in the bottom left-hand corner, off the screen. Implement collisions between the ball and the border. How big is the ball? – Steve Ives Dec 08 '16 at 12:08