3

I have been trying to create a simple SpriteKit app using Swift. The purpose is to have a red ball re-locate itself on the screen when clicked on. But the variables self.frame.width and self.frame.height do not return the boundaries of the visible screen. Instead they return boundaries of the whole screen. Because I am choosing the location of the ball at random I need the visible boundaries. Couldn't find an answer after hours of research. How can I achieve this?

var dot = SKSpriteNode()
let dotScreenHeightPercantage = 10.0
let frameMarginSize = 30.0

override func didMoveToView(view: SKView) {

    var dotTexture = SKTexture(imageNamed: "img/RedDot.png")
    dot = SKSpriteNode(texture: dotTexture)
    dot.size.height = CGFloat( Double(self.frame.height) / dotScreenHeightPercantage )
    dot.size.width = dot.size.height
    dot.name = "dot"

    reCreateDot()
}

func reCreateDot() {
    dot.removeFromParent()

    let dotRadius = Double(dot.size.height / 2)
    let minX = Int(frameMarginSize + dotRadius)
    let maxX = Int(Double(self.frame.width) - frameMarginSize - dotRadius)
    let minY = Int(frameMarginSize + dotRadius)
    let maxY = Int(Double(self.frame.height) - frameMarginSize - dotRadius)
    let corX = randomInt(minX, max: maxX)
    let corY = randomInt(minY, max: maxY)
    println("result: \(corX) \(corY)")
    dot.position = CGPoint(x: corX, y: corY)

    self.addChild(dot)
}

func randomInt(min: Int, max:Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    for touch: AnyObject in touches {
        let location = touch.locationInNode(self)
        let node = nodeAtPoint(location)
        if node.name == "dot" {
            println("Dot tapped.")
            reCreateDot()
        }
    }
}

ball falling of frame

orkun1675
  • 171
  • 1
  • 8

2 Answers2

12

Adding this bit of code to the GameViewController seems to have fixed the issue.

            /* Set the scale mode to scale to fit the window */
            scene.scaleMode = .AspectFill
            scene.size = skView.bounds.size
            skView.presentScene(scene)

Thank you @ABakerSmith for pointing me in the right direction.

orkun1675
  • 171
  • 1
  • 8
  • 1
    I may be wrong, but isn't this equivalent to setting scaleMode to .ResizeFill, which automatically sets the scene size to the view size anyway? If the view size is set to the same size as the view the scaleMode property almost becomes redundant given the point of it is to control how the scene is scaled to the view which only matters if they are different sizes. Ie I suspect if you changed scale mode from .AspectFill to .AspectFit, or to anything else it would not have any effect. – Weyland Yutani Aug 29 '16 at 10:49
6

I tried with your code and setting the size of the scene fixed the issue. If you're unarchiving the scene, its size will be the size set in the sks file. Therefore you need to set the size of the scene to the size of your SKView.

if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
    scene.size = skView.frame.size
    skView.presentScene(scene)
}

or in didMoveToView of your SKScene subclass:

override func didMoveToView(view: SKView) {
     super.didMoveToView(view)
     self.size = view.frame.size
}
ABakerSmith
  • 22,759
  • 9
  • 68
  • 78