因此,我一直在尝试使用多对等连接来通过iOS设备控制appleTV游戏。出于测试目的,考虑到appleTV模拟器在使用spriteKit时滞后的事实,我将游戏移植到MacOS进行测试。
我遇到了发送和接收数据之间的延迟问题,考虑到我正在发送传感器数据,我发现这是不可能的。我尝试使用sendData()并尝试使用Stream。 使用闪电电缆将设备连接到计算机时,不存在延迟。
我玩过很多使用iOS设备作为控制器的游戏,并且我假设它们使用Multipeer Connectivity。 是否有更好的替代方法?
这可能是代码问题,但我对此表示高度怀疑。 感谢您的帮助。
import Foundation
import MultipeerConnectivity
var defaults = UserDefaults()
class GameService : NSObject, MCSessionDelegate, StreamDelegate {
static var shared = GameService() //shared global instance of this class
var playerNumbers: [MCPeerID : UInt8] = [:]
private let myPeerID: MCPeerID
private let serviceName = "olik"
private let serviceBrowser: MCNearbyServiceBrowser
var dataDelegate:DataPassingDelegate?
lazy var session : MCSession = {
let session = MCSession(peer: self.myPeerID, securityIdentity: nil, encryptionPreference: .required)
session.delegate = self
return session
}()
override init() {
self.myPeerID = MCPeerID(displayName: "AppleTV")
self.serviceBrowser = MCNearbyServiceBrowser(peer: myPeerID, serviceType: serviceName)
super.init()
self.serviceBrowser.delegate = self
startBrowsing()
}
func startBrowsing() {
serviceBrowser.startBrowsingForPeers()
}
func stopBrowsing() {
serviceBrowser.stopBrowsingForPeers()
}
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
if state == MCSessionState.connected {
let newNumber = UInt8(playerNumbers.count)
playerNumbers[peerID] = newNumber
let data = Data(from: UInt8(exactly: newNumber))
do {
try self.session.send(data, toPeers: [peerID], with: .reliable)
NSLog("%@", "sending player number \(newNumber) to peer with display Name: \(peerID.displayName)")
}
catch let error {
NSLog("%@", "Error for sending: \(error)")
}
}
}
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
NSLog("%@", "recieved stream")
stream.delegate = self
stream.schedule(in: RunLoop.main, forMode: RunLoop.Mode.default)
stream.open()
}
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
}
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
print("stream event, stream: \(aStream)")
if let inputStream = aStream as? InputStream, eventCode == Stream.Event.hasBytesAvailable {
print("bytes available")
var bytes = [UInt8](repeating:0, count: 2)
inputStream.read(&bytes, maxLength: 2)
dataDelegate?.passData(sender: bytes[0], data: bytes[1])
/*
var userInfo: [String: UInt8] = [:]
userInfo["sender"] = bytes[0]
userInfo["data"] = bytes[1]
DispatchQueue.main.async {
NotificationCenter.default.post(name: dataNotification, object: nil, userInfo: userInfo)
*/
}
}
}
extension GameService: MCNearbyServiceBrowserDelegate {
func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
NSLog("%@", "found peer with display name: \(peerID.displayName)")
browser.invitePeer(peerID, to: self.session, withContext: nil, timeout: 0)
}
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
NSLog("%@", "lost peer with display name: \(peerID.displayName)")
}
}
protocol DataPassingDelegate {
func passData(sender: UInt8, data: UInt8)
}
extension Data {
init<T>(from value: T) {
var value = value
self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func to<T>(type: T.Type) -> T {
return self.withUnsafeBytes { $0.pointee }
}
}
import Foundation
import MultipeerConnectivity
var defaults = UserDefaults()
let notificationConnecting = Notification.Name(rawValue: "com.notification.MPCconnecting")
let notificationConnected = Notification.Name(rawValue: "com.notification.MPCconnected")
let notificationSearching = Notification.Name(rawValue: "com.notification.MPCsearching")
let notificationDisconnected = Notification.Name(rawValue: "com.notification.MPCdisconnected")
class GameService: NSObject, StreamDelegate {
static var shared = GameService() //shared global instance of this class
private var connection: MCSessionState
private let myPeerID: MCPeerID
private let serviceName = "olik"
private let serviceAdvertiser : MCNearbyServiceAdvertiser
private var outputStream: OutputStream?
var appleTvPeer: MCPeerID?
private var playerNumber: Int8?
lazy var session : MCSession = {
let session = MCSession(peer: self.myPeerID, securityIdentity: nil, encryptionPreference: .required)
session.delegate = self
return session
}()
override init() {
connection = MCSessionState.notConnected
myPeerID = MCPeerID(displayName: defaults.string(forKey: "displayName") ?? UIDevice.current.name)
//create peerID with displayName in defaults. If nil, use device name
serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerID, discoveryInfo: nil, serviceType: serviceName)
//create Advertiser
super.init()
serviceAdvertiser.delegate = self
}
func startAdvertising() {
//start Advertising Peer
appleTvPeer = nil
self.serviceAdvertiser.startAdvertisingPeer()
DispatchQueue.main.async {
NotificationCenter.default.post(name: notificationSearching, object: nil, userInfo: nil)
}
}
func stopAdvertising() {
//stop Advertising Peer
self.serviceAdvertiser.stopAdvertisingPeer()
}
func sendData(data: Int8) {
let dataToSend: [UInt8] = [UInt8(bitPattern: playerNumber!), UInt8(bitPattern: data)]
let bytesWritten = outputStream?.write(dataToSend, maxLength: 2)
NSLog("%@", "writing bytes \(dataToSend) to outputStream")
/*
do {
try self.session.send(dataToSend, toPeers: [appleTvPeer!], with: .unreliable)
NSLog("%@", "sending data: \(data) to peer \(String(describing: appleTvPeer))")
}
catch let error {
NSLog("%@", "Error for sending: \(error)")
}
*/
}
}
enum ConnectionState {
case notConnected //The device is advertising but didnt find a connection
case connecting //The device is in the Connecting process
case connected //The device is succesfully connected - pressing the button while in this state should disconnect from Browser
}
extension GameService: MCNearbyServiceAdvertiserDelegate {
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
NSLog("%@", "recieved an invitation from peer with display name: \(peerID.displayName)")
invitationHandler(true, self.session)
appleTvPeer = peerID
}
}
extension GameService: MCSessionDelegate {
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
if peerID == appleTvPeer {
switch state {
case .notConnected:
NSLog("%@", "lost connection from peer with display name: \(peerID.displayName)")
DispatchQueue.main.async {
NotificationCenter.default.post(name: notificationDisconnected, object: nil, userInfo: nil)
}
case .connecting:
NSLog("%@", "now connecting to peer with display name: \(peerID.displayName)")
DispatchQueue.main.async {
NotificationCenter.default.post(name: notificationConnecting, object: nil, userInfo: nil)
}
case .connected:
NSLog("%@", "succesfully connected to peer with display name: \(peerID.displayName)")
DispatchQueue.main.async {
NotificationCenter.default.post(name: notificationConnected, object: nil, userInfo: nil)
}
}
}
}
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
// get data from appleTV
let int = data.to(type: Int8.self)
NSLog("%@", "recieved data from peer: \(int)")
if int < 10 {
// if the number sent is between 0-9, set it as player number
playerNumber = int
NSLog("%@", "recieved player number: \(int)")
do {
try outputStream = session.startStream(withName: String(int), toPeer: peerID)
NSLog("%@", "created output stream")
} catch {
print("error in creating OutputStraeam")
}
outputStream?.delegate = self
//outputStream?.setValue(playerNumber, forKey: "playerNumber")
outputStream?.schedule(in: RunLoop.main, forMode: RunLoop.Mode.default)
outputStream?.open()
}
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
}
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
}
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {
}
}
extension Data {
init<T>(from value: T) {
var value = value
self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func to<T>(type: T.Type) -> T {
return self.withUnsafeBytes { $0.pointee }
}
}