I'm currently working on my first test game in which the player have to jump over some randomly generated bars.
I wrote a func which should generate the bars outside of my scene.
My problem at the moment is that when I'm trying to call the created bars with "self.childNode(withName:)" xCode is telling me "Fatal error: Unexpectedly found nil while unwrapping an Optional value".
I've already read the Apple Documentation for "childNode(withName:)" and added "//" before the name of the node. In addition I used the stackoverflow search but I can't find anything that solved my problem.
//
// GameScene.swift
// PlaxerJump
//
//
import SpriteKit
import AVFoundation
class GameScene: SKScene {
let bottom1 = SKSpriteNode(imageNamed: "Bottom")
let bottom2 = SKSpriteNode(imageNamed: "Bottom")
let player = SKSpriteNode(imageNamed: "Player")
var velocity = CGFloat(0)
var onGround = true
var value = CGFloat(5)
override func didMove(to view: SKView) {
// Hintergrund
self.backgroundColor = SKColor.lightGray
bottom1.anchorPoint = CGPoint.zero
bottom1.position = CGPoint.zero
bottom1.zPosition = 1
self.addChild(bottom1)
bottom2.anchorPoint = CGPoint.zero
bottom2.position = CGPoint(x: bottom1.size.width - 1, y: 0)
bottom2.zPosition = 1
self.addChild(bottom2)
// Spieler
player.position = CGPoint(x: player.size.width / 2 + 20, y: bottom1.size.height + player.size.height / 2)
player.zPosition = 2
self.addChild(player)
//Balken
addBalken(xScale: 1.5, yScale: 1, name: "ba1", xPoint: 0)
}
func addBalken(xScale: CGFloat, yScale: CGFloat, name: String, xPoint: CGFloat) {
let balken = SKSpriteNode(imageNamed: "Balken")
balken.anchorPoint = CGPoint.zero
balken.position = CGPoint(x: self.size.width + (2 * balken.size.width) + xPoint, y: bottom1.size.height - 16)
balken.zPosition = 1
balken.xScale = xScale
balken.yScale = yScale
balken.name = name
addChild(balken)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if onGround == true {
velocity = -16
onGround = false
self.run(SKAction.playSoundFileNamed("Jump.wav", waitForCompletion: false))
}
}
override func update(_ currentTime: TimeInterval) {
//Player
player.zRotation -= CGFloat(Double.pi * 5) / 180
velocity += 0.6
player.position.y -= velocity
if player.position.y <= bottom1.size.height {
player.position.y = bottom1.size.height
velocity = 0
onGround = true
}
//Bottom
bottom1.position.x -= 4
bottom2.position.x -= 4
if bottom1.position.x < -bottom1.size.width {
bottom1.position.x = bottom2.position.x + bottom2.size.width
} else if bottom2.position.x < -bottom2.size.width {
bottom2.position.x = bottom1.position.x + bottom1.size.width
}
//Balken - ** THIS IS THE PART WHERE THE ERROR OCCURS **
let balke1 = self.childNode(withName: "//ba1") as! SKSpriteNode
balke1.position.x -= value
if balke1.position.x < self.size.width {
balke1.position.x = self.size.width + (2 * balke1.size.width)
value = CGFloat(arc4random_uniform(UInt32(value)))
}
}
}
I just want to call the node so I can use it to implement the bars in the game.
Change this line of code:
addBalken(xScale: 1.5, yScale: 1, name: "//ba1", xPoint: 0)
to:
addBalken(xScale: 1.5, yScale: 1, name: "ba1", xPoint: 0)
The // only applies when searching for the node, so keep these characters in this line:
let balke1 = self.childNode(withName: "//ba1") as! SKSpriteNode
EDIT:
I think the root cause of your problem is that you forgot to call addChild in your addBalken function. Simply creating a node isn't enough. The node must also be added to the scene as well. So this is the final code:
func addBalken(xScale: CGFloat, yScale: CGFloat, name: String, xPoint: CGFloat) {
let balken = SKSpriteNode(imageNamed: "Balken")
balken.anchorPoint = CGPoint.zero
balken.position = CGPoint(x: self.size.width + (2 * balken.size.width) + xPoint, y: bottom1.size.height - 16)
balken.zPosition = 1
balken.xScale = xScale
balken.yScale = yScale
balken.name = name
//add the node to the scene
addChild(balken)
}
I've create a SKNode with physicsBody edgeFromLoop circular inside which i've added 8 small circular nodes. and 8 circular nodes are moving with CMMotionManager inside Parent circular node. with fast motion shake some balls disappears from screen. SKScene Class given below
Balls only disappears when anyone shake mobile hard randomly.
There are 8 balls initially but after some hard shake reduced.
class GameScene: SKScene {
let motionManager = CMMotionManager()
var Circle = SKShapeNode(circleOfRadius: 108)
var sound = SKAction.playSoundFileNamed(getRandomSound(), waitForCompletion: false)
var collisionBitmasks: [UInt32] = [UInt32]()
override func didMove(to view: SKView) {
Circle.fillTexture = SKTexture.init(image: UIImage.init(named: "img_Ball") ?? UIImage())
Circle.position = CGPoint.init(x: 0, y: 0)
Circle.name = "defaultCircle"
Circle.lineWidth = 0.0
Circle.fillColor = SKColor.lightGray.withAlphaComponent(0.8)
Circle.physicsBody = SKPhysicsBody.init(edgeLoopFrom: UIBezierPath.init(ovalIn: CGRect.init(x: Circle.frame.minX + 12,
y: Circle.frame.minY + 12,
width: Circle.frame.width - 24,
height: Circle.frame.height - 24)).cgPath)
Circle.physicsBody?.isDynamic = true
Circle.physicsBody?.affectedByGravity = false
Circle.physicsBody?.allowsRotation = false
addChild(Circle)
self.physicsWorld.contactDelegate = self
startAcceleroMeter()
for index in 1...8 {
addBalls(index)
}
}
func stop() {
motionManager.stopAccelerometerUpdates()
Circle.children.forEach { (ball) in
ball.physicsBody?.isDynamic = false
ball.physicsBody?.affectedByGravity = false
}
}
func startAcceleroMeter() {
Circle.children.forEach { (ball) in
ball.physicsBody?.isDynamic = true
ball.physicsBody?.affectedByGravity = true
}
motionManager.startAccelerometerUpdates()
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdates(to: .main) { (motionData, error) in
let gravity = CGVector.init(dx: (motionData?.acceleration.x ?? 0.0) * 20, dy: (motionData?.acceleration.y ?? 0.0) * 20)
print(gravity)
self.physicsWorld.gravity = gravity
}
}
func stopPlaying() -> [String] {
var dictionary = [String]()
for (_, ball) in (Circle.children).enumerated() {
dictionary.append("\(ball.position.x), \(ball.position.y), 0.0")
}
return dictionary
}
func addBalls(_ ballNo: Int) {
let ball = SKShapeNode.init(circleOfRadius: 12)
ball.name = "ball\(ballNo)"
ball.fillTexture = SKTexture.init(linearGradientWithAngle: CGFloat.pi, colors: [BallColors(rawValue: ballNo)?.toUIColor(false) ?? UIColor(), BallColors(rawValue: ballNo)?.toUIColor(true) ?? UIColor()], locations: [0, 1], size: ball.frame.size)
ball.fillColor = UIColor.white
ball.physicsBody = SKPhysicsBody.init(circleOfRadius: 12)
ball.physicsBody?.isDynamic = true
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.allowsRotation = true
ball.physicsBody?.friction = 0.2
ball.physicsBody?.restitution = 0.9
ball.physicsBody?.linearDamping = 0.1
ball.physicsBody?.angularDamping = 0.1
ball.physicsBody?.mass = 0.349065870046616
ball.physicsBody?.usesPreciseCollisionDetection = true
ball.position = CGPoint(x: Circle.frame.midX - CGFloat(ballNo), y: Circle.frame.midY - CGFloat(ballNo))
ball.physicsBody?.fieldBitMask = 1
ball.physicsBody?.categoryBitMask = UInt32.init(ballNo + 100)
let collisionBitMask = UInt32.init(ballNo + 20) | UInt32.init(ballNo + 100)
collisionBitmasks.append(collisionBitMask)
ball.physicsBody?.collisionBitMask = collisionBitMask //To be different for each
ball.physicsBody?.contactTestBitMask = UInt32.init(ballNo + 20)
Circle.addChild(ball)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
if collisionBitmasks.contains(contact.bodyA.collisionBitMask) && collisionBitmasks.contains(contact.bodyB.collisionBitMask) {
run(sound)
}
}
}
You need a hidden magic here. Each small ball adds a constraint that can prevent any accident from high speeds:
ball.constraints = [SKConstraint.distance(SKRange(upperLimit: 108 - 12), to: Circle)]
Here is the entire coded
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var logo: UIImageView!
#IBOutlet weak var gameOver: UIImageView!
#IBAction func Play(_ sender: Any) { //What Happens After you click the "Play" button
tapsValid = true
ballChange = true
self.gameOver.isHidden = true
self.retry.isHidden = true
self.Ball.isHidden = false
self.logo.isHidden = true
self.Play.isHidden = true
self.scoreBoard.isHidden = true
self.Ball.center.x = 178.0
self.Ball.center.y = 390.0
self.pillar.center = CGPoint(x: 175.0,y: 436.0)
self.pillar2.center = CGPoint(x: 214.0,y: 407.0)
timer = Timer.scheduledTimer(timeInterval: 0.045, target: self, selector: #selector(ViewController.movement), userInfo: nil, repeats: true)
self.pillar3.center = pillarPlacement(x: pillar2.center.x, y: pillar2.center.y)
self.pillar4.center = pillarPlacement(x: pillar3.center.x, y: pillar3.center.y)
self.pillar5.center = pillarPlacement(x: pillar4.center.x, y: pillar4.center.y)
self.pillar6.center = pillarPlacement(x: pillar5.center.x, y: pillar5.center.y)
self.pillar7.center = pillarPlacement(x: pillar6.center.x, y: pillar6.center.y)
self.pillar8.center = pillarPlacement(x: pillar7.center.x, y: pillar7.center.y)
self.pillar9.center = pillarPlacement(x: pillar8.center.x, y: pillar8.center.y)
self.pillar10.center = pillarPlacement(x: pillar9.center.x, y: pillar9.center.y)
self.pillar.isHidden = false
self.pillar2.isHidden = false
self.pillar3.isHidden = false
self.pillar4.isHidden = false
self.pillar5.isHidden = false
self.pillar6.isHidden = false
self.pillar7.isHidden = false
self.pillar8.isHidden = false
self.pillar9.isHidden = false
self.pillar10.isHidden = false
self.pillarTop.isHidden = false
self.pillarTop2.isHidden = false
self.pillarTop3.isHidden = false
}
#IBAction func Retry(_ sender: Any) {
}
#IBOutlet var gameView: UIView!
#IBOutlet weak var pillar10: UIImageView!
#IBOutlet weak var pillar9: UIImageView!
#IBOutlet weak var pillar8: UIImageView!
#IBOutlet weak var pillar7: UIImageView!
#IBOutlet weak var pillar6: UIImageView!
#IBOutlet weak var pillar5: UIImageView!
#IBOutlet weak var pillar4: UIImageView!
#IBOutlet weak var pillar3: UIImageView!
#IBOutlet weak var pillar2: UIImageView!
#IBOutlet weak var pillar: UIImageView!
#IBOutlet weak var pillarTop3: UIImageView!
#IBOutlet weak var pillarTop2: UIImageView!
#IBOutlet weak var pillarTop: UIImageView!
#IBOutlet weak var Play: UIButton!
var timer = Timer()
var tapsValid:Bool?
var ballRight:Bool?
var ballChange:Bool?
var ballCenter: CGPoint?
var pillarCenter: CGPoint?
var pillar2Center: CGPoint?
var pillar3Center: CGPoint?
var pillar4Center: CGPoint?
var pillar5Center: CGPoint?
var pillar6Center: CGPoint?
var pillar7Center: CGPoint?
var pillar8Center: CGPoint?
var pillar9Center: CGPoint?
var pillar10Center: CGPoint?
var pillarTopCenter: CGPoint?
var pillarTop2Center: CGPoint?
var pillarTop3Center: CGPoint?
#IBOutlet weak var scoreBoard: UIImageView!
#IBOutlet weak var retry: UIButton!
#IBOutlet weak var Ball: UIImageView!
//Start Screen
override func viewDidLoad() {
super.viewDidLoad()
self.gameOver.isHidden = true
self.retry.isHidden = true
self.Ball.isHidden = true
self.logo.isHidden = false
self.Play.isHidden = false
self.scoreBoard.isHidden = true
self.Ball.isHidden = true
self.pillar.isHidden = true
self.pillar2.isHidden = true
self.pillar3.isHidden = true
self.pillar4.isHidden = true
self.pillar5.isHidden = true
self.pillar6.isHidden = true
self.pillar7.isHidden = true
self.pillar8.isHidden = true
self.pillar9.isHidden = true
self.pillar10.isHidden = true
self.pillarTop.isHidden = true
self.pillarTop2.isHidden = true
self.pillarTop3.isHidden = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if tapsValid == true
{
if ballRight == true
{
ballChange = false
} else
{
ballChange = true
}
}
}
func movement()
{
ballCenter = self.Ball.center
pillarCenter = self.pillar.center
pillar2Center = self.pillar2.center
pillar3Center = self.pillar3.center
pillar4Center = self.pillar4.center
pillar5Center = self.pillar5.center
pillar6Center = self.pillar6.center
pillar7Center = self.pillar7.center
pillar8Center = self.pillar8.center
pillar9Center = self.pillar9.center
pillar10Center = self.pillar10.center
if ballChange == false
{
ballRight = false
} else
{
ballRight = true
}
if ballRight == true
{
Ball.center.x += 6.5
Ball.center.y -= 0.5
}else
{
Ball.center.x -= 6.5
Ball.center.y -= 0.5
}
Ball.center.y += 0.5
pillar.center.y += 5.0
pillar2.center.y += 5.0
pillar3.center.y += 5.0
pillar4.center.y += 5.0
pillar5.center.y += 5.0
pillar6.center.y += 5.0
pillar7.center.y += 5.0
pillar8.center.y += 5.0
pillar9.center.y += 5.0
pillar10.center.y += 5.0
pillar.center = movePillarUp(floatx: pillar.center.x, floaty: pillar.center.y, pillarNumber: 1)
pillar2.center = movePillarUp(floatx: pillar2.center.x, floaty: pillar2.center.y, pillarNumber: 2)
pillar3.center = movePillarUp(floatx: pillar3.center.x, floaty: pillar3.center.y, pillarNumber: 3)
pillar4.center = movePillarUp(floatx: pillar4.center.x, floaty: pillar4.center.y, pillarNumber: 4)
pillar5.center = movePillarUp(floatx: pillar5.center.x, floaty: pillar5.center.y, pillarNumber: 5)
pillar6.center = movePillarUp(floatx: pillar6.center.x, floaty: pillar6.center.y, pillarNumber: 6)
pillar7.center = movePillarUp(floatx: pillar7.center.x, floaty: pillar7.center.y, pillarNumber: 7)
pillar8.center = movePillarUp(floatx: pillar8.center.x, floaty: pillar8.center.y, pillarNumber: 8)
pillar9.center = movePillarUp(floatx: pillar9.center.x, floaty: pillar9.center.y, pillarNumber: 9)
pillar10.center = movePillarUp(floatx: pillar10.center.x, floaty: pillar10.center.y, pillarNumber: 10)
}
func movePillarUp(floatx: CGFloat, floaty: CGFloat, pillarNumber: Int) -> (CGPoint)
{
var center = CGPoint(x: floatx,y: floaty)
if checkPillarPosition(y: floaty) == true
{
switch pillarNumber
{
case 1:
gameView.sendSubview(toBack: pillar)
center = pillarPlacement(x: self.pillar10.center.x, y: self.pillar10.center.y)
break
case 2:
gameView.sendSubview(toBack: pillar2)
center = pillarPlacement(x: self.pillar.center.x, y: self.pillar.center.y)
break
case 3:
gameView.sendSubview(toBack: pillar3)
center = pillarPlacement(x: self.pillar2.center.x, y: self.pillar2.center.y)
break
case 4:
gameView.sendSubview(toBack: pillar4)
center = pillarPlacement(x: self.pillar3.center.x, y: self.pillar3.center.y)
break
case 5:
gameView.sendSubview(toBack: pillar5)
center = pillarPlacement(x: self.pillar4.center.x, y: self.pillar4.center.y)
break
case 6:
gameView.sendSubview(toBack: pillar6)
center = pillarPlacement(x: self.pillar5.center.x, y: self.pillar5.center.y)
break
case 7:
gameView.sendSubview(toBack: pillar7)
center = pillarPlacement(x: self.pillar6.center.x, y: self.pillar6.center.y)
break
case 8:
gameView.sendSubview(toBack: pillar8)
center = pillarPlacement(x: self.pillar7.center.x, y: self.pillar7.center.y)
break
case 9:
gameView.sendSubview(toBack: pillar9)
center = pillarPlacement(x: self.pillar8.center.x, y: self.pillar8.center.y)
break
case 10:
gameView.sendSubview(toBack: pillar10)
center = pillarPlacement(x: self.pillar9.center.x, y: self.pillar9.center.y)
break
default:
break
}
}
return(center)
}
func checkPillarPosition(y: CGFloat) -> (Bool)
{
var low = false
if y>720
{
low = true
}
return(low)
}
override func viewDidLayoutSubviews()
{
if let newBallCenter = ballCenter{
self.Ball.center = newBallCenter
}
if let newPillarCenter = pillarCenter{
self.pillar.center = newPillarCenter
}
if let newPillar2Center = pillar2Center{
self.pillar2.center = newPillar2Center
}
if let newPillar3Center = pillar3Center{
self.pillar3.center = newPillar3Center
}
if let newPillar4Center = pillar4Center{
self.pillar4.center = newPillar4Center
}
if let newPillar5Center = pillar5Center{
self.pillar5.center = newPillar5Center
}
if let newPillar6Center = pillar6Center{
self.pillar6.center = newPillar6Center
}
if let newPillar7Center = pillar7Center{
self.pillar7.center = newPillar7Center
}
if let newPillar8Center = pillar8Center{
self.pillar8.center = newPillar8Center
}
if let newPillar9Center = pillar9Center{
self.pillar9.center = newPillar9Center
}
if let newPillar10Center = pillar10Center{
self.pillar10.center = newPillar10Center
}
if let newPillarTopCenter = pillarTopCenter{
self.pillarTop.center = newPillarTopCenter
}
if let newPillarTop2Center = pillarTop2Center{
self.pillarTop2.center = newPillarTop2Center
}
if let newPillarTop3Center = pillarTop3Center{
self.pillarTop3.center = newPillarTop3Center
}
}
// This Function Places the Pillars
func pillarPlacement(x:CGFloat , y:CGFloat ) -> (CGPoint)
{
var pillarNewX:CGFloat
var pillarNewY:CGFloat
var random:Int = Int(arc4random() % 2)
if random == 1
{
pillarNewX = x + 39
pillarNewY = y - 29
if pillarNewX >= 319
{
pillarNewX = x-40
pillarNewY = y-30
}
}
else
{
pillarNewX = x - 40
pillarNewY = y - 30
if pillarNewX <= 17
{
pillarNewX = x+39
pillarNewY = y-29
}
}
var newPillarCenter = CGPoint(x: pillarNewX,y: pillarNewY)
return(newPillarCenter)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The problem pops up here
func movement()
{
ballCenter = self.Ball.center
pillarCenter = self.pillar.center
pillar2Center = self.pillar2.center
pillar3Center = self.pillar3.center
pillar4Center = self.pillar4.center
pillar5Center = self.pillar5.center
pillar6Center = self.pillar6.center
pillar7Center = self.pillar7.center
pillar8Center = self.pillar8.center
pillar9Center = self.pillar9.center
pillar10Center = self.pillar10.center
if ballChange == false
{
ballRight = false
} else
{
ballRight = true
}
if ballRight == true
{
Ball.center.x += 6.5
Ball.center.y -= 0.5
}else
{
Ball.center.x -= 6.5
Ball.center.y -= 0.5
}
Ball.center.y += 0.5
pillar.center.y += 5.0
pillar2.center.y += 5.0
pillar3.center.y += 5.0
pillar4.center.y += 5.0
pillar5.center.y += 5.0
pillar6.center.y += 5.0
pillar7.center.y += 5.0
pillar8.center.y += 5.0
pillar9.center.y += 5.0
pillar10.center.y += 5.0
pillar.center = movePillarUp(floatx: pillar.center.x, floaty: pillar.center.y, pillarNumber: 1)
pillar2.center = movePillarUp(floatx: pillar2.center.x, floaty: pillar2.center.y, pillarNumber: 2)
pillar3.center = movePillarUp(floatx: pillar3.center.x, floaty: pillar3.center.y, pillarNumber: 3)
pillar4.center = movePillarUp(floatx: pillar4.center.x, floaty: pillar4.center.y, pillarNumber: 4)
pillar5.center = movePillarUp(floatx: pillar5.center.x, floaty: pillar5.center.y, pillarNumber: 5)
pillar6.center = movePillarUp(floatx: pillar6.center.x, floaty: pillar6.center.y, pillarNumber: 6)
pillar7.center = movePillarUp(floatx: pillar7.center.x, floaty: pillar7.center.y, pillarNumber: 7)
pillar8.center = movePillarUp(floatx: pillar8.center.x, floaty: pillar8.center.y, pillarNumber: 8)
pillar9.center = movePillarUp(floatx: pillar9.center.x, floaty: pillar9.center.y, pillarNumber: 9)
pillar10.center = movePillarUp(floatx: pillar10.center.x, floaty: pillar10.center.y, pillarNumber: 10)
}
Specifically this line
pillar9.center = movePillarUp(floatx: pillar9.center.x, floaty: pillar9.center.y, pillarNumber: 9)
Any help would be appreciated. Sorry If this question was already asked, but, I could not find it anywhere. I am new to Swift and XCode, so if you could go into some depth of what I am doing wrong, that would be lovely and extremely helpful. Thank you for all the help!
Aside from there being a breakpoint set (which should be checked first, of course!) you have a lot of repeated code which can be a great source of errors. Not having your entire project I can't test it all but I've simplified it quite a bit by using an array to hold your pillar UIImageView objects:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var logo: UIImageView!
#IBOutlet weak var gameOver: UIImageView!
#IBAction func Play(_ sender: Any) { //What Happens After you click the "Play" button
tapsValid = true
ballChange = true
self.gameOver.isHidden = true
self.retry.isHidden = true
self.Ball.isHidden = false
self.logo.isHidden = true
self.Play.isHidden = true
self.scoreBoard.isHidden = true
self.Ball.center.x = 178.0
self.Ball.center.y = 390.0
timer = Timer.scheduledTimer(timeInterval: 0.045, target: self, selector: #selector(ViewController.movement), userInfo: nil, repeats: true)
// verify that we have more than 2 pillars before we use subscripts
guard pillars.count > 2 else { return }
self.pillars[0].isHidden = false
self.pillars[0].center = CGPoint(x: 175.0,y: 436.0)
self.pillars[1].center = CGPoint(x: 214.0,y: 407.0)
var last = self.pillars[1]
for pillar in self.pillars.suffix(from: 2) {
last.isHidden = false
pillar.center = pillarPlacement(center: last.center)
last = pillar
}
}
#IBAction func Retry(_ sender: Any) {
}
// outlet collection
#IBOutlet var pillars: [UIImageView]!
#IBOutlet var gameView: UIView!
#IBOutlet weak var pillarTop3: UIImageView!
#IBOutlet weak var pillarTop2: UIImageView!
#IBOutlet weak var pillarTop: UIImageView!
#IBOutlet weak var Play: UIButton!
var timer = Timer()
var tapsValid:Bool?
var ballRight:Bool?
var ballChange:Bool?
var ballCenter: CGPoint?
var pillarTopCenter: CGPoint?
var pillarTop2Center: CGPoint?
var pillarTop3Center: CGPoint?
#IBOutlet weak var scoreBoard: UIImageView!
#IBOutlet weak var retry: UIButton!
#IBOutlet weak var Ball: UIImageView!
//Start Screen
override func viewDidLoad() {
super.viewDidLoad()
self.gameOver.isHidden = true
self.retry.isHidden = true
self.Ball.isHidden = true
self.logo.isHidden = false
self.Play.isHidden = false
self.scoreBoard.isHidden = true
self.Ball.isHidden = true
self.pillarTop.isHidden = true
self.pillarTop2.isHidden = true
self.pillarTop3.isHidden = true
// set the whole collection at once
self.pillars.forEach { $0.isHidden = true }
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if tapsValid == true
{
if ballRight == true
{
ballChange = false
} else
{
ballChange = true
}
}
}
func movement()
{
ballCenter = self.Ball.center
if ballChange == false
{
ballRight = false
} else
{
ballRight = true
}
if ballRight == true
{
Ball.center.x += 6.5
Ball.center.y -= 0.5
} else
{
Ball.center.x -= 6.5
Ball.center.y -= 0.5
}
Ball.center.y += 0.5
// move all the pillars
pillars.forEach(movePillarUp)
}
func movePillarUp(pillar: UIImageView)
{
pillar.center.y += 5.0
if pillar.center.y > 720
{
gameView.sendSubview(toBack: pillar)
pillar.center = pillarPlacement(center: pillar.center)
}
}
override func viewDidLayoutSubviews()
{
if let newBallCenter = ballCenter{
self.Ball.center = newBallCenter
}
if let newPillarTopCenter = pillarTopCenter{
self.pillarTop.center = newPillarTopCenter
}
if let newPillarTop2Center = pillarTop2Center{
self.pillarTop2.center = newPillarTop2Center
}
if let newPillarTop3Center = pillarTop3Center{
self.pillarTop3.center = newPillarTop3Center
}
}
// This Function Places the Pillars
func pillarPlacement(center: CGPoint) -> CGPoint
{
var newCenter = center
if Int(arc4random() % 2) == 1
{
newCenter.x += 39
newCenter.y -= 29
if newCenter.x >= 319
{
newCenter.x -= 40
newCenter.y -= 30
}
}
else
{
newCenter.x -= 40
newCenter.y -= 30
if newCenter.x <= 17
{
newCenter.x += 39
newCenter.y -= 29
}
}
return newCenter
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can connect to the pillars outlet collection the same way you do a normal outlet, it will appear under the heading "Outlet Connections". The order in which you add the connections will determine the index of each connection. Now all of your pillars can be under one collection and can be handled at once using loops and other methods. This will reduce code size, decrease the chance of errors, and allow for easier development.
Please test this code and see if it clears up your issue.
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)
}
This is a part of GameScene.swift.
I want to make Background and Lives auto sizable. This is the code that works only for iPad. I want that it can work on iPhone and I don't know how to do, because of the function createLives.
import SpriteKit
import AVFoundation
class GameScene: SKScene {
var scoreLabel: SKLabelNode!
var score: Int = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
var livesImages = [SKSpriteNode]()
var lives = 3
var activeSliceBG: SKShapeNode!
var activeSliceFG: SKShapeNode!
var activeSlicePoints = [CGPoint]()
var swooshSoundActive = false
override func didMoveToView(view: SKView) {
let background = SKSpriteNode(imageNamed:"sliceBackground")
background.position = CGPoint(x: 512, y: 384)
background.blendMode = .Replace
background.zPosition = -10
addChild(background)
physicsWorld.gravity = CGVector(dx: 0, dy: -6)
physicsWorld.speed = 0.85
createScore()
createLives()
createSlices()
}
func createScore(){
scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
scoreLabel.text = "Score: 0"
scoreLabel.horizontalAlignmentMode = .Left
scoreLabel.fontSize = 48
addChild(scoreLabel)
}
func createLives() {
for i in 0 ..< 3 {
let spriteNode = SKSpriteNode(imageNamed: "sliceLife")
spriteNode.position = CGPoint(x: CGFloat(834 + (i * 70)), y: 720)
addChild(spriteNode)
livesImages.append(spriteNode)
}
}