SpriteKitでのタブの実装方法

SKScene内に複数のSKNodeを配置し、タブをタップした際に、表示するノードを切り替える必要があります。以下は、SpriteKitでタブのような機能を実装するプログラム例です。

class TabScene: SKScene {

    // タブのボタン
    let tabButtons = [SKSpriteNode(imageNamed: "tab1"), SKSpriteNode(imageNamed: "tab2"), SKSpriteNode(imageNamed: "tab3")]

    // タブのコンテンツ
    let tabContents = [SKNode(), SKNode(), SKNode()]

    var currentTab = 0

    override func didMove(to view: SKView) {
        // タブボタンを配置する
        let tabButtonHeight: CGFloat = 50
        for (index, button) in tabButtons.enumerated() {
            button.position = CGPoint(x: size.width / 2 + (CGFloat(index) - 1) * button.size.width, y: size.height - tabButtonHeight / 2)
            addChild(button)
        }

        // 初期タブのコンテンツを表示する
        showTabContent()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }

        let location = touch.location(in: self)

        // タブがタップされた場合、タブを切り替える
        for (index, button) in tabButtons.enumerated() {
            if button.contains(location) {
                currentTab = index
                showTabContent()
                break
            }
        }
    }

    func showTabContent() {
        // 現在のタブのコンテンツを削除する
        for node in children {
            node.removeFromParent()
        }

        // 現在のタブのコンテンツを表示する
        for (index, content) in tabContents.enumerated() {
            if index == currentTab {
                addChild(content)
                break
            }
        }
    }
}

上記の例では、TabSceneという名前のSKSceneを作成しています。SKScene内には、tabButtonsとtabContentsという2つの配列を定義しています。tabButtonsには、タブのボタンを格納しており、tabContentsには、タブのコンテンツを格納しています。currentTab変数は、現在表示しているタブを示しています。

didMove(to:)メソッド内では、タブボタンを配置しています。タブボタンをタップした際には、touchesBegan(_:with:)メソッドが呼ばれ、現在のタブを変更する処理が行われます。showTabContent()メソッドを呼び出すことで、現在のタブのコンテンツを表示します。

showTabContent()メソッド内では、現在のタブのコンテンツを表示する前に、すでに表示されているコンテンツをすべて削除しています。その後、現在のタブに対応するコンテンツを追加しています。

上記の例では、tabButtonsとtabContentsに、それぞれ3つの要素を設定しています。これは、タブの数とコンテンツの数を表しています。また、タブのボタンとコンテンツは、それぞれ配列のインデックスで対応付けられています。

各タブのコンテンツは、TabSceneクラスを継承した別のクラスで定義することができます。タブごとに表示するノードを追加して、タブのコンテンツを設定することができます。

以上のように、SKScene内に複数のノードを配置し、タブをタップした際に、表示するノードを切り替えることで、SpriteKitでタブのような機能を実装することができます。

以下は、TabSceneを使ったサンプルアプリの例です。

まずは、3つのタブに対応するコンテンツを用意します。ここでは、それぞれ、赤、緑、青の背景色を持つSKSpriteNodeを作成します。

class RedTabContent: SKSpriteNode {
    override init() {
        super.init(texture: nil, color: .red, size: CGSize(width: 100, height: 100))
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class GreenTabContent: SKSpriteNode {
    override init() {
        super.init(texture: nil, color: .green, size: CGSize(width: 100, height: 100))
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class BlueTabContent: SKSpriteNode {
    override init() {
        super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

次に、これらのタブコンテンツをTabSceneに追加します。タブボタンには、画像ファイルを使用します。

class GameScene: SKScene {
    override func didMove(to view: SKView) {
        let tabScene = TabScene(size: size)

        let redTabContent = RedTabContent()
        let greenTabContent = GreenTabContent()
        let blueTabContent = BlueTabContent()

        tabScene.tabButtons[0].texture = SKTexture(imageNamed: "redTabButton")
        tabScene.tabContents[0] = redTabContent

        tabScene.tabButtons[1].texture = SKTexture(imageNamed: "greenTabButton")
        tabScene.tabContents[1] = greenTabContent

        tabScene.tabButtons[2].texture = SKTexture(imageNamed: "blueTabButton")
        tabScene.tabContents[2] = blueTabContent

        addChild(tabScene)
    }
}

上記の例では、GameScene内に、TabSceneを追加しています。また、赤、緑、青のタブコンテンツを作成して、TabSceneに追加しています。また、タブボタンには、画像ファイルを使用しています。

以上のように、SKScene内に複数のノードを配置し、タブをタップした際に、表示するノードを切り替えることで、SpriteKitでタブのような機能を実装することができます。この例では、TabSceneにタブボタンとタブコンテンツを追加しています。また、GameScene内にTabSceneを追加しています。

SKSpriteNodeを使用したボタンの実装例

SpriteKitでは、SKSpriteNodeを使用してボタンを作成することができます。以下は、SpriteKitでボタンを実装する例です。

class ButtonNode: SKSpriteNode {

    init(imageNamed: String) {
        let texture = SKTexture(imageNamed: imageNamed)
        super.init(texture: texture, color: .clear, size: texture.size())
        isUserInteractionEnabled = true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // ボタンがタップされた時の処理を実装する
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        // ボタンがタップされた後の処理を実装する
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        // タッチがキャンセルされた場合の処理を実装する
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

上記の例では、ButtonNodeという名前のクラスを作成しています。SKSpriteNodeを継承しているため、SKTextureを使用してボタンの画像を読み込んでいます。

また、isUserInteractionEnabledプロパティをtrueに設定することで、SKSpriteNodeをタッチ可能にしています。touchesBegan、touchesEnded、touchesCancelledメソッドをオーバーライドすることで、タップされた際の処理を実装することができます。

ボタンの初期化時に、以下のようにButtonNodeクラスをインスタンス化して、SKSceneに追加することで、ボタンを表示することができます。

let button = ButtonNode(imageNamed: "buttonImageName")
button.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
self.addChild(button)

上記の例では、ButtonNodeクラスのインスタンスを作成し、positionプロパティを使用して、ボタンの位置を調整しています。addChildメソッドを使用して、SKSceneにボタンを追加しています。

以上のように、SpriteKitではSKSpriteNodeを使用してボタンを作成することができます。タッチされた際の処理をオーバーライドすることで、ボタンをタップした際の動作を実装することができます。

SKsceneの切り替え方法について

SpriteKitでシーンの切り替え方法について記載します。

  1. SKView.presentScene(_:)メソッドを使用する

SKView.presentScene(_:)メソッドを使用することで、現在表示されているSKSceneを切り替えることができます。

let newScene = MyScene(size: self.size)
self.view?.presentScene(newScene)

上記の例では、MySceneクラスのインスタンスを作成し、presentSceneメソッドを使用して、現在表示されているSKSceneをMySceneに切り替えています。

  1. SKTransitionを使用する

SKTransitionを使用することで、SKSceneの切り替え時にアニメーションを追加することができます。

let newScene = MyScene(size: self.size)
let transition = SKTransition.fade(withDuration: 0.5)
self.view?.presentScene(newScene, transition: transition)

上記の例では、MySceneクラスのインスタンスを作成し、SKTransition.fadeを使用して、現在表示されているSKSceneをフェードアウトさせながらMySceneに切り替えています。

基本的には2を使用してViewの切り替えを行うことが一般的かと思います。ただ、アニメーション使うと少しうざったい可能性もあるので、時と場合によって変えていくんでしょうね。

Transitionの種類もたくさんありますので、何個か試してみて気に入ったものを使っていきましょう。切り替えアニメーションの時間が長くなると待ちが増えますので、それも注意が必要です。


以下は、複数のSKSceneがある場合の例です。

let newScene: SKScene

if someCondition {
    newScene = MyScene1(size: self.size)
} else {
    newScene = MyScene2(size: self.size)
}

self.view?.presentScene(newScene)

上記の例では、someConditionという条件に基づいて、新しいSKSceneを選択しています。someConditionがtrueの場合は、MyScene1を、falseの場合はMyScene2を選択しています。新しいSKSceneを選択した後に、SKView.presentScene(_:)メソッドを使用して、現在表示されているSKSceneを切り替えています。

また、SKTransitionを使用して、SKSceneの切り替えにアニメーションを追加することもできます。以下は、一例です。

let newScene: SKScene

if someCondition {
    newScene = MyScene1(size: self.size)
} else {
    newScene = MyScene2(size: self.size)
}

let transition = SKTransition.fade(withDuration: 0.5)
self.view?.presentScene(newScene, transition: transition)

上記の例では、SKTransition.fadeを使用して、フェードアウトしながらSKSceneを切り替えています。

以上のように、複数のSKSceneがある場合でも、SKView.presentScene(_:)メソッドを使用して、SKSceneの切り替えを行うことができます。切り替えるSKSceneを選択する前に、必要に応じて条件分岐などを行うことができます。また、SKTransitionを使用してアニメーションを追加することもできます。