Explanation
I'm trying to build a character selection menu similar to Crossy Road's one (as you can see here). So I found this iCarousel, which would help me with all of it, but everything I read talk about implementing it to a ViewController, which isn't my case. I'm using GameScene and I didn't found anything talking about it. Is there anyway I could implement it to my game? or even another effect similar to the character selection menu I mentioned above?
Attempt (beyowulf)
You can download it here.
GameScene.swift
import SpriteKit
class GameScene: SKScene {
var show = SKSpriteNode()
var hide = SKSpriteNode()
func showCharPicker(){
NSNotificationCenter.defaultCenter().postNotificationName("showCharPicker", object: nil)
}
func hideCharPicker(){
NSNotificationCenter.defaultCenter().postNotificationName("hideCharPicker", object: nil)
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
print("didMoveToView")
show = SKSpriteNode(imageNamed: "show")
show.anchorPoint = CGPointZero
show.position = CGPointZero
addChild(show)
hide = SKSpriteNode(imageNamed: "hide")
hide.anchorPoint = CGPointZero
hide.position = CGPoint(x: self.frame.width / 2 - hide.frame.width / 2, y: 0)
addChild(hide)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if node == show{
print("show")
showCharPicker()
}
else if node == hide{
print("hide")
hideCharPicker()
}
}
}
}
GameViewController.swift
import UIKit
import SpriteKit
class GameViewController: UIViewController, iCarouselDataSource, iCarouselDelegate{
var squaresArray : NSMutableArray = NSMutableArray()
#IBOutlet weak var carousel: iCarousel!
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func showCarousel(){
self.carousel.hidden = false
}
func hideCarousel(){
self.carousel.hidden = true
}
override func viewDidLoad(){
super.viewDidLoad()
// Configure iCarousel
carousel.dataSource = self
carousel.delegate = self
carousel.type = .CoverFlow
carousel.reloadData()
self.carousel.hidden = true
// Register showCarousel and hideCarousel functions
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showCarousel), name: "showCharPicker", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.hideCarousel), name: "hideCharPicker", object: nil)
// Configure view
let skView = SKView()
self.view.insertSubview(skView, belowSubview: self.carousel)
skView.frame = self.view.bounds
// Additionals
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
// Configure scene
let scene = GameScene(size:self.view.bounds.size)
scene.scaleMode = .ResizeFill
scene.size = self.view.bounds.size
skView.presentScene(scene)
}
//iCarousel
override func awakeFromNib(){
super.awakeFromNib()
squaresArray = NSMutableArray(array: ["square1","square2","square3"])
}
func numberOfItemsInCarousel(carousel: iCarousel) -> Int{
return squaresArray.count
}
func carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger){
//self.hideCarousel()
}
func carousel(carousel: iCarousel, viewForItemAtIndex index: Int, reusingView view: UIView?) -> UIView{
var itemView: UIImageView
if (view == nil){
itemView = UIImageView(frame:CGRect(x:0, y:0, width:200, height:200))
itemView.contentMode = .Center
}
else{
itemView = view as! UIImageView;
}
itemView.image = UIImage(named: "\(squaresArray.objectAtIndex(index))")
return itemView
}
func carousel(carousel: iCarousel, valueForOption option: iCarouselOption, withDefault value: CGFloat) -> CGFloat{
if (option == .Spacing){
return value * 2
}
return value
}
}
What's happening:
Thanks in advance,
Luiz.
You can use NSNotifications to show your character picker. You just need to observe the notifications posted by your SKScene. Your viewDidLoad should look something like:
override func viewDidLoad(){
super.viewDidLoad()
carousel.type = .CoverFlow
carousel.reloadData()
let spriteKitView = SKView()
spriteKitView.frame = self.view.bounds
self.view.insertSubview(spriteKitView, belowSubview: self.carousel)
spriteKitView.showsFPS = true
spriteKitView.showsNodeCount = true
spriteKitView.ignoresSiblingOrder = true
self.gameScene = GameScene(size:self.view.bounds.size)
self.gameScene.scaleMode = .AspectFill
self.gameScene.imageName = self.images[0] as! String
self.carousel.hidden = true
spriteKitView.presentScene(self.gameScene)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showCarousel), name: gameScene.kShowNotification, object: nil)
}
You'll want to implementing carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger) so you know what is selected, and so you can return to game play. For example:
func carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger)
{
self.gameScene.imageName = self.images[index] as! String
self.hideCarousel()
}
You also need to remove observing before your view controller is deallocated.
deinit
{
NSNotificationCenter.defaultCenter().removeObserver(self)
}
Your SKScene can then post a notifications:
import SpriteKit
class GameScene: SKScene {
var imageName = "square1"{
didSet{
self.hidden = false
self.childNode.texture = SKTexture(imageNamed: imageName)
}
}
let kShowNotification = "showPicker"
var childNode = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.childNode = SKSpriteNode(imageNamed: imageName)
self.childNode.anchorPoint = CGPointZero
self.childNode.position = CGPointZero
self.addChild(self.childNode)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.showCharPicker()
}
func showCharPicker()
{
self.hidden = true
NSNotificationCenter.defaultCenter().postNotificationName(kShowNotification, object: nil)
}
}
If you want to change hit detection, you need to subclass the view for which you need it to change. This case your iCarousel view.
You can then either override hitTest or pointInside. I've created an iCarousel subclass and overrode pointInside to only return true when the point is inside one of the carousel's contentView's subviews.
class CarouselSubclass: iCarousel {
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
var inside = false
for view in self.contentView.subviews
{
inside = CGRectContainsPoint(view.frame, point)
if inside
{
return inside
}
}
return inside
}
}
You need to remember to change the class of your carousel in interface builder and update your outlet as well.
Related
I have this UIViewController in which i've overrided the touchBegan and touchEnded functions. I also have a button that segueues (push) to another view controller with an SKView on it. But the overrided function in the first controller are still active ei. the calculations done there are still showing on the second ViewController.
Maybe theres something im missing or something im assuming thats wrong. Any help would be appreciated
This is the first view controller
import UIKit
import CoreMotion
class PortraitViewController: UIViewController {
var vc: UIViewController?
var startPoint: CGPoint?
var endPoint: CGPoint?
var movedPoint: CGPoint?
var previousMove = CGPoint(x: 0, y: 0)
var beginTouch: UITouch?
var scaleSum = 0
var isPortrait = true
let DEBUG: Bool = true
// MARK:
// MARK: Overriden Variables
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask{return .portrait}
open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation{return .portrait}
override var shouldAutorotate: Bool {return false}
#IBAction func pinch(_ sender: UIPinchGestureRecognizer) {
if (isPortrait){
let scale = sender.scale
scaleSum += scale.exponent
print(scaleSum)
if(scaleSum > 10) {
scaleSum = 0
print(">10")
}
else if(scaleSum < -10) {
print("<10")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if(isPortrait){
if let theTouch = touches.first {
endPoint = theTouch.location(in: self.view)
let diffx = (endPoint!.x - startPoint!.x)
let diffy = (endPoint!.y - startPoint!.y)
if(diffx != 0 && diffy != 0){
let vector = CGVector(dx: diffx, dy: diffy)
var angle = atan2(vector.dy, vector.dx) * CGFloat(180.0 / M_PI)
if angle < 0 { angle *= -1 } else { angle = 360 - angle }
}
}
}
super.touchesEnded(touches, with: event)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if(isPortrait){
if let theTouch = touches.first {
startPoint = theTouch.location(in: self.view)
}
}
super.touchesBegan(touches, with: event)
}
//One of my attempts to jerry rig a solution
#IBAction func prepToLandscape(_ sender: UIBarButtonItem) {
self.isPortrait = false
print("isPortrait = \(self.isPortrait)")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.setNavigationBarHidden(true, animated: false)
}
}
This is the second view controller
import UIKit
import CoreMotion
import SpriteKit
class LandScapeViewController: UIViewController {
var vc: UIViewController?
// MARK:
// MARK: Overriden Variables
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask{return .landscape}
open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation{return .landscapeLeft
// MARK:
// MARK: Functions
override func viewDidLoad() {
super.viewDidLoad()
let controllerStoryBoard = UIStoryboard(name: "Main", bundle: nil)
vc = controllerStoryBoard.instantiateViewController(withIdentifier: "Root")
// Part of my attempt to jerry rig a solution
let vcP: PortraitViewController = UIStoryboard(name:"Controller",bundle: nil).instantiateViewController(withIdentifier: "PortraitController") as! PortraitViewController
vcP.isPortrait = false
print("vcP.isPortrait = \(vcP.isPortrait)")
}
override func viewWillAppear(_ animated: Bool) {
self.view.isMultipleTouchEnabled = true
let scene = GameScene(size: joystickView.bounds.size)
scene.backgroundColor = .gray
if let skView = joystickView as? SKView {
skView.showsFPS = false
skView.ignoresSiblingOrder = true
skView.backgroundColor = .red
skView.presentScene(scene)
}
navigationController?.setNavigationBarHidden(true, animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func toPortrait(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: {() -> Void in
}
}
Assuming the code shown is everything relevant, this makes sense. What's happening is this: the touch events are hit-tested to the joystickView, but because you haven't implemented a custom touchesBegan(_:with:) on that view, the touch event is passed up to the next UIResponder in the responder chain. That would be the LandScapeViewController. But that class also doesn't implement a custom touchesBegan(_:with:), so the event passes to the next class, which in this case is PortraitViewController. Because PortraitViewController does implement that method, it gets called. There's your confusion.
To fix this, implement the touches… methods on UIResponder for either joystickView or LandScapeViewController, even if they do nothing – but don't call super in them! Note the following, from the touchesBegan(_:with:) documentation:
If you override this method without calling super (a common use pattern), you must also override the other methods for handling touch events, even if your implementations do nothing.
Where you're overriding touchesBegan(_:with:), you probably don't want to call super. This is because the super implementation is the one that says "oh, shoot, I don't know how to handle this – pass it up the chain!" But when you handle the touch, it should end there, because you're handling it! So only call super when you're not handling the touch – which in your case looks like never, at least for PortraitViewController.
For more information, check out Event Delivery: The Responder Chain.
I'm writing simple math game with swift 3 and I have a problem with segues. I have two GameViewController's, oneUIViewController and one NavigationViewController.
I want to make two menus, one with game modes and one with difficulties, I want that the difficulties menu be interactive and have gravity so I decided to make it in SkScene. Everything works fine except segue between SkScene with dark screen and difficulties menu when user lost the game. I write a protocol which works when I'm going from main menu to second menu but when I'm going from SkScene with game it doesn't. I was trying to make a manual segue but protocol doesn't want to execute.
MyGVViewController code:
import UIKit
import SpriteKit
import GameplayKit
enum skad1 {
case game,menu
}
var skad = skad1.gra
class MyGVViewController: UIViewController, GameViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "Menugame") {
let gameScene = scene as! MySKScene
gameScene.gameViewControllerDelegate = self
gameScene.scaleMode = .aspectFill
gameScene.size = view.bounds.size
// Present the scene
view.presentScene(gameScene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
func goback() {
print("goback executed")
let view = self.view as! SKView?
view?.presentScene(nil)
navigationController?.popViewController(animated: true)
}
func goback2() {
print("goback2 executed")
let view = self.view as! SKView?
view?.presentScene(nil)
self.performSegue(withIdentifier: "comeback", sender: nil)
}
}
My SkScene with difficulties menu code:
import GameKit
import SpriteKit
import CoreMotion
protocol GameViewControllerDelegate: class {
func goback()
func goback2()
}
class MySKScene: SKScene {
//Variables
var motionManager: CMMotionManager!
var ball = SKSpriteNode()
var ball1 = SKSpriteNode()
var ball2 = SKSpriteNode()
var ball3 = SKSpriteNode()
var ball4 = SKSpriteNode()
weak var gameViewControllerDelegate: GameViewControllerDelegate?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if ball.contains(location){
showgame(zakres: 200)
}else if ball1.contains(location){
showgame(zakres: 100)
}else if ball2.contains(location) {
showgame(zakres: 50)
}else if ball3.contains(location) {
showgame(zakres: 150)
}else if ball4.contains(location) {
if skad == .menu{
print("should execut goback")
self.gameViewControllerDelegate?.goback()
}else{
print("should execut goback2")
self.gameViewControllerDelegate?.goback2()
}
}
}
}
func showgame(zakres:Int) {
if let view = self.view {
range = zakres
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
let gameScene = scene as! GameScene
gameScene.scaleMode = .aspectFill
// Present the scene
gameScene.size = view.bounds.size
view.presentScene(gameScene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override func didMove(to view: SKView) {
ball = self.childNode(withName: "ball") as! SKSpriteNode
ball1 = self.childNode(withName: "ball1") as! SKSpriteNode
ball2 = self.childNode(withName: "ball2") as! SKSpriteNode
ball3 = self.childNode(withName: "ball3") as! SKSpriteNode
ball4 = self.childNode(withName: "ball4") as! SKSpriteNode
motionManager = CMMotionManager()
motionManager.startAccelerometerUpdates()
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 0
self.physicsBody = border
}
override func update(_ currentTime: TimeInterval) {
if let accelerometerData = motionManager.accelerometerData {
physicsWorld.gravity = CGVector(dx: accelerometerData.acceleration.x * 20, dy: accelerometerData.acceleration.y * 35)
}
}
}
PS.
I'm reading what I wrote and I have to correct it, in difficulties menu I have a button which execute protocol that hide SKScene and show main menu. It works only when I'm going from main menu but when segue is from game when user lost, protocol isn't executed
How do I show an interstitial ad from admob every x times the user has died or every x times the user does something like presses a button? This is how I showed an interstitial ad on my GameScene and limited ad impressions with a simple if statement.
This will only work if you have the GoogleMobileAds.sdk and have imported the googlemobileads module into your GameViewController, and GameScene, OR GameOverScene.
I'll be showing you cross-scene ad implementation and programmatically limiting ad impressions.
First, in your GameViewController:
import GoogleMobileAds
class GameViewController: UIViewController, GADInterstitialDelegate {
var myAd = GADInterstitial()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.loadAndShow), name: "loadAndShow", object: nil)
}
Create two functions at the bottom of your GameViewController:
func loadAndShow() {
myAd = GADInterstitial()
let request = GADRequest()
myAd.setAdUnitID("ca-app-pub-3940256099942544/4411468910")
myAd.delegate = self
myAd.loadRequest(request)
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
if (self.myAd.isReady) {
myAd.presentFromRootViewController(self)
}
}
You are done with GameViewController. Now head to GameOverScene or GameScene, whatever you need.
Create a global int variable:
var playCount = Int()
In your DidMoveToView say:
playCount = 1
This part is sort of confusing, kinda, not really. Go to your touchesBegan and find where you add actions to a button if it's pressed. For example, a resetGame button resets the scene. Add this there and increment the playButton Int like so:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
let location = touch.locationInNode(self)
if resetGame.containsPoint(location) {
restartScene()
playCount += 1
}
Last step. Add these two functions to the bottom of the scene you want to show interstitial ads in:
func displayAd() {
NSNotificationCenter.defaultCenter().postNotificationName("loadAndShow", object: nil)
}
func checkAd() {
if playCount % 4 == 0 {
displayAd()
}
}
}
Now every fourth time that the user presses the reset game button or dies, an interstitial ad should show up. I hope this helps.
EDIT: I forgot to tell you to call the checkAd() function. Call this function wherever your players dies. So if you have a Bool variable called died or gameover call it in the same spot. For example..
if died == true {
checkAd()
}
import UIKit
import SpriteKit
import GoogleMobileAds
var playCount = Int()
class GameViewController: UIViewController, GADBannerViewDelegate {
#IBOutlet var banner: GADBannerView!
var myAd = GADInterstitial()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.loadAndShow), name: "loadAndShow", object: nil)
let scene = MainScene(size: CGSize(width: 1536, height: 2048))
// Configure the view.
let 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)
banner.hidden = true
banner.delegate = self
banner.adUnitID = "ca-app-pub-8889875503423788/7902691359"
banner.rootViewController = self
banner.loadRequest(GADRequest())
}
func loadAndShow() {
myAd = GADInterstitial()
let request = GADRequest()
myAd.setAdUnitID("ca-app-pub-8889875503423788/7902691359")
myAd.delegate = self
myAd.loadRequest(request)
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
if (self.myAd.isReady) {
myAd.presentFromRootViewController(self)
}
}
func adViewDidReceiveAd(bannerView: GADBannerView!) {
banner.hidden = false
}
func adView(bannerView: GADBannerView!, didFailToReceiveAdWithError error: GADRequestError!) {
banner.hidden = true
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
I recently implemented a scrollView into my GameViewController and it works really well, but the tutorial I looked at had only one scene which was the start up scene (GameScene) rather than a seperate scene which I'm going to be calling "Menu" so I managed to get it to launch the Menu scene rather than the regular "GameScene" but when I go from GameScene to the Menu scene with a button that I implemented in GameScene, the scrollview does not work, but it does show the pictures, but I just can't scroll through them.
My question is how do I get scrollView to work when I use the button (that is in GameScene) to go to the Menu scene?
This is the button (which is In GameScene)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: UITouch = touches.first!
let location: CGPoint = touch.locationInNode(self)
let node: SKNode = self.nodeAtPoint(location)
if (node == menubutton) {
let MenuScene = Menu(size: self.size, viewController: viewController)
let transition = SKTransition.flipVerticalWithDuration(0.5)
MenuScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view?.presentScene(MenuScene, transition: transition)
}
Here is my Menu scene:
import Foundation
import SpriteKit
let kMargin: CGFloat = 40
var backButton = SKSpriteNode()
var selectButton = SKSpriteNode()
class Menu: SKScene {
let world2 = SKSpriteNode()
private var imageSize = CGSize.zero
private weak var viewController: GameViewController?
init(size: CGSize, viewController: GameViewController?) {
self.viewController = viewController
super.init(size: size)
}
required init?(coder aDecoder: NSCoder) {
assert(false, "Use init(size:viewController:)")
super.init(coder: aDecoder)
}
override func didMoveToView(view: SKView) {
physicsWorld.gravity = CGVector.zero
imageSize = SKSpriteNode(imageNamed: "card_level01").size
let initialMargin = size.width/2
let marginPerImage = kMargin + imageSize.width
world2.size = CGSize(width: initialMargin*2 + (marginPerImage * 7), height: size.height)
addChild(world2)
for i in 1...8 {
let sprite = SKSpriteNode(imageNamed: String(format: "card_level%02d", i))
sprite.position = CGPoint(x: initialMargin + (marginPerImage * (CGFloat(i) - 1)), y: size.height / 2)
world2.addChild(sprite)
}
}
override func update(currentTime: NSTimeInterval) {
viewController?.applyScrollViewToSpriteKitMapping()
}
Here is my GameViewController
import UIKit
import SpriteKit
class GameViewController: UIViewController {
var scrollView: UIScrollView!
var contentView: UIView!
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let skView = view as! SKView
if (skView.scene === Menu.self) {
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
let scene = Menu(size: skView.bounds.size, viewController: self)
scene.scaleMode = .AspectFill
skView.presentScene(scene)
scrollView = UIScrollView(frame: self.view.bounds)
scrollView.delegate = self
scrollView.contentSize = scene.world2.frame.size
view.addSubview(scrollView)
contentView = UIView(frame: CGRect(origin: CGPoint.zero, size: scene.world2.size))
contentView.backgroundColor = UIColor.greenColor().colorWithAlphaComponent(0.2)
scrollView.addSubview(contentView)
applyScrollViewToSpriteKitMapping()
}
}
func applyScrollViewToSpriteKitMapping() {
let origin = contentView.frame.origin
let skPosition = CGPoint(x: -scrollView.contentOffset.x + origin.x, y: -scrollView.contentSize.height + CGRectGetHeight(view.bounds) + scrollView.contentOffset.y - origin.y)
let skView = view as! SKView
if let scene = skView.scene as? Menu {
scene.world2.position = skPosition
}
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return UIInterfaceOrientationMask.Portrait
} else {
return UIInterfaceOrientationMask.All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func shouldAutorotate() -> Bool {
return true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
extension GameViewController: UIScrollViewDelegate {
}
I recently helped another member with a similar question, check it out it might be helpful to you
How to create a vertical scrolling menu in spritekit?
In my way I am subclassing scroll view and therefore can add it to SKScenes directly rather than the view controllers.
If you want the scrollView on more than 1 SKScene without duplicate code than need to subclass your SKScnenes
class BaseScene: SKScene ...
// Add scroll view
class Menu: BaseScene...
class GameScene: BaseScene ...
As a side note, you shouldn't really reference your viewController in your SKScenes, they shouldn't have to know about each other.
I am trying to make a advent calendar with a snow affect in swift2. I am using the game template while using SpiteKit.
Here is my code so far:
GameScene.swift
import SpriteKit
class GameScene: SKScene {
/*override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
let location = touch.locationInNode(self)
print(location)
}
}*/
func test()
{
//Generate Doors
//Initilization
var adventDoors = [AdventDoor]()
let offset = CGVector(dx: 10,dy: 10)
var size = CGRectMake(offset.dx, offset.dy, 60, 60)
var ypos:CGFloat = 20
var xpos:CGFloat = 10
var index = 0
var xDoor = AdventDoor(frame: size)
let randomIdentifier = [Int](1...24).shuffle()
for _ in 1...4
{
for i in 1...6
{
size = CGRectMake(xpos, ypos, 60, 60)
xDoor = AdventDoor(frame: size)
xDoor.opaque = false
xDoor.restorationIdentifier = "\(randomIdentifier[index])"
xDoor.generateDoor()
adventDoors.append(xDoor)
print("1...6")
ypos += 80
//xpos += 20
index++
if i == 6
{
print("Moving to next view")
}
}
xpos += 80
ypos = 20
}
size = CGRectMake(10, 500, 300, 60)
xDoor = AdventDoor(frame: size)
xDoor.opaque = false
xDoor.restorationIdentifier = "\(25)"
xDoor.generateDoor()
adventDoors.append(xDoor)
index = 0
for door in adventDoors
{
index++
self.view?.addSubview(door)
}
print("\(index) doors were added")
}
}
GameViewController.swift
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
//skView.showsFPS = true
//skView.showsNodeCount = true
/* 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
scene.backgroundColor = UIColor.greenColor()
skView.presentScene(scene)
scene.test()
//Snow
let wrappedSnowPath = NSBundle.mainBundle().pathForResource("Snow", ofType: "sks")
if let snowPath = wrappedSnowPath
{
let snowEmitter:SKEmitterNode = NSKeyedUnarchiver.unarchiveObjectWithFile(snowPath) as! SKEmitterNode
let screenBounds = UIScreen.mainScreen().bounds
snowEmitter.position = CGPointMake(screenBounds.width, screenBounds.height)
scene.addChild(snowEmitter)
}
}
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
AdventDoor.swift just contains a custom UIView (AdventDoor) along with some more functions
This is what it looks like.
As you can see, the snow SKEmitterNode particles are behind the AdventDoors and not in front.
How would I get my snow to display in front of the UIView Advent Doors instead of behind?
Instead of addsubview for the door, What you need to do is rearrange how your views are laid out. What you need is a UIView as your main view, then you add the SKView as a child to the main view. Then if you want to add the doors in during the scene creation process, you need to do self.view.superview.insertSubView(door, atIndex:0) or self.view.superview.insertSubView(door, belowSubView:self.view) so that the doors are placed behind the scene subview