使用 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.
的所有实例
我是 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.
的所有实例