This is probably a dumb question ,but here is my situation.
I have an SKShapeNode rect that goes from left to right on the screen as follows :
// GameScene.swift
var rect = SKShapeNode()
var counter = 0{
didSet{
rect.position = CGPoint(x: CGFloat(counter) , y: frame.midY)
if CGFloat(counter) > frame.width{
counter = 0
}}}
override func update(_ currentTime: TimeInterval) {
counter = counter + 4
}
In the ViewController.swift I try to get the rect.position like this , which I know is wrong because it creates a new Instance.
//ViewController.swift
let gameScene = GameScene()
#IBAction func button(_ sender: Any) {
// gameScene.rect.position = games.frame.CGPoint(x: 200, y: 400)
print(gameScene.rect.position) // Always returns (0,0)
}
Question: How can I get rect.position in real time from the other class. So that whenever I press the button , I get the actual position of the rect?
UPDATE
On Ron's suggestion I updated the viewDidLoad method in my ViewController.swift from this :
let gameScene = GameScene()
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.spriteView {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}}
to this :
var gameScene : GameScene!
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.spriteView {
// Load the SKScene from 'GameScene.sks'
if let scene = GameScene(fileNamed: "GameScene") { // SKScene changed to GameScene
self.gameScene = scene // scene assigned to gameScene variable
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
}
INTENTION
I wanted to get the position of the moving bar when the play button was clicked.
Note that the GameScene only represents a part of the actual screen
When you first transition to your GameScene (Assuming that you are going directly from your GameViewController to your GameScene) create a class level variable for gameScene. Then when you need the information from GameScene use that same variable vs. creating a new GameScene variable
var gameScene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let gameScene = GameScene(fileNamed: "GameScene") {
self.gameScene = gameScene
gameScene = .aspectFill
// Present the scene
view.presentScene(gameScene)
}
}
}
func getCoords() {
print("gameScene.rect.position \(gameScene.rect.position)")
}
Related
I want to call a func of GameViewController from the GameScene.
-> If the game Ends I want to call GameViewController().GameOver()
I tried now a lot of different things like this one: LINK (I tried every answer more than once, still not working)
But doesn't matter what I tried it doesn't even call the func.
Hope anyone can help me with this.
CODE:
GameViewController:
class GameViewController: UIViewController {
#IBOutlet weak var Button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = GameScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
if UIDevice().userInterfaceIdiom == .phone {
scene.scaleMode = .aspectFill
}else{
scene.scaleMode = .aspectFit
}
// Present the scene
view.presentScene(scene)
skView = view
}
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
}
...
#IBAction func Button(_ sender: Any) {
animation()
if let gameScene = skView.scene as? GameScene { // check to see if the current scene is the game scene
gameScene.start()
}
}
func animation(){
UIButton.animate(withDuration: 1, animations: {
self.Button?.alpha = 0
})
}
func GameOver(){
UIButton.animate(withDuration: 1, animations: {
self.Button?.alpha = 1
})
}
}
GameScene:
class GameScene: SKScene, SKPhysicsContactDelegate {
...
func torpedoDidCollideWithAlien (torpedoNode:SKSpriteNode, alienNode:SKSpriteNode) {
GameViewController().GameOver()
removeAllActions()
removeAllChildren()
}
}
Option 1:
You should pass GameViewController instance when you are calling GameScene from GameViewController at the first time, Then just save this instance in some var gameVC: GameViewController! and initialize it like you do in prepare for segue method.
Then you'll be able to call gameVC.GameOver()
Option 2:
Put this in GameScene when you want to call GameOver():
if let controller = self.view?.window?.rootViewController as? GameViewController {
controller.GameOver()
}
I am creating a simple Game and I would like to get the actually size (width/height) of a SpriteKit scene to be able to present a SKNode ( / SKSpriteNode) to fill the whole display, but apparently
backgroundNode.size = CGSize(width: view.frame.width, height: view.frame.height)
or anything similar doesn't work. The node is presented, but is just a quarter of the actually screen size.
I present the SKScene from GameViewController.swift like this:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = GameScene(size: view.bounds.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
view.ignoresSiblingOrder = true
}
So how could one get the actually SpriteKit Scene size or is there another way to present an SKNode / SKSpriteNode fullscreen in a GameScene?
Update: I tried this as well:
let displaySize: CGRect = UIScreen.main.bounds
let displayWidth = displaySize.width
let displayHeight = displaySize.height
which gives me for an iPhone 8 375x667 as a size, but the Node is still displayed as a quarter of the screen.
I created a sample project with the code below. This creates a red-colored node that fills the screen. You can use UIScreen.main.bounds and I'm using it here as a global variable. I find it helpful this way since I can access it from any code file, as I often need to use the screen size in a calculation.
GameViewController.swift
import SpriteKit
let displaySize: CGRect = UIScreen.main.bounds
class GameViewController: UIViewController {
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let skView = self.view as! SKView
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = .aspectFill
scene.size = view.bounds.size
skView.ignoresSiblingOrder = true
skView.presentScene(scene)
}
}
}
GameScene.swift
import SpriteKit
class GameScene: SKScene {
let backgroundNode = SKSpriteNode()
override func didMove(to view: SKView) {
backgroundNode.size = CGSize(width: displaySize.width, height: displaySize.height)
backgroundNode.color = .red
self.addChild(backgroundNode)
}
}
I want to make the background for the scene in GameScene.sks. I have Tile Map Node there, but when I set background in GameScene.swift the picture is on my textures. I want it on the back of the scene.
Here is the code of GameScene.swift:
import SpriteKit
class GameScene: SKScene {
var background = SKSpriteNode(imageNamed: "BackGround")`
override func didMove (to view: SKView) {
background.zPosition = 1
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
addChild(background)
}
}
Here is the code of GameViewController.swift:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override var prefersStatusBarHidden: Bool {
return true
}
Does 1 the least z position in your scene? If so, try to set ignoresSiblingOrder property of your SKView to false. Also I would suggest you to read SKScene and SKNode documentations at least. And SpriteKit documentation in general.
I have a controller that is using a Singleton to change SKScenes in a single storyboard scene.
class GameViewController: UIViewController, GKGameCenterControllerDelegate, GADBannerViewDelegate, GADInterstitialDelegate, ADBannerViewDelegate, FBLoginViewDelegate, CLLocationManagerDelegate, MapViewControllerDelegate {
var sharedInstance = Singleton.sharedInstance
var skView:SKView!
var scene:GameScene! = GameScene.unarchiveFromFile("GameScene") as? GameScene
var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]
let locationManager = CLLocationManager()
var adHelper: AdHelper = AdHelper()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
// Configure the view.
skView = self.view as SKView
skView.showsFPS = false
skView.showsNodeCount = false
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene, transition: SKTransition.crossFadeWithDuration(kSceneTransitionSpeed))
}
// LOAD MAP SCENE
func showMap(){
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("MapController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)
}
}
In my game scene I have a button that I am calling to this controller to change to the other scene in the storyboard because I don't have a layout button to use an IBAction
import SpriteKit
class GameScene: SKScene {
var sharedInstance = Singleton.sharedInstance
let playButton = Button(imageNamed:"playButton");
let highscoresButton = Button(imageNamed:"highscoresButton");
let creditsButton = Button(imageNamed:"creditsButton");
let moreGamesButton = Button(imageNamed: "moreGamesButton")
override func didMoveToView(view: SKView) {
// background
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPointMake(self.size.width/2, self.size.height/2)
self.addChild(background)
// main image
let main = SKSpriteNode(imageNamed: "main")
main.position = CGPointMake(self.size.width/2, self.size.height/2)
self.addChild(main)
// buttons
moreGamesButton.position = CGPointMake(self.size.width/2 + playButton.size.width, main.position.y + main.size.height/2 + playButton.size.height)
self.sharedInstance.addChildFadeIn(moreGamesButton, target: self)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self);
if self.nodeAtPoint(location) == self.moreGamesButton {
var gameController: GameViewController=GameViewController()
gameController.showMap()
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
When I click this I don't get a defined error just hits a break and it the thread I get "Swift dynamic cast failed".
Can I not call the controller like that within my scene or is is it a problem in instantiating the other controller?
I thought it would be interesting to learn how to pass an image from an imagePicker to my GameScene to use as a SKSpriteNode(texture: SKTexture(image: UIImage)) but i keep getting an error after selecting my image and pressing a button to go into my gameScene
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "startSegue") {
var gameViewController = segue.destinationViewController as GameScene
gameViewController.imageToPass = pickedImage.image
}
anyone know what im doing wrong?
keep getting exc_breakpoint (code=exc_i386_bpt, subcode 0x0)
when initializing gameViewController as GameScene
I am trying to pass imageToPass to the GameScene.swift that is created when i create a new game project in Xcode
class GameScene: SKScene {
var imageToPass = UIImage()
var bird = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
var birdTexture = SKTexture(image: imageToPass)
bird = SKSpriteNode(texture: birdTexture)
bird.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(bird)
}
The destination view controller is a UIViewController or its subclass. Not an SKScene. So I don't think it can be converted to GameScene. GameScene is usually a property of a UIViewController that holds it. In my project the UIViewController is called GameViewController. GameViewController has a property called gameScene
So the code should be
if let gameViewController = segue.destinationViewController as? GameViewController
{
gameViewController.imageToPass = pickedImage.image
}
create a property in GameViewController called imageToPass. Set the imageToPass to GameScene.imageToPass in viewDidLoad.
class GameViewController: UIViewController {
var pickedImage : UIImage!
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
let skView = self.view as SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
scene.imageToPass = pickedImage
skView.presentScene(scene)
}
}
}
You can create a property observer on imageToPass to change it dynamically.
var bird : SKSpriteNode!
var imageToPass : UIImage!
{
didSet
{
createBird()
}
}
func createBird()
{
var birdTexture = SKTexture(image: imageToPass)
bird?.removeFromParent()
bird = SKSpriteNode(texture: birdTexture)
bird.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(bird)
}
In the default SpriteKit implementation, the View Controller created is a GameViewController. In Interface Builder, it has for its view an SKView. In viewDidLoad, the key lines are
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// Configure the view.
let skView = self.view as SKView
/* more setup */
skView.presentScene(scene)
}
It looks like you've edited your question to reflect this. I'm not a SpriteKit expert, but if you get imageToPass to the GameViewController, then you should be able to pass it to your GameScene in viewDidLoad before it's presented. Good luck.
Note "GameScene.swift" is just the name of the text file that contains the code, so you wouldn't pass anything to it, the class is created in class GameScene: SKScene { /* class properties and methods */
Original Answer:
Are you sure the destinationViewController is a GameScene? Really sure? Because you're using as, you're force downcasting the segue view controller as a "GameScene".
Take advantage of Swift's safety features:
if var gameViewController = segue.destinationViewController as? GameScene {
gameViewController.imageToPass = pickedImage.image
}
or using optional chaining:
var gameViewController = segue.destinationViewController as? GameScene
gameViewController?.imageToPass = pickedImage.image
The pickedImage won't get through if not a GameScene, regardless, but you won't get a crash.
EDIT: By the way, it really should be GameSceneViewController so its clear everywhere it's a View Controller. If it's not a View Controller, that's a problem and has no chance to work.