Подтвердить что ты не робот

Как определить перечисление битовой маски категории для SpriteKit в Swift?

Чтобы определить перечисление битовой маски категории в Objective-C, я использовал для ввода:

typedef NS_OPTIONS(NSUInteger, CollisionCategory)
{
    CollisionCategoryPlayerSpaceship = 0,
    CollisionCategoryEnemySpaceship = 1 << 0,
    CollisionCategoryChickenSpaceship = 1 << 1,
};

Как я могу добиться того же, используя Swift? Я экспериментировал с перечислениями, но не мог заставить его работать. Вот что я пробовал до сих пор.

error screenshot

4b9b3361

Ответ 1

Что вы можете сделать, это использовать бинарные литералы: 0b1, 0b10, 0b100 и т.д.

Однако в Swift вы не можете перечислить побитовое ИЛИ, поэтому нет смысла использовать битмаски в перечислениях. Ознакомьтесь с этим вопросом для замены NS_OPTION.

Ответ 2

Если вы посмотрите этот быстрый учебник, вы можете избежать всего преобразования toRaw() или rawValue, используя:

struct PhysicsCategory {
  static let None      : UInt32 = 0
  static let All       : UInt32 = UInt32.max
  static let Monster   : UInt32 = 0b1       // 1
  static let Projectile: UInt32 = 0b10      // 2
}

monster.physicsBody?.categoryBitMask = PhysicsCategory.Monster 
monster.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile 
monster.physicsBody?.collisionBitMask = PhysicsCategory.None 

Ответ 3

Взгляните на игру AdvertureBuilding SpriteKit. Они перестроили его в Swift, и вы можете скачать исходный код на сайте разработчиков iOS8.

Они используют следующий метод создания enum:

enum ColliderType: UInt32 {
  case Hero = 1
  case GoblinOrBoss = 2
  case Projectile = 4
  case Wall = 8
  case Cave = 16
}

И установка такая

physicsBody.categoryBitMask = ColliderType.Cave.toRaw()
physicsBody.collisionBitMask = ColliderType.Projectile.toRaw() | ColliderType.Hero.toRaw()
physicsBody.contactTestBitMask = ColliderType.Projectile.toRaw()

И проверь вот так:

func didBeginContact(contact: SKPhysicsContact) {

// Check for Projectile
    if contact.bodyA.categoryBitMask & 4 > 0 || contact.bodyB.categoryBitMask & 4 > 0   {
          let projectile = (contact.bodyA.categoryBitMask & 4) > 0 ? contact.bodyA.node : contact.bodyB.node
    }
}

Ответ 4

Как отмечено, user949350 вместо этого вы можете использовать литеральные значения. Но то, что он забыл указать, заключается в том, что ваша необработанная ценность должна быть в "квадратах". Обратите внимание, как образец кода Apple перечисляет категории. Они равны 1, 2, 4, 8 и 16 вместо обычных 1, 2, 3, 4, 5 и т.д.

Итак, в вашем коде должно быть что-то вроде этого:

enum CollisionCategory:UInt32 {
case PlayerSpaceShip = 1,
case EnemySpaceShip = 2,
case ChickenSpaceShip = 4,

}

И если вы хотите, чтобы ваш игрок node столкнулся с космическим кораблем противника или курятника, например, вы можете сделать что-то вроде этого:

playerNode.physicsBody.collisionBitMask = CollisionCategory.EnemySpaceShip.toRaw() | CollisionCategory.ChickenSpaceShip.toRaw()

Ответ 5

Попробуйте использовать ваши дела как UInt.

enum CollisionCategory: UInt{
    case PlayerSpaceship = 0
    case EnemySpaceship = UInt(1 << 0)
    case PlayerMissile = UInt(1 << 1)
    case EnemyMissile = UInt(1 << 2)
}

Это избавит меня от ошибок.

Ответ 6

Простым способом обработки битмаксов в swift является создание перечисления типа UInt32, содержащего все ваши разные типы конфликтов. Это

enum ColliderType: UInt32 {
    case Player = 1
    case Attacker = 2
}

И затем в классе проигрывателя добавьте физическое тело и настройте обнаружение столкновения

physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(size.width, size.height))
physicsBody.categoryBitMask = ColliderType.Player.toRaw()
physicsBody.contactTestBitMask = ColliderType.Attacker.toRaw()
physicsBody.collisionBitMask = ColliderType.Attacker.toRaw()

И для вашего класса атакующего (или снаряда, птицы, метеор и т.д.) установите физическое тело как

physicsBody = SKPhysicsBody(circleOfRadius: size.width / 2)
physicsBody.categoryBitMask = ColliderType.Attacker.toRaw()
physicsBody.contactTestBitMask = ColliderType.Player.toRaw()
physicsBody.collisionBitMask = ColliderType.Player.toRaw()

(Обратите внимание, что вы можете настроить физическое тело на любую желаемую форму)

Затем убедитесь, что у вас установлена ​​настройка SKPhysicsContactDelegate (например, вы можете позволить своей сцене быть делегатом), а затем реализовать необязательный метод протокола didBeginContact

class GameScene: SKScene, SKPhysicsContactDelegate {

    override func didMoveToView(view: SKView) {

        physicsWorld.contactDelegate = self
        // Additional setup...

    }

    func didBeginContact(contact: SKPhysicsContact!) {

        println("A collision was detected!")

        if (contact.bodyA.categoryBitMask == ColliderType.Player.toRaw() &&
            contact.bodyB.categoryBitMask == ColliderType.Attacker.toRaw()) {

            println("The collision was between the Player and the Attacker")
        }

    }

}

Добавив больше ColliderTypes, вы можете обнаружить больше конфликтов в своей игре.

Ответ 7

В UInt есть небольшая ошибка, но, учитывая, что я думаю, что только 32 бита используются, все равно это сработает. Я также предложил бы представить радар, вы должны иметь возможность использовать любое постоянное значение (1 < 2 всегда будет одинаковым)

В любом случае, здесь, когда они избавились от ошибок с помощью UInts, это сработает

enum CollisionCategory: Int {   case PlayerSpaceship = 0, EnemySpaceShip, PlayerMissile, EnemyMissile

func collisionMask()->Int{
    switch self{
    case .PlayerSpaceship:
        return 0;
    default:
        return 1 << (self.toRaw()-1)
    }
}
}
CollisionCategory.PlayerMissle.collisionMask()

Ответ 8

Swift 3 с перечислением:

enum PhysicsCategory: UInt32 {
  case none = 1
  case monster = 2
  case projectile = 4
  case wall = 8
}

monster.physicsBody?.categoryBitMask = PhysicsCategory.monster.rawValue 
monster.physicsBody?.contactTestBitMask = PhysicsCategory.projectile.rawValue
monster.physicsBody?.collisionBitMask = PhysicsCategory.none.rawValue 

Ответ 9

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

PS: это Swift 4.2

// MARK: Categories - UInt32
let playerCategory:UInt32 = 0x1 << 0
let obstacleCategory:UInt32 = 0x1 << 1
let powerUpCategory:UInt32 = 0x1 << 2