how to shorten grid game in swift - swift
I am making a grid game in swift where there is a five by five grid of squares and they each are a skspritenode and when the player moves on them they turn to a different color.
This is what i have done so far
import SpriteKit
class GameScene: SKScene {
var alive = Bool()
var targetColors = Array<UIColor>()
var permanent = Array<Bool>()
var has3Colors = Array<Bool>()
var secondColors = Array<UIColor>()
var positions = Array<CGPoint>()
var startColors = Array<UIColor>()
var circle = SKSpriteNode()
var completedSquares = Int()
var started = Bool()
var squares = Array<SKSpriteNode>()
var square1 = SKSpriteNode(imageNamed: "SquareTile")
var square2 = SKSpriteNode(imageNamed: "SquareTile")
var square3 = SKSpriteNode(imageNamed: "SquareTile")
var square4 = SKSpriteNode(imageNamed: "SquareTile")
var square5 = SKSpriteNode(imageNamed: "SquareTile")
var square6 = SKSpriteNode(imageNamed: "SquareTile")
var square7 = SKSpriteNode(imageNamed: "SquareTile")
var square8 = SKSpriteNode(imageNamed: "SquareTile")
var square9 = SKSpriteNode(imageNamed: "SquareTile")
var square10 = SKSpriteNode(imageNamed: "SquareTile")
var square11 = SKSpriteNode(imageNamed: "SquareTile")
var square12 = SKSpriteNode(imageNamed: "SquareTile")
var square13 = SKSpriteNode(imageNamed: "SquareTile")
var square14 = SKSpriteNode(imageNamed: "SquareTile")
var square15 = SKSpriteNode(imageNamed: "SquareTile")
var square16 = SKSpriteNode(imageNamed: "SquareTile")
var square17 = SKSpriteNode(imageNamed: "SquareTile")
var square18 = SKSpriteNode(imageNamed: "SquareTile")
var square19 = SKSpriteNode(imageNamed: "SquareTile")
var square20 = SKSpriteNode(imageNamed: "SquareTile")
var square21 = SKSpriteNode(imageNamed: "SquareTile")
var square22 = SKSpriteNode(imageNamed: "SquareTile")
var square23 = SKSpriteNode(imageNamed: "SquareTile")
var square24 = SKSpriteNode(imageNamed: "SquareTile")
var square25 = SKSpriteNode(imageNamed: "SquareTile")
var basicSize = CGSize()
var columb1 = CGFloat()
var columb2 = CGFloat()
var columb3 = CGFloat()
var columb4 = CGFloat()
var columb5 = CGFloat()
var row1 = CGFloat()
var row2 = CGFloat()
var row3 = CGFloat()
var row4 = CGFloat()
var row5 = CGFloat()
var targetColor = UIColor()
var isPermanent = Bool()
var hasThreeColors = Bool()
var secondColor = UIColor()
var position1 = CGPoint()
var startColor = UIColor()
var square = SKSpriteNode()
override func didMove(to view: SKView) {
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if started == false{
started = true
start()
for i in 0 ... 24{
targetColor = targetColors[i]
isPermanent = permanent[i]
hasThreeColors = has3Colors[i]
secondColor = secondColors[i]
position1 = positions[i]
startColor = startColors[i]
square = squares[i]
createSquare(targetColor: targetColor, permanent: isPermanent, has3Colors: hasThreeColors, secondColor: secondColor, position: position1, startColor: startColor, newSquare: square)
}
self.addChild(square1)
self.addChild(square2)
self.addChild(square3)
self.addChild(square4)
self.addChild(square5)
self.addChild(square6)
self.addChild(square7)
self.addChild(square8)
self.addChild(square9)
self.addChild(square10)
self.addChild(square11)
self.addChild(square12)
self.addChild(square13)
self.addChild(square14)
self.addChild(square15)
self.addChild(square16)
self.addChild(square17)
self.addChild(square18)
self.addChild(square19)
self.addChild(square20)
self.addChild(square21)
self.addChild(square22)
self.addChild(square23)
self.addChild(square24)
self.addChild(square25)
}
circle.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
func createSquare(targetColor: UIColor, permanent: Bool, has3Colors: Bool, secondColor: UIColor, position: CGPoint, startColor:UIColor, newSquare: SKSpriteNode){
var border = SKSpriteNode()
var firstTouch = Bool()
border = SKSpriteNode(imageNamed: "BorderTile")
newSquare.size = basicSize
newSquare.position = position
newSquare.color = startColor
border.size = newSquare.size
border.position = newSquare.position
firstTouch = true
self.addChild(border)
if permanent{
border.color = targetColor
}else{
let targetColor1 = targetColor.darker()
border.color = targetColor1
}
func start(){
basicSize = CGSize(width: self.frame.width / 7, height: self.frame.width / 7)
createCircle()
getArrays()
}
func getArrays(){
rowsAndColumbs()
squares = [square1,square2,square3,square4,square5,square6,square7,square8,square8,square10,square11,square12,square13,square14,square15,square16,square17,square1,square19,square20,square21,square22,square23,square24,square25]
positions = [CGPoint(x: row1,y:columb1),CGPoint(x: row1,y:columb2),CGPoint(x: row1,y:columb3),CGPoint(x: row1,y:columb4),CGPoint(x: row1,y:columb5),CGPoint(x: row2,y:columb1),CGPoint(x: row2,y:columb2),CGPoint(x: row2,y:columb3),CGPoint(x: row2,y:columb4),CGPoint(x: row2,y:columb5),CGPoint(x: row3,y:columb1),CGPoint(x: row3,y:columb2),CGPoint(x: row3,y:columb3),CGPoint(x: row3,y:columb4),CGPoint(x: row3,y:columb5),CGPoint(x: row4,y:columb1),CGPoint(x: row4,y:columb2),CGPoint(x: row4,y:columb1),CGPoint(x: row4,y:columb1),CGPoint(x: row4,y:columb1),CGPoint(x: row5,y:columb1),CGPoint(x: row5,y:columb2),CGPoint(x: row5,y:columb3),CGPoint(x: row5,y:columb4),CGPoint(x: row5,y:columb5)]
loadLvl1()
}
func loadLvl1(){
var targetColors1 = Array<UIColor>()
var permanent1 = Array<Bool>()
var has3Colors1 = Array<Bool>()
var secondColors1 = Array<UIColor>()
var startColors1 = Array<UIColor>()
targetColors1 = [.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green,.green]
permanent1 = [true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]
secondColors1 = [.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear,.clear]
has3Colors1 = [false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]
startColors1 = [.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue,.blue]
var lvl1Array = Array<Array<Any>>()
lvl1Array = [targetColors1,permanent1,has3Colors1,secondColors1,startColors1]
targetColors = lvl1Array[0] as! Array<UIColor>
permanent = lvl1Array[1] as! Array<Bool>
has3Colors = lvl1Array[2] as! Array<Bool>
secondColors = lvl1Array[3] as! Array<UIColor>
startColors = lvl1Array[4] as! Array<UIColor>
}
func rowsAndColumbs(){
columb1 = CGFloat( basicSize.width * 1.5)
columb2 = CGFloat( basicSize.width * 2.5)
columb3 = CGFloat( basicSize.width * 3.5)
columb4 = CGFloat( basicSize.width * 4.5)
columb5 = CGFloat( basicSize.width * 5.5)
row1 = CGFloat( basicSize.height * 5.5)
row1 = CGFloat( basicSize.height * 4.5)
row1 = CGFloat( basicSize.height * 3.5)
row1 = CGFloat( basicSize.height * 2.5)
row1 = CGFloat( basicSize.height * 1.5)
}
func createCircle(){
circle = SKSpriteNode(imageNamed: "Circle")
circle.size = CGSize(width: self.frame.width / 7, height: self.frame.width / 7)
circle .position = CGPoint(x: 50, y: 50)
self.addChild(circle)
//alive = true
}
override func update(_ currentTime: TimeInterval) {}
// Called before each frame is rendered
}
What i have done is there is a function that uses an array of arrays of values to make the grid but i know there would be a better way to do this and shorten it but i don't know how. I have considered structs but still they would be really long sense i have so any values and i know there is a better way to do this so can someone tell me.
Well, I'll just give you one hint. Think about replacing this:
var columb1 = CGFloat()
var columb2 = CGFloat()
var columb3 = CGFloat()
var columb4 = CGFloat()
var columb5 = CGFloat()
// ...
columb1 = CGFloat( basicSize.width * 1.5)
columb2 = CGFloat( basicSize.width * 2.5)
columb3 = CGFloat( basicSize.width * 3.5)
columb4 = CGFloat( basicSize.width * 4.5)
columb5 = CGFloat( basicSize.width * 5.5)
with this:
var columns : [CGFloat] = (1...5).map {basicSize.width * (CGFloat($0) + 0.5)}
Do you see the difference? I don't just mean the fact that we've reduced 10 lines to 1 line. I mean that we completely eliminated columb1, columb2, and so on — instead, we are using one variable, an array, and we're using it as an array.
You have a feeling something is wrong, and you're quite right. There is no need for all your intermediate variables with numbers on the end of the name. Throw them all away. An array serves exactly that purpose; that is what an array is — a name together with a number (the index number) that references one of many values. Use patterns, loops, and arrays for storage; that is what basic programming is.
You have a number of arrays that contain 25 items, one for each square. What you really need is a class or struct that represents a square that has the properties held by those arrays:
class Square {
var node = SKSpriteNode(imageNamed: "SquareTile")
var startColor = UIColor.blue
var secondColor = UIColor.clear
var targetColor = UIColor.green
var permanent = true
var has3Colors = false
}
// create the array of squares
var squares = (1...25).map { _ in Square() }
// add the nodes as children of self
squares.forEach { self.addChild($0.node) }
You then access each square by index: square[0], square[1], all the way to square[24].
The properties are accessed like square[0].startColor and square[7].has3Colors.
Related
Swift spritekit didbegincontact being called with delay
This is my GameScene code. class GameScene: SKScene, SKPhysicsContactDelegate { let orcWidth = UIScreen.main.bounds.width / 5 var orcCategory:UInt32 = 0x1 << 0 var knightCategory:UInt32 = 0x1 << 1 private var orc = SKSpriteNode() private var knight = SKSpriteNode() private var orcWalkingFrames: [SKTexture] = [] private var knightIdleFrames: [SKTexture] = [] private var knightAttackFrame: [SKTexture] = [] var background = SKSpriteNode(imageNamed: "game_background1") override func didMove(to view: SKView) { physicsWorld.contactDelegate = self physicsWorld.gravity = CGVector(dx: 0, dy: 0) setupbackground() startGame() } func setupbackground() { background.zPosition = 0 background.size = self.frame.size background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2) addChild(background) } func startGame() { buildRandomOrcs() buildKnight() } func stopGame() { } func buildOrc(yposition: CGFloat) { var orcWalkFrames: [SKTexture] = [] let orcAnimatedAtlas = SKTextureAtlas(named: "OrcWalking") let numImages = orcAnimatedAtlas.textureNames.count for i in 0...numImages - 1 { let orcTextureName = "0_Orc_Walking_\(i)" orcWalkFrames.append(orcAnimatedAtlas.textureNamed(orcTextureName)) } self.orcWalkingFrames = orcWalkFrames let firstFrameTexture = orcWalkingFrames[0] orc = SKSpriteNode(texture: firstFrameTexture) orc.name = "orc" orc.position = CGPoint(x: frame.minX-orcWidth/2, y: yposition) self.orc.zPosition = CGFloat(self.children.count) orc.scale(to: CGSize(width: orcWidth, height: orcWidth)) orc.physicsBody = SKPhysicsBody(rectangleOf: orc.size, center: orc.position) orc.physicsBody?.affectedByGravity = false orc.physicsBody?.isDynamic = true orc.physicsBody?.categoryBitMask = orcCategory orc.physicsBody?.contactTestBitMask = knightCategory orc.physicsBody?.collisionBitMask = knightCategory addChild(orc) walkOrc() moveOrcForward() } func buildKnight() { var knightIdleFrames: [SKTexture] = [] let knightIdleAtlas = SKTextureAtlas(named: "KnightIdle") let numImages = knightIdleAtlas.textureNames.count for i in 0...numImages - 1 { let orcTextureName = "_IDLE_00\(i)" knightIdleFrames.append(knightIdleAtlas.textureNamed(orcTextureName)) } self.knightIdleFrames = knightIdleFrames let firstFrameTexture = knightIdleFrames[0] knight = SKSpriteNode(texture: firstFrameTexture) knight.name = "knight" knight.position = CGPoint(x: frame.maxX-orcWidth/2, y: frame.midY) self.knight.zPosition = 1 knight.scale(to: CGSize(width: -orcWidth, height: orcWidth)) knight.physicsBody = SKPhysicsBody(rectangleOf: knight.size, center: knight.position) knight.physicsBody?.affectedByGravity = false knight.physicsBody?.isDynamic = false knight.physicsBody?.categoryBitMask = knightCategory knight.physicsBody?.contactTestBitMask = orcCategory knight.physicsBody?.collisionBitMask = orcCategory addChild(knight) idleKnight() } func idleKnight() { knight.run(SKAction.repeatForever(SKAction.animate(with: knightIdleFrames, timePerFrame: 0.1))) } func walkOrc() { orc.run(SKAction.repeatForever(SKAction.animate(with: orcWalkingFrames,timePerFrame: 0.025))) } func moveOrcForward() { orc.run(SKAction.repeatForever(SKAction.moveBy(x: 55, y: 0, duration: 0.25))) } func buildRandomOrcs () { let wait = SKAction.wait(forDuration: TimeInterval(makeRandomNumberBetween(min: 0, max: 0))) let spawn = SKAction.run { self.buildOrc(yposition: self.makeRandomCGFloatNumber()) } let spawning = SKAction.sequence([spawn,wait]) self.run(SKAction.repeat(spawning, count: 10)) } func makeRandomCGFloatNumber() -> CGFloat { let randomNumber = arc4random_uniform(UInt32((frame.maxY-orcWidth/2) - (frame.minY+orcWidth/2))) + UInt32(frame.minY+orcWidth/2) return CGFloat(randomNumber) } func makeRandomNumberBetween (min: Int, max: Int) -> Int{ let randomNumber = arc4random_uniform(UInt32(max - min)) + UInt32(min) return Int(randomNumber) } func didBegin(_ contact: SKPhysicsContact) { let collision:UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask if collision == orcCategory | knightCategory { self.scene?.view?.isPaused = true print("COLLIDED") } } } The problem is that the scene pauses almost 2-3 seconds after the collision. I changed the position of knight and delay time changed. For example, if I set position to frame.minX+orcWidth/2 there is no delay. What is wrong with my code?
Your problem isn't things are being delayed, your problem is your bounding box is not where you think it is use view.showPhysics = true to determine where your boxes are once you realize they are in the wrong spots, go to this line knight.physicsBody = SKPhysicsBody(rectangleOf: knight.size, center: knight.position) and fix it knight.physicsBody = SKPhysicsBody(rectangleOf: knight.size) Do so for the rest of your bodies
My guess is that manipulations of SKView properties must happen on main thread, i.e. DispatchQueue.main.async { [unowned self] in self.scene?.view?.isPaused = true print("COLLIDED") }
How to update a value within a mehod?
I am new to Swift and I want to update the value with this line: circleShape.strokeEnd = CGFloat(sum) every time I click "calculate" (to get the value of sum). How can I do that? This is my code: #IBOutlet weak var centerCircle: UIImageView! var num1 = 0.0 var num2 = 0.0 var sum = 0.0 var a = 0.0 var b = 0.0 #IBOutlet weak var label1: UILabel! #IBOutlet weak var label2: UILabel! #IBOutlet weak var sumNum: UILabel! #IBAction func vote1(sender: UIButton) { num1 = Double(label1.text!)! self.label1.text = String(num1 + 1) a = num1 + 1 } #IBAction func vote2(sender: UIButton) { num2 = Double(label2.text!)! self.label2.text = String(num2 + 1) b = num2 + 1 } #IBAction func calculate(sender: AnyObject) { sum = Double(a/(b+a)) sumNum.numberOfLines = 0 sumNum.lineBreakMode = NSLineBreakMode.ByWordWrapping sumNum.text = "\(sum)" } override func viewDidLoad() { super.viewDidLoad() // round view let roundView = UIView(frame: CGRectMake(85, 100, 150, 150)) roundView.backgroundColor = UIColor.whiteColor() roundView.layer.cornerRadius = roundView.frame.size.width / 2 // bezier path let circlePath = UIBezierPath(arcCenter: CGPoint (x: roundView.frame.size.width / 2, y: roundView.frame.size.height / 2), radius: roundView.frame.size.width / 2.2 , startAngle: CGFloat(-0.5 * M_PI), endAngle: CGFloat(1.5 * M_PI), clockwise: true) // circle shape let circleShape = CAShapeLayer() circleShape.path = circlePath.CGPath circleShape.strokeColor = UIColor.blackColor().CGColor circleShape.fillColor = UIColor.clearColor().CGColor circleShape.lineWidth = 14 // set start and end values circleShape.strokeStart = 0.0 circleShape.strokeEnd = CGFloat(sum) // add sublayer roundView.layer.addSublayer(circleShape) // add subview self.view.addSubview(roundView) self.view.insertSubview(roundView, belowSubview: centerCircle) }
You need to declare circleShape as a global variable and modify its strokeEnd value in the calculate function. #IBOutlet weak var centerCircle: UIImageView! var num1 = 0.0 var num2 = 0.0 var sum = 0.0 var a = 0.0 var b = 0.0 let circleShape = CAShapeLayer() #IBOutlet weak var label1: UILabel! #IBOutlet weak var label2: UILabel! #IBOutlet weak var sumNum: UILabel! #IBAction func vote1(sender: UIButton) { num1 = Double(label1.text!)! self.label1.text = String(num1 + 1) a = num1 + 1 } #IBAction func vote2(sender: UIButton) { num2 = Double(label2.text!)! self.label2.text = String(num2 + 1) b = num2 + 1 } #IBAction func calculate(sender: AnyObject) { sum = Double(a/(b+a)) sumNum.numberOfLines = 0 sumNum.lineBreakMode = NSLineBreakMode.ByWordWrapping sumNum.text = "\(sum)" circleShape.strokeEnd = CGFloat(sum) } override func viewDidLoad() { super.viewDidLoad() // round view let roundView = UIView(frame: CGRectMake(85, 100, 150, 150)) roundView.backgroundColor = UIColor.whiteColor() roundView.layer.cornerRadius = roundView.frame.size.width / 2 // bezier path let circlePath = UIBezierPath(arcCenter: CGPoint (x: roundView.frame.size.width / 2, y: roundView.frame.size.height / 2), radius: roundView.frame.size.width / 2.2 , startAngle: CGFloat(-0.5 * M_PI), endAngle: CGFloat(1.5 * M_PI), clockwise: true) // circle shape circleShape.path = circlePath.CGPath circleShape.strokeColor = UIColor.blackColor().CGColor circleShape.fillColor = UIColor.clearColor().CGColor circleShape.lineWidth = 14 // set start and end values circleShape.strokeStart = 0.0 circleShape.strokeEnd = CGFloat(sum) // add sublayer roundView.layer.addSublayer(circleShape) // add subview self.view.addSubview(roundView) self.view.insertSubview(roundView, belowSubview: centerCircle) }
How to reference SKSpriteNode without full instantiation in Swift3?
Previously, I had been using var progressBar = ProgressBar?() right above init within one of my SKSpriteNode subclasses, to allow various methods to reference progressBar throughout the class like so: class Ship:SKSpriteNode{ var progressBar = ProgressBar?() static var shipState = "norm" var powerupOn = false var moveSpeed:CGFloat var lives:Int var canShoot = false let las = SKSpriteNode(texture:laserTexture) var gun:GenericGun = GenericGun() let scaleFactor:CGFloat = 0.07 init(startPosition startPos:CGPoint, controllerVector:CGVector){ self.lives = 3 self.moveSpeed = 160 super.init(texture: ship0, color: UIColor.clear, size: ship0.size()) //Set position self.position = startPos attachGun(gun) self.setScale(scaleFactor) self.physicsBody = SKPhysicsBody(texture: self.texture!, size: self.size) self.physicsBody?.isDynamic = true self.physicsBody?.categoryBitMask = PhysicsCategory.Ship self.physicsBody?.collisionBitMask = 0 self.physicsBody?.contactTestBitMask = PhysicsCategory.Alien self.physicsBody?.allowsRotation = false self.physicsBody?.angularVelocity = CGFloat(0) self.physicsBody?.usesPreciseCollisionDetection = true self.physicsBody?.affectedByGravity = false //TBD self.physicsBody?.velocity.dx = controllerVector.dx * moveSpeed self.physicsBody?.velocity.dy = controllerVector.dy * moveSpeed self.name = "ship" //Call animations self.animateShip1() } func updateVelocity(_ v:CGVector){ self.physicsBody?.velocity.dx = v.dx * moveSpeed self.physicsBody?.velocity.dy = v.dy * moveSpeed } func attachGun(_ gun:GenericGun){ gun.position = CGPoint(x: 0, y: 0) self.addChild(gun) } func animateShip1() { let animate = SKAction.animate(with: shipFrames, timePerFrame: 0.1) let forever = SKAction.repeatForever(animate) self.run(forever) } func updateShipProperties(shipVelocity v:CGVector,laserStartPos laserStart:CGPoint){ updateVelocity(v) progressBar?.position = CGPoint(x: self.position.x - (self.size.width/2 + self.size.width/7.0), y: self.position.y) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } In Swift3 I'm getting an error that I need to provide full arguments, is there a way to achieve this same functionality in Swift3?
Error using waitforduration function
import SpriteKit class GameScene: SKScene { var greenBall = SKSpriteNode(imageNamed: "greenball") var redBall = SKSpriteNode(imageNamed: "redball") override func didMoveToView(view: SKView) { let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame) borderBody.friction = 0 self.physicsBody = borderBody backgroundColor = SKColor.purpleColor() // var bar0 = SKSpriteNode(imageNamed: "bar0") var bar1 = SKSpriteNode(imageNamed: "bar1") var bar2 = SKSpriteNode(imageNamed: "bar2") var bar3 = SKSpriteNode(imageNamed: "bar3") var bar4 = SKSpriteNode(imageNamed: "bar4") var bar5 = SKSpriteNode(imageNamed: "bar5") var bars = SKSpriteNode(imageNamed: "bar\(arc4random_uniform(6))") var bartest = SKSpriteNode(imageNamed: "bar0") bartest.position = CGPoint(x: frame.midX, y: frame.size.height * 0.633) addChild(bartest) var barra = SKShapeNode(rectOfSize: CGSize(width: frame.size.width, height: 10)) barra.name = "bar" barra.fillColor = SKColor.whiteColor() barra.position = CGPoint(x: frame.midX, y: frame.midY) greenBall.position = CGPoint(x: frame.midX-100, y: frame.midY) greenBall.yScale = 2 greenBall.xScale = 2 redBall.position = CGPoint(x: frame.midX+100, y: frame.midY) redBall.yScale = 2 redBall.xScale = 2 self.addChild(redBall) self.addChild(greenBall) self.addChild(barra) func makeBars() { var randomTopOrBot = arc4random_uniform(2) if randomTopOrBot == 0 { var MaxY = frame.size.height * 0.951 var MinY = (frame.size.height * 0.633)-bars.size.height var Range = CGFloat(MaxY - MinY) var barsSpawnX = (frame.midX) var barSpawnY = CGFloat(arc4random_uniform(UInt32(Range))) bars.position = CGPoint(x: frame.midX, y: barSpawnY) addChild(bars) } else { var MaxY = frame.size.height * 0.951 var MinY = (frame.size.height * 0.633)-bars.size.height var Range = CGFloat(MaxY - MinY) var barsSpawnX = (frame.midX) var randomBetweenRange = CGFloat(arc4random_uniform(UInt32((Range)))) bars.position = CGPoint(x: frame.midX, y: (MinY+randomBetweenRange)) println(frame.size.height * 0.633) addChild(bars) } } let wait = SKAction.waitForDuration(3, withRange: 2) let spawn = SKAction.runBlock { makeBars <--- this is where it's saying the problem is() } let sequence = SKAction.sequence([wait, spawn]) self.runAction(SKAction.repeatActionForever(sequence)) edit: So basically I've got 2 spawn locations I'm picking from, I randomly decide between the two with a random number, and now I'm wanting to apply the timer to the function makeBars, but it's telling me I can't reference the local function This is giving me an error that says "cannot reference a local function with captures from another local function". How can I fix this?
You declared your makerbars() method inside the didMoveToView method. So it was a function nesting problem after all, given the full code I was able to see the true issue. Change your code to my modified and corrected version below: import SpriteKit class GameScene: SKScene { var greenBall = SKSpriteNode(imageNamed: "greenball") var redBall = SKSpriteNode(imageNamed: "redball") override func didMoveToView(view: SKView) { let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame) borderBody.friction = 0 self.physicsBody = borderBody backgroundColor = SKColor.purpleColor() // var bar0 = SKSpriteNode(imageNamed: "bar0") var bar1 = SKSpriteNode(imageNamed: "bar1") var bar2 = SKSpriteNode(imageNamed: "bar2") var bar3 = SKSpriteNode(imageNamed: "bar3") var bar4 = SKSpriteNode(imageNamed: "bar4") var bar5 = SKSpriteNode(imageNamed: "bar5") var bartest = SKSpriteNode(imageNamed: "bar0") bartest.position = CGPoint(x: frame.midX, y: frame.size.height * 0.633) addChild(bartest) var barra = SKShapeNode(rectOfSize: CGSize(width: frame.size.width, height: 10)) barra.name = "bar" barra.fillColor = SKColor.whiteColor() barra.position = CGPoint(x: frame.midX, y: frame.midY) greenBall.position = CGPoint(x: frame.midX-100, y: frame.midY) greenBall.yScale = 2 greenBall.xScale = 2 redBall.position = CGPoint(x: frame.midX+100, y: frame.midY) redBall.yScale = 2 redBall.xScale = 2 self.addChild(redBall) self.addChild(greenBall) self.addChild(barra) let wait = SKAction.waitForDuration(3, withRange: 2) let spawn = SKAction.runBlock { self.makeBars() } let sequence = SKAction.sequence([wait, spawn]) self.runAction(SKAction.repeatActionForever(sequence)) } func makeBars() { var bars = SKSpriteNode(imageNamed: "bar\(arc4random_uniform(6))") var randomTopOrBot = arc4random_uniform(2) if randomTopOrBot == 0 { var MaxY = frame.size.height * 0.951 var MinY = (frame.size.height * 0.633)-bars.size.height var Range = CGFloat(MaxY - MinY) var barsSpawnX = (frame.midX) var barSpawnY = CGFloat(arc4random_uniform(UInt32(Range))) bars.position = CGPoint(x: frame.midX, y: barSpawnY) addChild(bars) } else { var MaxY = frame.size.height * 0.951 var MinY = (frame.size.height * 0.633)-bars.size.height var Range = CGFloat(MaxY - MinY) var barsSpawnX = (frame.midX) var randomBetweenRange = CGFloat(arc4random_uniform(UInt32((Range)))) bars.position = CGPoint(x: frame.midX, y: (MinY+randomBetweenRange)) println(frame.size.height * 0.633) addChild(bars) } } }
SKLabel won't show up
Im making a flappy bird type game in swift using sprite kit. The game works fine but I'm trying to make a way to score the game so I set up a variable and SKLabel that adds on to itself whenever a pipe is about half way across the screen. However I cannot get the label to show up any help doing this here is my code: // flappy rainbow sheep // // Created by Heather Arnold on 3/3/15. // Copyright (c) 2015 ian arnold. All rights reserved. // import SpriteKit class GameScene: SKScene { var bird = SKSpriteNode() var pipeUpTexture = SKTexture() var pipeDownTexture = SKTexture() var PipeMoveAndRemove = SKAction() let pipeGap = 225.0 var score: Int = 0 var scoreLabel: SKLabelNode = SKLabelNode(fontNamed:"System-Bold") override func didMoveToView(view: SKView) { /* Setup your scene here */ score = 0 //Physics self.physicsWorld.gravity = CGVectorMake(0.0, -10.0); //Bird var BirdTexture = SKTexture(imageNamed:"flappysheep") BirdTexture.filteringMode = SKTextureFilteringMode.Nearest bird = SKSpriteNode(texture: BirdTexture) bird.setScale(0.5) bird.position = CGPoint(x: self.frame.size.width * 0.35, y: self.frame.size.height * 0.6) scoreLabel.position.x = 50 scoreLabel.position.y = view.bounds.height - 50 scoreLabel.text = "0" scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left scoreLabel.hidden = false self.addChild(scoreLabel) bird.physicsBody = SKPhysicsBody(circleOfRadius:bird.size.height/4.0); bird.physicsBody?.dynamic = true bird.physicsBody?.allowsRotation = false self.addChild(bird) //off screen //Ground var groundTexture = SKTexture(imageNamed:"rainbowobstacle") var sprite = SKSpriteNode(texture: groundTexture) sprite.setScale(2.0) sprite.position = CGPointMake(self.size.width/2.0, sprite.size.height/2.0) self.addChild(sprite) var ground = SKNode() ground.position = CGPointMake(0, groundTexture.size().height) ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height * 2.0)) ground.physicsBody?.dynamic = false self.addChild(ground) //Pipes //create the pipes pipeUpTexture = SKTexture(imageNamed:"rainbowpipe") pipeDownTexture = SKTexture(imageNamed:"rainbowpipe") //move pipes let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUpTexture.size().width) let movePipes = SKAction.moveByX(-2500, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove)) let removePipes = SKAction.removeFromParent() PipeMoveAndRemove = SKAction.sequence([movePipes, removePipes]) //spwan pipes let spawn = SKAction.runBlock({() in self.spawnPipes()}) let delay = SKAction.waitForDuration(NSTimeInterval(0.2)) let spawnThenDelay = SKAction.sequence([spawn, delay]) let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay) self.runAction(spawnThenDelayForever) let pipeUp = SKSpriteNode(texture:pipeUpTexture) if (pipeUp.position.x + (pipeUp.size.width / 2) < self.view!.bounds.size.width / 2) { score++ } scoreLabel.hidden = false } func spawnPipes(){ let pipePair = SKNode() pipePair.position = CGPointMake(self.frame.size.width + pipeUpTexture.size().width * 2, 0) pipePair.zPosition = -10 let height = UInt32(self.frame.size.height / 4) let y = arc4random() % height + height let pipeDown = SKSpriteNode(texture:pipeDownTexture) pipeDown.setScale(2.0) pipeDown.position = CGPointMake(0.0, CGFloat(y) + pipeDown.size.height + CGFloat(pipeGap)) pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize:pipeDown.size) pipeDown.physicsBody?.dynamic = false pipePair.addChild(pipeDown) let pipeUp = SKSpriteNode(texture:pipeUpTexture) pipeUp.setScale(2.0) pipeUp.position = CGPointMake(0.0, CGFloat(y)) pipeUp.physicsBody = SKPhysicsBody(rectangleOfSize: pipeUp.size) pipeUp.physicsBody?.dynamic = false pipePair.addChild(pipeUp) pipePair.runAction(PipeMoveAndRemove) self.addChild(pipePair) } class GameScene: SKScene { let bird = SKSpriteNode() var gameOver = false override init(size: CGSize) { super.init(size: size) self.bird.position = CGPoint(x: 0, y: 0) self.addChild(self.bird) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func endGame(){ // restart the game let gameScene = GameScene(size: self.size) self.view!.presentScene(gameScene) } override func update(currentTime: NSTimeInterval) { // our bird doesnt intersect the frame, // we use gameOver bool so we dont call endGame more than once if !self.frame.intersects(self.bird.frame) && !self.gameOver{ self.gameOver = true self.endGame() } } } override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { /* Called when a touch begins */ for touch: AnyObject in touches { let location = touch.locationInNode(self) bird.physicsBody?.velocity = CGVectorMake(0, 0) bird.physicsBody?.applyImpulse(CGVectorMake(0, 8)) } } override func update(currentTime: CFTimeInterval) { /* Called before each frame is rendered */ } }
Your label might be covered over by another image. Try setting the SKLabelNode zPosition property to a higher value. Perhaps something like 900.
Try setting the zPosition of the label to one. scoreLabel.zPosition = 1 This should make the node appear even if another node passes over it. Here are two other functions that may assist you also: scoreLabel.color = UIColor.blackColor()//set color to black - you can use any almost color here scoreLabel.fontSize = 32//changes font size to make label bigger/smaller