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