случайный выбор узла skspritenode для появления из 5 спрайтов

у меня есть 5 skspritesnodes, я хочу создать 1 случайный узел за раз, я знаю, что должен использовать arc4random, но примеры, которые я пробовал, не работают. Мне нравится переменная, которую я могу затем ввести, когда мне нужно, чтобы начать создавать случайных «врагов».

var bird0 = SKSpriteNode(imageNamed: "back_bird")
var bird1 = SKSpriteNode(imageNamed: "blue_bird")
var bird2 = SKSpriteNode(imageNamed: "green_bird")
var bird3 = SKSpriteNode(imageNamed: "purple_bird")
var bird4 = SKSpriteNode(imageNamed: "orange_bird")

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


person TroyDeJ    schedule 26.12.2016    source источник
comment
Общее замечание: если ваши имена переменных содержат увеличивающиеся числа, вам почти всегда лучше использовать массив. Это также упрощает весь выбор случайного.   -  person luk2302    schedule 26.12.2016


Ответы (2)


В дополнение к ответу Sweeper вы можете сделать расширение:

import SpriteKit
import GameplayKit

extension Array {
    var randomElement: Element {
        return self[Int(arc4random_uniform(UInt32(count)))]
    }
}

и используйте его так:

class GameScene: SKScene {

    let sprites = [
        SKSpriteNode(color: .brown, size: CGSize(width:100,height:100)),
        SKSpriteNode(color: .blue, size: CGSize(width:100,height:100)),
        SKSpriteNode(color: .red, size: CGSize(width:100,height:100)),
        SKSpriteNode(color: .green, size: CGSize(width:100,height:100)),
        ]

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)

        if let randomBird = sprites.randomElement.copy() as? SKSpriteNode{

            if let location = touches.first?.location(in: self){
                randomBird.position = location
                addChild(randomBird)
            }
        }
    }
}
person Whirlwind    schedule 26.12.2016
comment
Зачем хранить узлы в массиве, если все, что вы делаете, это их копирование? Вы получите n узлов, которые никогда не используются. - person Epsilon; 26.12.2016
comment
@Epsilon Это (копирование) было моим способом позволить OP создавать узлы несколько раз, а не добавлять их только один раз (поскольку узел может иметь только одного родителя). Суть была на самом деле расширением, позволяющим немного удобным способом получить случайный элемент. Есть смысл? - person Whirlwind; 26.12.2016
comment
Я понимаю, почему вы скопировали узлы. Моя проблема связана с самим массивом. Я думаю, что функция с оператором switch имеет больше смысла. - person Epsilon; 26.12.2016
comment
@Epsilon Может работать (например, рандомизация индекса и возврат спрайта в переключателе). Но я могу найти проблему и с этим :p Вы слышали о объединении? Скажем, вы быстро порождаете спрайты... Всегда гораздо эффективнее предварительно размещать их в массиве, а не создавать их в переключателе, когда это необходимо. И это то, что ваш метод будет делать. - person Whirlwind; 26.12.2016
comment
Также, когда я говорил о рандомизации индекса, я имел в виду рандомизацию значения между, скажем, 0 и 1 и, исходя из этого, возвращение спрайта. Так что без массива. Но я бы придерживался массива и предварительно выделенных узлов. - person Whirlwind; 26.12.2016
comment
Я не уверен, что этот метод считается объединением в пул (предварительное выделение) или если копирование узла происходит быстрее, чем выделение нового. - person Epsilon; 27.12.2016
comment
@Epsilon Предварительное выделение узлов и их сохранение в массиве считается частью объединения. Позже вы повторно используете их или создаете новые, если это необходимо. Что вы считаете объединением? Кстати, где я упоминал, что копирование выполняется быстрее, чем размещение? Копирование не имеет ничего общего с объединением вещей, о которых я упоминал. - person Whirlwind; 27.12.2016
comment
Я предположил, что вы имели в виду, что ваш ответ объединяется. Вы также можете легко объединить оператор функции/переключателя. - person Epsilon; 27.12.2016
comment
@Epsilon Нет, я просто прокомментировал ваше решение без массива. Бассейн откуда? - person Whirlwind; 27.12.2016
comment
Вы можете предварительно выделить все необходимые узлы и выбрать их случайным образом с помощью переключателя. - person Epsilon; 27.12.2016
comment
@Epsilon Хорошо, но где вы храните свои узлы после их распределения? - person Whirlwind; 27.12.2016
comment
@Epsilon Не в массиве, верно? :) Вы наверное имели в виду что-то более подходящее... - person Whirlwind; 27.12.2016
comment
Я не пытаюсь критиковать ваш подход. Мне было любопытно, почему вы (и другой ответивший) решили использовать массив для выбора случайного спрайта, когда вам нужно было скопировать или создать новый спрайт перед добавлением его в сцену. - person Epsilon; 27.12.2016
comment
@Epsilon Потому что я начал с идеи, что спрайты будут создаваться заранее, храниться в массиве и повторно использоваться, а не создаваться во время появления, потому что в зависимости от того, как часто они появляются, какую текстуру они загружают или сколько у них детей, задержка может случаться. Кроме того, ИМО, но это только я, я думаю, что ваш оператор switch может выглядеть противно, если у вас должно быть много случаев. - person Whirlwind; 27.12.2016
comment
Также вам не нужно копировать эти спрайты или создавать новые, чтобы добавить их в сцену. Вы просто используете их, и прежде чем добавить их в сцену, вы проверяете, доступны ли они для добавления, например. проверьте, есть ли у них родитель. - person Whirlwind; 27.12.2016
comment
@Epsilon Если в вашей игре будет только n спрайтов, то имеет смысл их предварительное размещение в массиве, поскольку их легко перебирать и / или выбирать один случайным образом для помещения в сцену. Если вы собираетесь иметь много спрайтов n разных типов, все же имеет смысл поместить их в массив, поскольку массив может быть «фабрикой», которая легко порождает новые спрайты. Да, у вас будет n неиспользуемых SKSpriteNodes, но я подозреваю, что накладные расходы очень малы. Независимо от того, что вы делаете, вы должны создать или скопировать спрайт, прежде чем добавлять его в сцену, если только вы предварительно не выделили каждый возможный спрайт. - person Steve Ives; 29.12.2016
comment
@SteveIves У меня нет проблем с использованием массивов. Посмотрите на этот ответ, как он реализован, и скажите, как бы вы решили эту проблему. - person Epsilon; 04.01.2017
comment
@EpsilonvIt выглядит довольно хорошо - ответы Whirlwind заслуживают доверия. Но я думаю, что это ситуация, когда есть много «правильных» ответов. Например, это можно реализовать путем перебора массива цветов для создания массива спрайтов. Не говорю, что это будет лучше, просто альтернатива, если все спрайты одинаковы, за исключением одного атрибута. - person Steve Ives; 05.01.2017

Вам нужно поместить спрайты в массив. Затем вы можете получить доступ к случайному элементу в этом массиве.

Вот функция, которая возвращает случайную птицу.

func randomBird() -> SKSpriteNode {
    let array = [bird0, bird1, bird2, bird3, bird4]
    return array[Int(arc4random_uniform(UInt32(array.count)))]
}

Вы также можете поместить всех птиц в массив и удалить переменные bird0, bird1, bird2 и так далее:

let birds = [
    SKSpriteNode(imageNamed: "back_bird"),
    SKSpriteNode(imageNamed: "blue_bird"),
    SKSpriteNode(imageNamed: "green_bird"),
    SKSpriteNode(imageNamed: "purple_bird"),
    SKSpriteNode(imageNamed: "orange_bird")
]

Тогда birds[Int(arc4random_uniform(UInt32(array.count)))] даст вам случайную птицу.

person Sweeper    schedule 26.12.2016
comment
это не исправить UInt32(birds.count). затем, если я это исправлю, он говорит, что не может использовать индексное значение типа SKspritenode с типом индекса UInt32. - person TroyDeJ; 26.12.2016
comment
@TroyDeJ Я отредактировал свой ответ. Посмотрите, работает ли это. Если это так, пожалуйста, примите его, нажав на галочку! Кроме того, я рекомендую вам установить модуль SwiftRandom: https://github.com/thellimist/SwiftRandomhttps://github.com/thellimist/SwiftRandom - person Sweeper; 26.12.2016
comment
извините за то, что я новичок, но как вы это интегрируете? так как birds[Int(arc4random_uniform(UInt32(array.count)))] это не узел, а int - person TroyDeJ; 26.12.2016
comment
@TroyDeJ Поверьте мне, это узел. Позволь мне объяснить. UInt32(array.count) превращает array.count в uint32, чтобы его можно было использовать для вызова arc4random_uniform. Но arc4random_uniform возвращает uint32. Поэтому мне нужно преобразовать возвращаемое значение обратно в Int, чтобы его можно было использовать для доступа к массиву с использованием синтаксиса нижнего индекса. Поскольку birds имеет тип [SKSpriteNode], доступ к нему с помощью [] возвращает SKSpriteNode. Попробуй это! - person Sweeper; 26.12.2016
comment
заставил его работать между обоими вашими ответами, очень признателен. Как я могу теперь добавить физические тела к этим спрайтам? так как они в этом массиве, я не хочу его испортить - person TroyDeJ; 27.12.2016
comment
@TroyDeJ Просто прокрутите массив, используя цикл, подобный for bird in birds { }, и добавьте физические тела к каждой птице. - person Sweeper; 27.12.2016
comment
пока у меня есть ваше ухо, по какой причине я не могу изменить размер спрайта в for in? я могу добавить физику, но когда я использую CGsize, он применяет 1 размер ко всем, даже если тогда должны быть разные размеры. Довольно странно. - person TroyDeJ; 29.12.2016
comment
@TroyDeJ, это ожидаемое поведение циклов for in. Вы используете его, чтобы делать одно и то же действие со всеми элементами в последовательности. Поэтому, если вы хотите установить разные размеры для каждого спрайта, вместо этого используйте индекс для доступа к отдельным спрайтам: birds[0], birds[1] и т. д. - person Sweeper; 29.12.2016