Как добавить новые SKSprideNodes за пределы экрана и синхронизировать их анимацию с существующими объектами?

Я пытаюсь анимировать несколько SKSpriteNode одного и того же типа, используя один SKAction.

Что я хотел бы сделать, так это отобразить на экране четыре SKSpriteNode одного и того же типа. Затем анимируйте их все при нажатии кнопки и переместите их влево. Как только первый SKSpriteNode покинет экран, я хочу добавить еще один SKSpriteNode за пределы экрана с правой стороны и добавить его в этот цикл SKAction.

На изображении ниже подробно показано, что мне нужно.

введите здесь описание изображения

До сих пор мне удавалось отображать на экране четыре SKSpriteNode одного и того же типа и добавлять их в массив.

    var squareBox = SKSpriteNode()

    func addSquares(size:CGSize){

    for var i = 0; i < 4; i++ {

        // Create a new sprite node from an image
        squareBox = SKSpriteNode(imageNamed: "noBox")

        // Square pysics settings
        squareBox.physicsBody = SKPhysicsBody(rectangleOfSize: self.squareBox.frame.size)
        squareBox.physicsBody!.dynamic = false
        squareBox.physicsBody!.categoryBitMask = squareBoxCategory
        squareBox.physicsBody!.contactTestBitMask = leftEdgeCategory | edgeCategory

        // SquareBox positioning on X
        var xPos = size.width/5 + squareBox.size.height/2
        var xPosInt = Int(xPos) * (i + 1)
        xPos = CGFloat(xPosInt)
        var yPos = size.height/2 + (squareBox.size.height/2)

        squareBox.position = CGPointMake(xPos - squareBox.size.height/2, yPos)

        self.addChild(squareBox)
        squareArray.append(squareBox)

    }

}

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

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    for touch: AnyObject in touches {
        let location = touch.locationInNode(self)
        self.nodeAtPoint(location)
        if self.nodeAtPoint(location) == self.button {

            let move = SKAction.moveByX(-size.width/5 - squareBox.size.height/2, y: 0, duration: 1)

            print("button clicked!")

            for box in squareArray {
                box.runAction(move)
            }
        }
    }
}

Я создал невидимую линию шириной 1 пиксель на левом краю экрана, чтобы определить, когда первый SKSpriteNode покидает экран.

    func addLeftEdge(size:CGSize){

    let leftEdge = SKNode()
    leftEdge.physicsBody = SKPhysicsBody(edgeFromPoint: CGPointMake(1, 1), toPoint: CGPointMake(1, size.height))
    leftEdge.physicsBody!.categoryBitMask = leftEdgeCategory

    self.addChild(leftEdge)
}

Проблема с этим подходом заключается в том, что SKSpriteNode в массиве, когда я их анимирую, не реагируют на didBeginContact, когда они касаются линии 1px.

    func didBeginContact(contact: SKPhysicsContact) {

    println("contact!")

}

В конце концов, я хочу иметь возможность применять Force ко всем SKSpriteNode на экране в течение нескольких секунд, чтобы перемещать их влево и уменьшать скорость силы с течением времени, пока они все не остановятся. Моя идея заключалась в том, чтобы создать четыре объекта одного типа и добавить их на экран + добавить их в массив var squareArray = [SKSpriteNode](). Затем, когда первый SKSpriteNode покидает экран, я удаляю его из массива и снова добавляю в конец и размещаю за пределами экрана справа, чтобы он перемещался в бесшовной анимации.

У меня такое чувство, что весь мой подход неверен.

Пожалуйста, посоветуйте, как лучше всего анимировать несколько SKSpriteNode для достижения моей цели, как описано выше. Я на правильном пути?

Пожалуйста, помогите, спасибо.


person Omen    schedule 18.09.2014    source источник


Ответы (2)


Чтобы обнаружить контакт, один из SKSpriteNodes должен иметь physicsBody.Dynamic= YES;

Поскольку вы не хотите быть динамичным, я нашел быстрое решение:

leftEdge.physicsBody.Dynamic=YES; //This allows it to enter onContact
leftEdge.physicsBody.collisionBitMask=0; //Disables edge from being moved by collision
leftEdge.physicsBody.AffectedByGravity=NO; //Prevents any in game gravity from moving the edge

Это позволяет вам иметь динамическое ребро, которое может запускать onContact, но при этом ребро будет действовать так, как если бы оно не было динамическим.

person meisenman    schedule 18.09.2014
comment
Мне удалось решить проблему, создав битмаски категорий для каждого объекта (линия, квадрат, край кадра) и соответствующим образом настроив битмаски столкновения. Спасибо за подсказку! - person Omen; 22.09.2014
comment
Нет проблем. Правила, которые я перечислил, будут по-прежнему применяться. Вы не включили свои битовые маски в свой код, поэтому я предположил, что они верны. Рад, что вы нашли свой ответ. - person meisenman; 22.09.2014
comment
Спасибо за вашу помощь. Всегда приятно знать, что есть другой вариант сделать то же самое. Ваше здоровье! - person Omen; 23.09.2014

Я думаю, что это решение не очень чистое и требует гораздо больше кода, чем необходимо для получения этого эффекта. В функции update(), поскольку есть только 4 или 5 полей, почему бы вам просто не пройтись по объектам и не проверить, меньше ли какие-либо из их frame minX 0, и не сбрасываются ли они в начальную точку, которую я предполагая, что это (view.frame.width + box.size.width), потому что это полностью за кадром. Таким образом, нет никаких манипуляций с массивом, поскольку вам не нужно удалять и добавлять объекты в массив. Также вам не нужно прикреплять physicsBody там, где это не требуется. И вам не нужен левый край

person Manav Gabhawala    schedule 02.07.2015