Надеюсь, вы попали сюда через другие мои статьи, эта четвертая в той же серии. Все они основаны друг на друге, поэтому вам нужно пройти через них, чтобы попасть сюда. Вот список ссылок.
Голая сеть с SwiftUI
Больше голой сети, больше SwiftUI
Голая сеть, SwiftUI и план игры
Где это "тут. Я начал с создания сервера прослушивания UDP под iOS. Затем я создал передающий клиент и в последней статье связал все это вместе в приложении, позволяющем вам играть в пинг-понг друг с другом. Приложение должно работать на двух устройствах в одной сети.
Но это не закончено. Нам нужно ввести геймификацию. Встроить элемент вызова, элемент, который даст двум игрокам возможность соревноваться друг с другом.
Давайте добавим элемент синхронизации. Давайте давать каждому игроку все меньше и меньше времени на возврат пинга, пока один из них не сможет этого сделать. Нам тоже нужно следить за тем, кто выигрывает.
А как насчет еще нескольких кнопок и заставить приемник выбирать одну из них случайным образом, когда он получает пинг? Затем это становится игрой, в которой вам нужно нажать одну из кнопок X, чтобы вернуть мяч. .
Наконец, давайте добавим немного специй, анимировав наши кнопки. В конце концов, мы могли бы также подумать о том, как игра будет/может работать с более чем двумя игроками. В конце концов, нашу UDP-трансляцию ловят до 255 игроков.
Хорошо, как видите, здесь есть над чем поработать и действительно над чем подумать. Давайте начнем.
Сеть
Давайте начнем с изменения нашего pingPublisher в Connect.swift, чтобы он отправлял данные вместе с уведомлением.
let pingPublisher = PassthroughSubject<String, Never>()
Мы хотим отправить время, которое потребовалось для возврата пинга. Поэтому нам нужно записывать, когда мы отправляем его, чтобы затем мы могли определить разницу, когда получим его обратно. Позвольте мне записать это в коде.
private var startingTime: Date? private var endingTime: Date? ...
Нам нужны две переменные, startTime и endingTime. Когда мы возвращаем пинг, мы сохраняем startTime. Код, выделенный полужирным курсивом, — это новый код, который необходимо добавить.
func sendUDP(_ content: String) { startingTime = Date() ...
Теперь, когда мы получаем ответ, нам нужно рассчитать, сколько времени это заняло; это время между нашей отправкой и ответом другого игрока.
func receive(on connection: NWConnection) { endingTime = Date() var string2Send: String = "8" if startingTime != nil { let answer = DateInterval(start: startingTime!, end: endingTime!) string2Send = String(answer.duration) } ... DispatchQueue.main.async { globalVariable.score = backToString pingPublisher.send(string2Send) }
Фактически это означает, что время, которое вам нужно для ответа, будет постепенно становиться все короче и короче.
SwiftUI
Конечно, теперь вам также нужно внести несколько изменений в пользовательский интерфейс. Новый Кодекс выделен жирным курсивом.
@State var refresh = false @State var youLose: Timer? ... .onReceive(pingPublisher) { ( data ) in print("data ",data) self.disable = false var countDown = Float(data) self.youLose = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { timer in countDown = countDown! - 0.1 if countDown! < 0.0 { self.disable = true self.youLose?.invalidate() } }) }
Теперь здесь происходят две вещи. Нам нужно было внести нано-изменение в .onRecieve, поскольку теперь мы заботимся о возвращаемых данных. Затем мы устанавливаем таймер обратного отсчета, используя указанные данные, чтобы записать, сколько времени у нас осталось, прежде чем нам нужно будет отключить кнопку возврата назад.
Как только таймер станет меньше нуля, нам, конечно же, нужно его остановить.
Button(action: { if self.model.state { makeConnect(port: "1984", message: "ping") self.disable = true self.refresh = !self.refresh self.youLose?.invalidate() } else { makeConnect(port: "4891", message: "pong") self.disable = true self.refresh = !self.refresh self.youLose?.invalidate() } }) { Text("whack") .disabled(disable) }
Вы наверняка протестируете сейчас. Изначально у вас есть неопределенное количество времени, а затем, в зависимости от скорости реакции другого игрока, оно начнет уменьшаться. В конце концов вы оба будете заблокированы. Игра закончена.
Но подождите, обратите внимание, теперь вы оба инвалиды, и мы застряли, и это тоже не очевидно, что произошло. Давайте добавим новую метку, показывающую, сколько времени осталось до ответа.
@State var timeToDie = "" ... self.youLose = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { timer in countDown = countDown! - 0.1 self.timeToDie = String(countDown!) if countDown! < 0.0 { self.disable = true self.youLose?.invalidate() } }) }) { Text("whack") .disabled(disable) } Text(timeToDie)
Это работает лучше, но вы можете играть только в одну игру, и нет никаких признаков, кроме того факта, что у вас закончилось время, кто выиграл, а кто проиграл. Вам нужно читать дальше, чтобы увидеть, как я это исправляю…