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

Голая сеть с 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)

Это работает лучше, но вы можете играть только в одну игру, и нет никаких признаков, кроме того факта, что у вас закончилось время, кто выиграл, а кто проиграл. Вам нужно читать дальше, чтобы увидеть, как я это исправляю…