SpriteKit - обновляйте энергию в течение нескольких сцен - PullRequest
0 голосов
/ 18 февраля 2019

У меня есть игра, в которой я хочу обновить «энергетический» бар со временем.Таким образом, каждые 5 минут игрок должен получать еще одну единицу энергии для использования.Я бы знал, как сделать это на одной сцене, но это то, что должно обновляться независимо от того, на какой сцене вы находитесь, а также на заднем плане, но я борюсь с тем, как лучше всего этого достичь.

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

То, с чем я борюсь, - лучший способуправлять этим в разных сценах и соответственно обновлять пользовательский интерфейс (я планирую отображать это в левом верхнем углу всех экранов).Моя первая мысль - иметь одноэлементный объект, который считывает сохраненный уровень энергии и имеет таймер (вне цикла обновления наборов спрайтов).Это выполняется каждые 5 минут и обновляет уровень энергии.Затем он может опубликовать уведомление, чтобы любые представления, не относящиеся к SpriteKit, могли отображать текущую энергию, аналогично, любые сцены SpriteKit могут просто использовать цикл обновления, чтобы прочитать значение и отобразить его соответствующим образом.Но я не уверен, что это правильный подход.

Должен ли я просто прикрепить объект к приложению, чтобы сделать что-то похожее на синглтон.Это позволило бы мне легко сравнить время, когда приложение снова стало активным (например, если для обновления уровня энергии потребовалось 2,5 минуты)

Кто-нибудь может подсказать, является ли это хорошим подходом или есть лучший способдостичь этого?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Это один из тех редких случаев, когда вы хотите использовать Timer.

let date = Date().addingTimeInterval(5)
let timer = Timer(fireAt: date, interval: 0, target: self, selector: #selector(runCode), userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .common)

Это потому, что вы зависите от реального времени, а не от игрового времени.

Имейте в виду, что вам нужно отслеживать любые пропуски зажигания из таймера, потому что вы выключеныделать другие вещи.Ваша функция runCode должна ссылаться на делегатов обновляемых вами сцен, а также не должна увеличиваться.Вместо этого он должен проверять, когда ваш код в последний раз срабатывал, и сравнивать его с текущим временем, когда ваш код сработал, чтобы определить, сколько точек нужно добавить.Он должен вести себя точно так же, как и код, который вы используете при выходе и возвращении в приложение.

Теперь, если вам необходимо выполнить какие-либо обновления пользовательского интерфейса, я бы предложил подключить его к SKAction, который вы прикрепляете к сцене.Таким образом, если ваша сцена находится в состоянии паузы или не загружена, она будет срабатывать при возобновлении сцены.Это также гарантирует, что ваши изменения пользовательского интерфейса выполняются в основном потоке, в отличие от того, в каком потоке ваш таймер может быть.

Теперь, в зависимости от того, как вы разрабатываете свою игру, я бы рекомендовал другой подход.Если у вас есть несколько сцен с одинаковым наложением, я бы порекомендовал наложение даже не быть частью SpriteKit.Вместо этого создайте слой UIView, который лежит поверх ваших сцен SpriteKit.Это представление использует узлы, которые не нужно обновлять каждый кадр за пределами вашей сцены, что позволяет вашей сцене работать быстрее, так как она должна рендерить, сортировать и фильтровать между меньшим количеством узлов.Кроме того, вам нужно обновить только 1 вид, а не количество сцен X.

0 голосов
/ 18 февраля 2019

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

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

Что я делал в одной из моих игр с глобальнымменю было таким: я создал отдельную сцену SpriteKit (файл .sks) для меню.Затем я добавил SKReferenceNode в файл GameScene.sks.В файле GameScene.swift я просто рассматривал ReferenceNode как обычный SKSpriteNode следующим образом:

class GameScene: SKScene {

// Reference node added in GameScene.sks
var playerHealthBar : SKSpriteNode!


override func didMove(to view: SKView) {

    // Reference node
    playerHealthBar = self.childNode(withName: “//playerHealthBar”) as? SKSpriteNode

 }

}

С помощью SKReferenceNode вы можете реализовать этот узел во всех наших сценах.После этого вы сможете обновить узел в любое время.Я использую этот метод для создания глобальных меню в моих играх (где, например, может отображаться золото пользователя, очки здоровья и т. Д.)

А для данных, касающихся playerHealthBar (например, точки здоровья), вы можете загружать / сохранятьэто из UserDefaults.

Что касается второго вопроса, то идея состоит в том, чтобы сохранить переменную с именем lastActive в UserDefaults.Обновите это значение, когда приложение входит в фоновый режим.

Когда приложение выходит на передний план, вам нужно сравнить текущее время с переменной lastActive.

Взгляните на это:

 func timeSpentAwayInSeconds() -> Int {
    // We then check when the player was last active
    let lastActive = UserDefaults.standard.object(forKey: "lastActive")

    // Then we compare that to the current date
    let elapsedTime = Date().timeIntervalSince(lastActive as! Date)

    // Covert that to seconds
    let elapsedTimeInSeconds : Int = Int(elapsedTime)

    return elapsedTimeInSeconds
}

Надеюсь, это немного поможет.Пожалуйста, отметьте как отвеченный, если это решило вашу проблему :-)

Удачного кодирования!

...