Установка положения пользовательского SKSpriteNode из GameScene

Я делаю собственный SKSpriteNode, когда я вызываю createShip, константа heroShip в классе верна, но когда я возвращаюсь к gameScene, константа heroShip не имеет свойств, которые я назначил при вызове createShip, я не уверен что я делаю неправильно. Я пытался использовать функцию класса, но это не работает с использованием свойств высоты и ширины.

Пользовательский класс SKSpriteNode

class hero: SKSpriteNode {
    var width: CGFloat = 0.0
    var height: CGFloat = 0.0

     func createShip() -> SKSpriteNode {
        let heroShip = SKSpriteNode(imageNamed: "heroShip")
            heroShip.anchorPoint = CGPointMake(1.0, 0.5)
            heroShip.physicsBody = SKPhysicsBody(rectangleOfSize: heroShip.size)
            heroShip.physicsBody?.usesPreciseCollisionDetection = true
              heroShip.zPosition = 1.0
            heroShip.physicsBody?.mass = 0.02
            heroShip.physicsBody?.dynamic = true
            heroShip.physicsBody?.affectedByGravity = false
            heroShip.physicsBody?.categoryBitMask = ObjectCategory.collisionHeroCategory.rawValue
            heroShip.physicsBody?.contactTestBitMask = ObjectCategory.sceneCategory.rawValue
            heroShip.physicsBody?.collisionBitMask = 0x0 | ObjectCategory.sceneCategory.rawValue

            //heroShip.position = CGPointMake((scene?.frame.size.width)!/6.0, (scene?.frame.size.height)!/2.0)

        heroShip.position = CGPointMake(width, height)

        return heroShip


    }
}

Моя игровая сцена

class GameScene: SKScene,SKPhysicsContactDelegate{


    let background = SKSpriteNode(imageNamed: "background")
    var score:Int = 0
    let scoreLabel = SKLabelNode(fontNamed: "Courier")
    let MotionManager = CMMotionManager()
    var heroShip = hero()
    override func didMoveToView(view: SKView) {
        heroShip.width = self.size.width/6.0
        heroShip.height = self.size.height/2.0
        heroShip.createShip()
        let enemyShip = SKSpriteNode(imageNamed: "enemyShip")
        /* Setup your scene here */
        self.physicsWorld.contactDelegate = self
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(0,heroShip.size.width/1.25,frame.width,frame.height - heroShip.size.width*1.6))
        scene?.physicsBody?.contactTestBitMask = ObjectCategory.sceneCategory.rawValue
        scene?.physicsBody?.categoryBitMask = ObjectCategory.sceneCategory.rawValue
        background.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
        scoreLabel.fontColor = SKColor.whiteColor()
        scoreLabel.text = String(format: "Score: %01u",score)
        scoreLabel.position = CGPointMake(frame.size.width/2, frame.size.height - scoreLabel.frame.size.width/1.2)
        scoreLabel.zPosition = 1.0


        enemyShip.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
        enemyShip.zPosition = 1.0
        enemyShip.physicsBody = SKPhysicsBody(rectangleOfSize: heroShip.size)
        enemyShip.physicsBody?.usesPreciseCollisionDetection = true
        enemyShip.physicsBody?.mass = 0.02
        enemyShip.physicsBody?.dynamic = true
        enemyShip.physicsBody?.affectedByGravity = false
        enemyShip.physicsBody?.categoryBitMask = ObjectCategory.collisionEnemyCategory.rawValue
        enemyShip.physicsBody?.contactTestBitMask = ObjectCategory.collisionBulletCategory.rawValue
        enemyShip.physicsBody?.collisionBitMask = 0x0

        self.addChild(enemyShip)
        self.addChild(background)
        self.addChild(self.heroShip)
        self.addChild(scoreLabel)

        if MotionManager.accelerometerAvailable{
            MotionManager.startAccelerometerUpdates()
        }

    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let bullet = SKSpriteNode(imageNamed: "bullet")
        bullet.position = CGPointMake(heroShip.position.x, heroShip.position.y)
        bullet.zPosition = 1.0
        // Add physics body for collision detection
        bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.frame.size)
        bullet.physicsBody?.dynamic = true
        bullet.physicsBody?.affectedByGravity = false
        bullet.physicsBody?.categoryBitMask = ObjectCategory.collisionBulletCategory.rawValue
        bullet.physicsBody?.contactTestBitMask = ObjectCategory.collisionHeroCategory.rawValue
        bullet.physicsBody?.collisionBitMask = 0x0;
        let action = SKAction.moveToX(CGRectGetMaxX(self.frame) + bullet.size.width, duration: 0.75)
        self.addChild(bullet)
        bullet.runAction(action, completion: {
            bullet.removeAllActions()
            bullet.removeFromParent()
        })
    }

    func didBeginContact(contact: SKPhysicsContact) {
        if contact.bodyB.categoryBitMask == ObjectCategory.collisionBulletCategory.rawValue && contact.bodyA.categoryBitMask == ObjectCategory.collisionEnemyCategory.rawValue{
        score++
        }
    }



    override func update(currentTime: CFTimeInterval) {
        let data = MotionManager.accelerometerData
        if data?.acceleration.x == nil{
            print("nil")
        }
        else if fabs((data?.acceleration.x)!) > 0.2 {
            heroShip.physicsBody?.applyForce(CGVectorMake(0.0, CGFloat(40 * (data?.acceleration.x)!)))
        }

        scoreLabel.text = String(format: "Score: %01u",score)


    }
}

person Brandon Tomblinson    schedule 19.01.2016    source источник


Ответы (2)


Ты бежишь

heroShip.createShip()

а затем никогда ничего не делайте с возвращаемым SKSpriteNode. Насколько я могу судить, класс героя это корабль-герой. Я исхожу из этого предположения для остальной части этого ответа.

Начиная с вершины GameScene, вам следует провести некоторый рефакторинг.

var heroShip = hero() будет заменен на init с использованием структуры SKSpriteNode:

var heroShip = hero(imageNamed: "heroShip")

Переходя к hero классу, func createShip() -> SKSpriteNode { нужно превратить в func createShip() {. Поскольку у вас уже настроен узел с текстурой изображения и вы используете класс hero в качестве узла, нет необходимости возвращать SKSpriteNode.

Удалите let heroShip = SKSpriteNode(imageNamed: "heroShip"), поскольку класс hero будет нашим heroShip.

Замените любое использование переменной heroShip.whatever на self.whatever. В конце удалите файл return heroShip.

person Gliderman    schedule 19.01.2016
comment
Зачем делать это двухэтапным процессом? Просто перепишите удобный init для обработки SKPhysicsBody, это на 1 шаг меньше, о котором нужно беспокоиться при создании нового героя. - person Knight0fDragon; 20.01.2016
comment
@Knight0fDragon Я не был уверен, каков план ОП на это, поэтому я не стал его трогать. - person Gliderman; 20.01.2016
comment
Мне нужно будет убедиться, что когда я вернусь домой, я не думаю, что вам придется его реализовывать, поскольку вы используете назначенный конструктор базового класса, но я могу ошибаться. - person Knight0fDragon; 20.01.2016
comment
@Gliderman, так как бы вы справились с динамической позицией, чтобы она масштабировалась для всех размеров экрана? Моя главная проблема заключалась в том, как получить «GameScene.size» в createShip. - person Brandon Tomblinson; 20.01.2016
comment
Просто получите размер родительского узла вашего героя - person Knight0fDragon; 20.01.2016
comment
и вы не реализуете createShip, используя это, чтобы установить физику, положение и т. д. - person Brandon Tomblinson; 20.01.2016
comment
как бы вы сделали это из класса героев @Knight0fDragon - person Brandon Tomblinson; 20.01.2016
comment
Давайте продолжим обсуждение в чате. - person Knight0fDragon; 20.01.2016

Похоже, вы не понимаете, что происходит с вашим кодом.

На данный момент createShip() создает корабль-герой, но вы никогда его не используете.

Глядя на ваш код, кажется, что createShip() даже не нужен. Глядя на это, герой ЕСТЬ heroShip, так что сделайте код в вашем файле init.

    convenience init(imageNamed: String,sceneSize:CGSize) {
    let heroTexture = SKTexture(imageNamed: imageNamed)

    self.init(texture: heroTexture, color: UIColor.whiteColor(), size: heroTexture.size()) //This may need to be tweeked, my mac is dead right now to verify.
    self.anchorPoint = CGPointMake(1.0, 0.5)
    self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
    self.physicsBody?.usesPreciseCollisionDetection = true
    self.zPosition = 1.0
    self.physicsBody?.mass = 0.02
    self.physicsBody?.dynamic = true
    self.physicsBody?.affectedByGravity = false
    heroShip.physicsBody?.categoryBitMask = ObjectCategory.collisionHeroCategory.rawValue
        heroShip.physicsBody?.contactTestBitMask = ObjectCategory.sceneCategory.rawValue
        heroShip.physicsBody?.collisionBitMask = 0x0 | ObjectCategory.sceneCategory.rawValue

    //self.position = CGPointMake((scene?.frame.size.width)!/6.0, (scene?.frame.size.height)!/2.0)

    self.position = CGPointMake(sceneSize.width, sceneSize.height)



}

Теперь вы сталкиваетесь с другой проблемой, и это то, что ваш SKPhysicsBody не будет выровнен с вашей точкой привязки.

Чтобы исправить это, создайте SKPhysicsBody следующим образом:

let centerPoint = CGPointMake(self.size.width / 2 - (self.size.width * self.anchorPoint.x), self.size.height / 2 - (self.size.height * self.anchorPoint.y))
self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size, center: centerPoint)
person Knight0fDragon    schedule 19.01.2016
comment
Я исправил это, также нужно было добавить цвет, так как это тот, который связан с делегирующим конструктором, плюс я добавил sceneSize, так как мы говорили о том, что он вам нужен в чате, поэтому, чтобы создать героя, сделайте let heroShip = hero(imageNamed:heroShip ,sceneSize:self.size) - person Knight0fDragon; 20.01.2016
comment
у вас есть и другие проблемы, ваши другие проблемы заключаются в том, что bodyA никогда не гарантируется как пуля, поэтому вам необходимо учитывать оба случая, когда bodyA является пулей, а bodyB - пулей, и ваши категории должны быть в степени 2, это флаги битовой маски, поэтому 3 на самом деле означает sceneCategory и collissionHero, потому что в двоичном формате 3 равно 0011 (таким образом, 2 категории), но вам нужно сделать его 0100 в двоичном формате, чтобы дать ему уникальную категорию - person Knight0fDragon; 20.01.2016