override func viewDidLoad() {
super.viewDidLoad()
//create timer to transition from title screen to menu screen
let titleTimer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(GameViewController.transition), userInfo: nil, repeats: false)
//load title screen -----------------------------------------------------------------------
if let view = self.view as! SKView? {
// Load the SKScene from 'TitleScreen.sks'
if let titleScene = SKScene(fileNamed: "TitleScreen.sks") {
// Set the scale mode to scale to fit the window
titleScene.scaleMode = .aspectFill
// Present the scene
view.presentScene(titleScene)
}
//transition to menu -----------------------------------------------------------------------
if let newScene = SKScene(fileNamed: "Menu.sks") {
// Set the scale mode to scale to fit the window
newScene.scaleMode = .aspectFill
let sceneTransition = SKTransition.fade(withDuration: 3)
#objc func transition() {
view.presentScene(newScene, transition: sceneTransition)
}
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
I'm looking to transition from the title screen to the menu after 1.5 seconds using a Timer (which needs a selector). The #objc func transition() isn't being allowed to be created due to the #objc, does the function need to be located somewhere else?
Your function is not on you object (its inside ViewDidLoad). In any case you no longer need the selector or function in Swift. There is now a Timer initializer that takes a closure.
Example:
import PlaygroundSupport
let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
print("Hello in one second")
}
PlaygroundPage.current.needsIndefiniteExecution = true
Related
Apple's documentation states I can't change the position using the position getter/setter. I've tried the anchor point suggestion but still unable to move my scene's position in Scene Editor to the top. Does anyone have any ideas?
Implementation has been done via Scene Editor, currently the only code submitted to help scene present is below:
import UIKit
import SpriteKit
import GameplayKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Load 'GameScene.sks' as a GKScene. This provides gameplay related content
// including entities and graphs.
if let scene = GKScene(fileNamed: "GameScene") {
// Get the SKScene from the loaded GKScene
if let sceneNode = scene.rootNode as! GameScene? {
// Copy gameplay related content over to the scene
sceneNode.entities = scene.entities
sceneNode.graphs = scene.graphs
// Set the scale mode to scale to fit the window
sceneNode.scaleMode = .aspectFit
print(sceneNode.anchorPoint)
print(sceneNode.position)
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
}
In AppDelegate bypass storyboard.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let viewController = GameViewController()
window?.rootViewController = viewController
window?.makeKeyAndVisible()
return true
}
In GameViewController
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(skView)
setupSKView()
}
let skView: SKView = {
let view = SKView()
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = .fill
view.presentScene(scene)
}
return view
}()
func setupSKView(){
skView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height / 2)
}
}
I try to make a view controller, where i.e top half of the screen is SKScene, and bottom half of the screen is normal scene, I mean with buttons etc. Is this possible? I created a Single View application, and I am adding some code snippets below, which is the code from viewcontroller.swift file. But it doesn't create boxes to the tapped locations and also it doesn't move as expected a free fall motion when tapped. Maybe is there an issue about that I created a Single view application rather than choosing Game application when first creating the project? Maybe Metal enable/disable needed? I am not professional, therefore just guesses.
import UIKit
import SwiftUI
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
let box = SKSpriteNode(color: .red, size: CGSize(width: 0.04, height: 0.04))
box.physicsBody = SKPhysicsBody(rectangleOf: box.frame.size)
box.position = location
addChild(box)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = .aspectFill
scene.backgroundColor = .clear
let transition = SKTransition.fade(withDuration: 1)
view.presentScene(scene, transition: transition)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
view.allowsTransparency = true
view.backgroundColor = UIColor.clear
}
}
}
I tried to add a subview to my GameViewController (because I want to add a banner ad at the bottom). I created it as follows:
if let view = self.view as! SKView? {
let subView = SKView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 415, height: 685)))
view.addSubview(subView)
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = SKSceneScaleMode.aspectFit
subView.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
view.showsDrawCount = false
addBannerViewToView(bannerView)
}
}
This works initially - it presents my GameScene. But later, I ask my GameScene to present another subclass of SKScene that I created, which I call Shop, using the following code:
func initializeShop() {
let shop = Shop(size: self.size)
let transition = SKTransition.fade(withDuration: 0.1)
self.view?.presentScene(shop!, transition: transition)
}
And it simply does not present. It remains on the current view.
This works completely fine if I do NOT add a subview to the initial view in the GameViewController, i.e.
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = SKSceneScaleMode.aspectFit
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
view.showsDrawCount = false
}
}
So it seems like there is some property of the GameViewController's default SKView that allows presentation, but not a subview. But I can't find any documentation that says that - from what I can tell, all SKViews should be able to present SKScenes.
Any help would be much appreciated.
how would I make this button open the GameScene1 when clicked?
This is my code so far.
class GameScene1: SKScene{
override func didMove(to view: SKView){
}
}
let scene1 = GameScene1(size: CGSize(width: 400, height: 640))
scene1.scaleMode = .aspectFill
scene1.backgroundColor = .blue
let view2 = SKView(frame: CGRect(x:0, y:0, width: scene1.size.width, height: scene1.size.height
view2.presentScene(scene)
PlaygroundPage.current.liveView = view2
class Receiver{
#objc func buttonClicked(){
}
}
let view1 = UIView()
let receiver = Receiver()
let button = UIButton(frame: CGRect(x:10, y:10, width:100, height:50))
button.setTitle("start", for: .normal)
button.addTarget(receiver, action: #selector(Receiver.buttonClicked), for: .touchUpInside)
view.addSubview(button)
I have no idea how to do this.
Okay, I don't have a lot of experience with SKScene's, but this is what I would do. You really only need one SKView in your playground, which you could store as a static let inside a file with game variables. You could then create different scenes, for instance one for the menu, one for the first level, second level etc.
The following code creates a button and gives it an action. The action creates a constant called scene, which is the scene you want to move to next. Then you just call presentScene() with the scene, and a SKTransition, like the one below, which is simply a 2.5 second sliding animation from the right.
ButtonNode class, which is simply a node that acts as a button, which you can add to your scene.
class ButtonNode: SKSpriteNode {
var action: ((ButtonNode) -> Void)?
var isSelected: Bool = false {
didSet {
alpha = isSelected ? 0.8 : 1
}
}
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}
init(texture: SKTexture, size: CGSize) {
super.init(texture: texture, color: SKColor.white, size: size)
isUserInteractionEnabled = true
}
override func touchesBegan(with event: NSEvent) {
action?(self)
}
override func mouseDown(with event: NSEvent) {
action?(self)
}
}
Creating the button and giving it the action to move to a next scene. This can be done in any SKScene class.
startButton = ButtonNode(texture: SKTexture(imageNamed: "start-button"), size: CGSize(width: 184, height: 72))
startButton.position = CGPoint(x: 0.0, y: 0.0)
startButton.action = { (button) in
if let scene = IntroCutScene(fileNamed: "IntroCutScene") {
// Set the scale mode to scale to fit the window
self.scene!.scaleMode = .aspectFill
// Present the scene
GameVariables.sceneView.presentScene(scene, transition: SKTransition.moveIn(with: SKTransitionDirection.right, duration: 2.5))
}
}
self.addChild(startButton)
I am working on a game for macOS using Spritekit. Want to use a second scene. How do I set up App Delegate and ViewController to accomplish that?
I can make a transition to a second scene
var secondScene = SecondScene(size: self.size)
var transition = SKTransition.flipVertical(withDuration: 1.0)
secondScene.scaleMode = SKSceneScaleMode.aspectFill
self.scene!.view?.presentScene(secondScene, transition: transition)
Similar code in the SecondScene to return results in a crash during reloading of the previous scene, which loads fine the first time around.
self.scene!.view?.presentScene(FirstScene, transition: transition)
This is what my ViewController looks like.
class ViewController: NSViewController {
#IBOutlet var skView: SKView!
#IBOutlet weak var msg: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.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
}
}
}