在Swift 2.1中的spritekit游戏中获取EXC_BAD_ACCESS

时间:2016-02-06 12:49:07

标签: swift macos sprite-kit

使用SpriteKit在swift中编写我自己的游戏我遇到了一个似乎无法解决的问题。 我正在编写的游戏是针对OS X平台(非移动),使用非常标准的代码布局:

首先是我的AppDelegate:

import Cocoa
import SpriteKit

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate
{
    @IBOutlet weak var window: NSWindow!
    @IBOutlet weak var skView: SKView!

    func applicationDidFinishLaunching(aNotification: NSNotification)
    {
        /* Pick a size for the scene */
        if let scene = MainMenu(fileNamed:"MainMenu")
        {
            scene.size = CGSize(width: 1024, height: 768)
            /* Set the scale mode to scale to fit the window */
            scene.scaleMode = .AspectFit
            scene.backgroundColor = NSColor.blackColor()

            self.skView!.presentScene(scene)

            /* Sprite Kit applies additional optimizations to improve rendering performance */
            self.skView!.ignoresSiblingOrder = true

            self.skView!.showsFPS = true
            self.skView!.showsNodeCount = true

            window.acceptsMouseMovedEvents = true
        }
    }

    func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool
    {
        return true
    }
}

这会打开MainMenu场景,我有很多按钮,每个按钮都会导致其他场景。对于按钮,我已经创建了自己的SPriteKitNode子类:

    import Foundation
import SpriteKit

class Button: SKSpriteNode
{
    var isHighLighted = false
    var isPressed = false
    var normal: SKTexture
    var highlighted: SKTexture
    var pressed: SKTexture
    var disabled: SKTexture
    var isDisabled = false

    init(normal: SKTexture, highlighted: SKTexture, pressed: SKTexture, disabled: SKTexture)
    {
        self.normal = normal
        self.highlighted = highlighted
        self.pressed = pressed
        self.disabled = disabled
        super.init(texture: normal, color: NSColor.clearColor(), size: normal.size())
    }

    required init?(coder aDecoder: NSCoder)
    {
        normal = SKTexture()
        highlighted = SKTexture()
        pressed = SKTexture()
        disabled = SKTexture()
        super.init(coder: aDecoder)
    }

    func disableButton()
    {
        self.texture = disabled
        isDisabled = true
    }

    func enableButton()
    {
        self.texture = normal
        isDisabled = false
    }

    //overrides
    override func mouseEntered(theEvent: NSEvent)
    {
        if !isDisabled
        {
            isHighLighted = true
            self.texture = highlighted
        }
    }

    override func mouseExited(theEvent: NSEvent)
    {
        if !isDisabled
        {
            isHighLighted = false
            self.texture = normal
        }
    }

    override func mouseDown(theEvent: NSEvent)
    {
        if !isDisabled
        {
            isPressed = true
            self.texture = pressed
            scene?.mouseDown(theEvent)
        }
    }

    override func mouseUp(theEvent: NSEvent)
    {
        if !isDisabled
        {
            isPressed = false
            self.texture = highlighted
        }
    }
}

主菜单(不是完整的代码)在这里:

    import SpriteKit

class MainMenu: SKScene
{
    let quickGame = Button(normal: SKTexture(imageNamed: "quick"), highlighted: SKTexture(imageNamed: "quick-high"), pressed: SKTexture(imageNamed: "quick-down"), disabled: SKTexture(imageNamed: "quick-dis"))

override func didMoveToView(view: SKView)
    {
        let options = NSTrackingAreaOptions.MouseMoved.union(NSTrackingAreaOptions.ActiveInKeyWindow)
        let trackingArea = NSTrackingArea(rect: view.frame, options: options, owner: self, userInfo: nil)
        view.addTrackingArea(trackingArea)

let background = SKSpriteNode(imageNamed: "splash")
        background.position = CGPoint(x: background.size.width, y: background.size.height)
        background.userInteractionEnabled = true
        background.position = CGPoint.zero
        background.anchorPoint = CGPoint.zero
        background.zPosition = 0
        //background.setScale(1.0)
        self.addChild(background)

        //let background = self.childNodeWithName("splash")

        //let quickGame = Button(normal: textureAtlas.textureNamed("quick"), highlighted: textureAtlas.textureNamed("quick-high"), pressed: textureAtlas.textureNamed("quick-down"))

        quickGame.name = "quick game"
        quickGame.anchorPoint = CGPoint.zero
        quickGame.position = CGPoint(x: 230, y: 97)
        quickGame.userInteractionEnabled = true
        quickGame.zPosition = 100
        background.addChild(quickGame)

… rest of init here…
}

override func mouseDown(theEvent: NSEvent)
    {
        if newGame.isPressed
        {

        }
        else if quickGame.isPressed
        {
            if let quickGameScene = QuickGame(fileNamed: "QuickGame")
            {
                quickGameScene.scaleMode = self.scaleMode
                let transition = SKTransition.fadeWithDuration(1.0)
                self.removeAllChildren()
                self.removeAllActions()
                view?.presentScene(quickGameScene, transition: transition)
            }

        }
        else if quitGame.isPressed
        {
            NSApp.terminate(self)
        }
    }
}

当我点击quickGame按钮时,我收到了EXC_BAD_ACCESS。点击确定,新场景显示但是在第二次或第二次游戏崩溃后,错误被放置在Ainside AppDelegate类声明中。

我怀疑我在Button类中调用mouseDown做错了。

我希望在这里完成的是事件驱动系统,当事件触发时,消息从按钮发送到场景类,我不需要遍历所有按钮(因为在某些场景中会有很多按钮和可按下/可选元素),但只执行代码(在我目前的情况下切换场景)。

我做了一些调试,在MainMenu类调试器中更改场景之后回到了Button类,所以我认为问题就在于切换场景这个MainMen enter code here u实例可能与所有按钮一起被破坏和元素,当代码返回Button时,它的实例不再存在。我不是100%,也不知道如何解决这个问题,因为我已经开始使用swift和SPriteKit了。

1 个答案:

答案 0 :(得分:-1)

在一些日本论坛上找到了解决方案。 custom button for spritekit in swift

这可以在OS X和iOS上使用。

解决问题的方法是使用包含按钮函数的Protocol on Scene类,并通过可选委托(父场景实例)从按钮类调用这些函数。