Атлас анимации и динамическая физика тела в Swift 3

Я сделал небольшой тестовый проект, используя шаблон Sprite-kit "Hello World", где есть атласная анимация, составленная из этих кадров: введите здесь описание изображения

-

Я хочу показать этого рыцаря и его анимацию.

Я хочу установить ДИНАМИЧЕСКОЕ физическое тело.

Итак, я использовал инструмент для разделения отдельных кадров и создал папку atlasc, поэтому код должен быть таким:

import SpriteKit
class GameScene: SKScene {
    var knight: SKSpriteNode!
    var textures : [SKTexture] = [SKTexture]()
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector(dx:0, dy:-2)
        let plist = "knight.plist"
        let genericAtlas = SKTextureAtlas(named:plist)
        let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
        for i in 0 ..< genericAtlas.textureNames.count
        {
            let textureName = (String(format:"%@%02d",filename,i))
            textures.append(genericAtlas.textureNamed(textureName))
        }
        if textures.count>0 {
            knight = SKSpriteNode(texture:textures.first)
            knight.zPosition = 2
            addChild(knight)
            knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        }
        //
        self.setPhysics()
        let animation = SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false)
        knight.run(animation, withKey:"knight")
    }
    func setPhysics() {
        knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.size)
        knight.physicsBody?.isDynamic = false
    }
}

Вывод:

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

Как видите, physicsBody является СТАТИЧЕСКИМ, не обращайте внимания на анимацию: это нормально, потому что во время анимации размер/размер текстуры меняются, и мы не меняем physicsBody, которые остаются неизменными во время Действие.

По источникам нет методов, которые во время SKAction.animate позволяют изменить physicsBody.

Хотя мы используем:

/**
Creates an compound body that is the union of the bodies used to create it.
*/
public /*not inherited*/ init(bodies: [SKPhysicsBody])

чтобы создать тела для каждого кадра нашей анимации, эти тела остаются все вместе в сцене, создавая уродливую причудливую ситуацию, как на этом рисунке:

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


Итак, правильный способ сделать это должен перехватывать кадры во время анимации и менять physicsBody на лету. Мы также можем использовать метод update() из SKScene, но я думал о расширении.

Моя идея состоит в том, чтобы объединить действие animation с SKAction.group, сделать еще одно пользовательское действие, которое проверяет выполнение первого действия, перехватывает кадры, соответствующие текущему knight.texture с массивом textures, и изменяет physicsBody, запуская внешний метод, в данном случае setPhysicsBody.

Затем я пишу это:

extension SKAction {
    class func animateWithDynamicPhysicsBody(animate:SKAction, key:String, textures:[SKTexture], duration: TimeInterval, launchMethod: @escaping ()->()) ->SKAction {
        let interceptor = SKAction.customAction(withDuration: duration) { node, _ in
            if node is SKSpriteNode {
                let n = node as! SKSpriteNode
                guard n.action(forKey: key) != nil else { return }
                if textures.contains(n.texture!) {
                    let frameNum = textures.index(of: n.texture!)
                    print("frame number: \(frameNum)")
                    // Launch a method to change physicBody or do other things with frameNum
                    launchMethod()
                }
            }
        }
        return SKAction.group([animate,interceptor])
    }
}

Добавляя это расширение, мы меняем анимационную часть кода на:

 //
        self.setPhysics()
        let animation = SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false)
        let interceptor = SKAction.animateWithDynamicPhysicsBody(animate: animation, key: "knight", textures: textures, duration: 60.0, launchMethod: self.setPhysics)
        knight.run(interceptor,withKey:"knight")
    }
    func setPhysics() {
        knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.size)
        knight.physicsBody?.isDynamic = false
    }

Это, наконец, работает, вывод:

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

Знаете ли вы лучший способ или более элегантный метод для получения этого результата?


person Alessandro Ornano    schedule 22.12.2016    source источник
comment
Поскольку вы просто делаете тела в штучной упаковке, присоедините дочерний узел, присоедините физическое тело к дочернему узлу и масштабируйте дочерний узел до размера вашего персонажа. Если у меня будет время, я напишу быстрый пример   -  person Knight0fDragon    schedule 23.12.2016
comment
@Knight0fDragon Спасибо за ваше предложение, хорошо, я жду его ..   -  person Alessandro Ornano    schedule 23.12.2016


Ответы (4)


Как я упоминал в комментариях, поскольку вы делаете физику в штучной упаковке, добавьте дочерний узел SKSpriteNode к вашему рыцарю, который будет обрабатывать контактную часть физики и просто масштабировать на основе фрейма рыцаря:

(Примечание: это только для демонстрационных целей, я уверен, что вы можете придумать более элегантный способ справиться с этим для нескольких спрайтов)

import SpriteKit
class GameScene: SKScene {
    var knight: SKSpriteNode!
    var textures : [SKTexture] = [SKTexture]()
    private var child = SKSpriteNode(color:.clear,size:CGSize(width:1,height:1))
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector(dx:0, dy:-2)
        let plist = "knight.plist"
        let genericAtlas = SKTextureAtlas(named:plist)
        let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
        for i in 0 ..< genericAtlas.textureNames.count
        {
            let textureName = (String(format:"%@%02d",filename,i))
            textures.append(genericAtlas.textureNamed(textureName))
        }
        if textures.count>0 {
            knight = SKSpriteNode(texture:textures.first)
            knight.zPosition = 2
            addChild(knight)
            knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        }
        //
        self.setPhysics()
        let animation = SKAction.repeatForever(SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false))
       knight.run(animation,withKey:"knight")
    }
    override func didEvaluateActions() {
        child.xScale = knight.frame.size.width
        child.yScale = knight.frame.size.height

    }
    func setPhysics() {
        child.physicsBody = SKPhysicsBody.init(rectangleOf: child.size)
        child.physicsBody?.isDynamic = false
        knight.addChild(child)
    }
}

Для обработки тел на основе текстуры. Я бы написал собственную анимацию, чтобы справиться с этим:

extension SKAction
{
    static func animate(withPhysicsTextures textures:[(texture:SKTexture,body:SKPhysicsBody)], timePerFrame:TimeInterval ,resize:Bool, restore:Bool) ->SKAction {

        var originalTexture : SKTexture!;
        let duration = timePerFrame * Double(textures.count);

        return SKAction.customAction(withDuration: duration)
        {
            node,elapsedTime in
            guard let sprNode = node as? SKSpriteNode
            else
            {
                    assert(false,"animatePhysicsWithTextures only works on members of SKSpriteNode");
                    return;
            }
            let index = Int((elapsedTime / CGFloat(duration)) * CGFloat(textures.count))
            //If we havent assigned this yet, lets assign it now
            if originalTexture == nil
            {
                originalTexture = sprNode.texture;
            }


            if(index < textures.count)
            {
                sprNode.texture = textures[index].texture
                sprNode.physicsBody = textures[index].body
            }
            else if(restore)
            {
                sprNode.texture = originalTexture;
            }

            if(resize)
            {
                sprNode.size = sprNode.texture!.size();
            }

        }
    }
}


import SpriteKit
class GameScene: SKScene {
    var knight: SKSpriteNode!
    var textures = [texture:SKTexture,body:SKPhysicsBody]()
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector(dx:0, dy:-2)
        let plist = "knight.plist"
        let genericAtlas = SKTextureAtlas(named:plist)
        let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
        for i in 0 ..< genericAtlas.textureNames.count
        {
            let textureName = (String(format:"%@%02d",filename,i))
            let texture = genericAtlas.textureNamed(textureName)
            let body = SKPhysicsBody(texture:texture)
            body.isDynamic = false
            textures.append((texture:texture,body:body))
        }
        if textures.count>0 {
            knight = SKSpriteNode(texture:textures.first.texture)
            knight.zPosition = 2
            addChild(knight)
            knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        }
        //
        let animation = SKAction.animate(withPhysicsTextures: textures, timePerFrame: 0.15, resize: true, restore: false)
        knight.run(animation, withKey:"knight")
    }
}
person Knight0fDragon    schedule 22.12.2016
comment
Это еще одна интересная идея, очевидно, она не заботится о кадрах: различные текстуры, которые тем временем запускаются в действие, потому что physicsBody - это простой прямоугольник, а не текстура, как вы сказали. Этот ответ не распространяется на создание текстуры physicsBody, но избегает создания вторичного действия, а создает еще один спрайт. И используйте didEvaluateActions(), еще одну интересную часть. - person Alessandro Ornano; 23.12.2016
comment
Добавлена ​​пользовательская анимация для обработки тел на основе текстур. - person Knight0fDragon; 25.12.2016

Решение для isDynamic = false.

*Обновление до 2017 г. ниже

После нескольких дней тестирования, проведенного с моим ответом, ответ Knight0fDragon и некоторые другие идеи пришли из других ответов SO (предложения Confused и Whirlwind..) Я увидел, что есть новая проблема: physicsBody не может адекватно и правильно распространять свои свойства на другие тела. Другими словами, скопировать все свойства из тела в другое тело этого недостаточно. Это связано с тем, что Apple ограничивает доступ к некоторым методам и свойствам исходного класса physicsBody. Может случиться так, что когда вы запускаете physicsBody.applyImpulse, адекватно распространяя velocity, гравитация еще не соблюдается должным образом. Это действительно ужасно видеть... и очевидно, что это неправильно.

Итак, главная цель: не изменять physicBody воссоздавая его. Другими словами, НЕ СОЗДАВАЙТЕ ЭТО ВОССОЕДИНЯЕТСЯ!

Я подумал, что вместо того, чтобы создавать дочерние спрайты, вы могли бы создать спрайты-призраки, которые выполняют работу вместо основного спрайта, и основной спрайт использует преимущества изменений призрака, но ТОЛЬКО основной спрайт имеет физико-тело.

Кажется, это работает!

import SpriteKit
class GameScene: SKScene {
    var knight: SKSpriteNode!
    private var ghostKnight:SKSpriteNode!
    var textures : [SKTexture] = [SKTexture]()
    var lastKnightTexture : SKTexture!
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector.zero
        let plist = "knight.plist"
        let genericAtlas = SKTextureAtlas(named:plist)
        let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
        for i in 0 ..< genericAtlas.textureNames.count
        {
            let textureName = (String(format:"%@%02d",filename,i))
            textures.append(genericAtlas.textureNamed(textureName))
        }
        if textures.count>0 {
            // Prepare the ghost
            ghostKnight = SKSpriteNode(texture:textures.first)
            addChild(ghostKnight)
            ghostKnight.alpha = 0.2
            ghostKnight.position = CGPoint(x:self.frame.midX,y:100)
            lastKnightTexture = ghostKnight.texture
            // Prepare my sprite
            knight =  SKSpriteNode(texture:textures.first,size:CGSize(width:1,height:1))
            knight.zPosition = 2
            addChild(knight)
            knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        }
        let ghostAnimation = SKAction.repeatForever(SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false))
        ghostKnight.run(ghostAnimation,withKey:"ghostAnimation")
        let animation = SKAction.repeatForever(SKAction.animate(with: textures, timePerFrame: 0.15, resize: false, restore: false))
        knight.run(animation,withKey:"knight")

    }
    override func didEvaluateActions() {
        if ghostKnight.action(forKey: "ghostAnimation") != nil {
            if ghostKnight.texture != lastKnightTexture {
                setPhysics()
                lastKnightTexture = ghostKnight.texture
            }
        }
    }
    func setPhysics() {
        if let _ = knight.physicsBody{
            knight.xScale = ghostKnight.frame.size.width
            knight.yScale = ghostKnight.frame.size.height
        } else {
            knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.frame.size)
            knight.physicsBody?.isDynamic = true
            knight.physicsBody?.allowsRotation = false
            knight.physicsBody?.affectedByGravity = true
        }
    }
}

Вывод:

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

Очевидно, вы можете скрыться, установив alpha на 0.0 и переместив призрака так, как вы хотите, чтобы он исчез.


Обновление 2017:

После нескольких часов тестирования я попытался улучшить код, наконец, мне удалось удалить спрайт-призрак, но для хорошей работы очень важно одно условие: вы не должны использовать SKAction.animate с resize в true. Это потому, что этот метод изменяет размер спрайтов и не учитывает масштаб (я действительно не понимаю, почему, надеюсь на некоторые будущие улучшения Apple..). Это лучшее, что я получил на данный момент:

  • НЕТ ДЕТЕЙ
  • НИКАКИХ ДРУГИХ ПРИЗРАЧНЫХ СПРАЙТОВ
  • БЕЗ ПРОДЛЕНИЯ
  • НИ ОДИН АНИМАТИЧЕСКИЙ МЕТОД НЕ ВОССТАНАВЛИВАЕТСЯ

Код:

import SpriteKit
class GameScene: SKScene {
    var knight: SKSpriteNode!
    var textures : [SKTexture] = [SKTexture]()
    var lastKnightSize: CGSize!
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector.zero
        let plist = "knight.plist"
        let genericAtlas = SKTextureAtlas(named:plist)
        let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
        for i in 0 ..< genericAtlas.textureNames.count
        {
            let textureName = (String(format:"%@%02d",filename,i))
            textures.append(genericAtlas.textureNamed(textureName))
        }
        if textures.count>0 {
            // Prepare my sprite
            knight =  SKSpriteNode(texture:textures.first,size:CGSize(width:1,height:1))
            knight.zPosition = 2
            addChild(knight)
            knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
            lastKnightSize = knight.texture?.size()
            setPhysics()
        }
        let animation = SKAction.repeatForever(SKAction.animate(with: textures, timePerFrame: 0.15, resize: false, restore: false))
        knight.run(animation,withKey:"knight")
    }
    override func didEvaluateActions() {
        lastKnightSize = knight.texture?.size()
        knight.xScale = lastKnightSize.width
        knight.yScale = lastKnightSize.height
    }
    func setPhysics() {
        knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.frame.size)
        knight.physicsBody?.isDynamic = true
        knight.physicsBody?.allowsRotation = false
        knight.physicsBody?.affectedByGravity = true
    }
}

Важная деталь:

О isDynamic = true это невозможно просто потому, что во время частых изменений размера Apple также часто сбрасывает физику рыцаря, но не применяет наследование последних свойств physicsBody к новому сброшенному physicsBody, это настоящий позор, вы можете проверить это при обновлении печатается knight.physicsBody?.velocity (всегда равно нулю, но должно измениться из-за гравитации...). Вероятно, поэтому Apple рекомендовала не масштабировать спрайты во время физики. На мой взгляд, это ограничение Sprite-kit.

person Alessandro Ornano    schedule 10.01.2017

Другой идеей может быть предложение о didEvaluateActions() поиске более общего метода, чтобы иметь "переменную" physicsBody, которая следует за реальной текущей текстурой рыцаря ИЛИ физическими настройками как a прямоугольное тело, как в этом случае:

Обновление: (благодаря вмешательствам Knight0fDragon и 0x141E)

import SpriteKit
class GameScene: SKScene {
    var knight: SKSpriteNode!
    var textures : [SKTexture] = [SKTexture]()
    var lastKnightTexture : SKTexture!
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector(dx:0, dy:-2)
        let plist = "knight.plist"
        let genericAtlas = SKTextureAtlas(named:plist)
        let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
        for i in 0 ..< genericAtlas.textureNames.count
        {
            let textureName = (String(format:"%@%02d",filename,i))
            textures.append(genericAtlas.textureNamed(textureName))
        }
        if textures.count>0 {
            knight = SKSpriteNode(texture:textures.first)
            lastKnightTexture = knight.texture
            knight.zPosition = 2
            addChild(knight)
            knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        }
        let animation = SKAction.repeatForever(SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false))
        knight.run(animation,withKey:"knight")
    }
    override func didEvaluateActions() {
        if knight.action(forKey: "knight") != nil {
            if knight.texture != lastKnightTexture {
                setPhysics()
                lastKnightTexture = knight.texture
            }
        }
    }
    func setPhysics() {
        knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.size)
        knight.physicsBody?.isDynamic = false
    }
}
person Alessandro Ornano    schedule 23.12.2016
comment
Я бы не стал использовать этот подход, я бы придерживался вашего оригинала, чтобы код оставался простым. то, что я сделал, хотя в одной из моих игр был создан массив кортежей, который был (SKTexture, SKPhysicsBody) и сделал пользовательскую анимацию, которая ведет себя как анимация с текстурами - person Knight0fDragon; 24.12.2016
comment
Нет, я не согласен воссоздавать официальный метод фреймворка skaction.animate с customAction по многим причинам... но если у вас есть рабочий пример, возможно, это возможно. Однако я предпочитаю использовать доступную функцию анимации. - person Alessandro Ornano; 24.12.2016
comment
Но у вас уже есть действие, делающее это уже в исходном коде. - person Knight0fDragon; 24.12.2016
comment
При таком подходе вы создаете новые тела skphysics прямо перед тем, как они будут использованы, это нормально, может быть, если вы используете только 1 спрайт, но если у вас их много, это может стать беспокойным. - person Knight0fDragon; 24.12.2016
comment
Я предпочитаю подход в этом ответе и ваш ответ без параллельных действий или воссоздания основной анимации. Код в моем вопросе - это только первый рабочий подход. Абсурд заключается в том, что не я и не вы или кто-то другой должен решать этот пробел, дыры в спрайт-ките, а это должна делать команда Apple, улучшая свой фреймворк. - person Alessandro Ornano; 24.12.2016
comment
Я не думаю, что выделять новое физическое тело примерно 60 раз в секунду — хорошая идея. Возможно, вы можете предварительно выделить тела, сохранить их в словаре и использовать хешируемую версию knight.size в качестве ключа. - person 0x141E; 25.12.2016
comment
@ 0x141E Интересная идея. Предположим, у вас есть 80 кадров: временная перегрузка памяти с 80 прямоугольниками может быть в порядке, с 80 текстурами я начинаю думать, что это не очень хорошая идея. - person Alessandro Ornano; 25.12.2016
comment
В любом случае, и Knight0fDragon, и 0x141E сделали отличный вывод: выделять новое физическое тело примерно 60 раз в секунду — НЕ очень хорошая идея. Итак, я попытался улучшить свой код с помощью этого нового обновления (это должно ограничивать вызовы создания physicsBody только при необходимости), но, как обычно, если вы думаете о лучшем способе, пожалуйста, выскажите свою идею (прокомментируйте или ответьте). Большое спасибо, ребята, я ценю каждое вмешательство. - person Alessandro Ornano; 25.12.2016
comment
На самом деле хорошая идея ... Но разве то, что сказал @Knight0fDragon, не лучший способ добиться этого? Я не смотрел внимательно, но кажется, что он масштабирует спрайт, что приводит к масштабированию физического тела, что означает отсутствие перераспределения (если я ошибаюсь, пожалуйста, поправьте меня). В любом случае, если Knight0fDragon не так представлял себе это, я бы попробовал масштабирование (помню, что это работало на некоторых версиях iOS). - person Whirlwind; 25.12.2016
comment
@Whirlwind да, это работает, но только если вы не используете текстуры для создания физических тел, поэтому мы можем легко масштабировать прямоугольное тело, как это сделал хороший knight0fdragon. Я пытаюсь сделать метод для тех, кто хочет использовать текстуры, подобные этому, в ответ. - person Alessandro Ornano; 25.12.2016
comment
@AlessandroOrnano, когда дело доходит до времени, вы можете подумать о том, чтобы пожертвовать оперативной памятью. То, как вы настроили его сейчас, допускает пики задержки при выполнении анимации вместо постоянной задержки, которую пользователь может даже не заметить, потому что она постоянна. - person Knight0fDragon; 25.12.2016
comment
@Knight0fDragon Не могли бы вы объяснить немного больше (если вы найдете время) о задержке и ОЗУ. У меня еще не было возможности попробовать все примеры, но мне интересны подробности. - person Whirlwind; 25.12.2016
comment
Циклы ОЗУ и ЦП имеют противоположную корреляцию. Если вы хотите, чтобы что-то использовало меньше циклов ЦП, обычно вы в конечном итоге используете больше ОЗУ, а если вы хотите использовать меньше ОЗУ, обычно вы используете больше циклов ЦП. В случае с Алессандро мы обычно пытаемся думать о наихудшем сценарии. То есть кадр анимации всегда меняется. Это самый лаговый момент, который может быть в нашей игре, скажем, для завершения требуется 1/30FPS. Теперь проведенная оптимизация представляет собой простую проверку необходимости нового тела. Для завершения требуется 1/60FPS. Теперь мы играем в игру, в которой каждые 5 кадров мы попадаем в худший случай,... - person Knight0fDragon; 25.12.2016
comment
Сейчас мы видим обновление 1/60,1/60,1/60,1/60,1/30. Мы попали в пик отставания, и это будет очень заметно. Если вы все время делаете наихудший случай, вы достигаете 1/30 5 раз, и, поскольку время постоянно, пользовательский опыт таков, как разработана игра, а не то, что она отстает, и она становится более приемлемой. @Вихрь - person Knight0fDragon; 25.12.2016
comment
Теперь да, есть и другие оптимизации, которые вступают в игру, это просто очень простое обобщение об обработке циклов обновления. - person Knight0fDragon; 25.12.2016
comment
@Knight0fDragon А, хорошо. Ага, лучше иметь даже постоянную меньшую частоту кадров, чем колебания. LearnCocos2d объяснил [что-то вроде этого]((stackoverflow.com/a/13836512/3402095)) ранее, так что это может будет хорошим чтением для тех, кто интересуется всем этим. В любом случае, мне было любопытно, испытываете ли вы какое-то отставание в настоящее время или нет, и в каких условиях. - person Whirlwind; 25.12.2016
comment
@Whirlwind нет, я ничего не испытываю, я стараюсь думать в более широком масштабе, легче планировать заранее, чем возвращаться и исправлять - person Knight0fDragon; 25.12.2016

Я готовлюсь погрузиться в некоторые тела с текстурной физикой и некоторое время назад столкнулся с этой проблемой.

Прочитав это, я думаю о таком подходе:

При анимации почему бы не иметь базовый узел (центральный узел), а затем дочерние элементы, каждый из которых является кадром анимации. Затем шаблоны скрытия и отображения дочерних узлов, где каждый дочерний узел (который я буду делать) использует альфа текстуры (все загруженные) для своих PB. А просто СКРЫТЬ/ПОКАЗАТЬ (мой ответ).

Я имею в виду, какой штраф мы понесем, имея 12 узлов как таковых, базового узла, которые являются кадрами анимации, по сравнению с загрузкой и выгрузкой изображений для анимации.

Любое наказание, на мой взгляд, стоило бы иметь возможность иметь множество различных физических тел.

person rezwits    schedule 19.03.2021
comment
Вам придется выключить физику contactTestBitMask и collisionBitMask, пока они скрыты, потому что они задерживаются, даже когда они скрыты. - person rezwits; 19.03.2021
comment
Это решение может быть полезно, если в вашей игре мало анимаций: как насчет десяти персонажей, у каждого из которых есть десять анимаций, где средняя анимация состоит из 30 спрайтов? - person Alessandro Ornano; 19.03.2021
comment
Ну, как я уже сказал (в моем примере с использованием альфа-каналов для PB), любой штраф стоил бы того, чтобы иметь 99% физических тел, по сути. Плюс, скажем, у вас есть мир, скажем, с 1000 базовых узлов, а с окклюзией у вас максимум будет, скажем, 20 объектов на экране, а это будет 240 узлов? SpriteKit справится с этим без проблем... - person rezwits; 20.03.2021
comment
А как насчет 2D тайловых карт и их физических узлов? Я сказал в качестве примера только персонажей, а как насчет остальной части игры.. fps неизбежно падает - person Alessandro Ornano; 20.03.2021