使用 spritekit swift 为 swift 中的游戏创建主菜单

Create a main menu for game in swift using spritekit swift

我是 swift 的新手,我有一个 SKScene,我在其中创建了一个游戏。但是,我似乎无法弄清楚如何构建菜单。如果看到创建另一个视图控制器或另一个 SKScene 的两种解决方案,但它们都非常混乱和复杂。我愿意使用这些方法或任何其他方法,有没有人有解决这个问题的技巧。一些代码会有所帮助。感谢您的帮助。

方法:

下面提到的代码使用 UIStackview 创建 2 个部分。 您可以使用类似的方法。

输出:

代码:

class ViewController: UIViewController {

    private let baseSection = UIStackView()
    private let section1    = UIStackView()

    private let titleLabel  = UILabel()
    private let button1     = UIButton(type: .custom)
    private let button2     = UIButton(type: .custom)
    private let button3     = UIButton(type: .custom)
    

    //MARK: Load view
    override func viewDidLoad() {
        super.viewDidLoad()

        setupViews()
    }

    
    //MARK: Setup views
    private func setupViews() {
        
        setupBaseSection()
        setupTitleLabel()
        setupButton1()
        setupSection1()
        setupButton2()
        setupButton3()
    }
    
    private func setupTitleLabel() {
        
        titleLabel.text      = "Swirl"
        titleLabel.font      = UIFont.preferredFont(forTextStyle: .headline)
        titleLabel.textColor = #colorLiteral(red: 0.8156862745, green: 0.9137254902, blue: 0.1647058824, alpha: 1)
        
        baseSection.addArrangedSubview(titleLabel)
    }
    
    private func setupButton1() {
        
        button1.backgroundColor = #colorLiteral(red: 0.9098039216, green: 0.168627451, blue: 0.3921568627, alpha: 1)
        
        baseSection.addArrangedSubview(button1)
        
        button1.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.2).isActive = true
        button1.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }
    
    private func setupButton2() {
        
        button2.backgroundColor = #colorLiteral(red: 0.8156862745, green: 0.9137254902, blue: 0.1647058824, alpha: 1)
        
        section1.addArrangedSubview(button2)
        
        button2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.1).isActive = true
        button2.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }
    
    private func setupButton3() {
        
        button3.backgroundColor = #colorLiteral(red: 0.8156862745, green: 0.9137254902, blue: 0.1647058824, alpha: 1)
        
        section1.addArrangedSubview(button3)
        
        button3.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.2).isActive = true
        button3.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }
    
    //MARKL Set up stack views
    
    private func setupBaseSection() {

        baseSection.axis          = .vertical
        baseSection.distribution  = .fill
        baseSection.alignment     = .center
        baseSection.spacing       = 10

        
        baseSection.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(baseSection)
        
        baseSection.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        baseSection.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        baseSection.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }
    
    private func setupSection1() {
        
        section1.axis         = .horizontal
        section1.distribution = .equalSpacing
        section1.alignment    = .fill
        section1.spacing      = 20
        
        baseSection.addArrangedSubview(section1)
    }
}

Sprite-Kit中有多种获取菜单的方法。

通常人们会画一些SKLabelNode,或SKSpriteNode来构建菜单语音或制作特定的SKNode来构建这种结构。

但我想听从关于 StackView 的评论的建议。 我们知道 StackView 是一个 UIKit 元素:

Provides a streamlined interface for laying out a collection of views in either a column or a row.

因此,我们可以构建一个垂直 StackView 包含所有菜单声音(P.S。下面的代码显示了一个简单的标签集合,您可以自定义您的 StackView 视图如你所愿):

import SpriteKit
import UIKit
protocol StackViewDelegate: class {
    func didTapOnView(at index: Int)
}
class GameMenuView: UIStackView {
    weak var delegate: StackViewDelegate?
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.axis = .vertical
        self.distribution = .fillEqually
        self.alignment = .fill
        self.spacing = 5
        self.isUserInteractionEnabled = true
        //set up a label
        for i in 1...5 {
            let label = UILabel()
            label.text = "Menu voice \(i)"
            label.textColor = UIColor.white
            label.backgroundColor = UIColor.blue
            label.textAlignment = .center
            label.tag = i
            self.addArrangedSubview(label)
        }
        configureTapGestures()
    }
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func configureTapGestures() {
        arrangedSubviews.forEach { view in
            view.isUserInteractionEnabled = true
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapOnView))
            view.addGestureRecognizer(tapGesture)
        }
    }
    func didTapOnView(_ gestureRecognizer: UIGestureRecognizer) {
        if let index = arrangedSubviews.index(of: gestureRecognizer.view!) {
            delegate?.didTapOnView(at: index)
        }
    }
}
class GameScene: SKScene, StackViewDelegate {
    var gameMenuView = GameMenuView()
    private var label : SKLabelNode?
    override func didMove(to view: SKView) {
        self.label = self.childNode(withName: "//helloLabel") as? SKLabelNode
        if let label = self.label {
            label.alpha = 0.0
            label.run(SKAction.fadeIn(withDuration: 2.0))
        }
        // Menu setup with stackView
        gameMenuView.frame=CGRect(x:20,y:50,width:280,height:200)
        view.addSubview(gameMenuView)
        gameMenuView.delegate = self
    }
    func didTapOnView(at index: Int) {
        switch index {
        case 0: print("tapped voice 1")
        case 1: print("tapped voice 2")
        case 2: print("tapped voice 3")
        case 3: print("tapped voice 4")
        case 4: print("tapped voice 5")
        default:break
        }
    }
}

输出:

我经历过向 SpriteKit 场景添加 UI 按钮和 UI 标签可能会遇到定位它们的技术问题。由于 UI Objects 位于视图上,而不是直接位于 SpriteKit 场景上。您可以使用 SKSpriteNode 作为按钮和 SKLabelNode 作为标题,用于菜单场景。

Sprite 套件场景放置在 UIView 上,并根据您定义的缩放模式进行缩放。 Apple 的默认缩放模式 .aspectFill 不需要调整 Sprite 套件 objects 在不同 Phone 设备屏幕尺寸上的定位。

这是 SKSpriteNode 的自定义 Class,具有与按钮相同的功能。

 import Foundation
 import SpriteKit

 class ButtonLabelNode : SKSpriteNode {

let buttonPressed: () -> ()

init(texture: SKTexture?, color: UIColor, size: CGSize, text: String, buttonPressed: @escaping () -> ()) {

    self.buttonPressed = buttonPressed

    super.init(texture: texture, color: color, size: size)

    let label = SKLabelNode(fontNamed: "Futura")
    label.fontSize = 50
    label.fontColor = SKColor.red
    label.position = CGPoint.init(x: 0.0, y: 0.0)
    label.zPosition = 1
    label.verticalAlignmentMode = .center
    label.text = text
    self.addChild(label)

    self.isUserInteractionEnabled = true

}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    self.alpha = 0.8

}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    self.alpha = 1.0

  buttonPressed()
}

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

 }

当在 SpriteNode 上开始触摸时,alpha 降低到 0.8,并在触摸结束时回到 1.0,使其具有与 UIButton 相同的视觉效果。在重写的函数中'touchesEnded'有一个函数会在每次按下按钮时调用,该函数被添加到初始化程序中,可以在您的游戏场景中进行初始化。

override func didMove(to view: SKView) {

    let labelNode = LabelNode(texture: nil, color: .white, size: CGSize.init(width: 200, height: 100), text: "Play", buttonPressed: playButton)
    labelNode.position = CGPoint(x: self.frame.midX, y: self.frame.midY)

    self.addChild(labelNode)

    }

    func playButton() 
    {
    print("play")
     }

您可以根据需要创建任意数量的此 class 实例,并赋予它们自己的功能,因为添加的初始化函数对其自身的实例而言是独一无二的。与 class 所需的协议方法不同,因为这会影响 class.

的所有实例