whose view is not in the window hierarchy - swift

I am developing a game and I am trying to move from my game scene to my view controller but it gives me the error:
Warning: Attempt to present <Breakout.GameViewController: 0x7f8874d19ed0> on whose view is not in the window hierarchy!.
My game is set up so I do level 1 and finish it then it takes me to the vc where I can do level 1. That works, but then when I finish level 2 and try to go back to the vc, it does not work and gives me the error.
I have looked at other posts but nothing has directly linked to this.
My Game Scene Controller:
class Level1: SKScene,SKPhysicsContactDelegate {
var ball:SKSpriteNode!
var paddle:SKSpriteNode!
var scoreLabel:SKLabelNode!
var score:Int = 0 {
didSet{
scoreLabel.text = "Score:\(score)"
}
}
override func didMove(to view: SKView) {
ball = self.childNode(withName: "Ball") as! SKSpriteNode
paddle = self.childNode(withName: "Paddle") as! SKSpriteNode
scoreLabel = self.childNode(withName: "Score") as! SKLabelNode
ball.physicsBody?.applyImpulse(CGVector(dx: 50, dy: 50))
ball.physicsBody?.mass=0.1
let border = SKPhysicsBody(edgeLoopFrom: (view.scene?.frame)!)
border.friction = 0
self.physicsBody = border
ball.physicsBody?.mass = 0.09
self.physicsWorld.contactDelegate = self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let touchLocation = touch.location(in: self)
paddle.position.x = touchLocation.x
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let touchLocation = touch.location(in: self)
paddle.position.x = touchLocation.x
}
}
func didBegin(_ contact: SKPhysicsContact) {
let bodyAName = contact.bodyA.node?.name
let bodyBName = contact.bodyB.node?.name
if bodyAName == "Ball" && bodyBName == "Brick" || bodyAName == "Brick" && bodyBName == "Ball"{
if bodyAName == "Brick" {
contact.bodyA.node?.removeFromParent()
score += 1
} else if bodyBName == "Brick" {
contact.bodyB.node?.removeFromParent()
score += 1
}
}
}
override func update(_ currentTime: TimeInterval) {
if (score == 9) {
scoreLabel.text = "You Won!"
self.view?.isPaused = true
sleep(2)
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "GameViewController")
self.view?.window?.rootViewController?.present(vc, animated: true, completion: nil)
level1done = true
}
if (ball.position.y < paddle.position.y) {
scoreLabel.text = "You Lost!"
self.view?.isPaused = true
sleep(2)
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "GameViewController")
self.view?.window?.rootViewController?.present(vc, animated: true, completion: nil)
}
}
}

Related

SpriteKit Main Menu button issue

Wondering if you could help, I created a main menu with a background and button node. When I tap on the PLAY button, the game does not navigate to my GameScene and instead calls my print statement. Here is the code below:
import Foundation
import SpriteKit
import GameplayKit
class MainMenu: SKScene, SKPhysicsContactDelegate {
override func didMove(to view: SKView) {
background()
playButton()
}
func background()
{
let back = SKSpriteNode(imageNamed: "MainMenu")
back.anchorPoint = CGPoint(x: 0, y: 0)
back.zPosition = 1
back.size = CGSize(width: frame.width,height: frame.height)
back.name = "Background"
addChild(back)
}
func playButton()
{
let button = SKSpriteNode(imageNamed: "button")
button.zPosition = 2
button.name = "Play Button"
button.position = CGPoint(x: frame.width/2, y: frame.height/2)
button.setScale(0.3)
addChild(button)
}
func loadGame(){
guard let skView = self.view as SKView? else{
print("Could not get Skview")
return
}
guard let scene = GameScene(fileNamed: "GameScene") else {
print("Error Getting GameScene")
return
}
//let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
skView.showsPhysics = true
scene.scaleMode = .aspectFill
skView.presentScene(scene)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else{
return
}
let touchLoation = touch.location(in: self)
let touchNodes = nodes(at: touchLoation)
let firstTouchedNode = atPoint(touchLoation).name
print(firstTouchedNode)
if firstTouchedNode == "Play Button"{
loadGame()
}
}
}
func loadGame(){
guard let skView = self.view as SKView? else{
print("Could not get Skview")
return
}
var scene:SKScene = GameScene(size: self.size)
}
//let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
skView.showsPhysics = true
scene.scaleMode = .aspectFill
var transition:SKTransition = SKTransition.fadeWithDuration(1)
self.view?.presentScene(scene, transition: transition)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let node = self.atPoint(location)
if node.name == "Play Button"{
//when playbutton is pressed execute code here
loadGame()
}
}

Detect image colour from touch location

I am trying to build a simple drawing app that can act as a virtual guest book. Ive managed to put something simple together which allows a user to draw onto a UIImage however I cannot figure out a way to erase a drawing somebody creates without using the eraser function that I create as white. I would like to set an image however I need to figure out a way that the eraser can detect the correct colour to use based on where the users finger will be when erasing to match the image.
My eraser currently updates a set of variables (red, green, blue) the erasers function is #IBAction func eraser
I've tried a few functions that I've came across which are outdated
//
// SecondViewController.swift
// Guest Book
//
// Created by Stephen Clifford on 25/07/2019.
// Copyright © 2019 Stephen Clifford. All rights reserved.
//
import Foundation
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var toolicon: UIButton!
#IBOutlet var imageView: UIImageView!
var lastPoint = CGPoint.zero
var swiped = false
var red:CGFloat = 0.00
var green:CGFloat = 0.00
var blue:CGFloat = 0.00
var alpha:CGFloat = 1
var lw:CGFloat = 2.5
var tool:UIImageView!
var isDrawing = true
override func viewDidLoad() {
super.viewDidLoad()
tool = UIImageView()
tool.frame = CGRect(x: self.view.bounds.size.width, y: self.view.bounds.height, width: 75, height: 75)
tool.image = #imageLiteral(resourceName: "pen")
self.view.addSubview(tool)
}
#IBAction func eraser(_ sender: AnyObject) {
if (isDrawing) {
(red,green,blue) = (1,1,1)
tool.image = #imageLiteral(resourceName: "eraser")
toolicon.setImage(#imageLiteral(resourceName: "pen"), for: .normal)
(lw) = (50)
} else {
(red,green,blue) = (0,0,0)
tool.image = #imageLiteral(resourceName: "pen")
toolicon.setImage(#imageLiteral(resourceName: "eraser"), for: .normal)
(lw) = (2.5)
}
isDrawing = !isDrawing
}
func delay(_ delay:Double, closure:#escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
#IBAction func save(_ sender: AnyObject) {
if let image = imageView.image {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
self.imageView.image = nil
// the alert view
let alert = UIAlertController(title: "", message: "Thank you, your guestbook entry has been saved. Redirecting you the home page", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 2.5
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
}
delay(3.0) {
// do stuff
self.performSegue(withIdentifier: "savetocam", sender: nil)
}
}
}
#IBAction func lineSize(_ sender: AnyObject) {
if sender.tag == 8 {
(lw) = (1)
} else if sender.tag == 9 {
(lw) = (2.5)
} else if sender.tag == 10 {
(lw) = (5)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
swiped = false
if let touch = touches.first {
lastPoint = touch.location(in: self.view)
}
}
#IBAction func colorsPicked(_ sender: AnyObject) {
if sender.tag == 0 {
(red,green,blue) = (0,0,0)
} else if sender.tag == 1 {
(red,green,blue) = (0.25,0.00,0.39)
} else if sender.tag == 2 {
(red,green,blue) = (0.65,0.62,0.75)
} else if sender.tag == 3 {
(red,green,blue) = (1.00,0.00,0.00)
} else if sender.tag == 4 {
(red,green,blue) = (0.49,0.77,0.46)
} else if sender.tag == 5 {
(red,green,blue) = (0.0,0.68,0.94)
} else if sender.tag == 6 {
(red,green,blue) = (0.96,0.56,0.34)
} else if sender.tag == 7 {
(red,green,blue) = (1.00,0.95,0.00)
}
}
#IBAction func reset(_ sender: AnyObject) {
self.imageView.image = nil
}
func drawLines(fromPoint:CGPoint,toPoint:CGPoint) {
UIGraphicsBeginImageContext(self.view.frame.size)
imageView.image?.draw(in: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
let context = UIGraphicsGetCurrentContext()
context?.move(to:CGPoint(x: fromPoint.x, y: fromPoint.y))
context?.addLine(to: CGPoint(x: toPoint.x, y: toPoint.y))
context?.setBlendMode(CGBlendMode.normal)
context?.setLineCap(CGLineCap.round)
context?.setLineWidth(lw)
context?.setStrokeColor(UIColor(red: red, green: green, blue: blue, alpha: alpha).cgColor)
context?.strokePath()
imageView.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
swiped = true
if let touch = touches.first {
let currentPoint = touch.location(in: self.view)
drawLines(fromPoint: lastPoint, toPoint: currentPoint)
lastPoint = currentPoint
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if !swiped {
drawLines(fromPoint: lastPoint, toPoint: lastPoint)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Update Label when 2 SKSpriteNodes collide

I want to add 1 point to the topLbl whenever the ball collides with the main. How would I do that? Thanks!
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var ball = SKSpriteNode()
var main = SKSpriteNode()
var topLbl = SKLabelNode()
var score = [Int]()
override func didMove(to view: SKView) {
startGame()
self.physicsWorld.contactDelegate = self
topLbl = self.childNode(withName: "topLabel") as! SKLabelNode
ball = self.childNode(withName: "ball") as! SKSpriteNode
main = self.childNode(withName: "main") as! SKSpriteNode
ball.physicsBody?.applyImpulse(CGVector(dx: 8, dy: 8))
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
self.physicsBody = border
}
func startGame() {
score = [0]
topLbl.text = "\(score[0])"
}
func addScore(byTouch : SKSpriteNode){
if byTouch == main {
score[0] += 1
}
print(score)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
main.run(SKAction.moveTo(x: location.x, duration: 0))
main.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
main.run(SKAction.moveBy(x: 4444, y: 4444, duration: 0))
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
func didBegin(contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == 1 && contact.bodyB.categoryBitMask == 2) {
if ball == contact.bodyA.node as! SKSpriteNode {
score[0] += 1
}
} else if (contact.bodyA.categoryBitMask == 2 && contact.bodyB.categoryBitMask == 1) {
if ball == contact.bodyB.node as! SKSpriteNode {
score[0] += 1
}
}
}
}

How to add 1 point every time SKNode is touched

I created a game involving falling balls. Every time the player taps a ball, they're supposed to get a point. I set up the score label, but it just stays at 0.
Is there something wrong with my code?
I use a GameElements.swift file as an extension. Here is the file:
extension GameScene {
//1st Ball//
func createPlayer() -> SKNode {
let playerNode = SKNode()
playerNode.position = CGPoint(x:self.size.width / 2, y:440)
let sprite = SKSpriteNode(imageNamed: "Ball")
sprite.name = "ballPoints"
playerNode.addChild(sprite)
playerNode.physicsBody = SKPhysicsBody(circleOfRadius: 120)
playerNode.physicsBody?.dynamic = true
playerNode.physicsBody?.allowsRotation = false
playerNode.physicsBody?.restitution = 3
playerNode.physicsBody?.friction = 0
playerNode.physicsBody?.angularDamping = 0
playerNode.physicsBody?.linearDamping = 0
playerNode.physicsBody?.usesPreciseCollisionDetection = true
playerNode.physicsBody?.categoryBitMask = CollisionBitMask.Player
playerNode.physicsBody?.categoryBitMask = 0
return playerNode
}
}
Here is the GameScene.swift file:
class GameScene: SKScene {
var foreground: SKNode!
var hud: SKNode!
var firstBall: SKNode!
var scoreLabel: SKLabelNode!
private var score = 0
override func didMoveToView(view: SKView) {
scoreLabel = SKLabelNode(fontNamed:"Geared-Slab")
scoreLabel.fontColor = UIColor.blackColor()
scoreLabel.position = CGPoint( x: self.frame.midX, y: 3 * self.frame.size.height / 4 )
scoreLabel.fontSize = 100.0
scoreLabel.zPosition = 100
scoreLabel.text = String(score)
self.addChild(scoreLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if(firstBall.containsPoint(location)) {
firstBall.physicsBody?.velocity = CGVectorMake(0, 600)
firstBall.physicsBody?.applyImpulse(CGVectorMake(0, 1100))
}
if
let touch : UITouch! = touches.first,
let tappedSprite = nodeAtPoint(touch!.locationInNode(self)) as? SKSpriteNode,
let scoreLabel = childNodeWithName("scoreLabel") as? SKLabelNode
where tappedSprite.name == "ballPoints" {
score += 1
scoreLabel.text = "Score: \(score)"
}
}
}
override init(size:CGSize) {
super.init(size: size)
foreground = SKNode()
addChild(foreground)
//1st Ball//
firstBall = createPlayer()
foreground.addChild(firstBall)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I know this is a lot of code, but I want experts to be able to test the code themselves. For background, I was following this tutorial: https://www.youtube.com/watch?v=0gOi_2Jwt28 up until a certain point.
Step 1
First of all let's create a class for the Ball
class Ball: SKSpriteNode {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let scene = self.scene as! GameScene
scene.score += 1
}
}
Step 2
Then inside createPlayer() let's replace this
let sprite = SKSpriteNode(imageNamed: "Ball")
with this
let sprite = Ball(imageNamed: "Ball")
sprite.userInteractionEnabled = true
Step 3
Let's remove the touchesBegan from GameScene.
Update
This code is working as expected for me
class GameScene: SKScene {
var scoreLabel: SKLabelNode!
var ball: Ball!
private var score = 0 {
didSet {
scoreLabel.text = "\(score)"
print(score)
}
}
override func didMoveToView(view: SKView) {
let ball = Ball()
ball.position = CGPoint(x:frame.midX, y: frame.midY)
addChild(ball)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// this is called when you tap outside of the Ball
// use self.ball to make the ball to jump
}
}
class Ball: SKSpriteNode {
init() {
let texture = SKTexture(imageNamed: "ball")
super.init(texture: texture, color: .clearColor(), size: texture.size())
userInteractionEnabled = true
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let scene = self.scene as! GameScene
scene.score += 1
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Dismissing GameCenter View in Swift

After showing a Game Center view it doesn't dismiss after tapping done. Here's my code to show it:
let gameCenterController = GKGameCenterViewController()
self.presentViewController(gameCenterController, animated:true, completion: nil)
What am I missing?
There is some good Q&A on this over at Ray Wenderlich. See the last method in the code below. Source:
http://www.raywenderlich.com/forums/viewtopic.php?f=2&t=18671
class GameViewController: UIViewController, GKGameCenterControllerDelegate {
var skView: SKView!
var scene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
// View
//------
skView = self.view as SKView
skView.ignoresSiblingOrder = true
scene = GameScene.sceneWithSize(skView.bounds.size)
scene.scaleMode = .AspectFill
scene.view?.window?.rootViewController = self
skView.presentScene(scene)
authenticateLocalPlayer()
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
var touch:UITouch = touches.anyObject() as UITouch
var location:CGPoint = touch.locationInNode(scene)
if (scene.gameCenterRect.contains(location) && GKLocalPlayer.localPlayer().authenticated) {
self.openGameCenter()
}
}
func openGameCenter() {
var gameCenter = GKGameCenterViewController()
gameCenter.gameCenterDelegate = self
self.presentViewController(gameCenter, animated: true, completion: nil)
}
func authenticateLocalPlayer(){
var localPlayer = GKLocalPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if ((viewController) != nil) {
self.presentViewController(viewController, animated: true, completion: nil)
}else{
println("(GameCenter) Player authenticated: \(GKLocalPlayer.localPlayer().authenticated)")
}
}
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!) {
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
[...] // standard methods
}