Randomly spawning nodes - ios

class GameScene: SKScene {
let balls = [
SKSpriteNode(imageNamed: "blueball.png"),
SKSpriteNode(imageNamed: "greenball.png"),
SKSpriteNode(imageNamed: "realredball.png"),
]
override func didMove(to view: SKView) {
spawnBalls()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for ball in balls{
ball.physicsBody = SKPhysicsBody()
ball.physicsBody?.affectedByGravity = true
}
}
func spawnBalls() {
for ball in balls{
balls[Int(arc4random_uniform(UInt32(balls.count)))]
ball.position = CGPoint(x: 0, y: 250)
ball.size = CGSize(width: 70, height: 70)
self.addChild(ball)
}
}
}
Every time my app loads the red ball spawns but it is supposed to randomly spawn either the red, blue or green ball. At first, it actually worked and would randomly spawn the red, green or blue, I don't know if i accidentally changed something but for the last two days it has just been spawning the red one.If someone could help that would be great. Thanks.

You're not actually doing anything with your random ball in spawnBalls. try this
func spawnBalls() {
let ball = balls[Int(arc4random_uniform(UInt32(balls.count)))]
ball.position = CGPoint(x: 0, y: 250)
ball.size = CGSize(width: 70, height: 70)
self.addChild(ball)
}

Related

How can I alter my code to make my sprite, which rotates in a circular orbit, jump up then back down when a user taps the screen?

I'm trying to make my orange circle sprite, which orbits in a circular motion, jump at ant point in its rotation and fall back down again when the user taps the screen but can't seem to figure out what I'm doing wrong. Please help.
I've tried taking the advice to somewhat similar post o here but have had no luck.
class GameScene: SKScene {
let sprite = SKSpriteNode(imageNamed: "circle")
let player = SKSpriteNode(imageNamed: "player")
var node2AngularDistance: CGFloat = 0
override func didMove(to view: SKView) {
backgroundColor = SKColor(red: 94.0/255, green: 63.0/255, blue: 107.0/255, alpha: 1)
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
sprite.size = CGSize(width: 150, height: 150)
sprite.position = CGPoint(x: 0,y: 0)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: 10)
player.size = CGSize(width: 100, height: 100)
player.position = CGPoint(x: 0+50, y: 0)
player.physicsBody = SKPhysicsBody(circleOfRadius: 10)
self.addChild(sprite)
self.addChild(player)
}
//dont touch blue lines that discard code and don't allow you to undo
override func update(_ currentTime: TimeInterval) {
let dt: CGFloat = 1.0/60.0 //Delta Time
let period: CGFloat = 3 //Number of seconds it takes to complete 1 orbit.
let orbitPosition = sprite.position //Point to orbit.
let orbitRadius = CGPoint(x: 150, y: 150) //Radius of orbit.
let normal = CGVector(dx:orbitPosition.x + CGFloat(cos(self.node2AngularDistance))*orbitRadius.x ,dy:orbitPosition.y + CGFloat(sin(self.node2AngularDistance))*orbitRadius.y);
self.node2AngularDistance += (CGFloat(Double.pi)*2.0)/period*dt;
if (abs(self.node2AngularDistance)>CGFloat(Double.pi)*2) {
self.node2AngularDistance = 0
}
player.physicsBody!.velocity = CGVector(dx:(normal.dx-player.position.x)/dt ,dy:(normal.dy-player.position.y)/dt);
//func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
//sprite.position = (touches.first! as! UITouch).location(in: self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
func touchDown(atPoint pos: CGPoint) {
jump()
}
func jump() {
player.texture = SKTexture(imageNamed: "player")
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 500))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos: CGPoint) {
player.texture = SKTexture(imageNamed: "player")
}
}
The expected results would be a small circle sprite called player that rotates in circular orbit around a larger circle called sprite and when the user taps the screen, the player(small circle) would jump up then back down at any point in its orbit.The actual results are the the circle rotates around the larger circle but does not jump up when I click on the screen in the iPhone simulator.
A jumpping state needs to record as : isJumpping. If isJumpping, the update will not perform, if this is what you need.
The second issue is after touching up, the player falls back to the orbital. A simple math is given here as the player directly falling to the circle.
But if the situation is complicated, you may consider to use PhysicsField to simulate the situation.
This is running in a Xcode 10 and playground
import UIKit
import PlaygroundSupport
import SpriteKit
import simd
class GameScene: SKScene {
let sprite = SKSpriteNode(imageNamed: "circle")
let player = SKSpriteNode(imageNamed: "player")
var node2AngularDistance: CGFloat = 0
override func didMove(to view: SKView) {
print(100)
// backgroundColor = SKColor(red: 94.0/255, green: 63.0/255, blue: 107.0/255, alpha: 1)
backgroundColor = SKColor.black
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
sprite.size = CGSize(width: 150, height: 150)
sprite.position = CGPoint(x: 0,y: 0)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: 10)
player.size = CGSize(width: 100, height: 100)
player.position = CGPoint(x: 0+50, y: 0)
player.physicsBody = SKPhysicsBody(circleOfRadius: 10)
self.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
self.addChild(sprite)
self.addChild(player)
}
//dont touch blue lines that discard code and don't allow you to undo
override func update(_ currentTime: TimeInterval) {
guard !isJumpping else {
return
}
let dt: CGFloat = 1.0/60.0 //Delta Time
let period: CGFloat = 3 //Number of seconds it takes to complete 1 orbit.
let orbitPosition = sprite.position //Point to orbit.
let orbitRadius = CGPoint(x: 150, y: 150) //Radius of orbit.
let currentDistance = distance(double2(x: Double(orbitPosition.x), y: Double(orbitPosition.y)), double2(x: Double(player.position.x), y: Double(player.position.y)))
if ( currentDistance > 150){
player.physicsBody!.velocity = CGVector(dx:(orbitPosition.x - player.position.x) ,dy:(orbitPosition.y - player.position.y));
let x = Double(player.position.x) - Double(orbitPosition.x)
let y = Double(player.position.y) - Double(orbitPosition.y)
self.node2AngularDistance = CGFloat(acos(x/currentDistance))
if y < 0 {
self.node2AngularDistance = 2 * CGFloat.pi - self.node2AngularDistance }
return;
}
let normal = CGVector(dx:orbitPosition.x + CGFloat(cos(self.node2AngularDistance))*orbitRadius.x ,dy:orbitPosition.y + CGFloat(sin(self.node2AngularDistance))*orbitRadius.y);
self.node2AngularDistance += (CGFloat(Double.pi)*2.0)/period*dt;
if (abs(self.node2AngularDistance)>CGFloat(Double.pi)*2) {
self.node2AngularDistance = 0
}
player.physicsBody!.velocity = CGVector(dx:(normal.dx-player.position.x)/dt ,dy:(normal.dy-player.position.y)/dt);
//func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
//sprite.position = (touches.first! as! UITouch).location(in: self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
func touchDown(atPoint pos: CGPoint) {
jump()
}
private var isJumpping : Bool = false
func jump() {
isJumpping.toggle()
player.texture = SKTexture(imageNamed: "player")
player.physicsBody?.applyImpulse(CGVector(dx: (self.player.position.x - self.sprite.position.x) / 100.0, dy: (self.player.position.y - self.sprite.position.y) / 100.0))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos: CGPoint) {
isJumpping.toggle()
player.texture = SKTexture(imageNamed: "player")
}
}
class GameViewCointroller: UIViewController{
var skview: SKView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
skview = SKView.init(frame: view.bounds)
let scene = GameScene.init(size: view.frame.size)
skview.presentScene(scene)
view.addSubview(skview)
}
}
PlaygroundPage.current.liveView = GameViewCointroller()

Trouble converting between coordinate spaces in SpriteKit

I am trying to get a SKShapeNode to follow a UITouch
My problem is that the location of the UITouch is relative to the bottom-left corner of the screen and the position of the SKShapeNode is relative to the location I gave it when I created it, the center of the screen.
For example: ball is centered at (189.0, 335.0), the center of the view. I click the ball, the location of the touch tells me the touch event occurred at (189.0, 335.0), but the ball.position will tell me (0.0, 0.0). How can I get the ball's position in the view's coordinate system?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var touched = false
var location = CGPoint.zero
var ball: SKShapeNode = SKShapeNode(circleOfRadius: 15)
var background: SKSpriteNode = SKSpriteNode(imageNamed: "background")
override func didMove(to view: SKView) {
background.size = frame.size
background.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
addChild(background)
let path = CGMutablePath()
path.addArc(center: CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2),
radius: 15,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: false)
ball = SKShapeNode(path: path) // Added to center of screen
ball.lineWidth = 1
ball.fillColor = .cyan
ball.strokeColor = .cyan
ball.glowWidth = 0.5
addChild(ball)
print(ball.position)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
moveNode()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
touched = true
for touch in touches {
location = touch.location(in: view)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
location = touch.location(in: view)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touched = false
}
func moveNode() {
if touched {
let speed: CGFloat = 1
if location.x < ball.position.x {
let newLocation = ball.position.x - speed
ball.position = CGPoint(x: newLocation, y: ball.position.y)
} else {
let newLocation = ball.position.x + speed
ball.position = CGPoint(x: newLocation, y: ball.position.y)
}
}
}
}
You never set the ball position so it is (0,0). The problem is that the ball is at (0,0) but its path represents something at (189,335) in ball coordinates.
Change to:
override func didMove(to view: SKView) {
background.size = frame.size
background.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
addChild(background)
let path = CGMutablePath()
// construct a path relative to center of the ball
path.addArc(center: CGPoint(x: 0, y: 0),
radius: 15,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: false)
ball = SKShapeNode(path: path)
// locate the ball at the center of the screen
ball.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
ball.lineWidth = 1
ball.fillColor = .cyan
ball.strokeColor = .cyan
ball.glowWidth = 0.5
addChild(ball)
print(ball.position)
}

My nodes aren't colliding

class GameScene: SKScene, SKPhysicsContactDelegate {
let balls = [
SKSpriteNode(imageNamed: "blueball.png"),
SKSpriteNode(imageNamed: "greenball.png"),
SKSpriteNode(imageNamed: "realredball.png")
]
let redRectangle = SKSpriteNode(imageNamed: "redrectangle.png")
let blueRectangle = SKSpriteNode(imageNamed: "bluerectangle.png")
let greenRectangle = SKSpriteNode(imageNamed: "greenrectangle.png")
override func didMove(to view: SKView) {
spawnBalls()
rectangles()
physicsWorld.contactDelegate = self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for ball in balls{
ball.physicsBody = SKPhysicsBody()
ball.physicsBody?.affectedByGravity = true
}
}
func spawnBalls() {
let ball = balls[Int(arc4random_uniform(UInt32(balls.count)))]
ball.physicsBody = SKPhysicsBody()
ball.physicsBody?.affectedByGravity = false
ball.position = CGPoint(x: 0, y: 250)
ball.size = CGSize(width: 70, height: 70)
ball.physicsBody?.categoryBitMask = 0
ball.physicsBody?.collisionBitMask = 1
self.addChild(ball)
}
func rectangles() {
redRectangle.position = CGPoint(x: -316.5, y: -657)
redRectangle.size = CGSize(width: 400, height: 20)
redRectangle.physicsBody = SKPhysicsBody()
redRectangle.physicsBody?.categoryBitMask = 1
redRectangle.physicsBody?.collisionBitMask = 0
blueRectangle.size = CGSize(width: 400, height: 20)
blueRectangle.position = CGPoint(x: -100, y: -657)
blueRectangle.physicsBody = SKPhysicsBody()
greenRectangle.position = CGPoint(x: 0, y: -657)
greenRectangle.size = CGSize(width: 400, height: 20)
greenRectangle.physicsBody = SKPhysicsBody()
self.addChild(redRectangle)
self.addChild(blueRectangle)
self.addChild(greenRectangle)
}
}
I want the balls to drop down and make contact with the rectangle nodes, although it looks like the balls are just going through them. I used collision and category bitmask. I'm wondering if someone could help fix this problem, thanks.
You initialise the balls correctly, but remove their physics body by creating a new one inside touchesBegan(_:). Just remove this line from the touchesBegan(_:) function:
ball.physicsBody = SKPhysicsBody()

Swift PhysicsBody not affected by Impulse

this is my first post here and i am new to iOS programming. I am using Xcode 8 and Swift 3 to build my practice game. All i want is i want to jump the ball when the screen is tapped but the impulse is not working. Here is the code i have written.
class GameScene: SKScene {
var footBall = SKSpriteNode(imageNamed: "sfb")
var Score = 0
var GameStarted = false
override func didMove(to view: SKView) {
self.removeAllChildren()
self.anchorPoint = CGPoint(x: 0.0, y: 0.0)
footBall.size = CGSize(width: 100, height: 100)
footBall.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
footBall.physicsBody = SKPhysicsBody(circleOfRadius: footBall.frame.height / 2)
footBall.physicsBody?.affectedByGravity = false
footBall.physicsBody?.allowsRotation = true
footBall.physicsBody?.isDynamic = true
self.addChild(footBall)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if(GameStarted == false){
GameStarted = true
footBall.physicsBody?.affectedByGravity = true
footBall.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
footBall.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 90))
}
else{
footBall.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
footBall.physicsBody?.applyForce(CGVector(dx: 0, dy: 90))
}
}
override func update(_ currentTime: TimeInterval) {
}
When clicked the velocity of the ball becomes zero for a moment but the impulse should drive it up which is not happening. Please help me through this and ignore any ignorance because this is my first question and i am new to this.
Please note that in the true branch you are applying a force, not an impulse.
Change:
footBall.physicsBody?.applyForce(CGVector(dx: 0, dy: 90))
to
footBall.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 90))
Don't understand why you always zero the velocity either.

As sprite moves up, more jump pads appear on screen

I am trying to make a Doodle Jump-like game. I want to make it so that as a sprite, my main character, moves above a certain Y point, more pads to jump on appear, giving it the illusion that it is jumping higher and higher.
How would I go about coding this? Any examples would be nice. I am using SpriteKit in Xcode 7.
Here is my code so far:
import SpriteKit
import Foundation
class GameScene: SKScene {
var mainSprite = SKSpriteNode()
var wallPair = SKNode()
var ground = SKSpriteNode()
var moveAndRemove = SKAction()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
mainSprite.size = CGSize(width: 30, height: 30)
mainSprite.color = SKColor.redColor();
mainSprite.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 - 100)
self.addChild(mainSprite)
ground.size = CGSize(width: self.frame.width, height: 300)
ground.color = SKColor.brownColor()
ground.position = CGPoint(x: self.frame.width / 2, y: 0)
self.addChild(ground)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
createWallMap()
for touch in touches {
let location = touch.locationInNode(self)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
func createWalls(height: CGFloat) {
wallPair = SKNode()
wallPair.name = "wallPair"
let rightWall = SKSpriteNode(imageNamed: "LeftWall.png") // I know it is opposite. Named the image wrong
let leftWall = SKSpriteNode(imageNamed: "RightWall.png")
rightWall.setScale(0.9)
leftWall.setScale(0.9)
rightWall.color = SKColor.redColor()
leftWall.color = SKColor.blueColor()
rightWall.position = CGPoint(x: self.frame.width / 2 + 340, y: height)
leftWall.position = CGPoint(x: self.frame.width / 2 - 340, y: height)
wallPair.addChild(rightWall)
wallPair.addChild(leftWall)
let randomPosition = CGFloat.random(min: -140, max: 140)
wallPair.position.x = wallPair.position.x + randomPosition
//wallPair.runAction(moveAndRemove)
self.addChild(wallPair)
}

Resources