swift - 在调用 super.init() 之前实例化调用自身的属性

标签 swift oop sprite-kit instantiation self

我在我的第一个 Swift 游戏中构建了 ShipGenericGun 类,我在实例化其中一个 Ships 时遇到了问题> 属性。有问题的属性 aGun 调用 self 作为其值,但出现错误是因为必须在调用 super.init()< 之前设置属性,该属性依赖于 self,它只能在 super.init() 被调用后访问。我玩了一堆,发现在变量上使用可选会使错误消失,但我不确定为什么也不知道它是否会长期有效。这是我的枪类:

class genericGun{

    var theShip:Ship
    var theGameScene:GameScene

    init(gameScene:GameScene, shipInstance:Ship){
        theShip = shipInstance
        theGameScene = gameScene
    }

    func addLaser(){
        let aLaser = Laser(laserPosition: theShip.position)
        theShip.lasers.append(aLaser)
    }

    //If statement on user touch to call this
    func shoot(){
        //Pull out the laser from the ship
        let availableLaser = theShip.lasers.removeLast()

        let constY:CGFloat = theShip.position.y
        availableLaser.position = CGPoint(x: theShip.position.x, y:constY)
        //Set its speed
        availableLaser.physicsBody?.velocity = CGVector(dx: 400.0,dy: 0)
        //Add it to the scene
        theGameScene.addChild(availableLaser)

        theShip.canShoot = false
        func printHey(){print("Hey!!!!!!!!!!!!!!!!!!!!!!")}
        let sayHey = SKAction.runBlock{printHey()}
        let reloadTime = SKAction.waitForDuration(1)
        let loadGun = SKAction.sequence([reloadTime, sayHey])

        theShip.runAction(SKAction.repeatActionForever(loadGun))
    }
}

激光类:

class Laser:SKSpriteNode{

    init(laserPosition:CGPoint){

        let laser = SKTexture(imageNamed: "Sprites/laser.jpg")

        super.init(texture: laser, color: UIColor.clearColor(), size: laser.size())

        //Laser physics
        self.physicsBody = SKPhysicsBody(circleOfRadius: laser.size().width/2)
        self.physicsBody?.dynamic = true
        self.physicsBody?.categoryBitMask = PhysicsCategory.Laser
        self.physicsBody?.contactTestBitMask = PhysicsCategory.Alien
        self.physicsBody?.collisionBitMask = PhysicsCategory.None
        self.physicsBody?.collisionBitMask = 0;
        self.physicsBody?.usesPreciseCollisionDetection = true
        self.physicsBody?.linearDamping = 0.0;
    }


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

船级:

class Ship:SKSpriteNode{

    static var shipState = "norm"

    //A dictionary with String keys and AnyType array values
    static var shipTypes: [String: [Any]] = [

        "norm":[SKTexture(imageNamed:"Sprites/fullShip.png"), SKTexture(imageNamed:"Sprites/laser.jpg"),7],
        "rapid":[SKTexture(imageNamed:"Sprites/fullShip.png"),7],
        "bazooka":[SKTexture(imageNamed:"Sprites/fullShip.png"),7]
    ]

    var moveSpeed:CGFloat
    var lives:Int

    var lasers = [SKSpriteNode]()
    var canShoot = false
    var aGun: genericGun? = nil
    var theGameScene:GameScene

    static var shipImage = SKTexture(imageNamed:"Sprites/fullShip.png")//: Int = Int(shipTypes[shipState]![0])

    init(gameScene:GameScene, startPosition startPos:CGPoint, controllerVector:CGVector){

        self.lives = 3
        self.moveSpeed = 200
        theGameScene = gameScene

        //Call super initilizer
        super.init(texture: Ship.shipImage, color: UIColor.clearColor(), size: Ship.shipImage.size())


        self.aGun = genericGun(gameScene: theGameScene, shipInstance: self)


        self.setScale(0.2)
        //Position is an property of SKSpriteNode so super must be called first
        self.position = startPos

        //Physics of the ship
        self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2)
        self.physicsBody?.dynamic = true
        self.physicsBody?.collisionBitMask = 0//PhysicsCategory.Ship
        self.physicsBody?.contactTestBitMask = PhysicsCategory.Ship
        self.physicsBody?.allowsRotation = false
        self.physicsBody?.angularVelocity = CGFloat(0)
        self.physicsBody?.affectedByGravity = false //TBD

        self.physicsBody?.velocity.dx = controllerVector.dx * moveSpeed
        self.physicsBody?.velocity.dy = controllerVector.dy * moveSpeed 
    }

    func updateVelocity(v:CGVector){

        if(v == CGVector(dx:0,dy:0)){
            self.physicsBody?.velocity = CGVector(dx: 0,dy: 0)
        }
        self.physicsBody?.velocity.dx = v.dx * moveSpeed
        self.physicsBody?.velocity.dy = v.dy * moveSpeed
    }

    func updateLaserPos(){
        //            laser.position = self.position
    }

    func updateShipProperties(shipVelocity v:CGVector,laserStartPos laserStart:CGPoint){
        updateVelocity(v)
        updateLaserPos()
    }

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

这就是飞船实例化的地方:

class GameScene: SKScene, SKPhysicsContactDelegate {
    var aShip = Ship(gameScene:GameScene(), startPosition: CGPoint(x:50,y:200),controllerVector: controlVector)

最佳答案

如果您的游戏设计方式是 Ship 需要创建 GunGun 需要 在初始化之前发送你会遇到很多麻烦。

SpriteKit already solved this kind of problem with the scene property available in SKNode. It returns the scene the current node belongs to.

你可以做类似的事情,让你的生活更轻松

class Ship: SKSpriteNode {
    lazy var gun: Gun? = { return self.children.flatMap { $0 as? Gun }.first }()
}

如您所见,我创建了一个惰性属性,当您调用 Shipgun 属性时,它会自动填充第一个 Gun 在它的 child 中找到。

您可以对 Gun 对象执行相同的操作,因为您可以看到它有一个惰性变量 ship,它的父对象有条件地转换为 Ship

class Gun: SKSpriteNode {
    lazy var ship: Ship? = { return self.parent as? Ship }()
}

测试

let gun = Gun()
let ship = Ship()
ship.name = "Enteprise"
ship.addChild(gun)

print(gun.ship?.name) // Optional("Enterprise")

注意事项

按照 SpriteKit 对 scene 属性所做的操作,我将属性 gunship 设为可选。这意味着如果 Gun 不是 Ship 的直接子级,那么它的 ship 属性将返回 nil

类似地,如果 Ship 在其子项中没有 Gun,那么它的 gun 属性将返回 nil.

性能

由于 shipgun 属性是lazy 它们将需要很少的时间(第一次读取它们时)被填充。您不会注意到延迟,但请记住它。

使用计算属性

您可以将它们定义为计算属性,而不是让 shipgun 成为惰性属性。在这种情况下,如果您将枪支从一艘船移到另一艘船,您将获得一致的结果。

另一方面,在这种情况下,每次阅读 shipgun 时,您都需要花费非常(非常非常)少的时间。

class Ship: SKSpriteNode {
    var gun: Gun? { return self.children.flatMap { $0 as? Gun }.first }
}

class Gun: SKSpriteNode {
    var ship: Ship? { return self.parent as? Ship }
}

关于swift - 在调用 super.init() 之前实例化调用自身的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38643240/

相关文章:

ios - 使用 swift 1.2 之前版本构建框架

swift - 需要解释在自定义类型上声明惰性属性

oop - Liskov 替换原则是否与开放/封闭原则冲突?

swift - 碰撞在 swift + sprite 套件中不起作用

swift - 重新启动 SKEmitterNode 而不删除粒子

uitableview - swift 为 UITableView 加载更多内容

ios - 当更改 Root View Controller 时,初始 View Controller 显示一秒或半秒

javascript对象,自引用问题

c# - OOP C# 问题 : Making a Fruit a Pear

ios - Swift SpriteKit 健康栏