swift - 在场景之间移动时从 SpriteKit 内部丢失对 GameViewController 的引用 - 想要在 SKScene 和 UITableView 之间移动
问题描述
我有一个简单的(多场景)spritekit 游戏,想使用 UITableViewContoller 实现和显示设置屏幕。我很接近,但是当我改变场景时,我一直失去对游戏视图控制器的引用,这意味着我只能在我的游戏开始时在第一个场景中继续使用 UITableViewController。我希望有人能帮忙。我在情节提要中设置了 UITableView,并从那里的 GameViewController 中设置了对 tableview 的 segue。
我的 GameViewController 文件中有以下设置:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene
if let scene = SKScene(fileNamed: "MenuScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
//I'VE ADDED THIS
if let gameScene = scene as? MenuScene {
gameScene.viewController = self
}
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
}
}
func showSettings() {
performSegue(withIdentifier: "openSettings", sender: self)
}
这让我从我的 SKScene 中引用了 GameViewController。然后,当用户触摸 SKLabelNode 时,我在 spritekit 中从我的 SKScene 加载 UITableViewController。我的 MenuScene 代码的更简单版本如下所示:
class MenuScene: SKScene {
var viewController: GameViewController?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
let touch:UITouch = touches.first!
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name
{
let transition:SKTransition = SKTransition.fade(withDuration: 0.75)
var scene:SKScene = SKScene()
if (name == "settingsBTN"){
viewController?.showSettings()
}
else if (name == "randomBTN"){
scene = StarScene(size: self.size)
scene.backgroundColor = SKColor.black
self.view?.presentScene(scene, transition: transition)
}
}
}
}//菜单场景结束
当我第一次开始游戏时点击设置 BTN 时,表格视图呈现良好。但是,如果我在我的游戏中访问另一个场景(例如,通过按 randomBTN)并返回菜单场景,我将无法继续进入设置视图,因为我失去了对视图控制器的引用(它显示为 nil)所以我可以不要在执行 segue 的 GameViewController 中调用 showSettings 方法(大概是因为我在视图控制器本身中设置了对视图控制器的引用)。
我不知道如何维护对我的 GameViewController 的引用,以便我可以随时显示设置屏幕。请有人帮忙。
解决方案
有两种简单的方法可以GameViewController
从其他类调用函数:通过 adelegate
或通过创建类实例static
。
// DELEGATE
//
// GameViewController.swift
protocol GameView_Delegate
{
func show_ui()
}
class GameViewController: UIViewController, GameView_Delegate
{
override func viewDidLoad()
{
// ...
if let view = self.view as! SKView?
{
if let scene = SKScene(fileNamed: "MenuScene")
{
scene.scaleMode = .aspectFill
// pass GameViewController reference
scene.gv_delegate = self
}
view.presentScene(scene)
}
// ...
}
func show_ui()
{
// show ui
// ...
}
}
// MenuScene.swift
class MenuScene: SKScene
{
var gv_delegate : GameView_Delegate!
func settings()
{
// call function show_ui from GameViewController
gv_delegate.show_ui()
}
func game_scene()
{
let transition = SKTransition.fade(with: UIColor.white, duration: 1.0)
let next_scene = GameScene()
next_scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
next_scene.scaleMode = self.scaleMode
next_scene.size = self.size
// before moving to next scene, we must pass the delegate, so we
// don't lose the connection with the GameViewController
next_scene.gv_delegate = gv_delegate
self.view?.presentScene(next_scene, transition: transition)
}
}
// GameScene.swift
class GameScene: SKScene
{
var gv_delegate : GameView_Delegate!
func settings()
{
// call function show_ui from GameViewController
gv_delegate.show_ui()
}
func main_scene()
{
let transition = SKTransition.fade(with: UIColor.white, duration: 1.0)
let next_scene = MainScene()
next_scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
next_scene.scaleMode = self.scaleMode
next_scene.size = self.size
// before moving to next scene, we must pass the delegate, so we
// don't lose the connection with the GameViewController
next_scene.gv_delegate = gv_delegate
self.view?.presentScene(next_scene, transition: transition)
}
}
例如,当您进入一个新场景时,我们案例中GameScene
的旧场景MainScene
被解除分配(所有变量被清空,所有引用被销毁)并GameScene
创建一个新实例并在屏幕上显示。如果之后您想退出该场景并进入MainScene
,则将创建该类的新实例,并且GameViewController
引用为空。我们应该再次引用它或在退出场景之前传递引用(如我的示例中所示)。
// STATIC
//
// GameViewController.swift
class GameViewController: UIViewController
{
static var shared : GameViewController!
override func viewDidLoad()
{
super.viewDidLoad()
GameViewController.shared = self
// ...
}
func show_ui()
{
// show ui
// ...
}
}
// MenuScene.swift
class MenuScene: SKScene
{
func settings()
{
// call function show_ui from GameViewController
GameViewController.shared.show_ui()
}
}
阅读每种方法的优缺点,然后选择最适合您的应用的方法。另外,避免在 SpriteKit 中使用 UIKit。
推荐阅读
- php - 我想打印一个表格而不打印所有行,有没有办法做到这一点?
- twilio - 如何更改 Twilio 正在进行的呼叫“收件人”字段?(使用 JS/节点)
- mysql - Aurora MySQL 加载数据无效的 utf8mb4 字符串
- regex - 根据初始字符串搜索返回一个值
- python - 线性回归图没有给我有意义的可视化
- javascript - 对对象数组进行排序不会在 javascript 中按日期正确排序所有项目
- python - 从 Python 字典将数据插入 InfluxDB
- python - 为什么以及如何在 SRGAN 中创建神经网络 [-1,1] 的输出图像范围?
- intellij-idea - AspectJ Java maven ajc:目标 JDK 应包含在“1.1”和“1.4”之间:8
- javassist - 使用javassist动态生成类做模型映射,出现java.lang.VerifyError