Spawning a circle in a random spot on screen

2019-03-02 17:09发布

问题:

I've been racking my brain and searching here and all over to try to find out how to generate a random position on screen to spawn a circle. I'm hoping someone here can help me because I'm completely stumped. Basically, I'm trying to create a shape that always spawns in a random spot on screen when the user touches.

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        let screenSize: CGRect = UIScreen.mainScreen().bounds
        let screenHeight = screenSize.height
        let screenWidth = screenSize.width

        let currentBall = SKShapeNode(circleOfRadius: 100)
        currentBall.position = CGPointMake(CGFloat(arc4random_uniform(UInt32(Float(screenWidth)))), CGFloat(arc4random_uniform(UInt32(Float(screenHeight)))))

        self.removeAllChildren()
        self.addChild(currentBall)
}

If you all need more of my code, there really isn't any more. But thank you for whatever help you can give! (Just to reiterate, this code kind of works... But a majority of the spawned balls seem to spawn offscreen)

回答1:

The problem there is that you scene is bigger than your screen bounds

let viewMidX = view!.bounds.midX
let viewMidY = view!.bounds.midY
print(viewMidX)
print(viewMidY)

let sceneHeight = view!.scene!.frame.height
let sceneWidth = view!.scene!.frame.width
print(sceneWidth)
print(sceneHeight)

let currentBall = SKShapeNode(circleOfRadius: 100)
currentBall.fillColor = UIColor.greenColor()

let xPosition = view!.scene!.frame.midX - viewMidX + CGFloat(arc4random_uniform(UInt32(viewMidX*2)))
let yPosition = view!.scene!.frame.midY - viewMidY + CGFloat(arc4random_uniform(UInt32(viewMidY*2)))
print(xPosition)
print(yPosition)

currentBall.position = CGPointMake(xPosition,yPosition)
view?.scene?.addChild(currentBall)

self.removeAllChildren()
self.addChild(currentBall)


回答2:

First: Determine the area that will be valid. It might not be the frame of the superview because perhaps the ball (let's call it ballView) might be cut off. The area will likely be (in pseudocode):

CGSize( Width of the superview - width of ballView , Height of the superview - height of ballView)

Once you have a view of that size, just place it on screen with the origin 0, 0.

Secondly: Now you have a range of valid coordinates. Just use a random function (like the one you are using) to select one of them.

Create a swift file with the following:

extension Int
{
    static func random(range: Range<Int>) -> Int
    {
        var offset = 0

        if range.startIndex < 0   // allow negative ranges
        {
            offset = abs(range.startIndex)
        }

        let mini = UInt32(range.startIndex + offset)
        let maxi = UInt32(range.endIndex   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

And now you can specify a random number as follows:

Int.random(1...1000) //generate a random number integer somewhere from 1 to 1000.

You can generate the values for the x and y coordinates now using this function.



回答3:

Given the following random generators:

public extension CGFloat {
    public static var random: CGFloat { return CGFloat(arc4random()) / CGFloat(UInt32.max) }

    public static func random(between x: CGFloat, and y: CGFloat) -> CGFloat {
        let (start, end) = x < y ? (x, y) : (y, x)
        return start + CGFloat.random * (end - start)
    }
}

public extension CGRect {
    public var randomPoint: CGPoint {
        var point = CGPoint()
        point.x = CGFloat.random(between: origin.x, and: origin.x + width)
        point.y = CGFloat.random(between: origin.y, and: origin.y + height)
        return point
    }
}

You can paste the following into a playground:

import XCPlayground
import SpriteKit

let view = SKView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
XCPShowView("game", view)

let scene = SKScene(size: view.frame.size)
view.presentScene(scene)

let wait = SKAction.waitForDuration(0.5)
let popIn = SKAction.scaleTo(1, duration: 0.25)
let popOut = SKAction.scaleTo(0, duration: 0.25)
let remove = SKAction.removeFromParent()

let popInAndOut = SKAction.sequence([popIn, wait, popOut, remove])

let addBall = SKAction.runBlock { [unowned scene] in
    let ballRadius: CGFloat = 25
    let ball = SKShapeNode(circleOfRadius: ballRadius)
    var popInArea = scene.frame
    popInArea.inset(dx: ballRadius, dy: ballRadius)
    ball.position = popInArea.randomPoint
    ball.xScale = 0
    ball.yScale = 0
    ball.runAction(popInAndOut)
    scene.addChild(ball)
}

scene.runAction(SKAction.repeatActionForever(SKAction.sequence([addBall, wait])))

(Just make sure to also paste in the random generators, too, or to copy them to the playground's Sources, as well as to open the assistant editor so you can see the animation.)