iCarousel in Sprite Kit

你说的曾经没有我的故事 提交于 2019-12-07 19:37:34

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/37756502/icarousel-in-sprite-kit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!