我目前正在成功地在一个乘法器会话中共享一个AR世界地图,并且我正在尝试从两个对等客户端通过网络发送各个弹丸数据(位置,角度,速度,类型),但我不太确定如何使用Codable序列化这些数据类型SCNVector3,也找不到有关此操作的任何文档..这就是为什么我在这里。我需要能够使用以下方法取消存档数据
let shouldSend = MovementData(velocity: data.velocity, angular: Float(data.angular), position: posStr , x:Float(data.x), y:Float(data.y),z:Float(data.z),type:"Striker")
guard let sendData = try? NSKeyedArchiver.archivedData(withRootObject: shouldSend, requiringSecureCoding: true)
else { fatalError("can't encode movementData") }
我正在尝试使用以下内容对数据进行编码
import SceneKit
open class MovementData: NSObject, NSSecureCoding {
public static var supportsSecureCoding: Bool = true
var velocity = CGPoint.zero,
angular = Float(0),
position:String = "SCNVector3(x:0,y:0.5,z:0)",
orientation = SCNVector3(),
x = Float(0),
y = Float(0),
z = Float(0),
type = String()
enum Key:String {
case velocity = "velocity"
case angular = "angular"
case position = "position"
case x = "x"
case y = "y"
case z = "z"
case type = "type"
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(velocity as CGPoint, forKey: Key.velocity.rawValue)
aCoder.encode(angular as Float, forKey: Key.angular.rawValue)
aCoder.encode(position as String, forKey: Key.position.rawValue)
aCoder.encode(x as Float, forKey: Key.x.rawValue)
aCoder.encode(y as Float, forKey: Key.y.rawValue)
aCoder.encode(z as Float, forKey: Key.z.rawValue)
aCoder.encode(type as String, forKey: Key.type.rawValue)
}
public convenience required init?(coder aDecoder: NSCoder) {
let _velocity = aDecoder.decodeCGPoint(forKey: Key.velocity.rawValue)
let _angular = aDecoder.decodeFloat(forKey: Key.angular.rawValue)
let _position = aDecoder.decodeObject(forKey: Key.position.rawValue)
let _x = aDecoder.decodeFloat(forKey: Key.x.rawValue)
let _y = aDecoder.decodeFloat(forKey: Key.y.rawValue)
let _z = aDecoder.decodeFloat(forKey: Key.z.rawValue)
let _type = aDecoder.decodeObject(forKey: Key.type.rawValue)
self.init(velocity: _velocity, angular: _angular, position: _position as! String, x:_x,y:_y,z:_z,type:_type as! String)
}
init(velocity: CGPoint, angular: Float, position:String, x:Float,y:Float,z:Float,type:String) {
self.velocity = velocity
self.angular = angular
self.position = position
self.x = x
self.y = y
self.z = z
self.type = type
}}
我正在使用以下模型
//
// Striker.swift
import Foundation
import SceneKit
public struct StrikerData: CustomStringConvertible {
var velocity = CGPoint.zero,
angular = CGFloat(0),
// position = SCNVector3()
x = CGFloat(0),
y = CGFloat(0.5),
z = CGFloat(0)
mutating func reset() {
velocity = CGPoint.zero
angular = 0
x = 0
y = 0.5
z = 0
}
public var description: String {
return "StrikerData(velocity: \(velocity), angular: \(angular), position: SCNVector3(x:\(x),y:\(y),z:\(z)))"
}
}
struct Striker {
var name: String
var x: String
var y: String
var z: String
var orientation: String
var velocity:String
init(name: String, orientation: String, velocity: String,x: String, y: String,z:String) {
self.name = name
self.orientation = orientation
self.velocity = velocity
self.x = x
self.y = y
self.z = z
}
}
//MARK: - OpponentStriker
open class OpponentStriker: SCNView {
var striker: Striker!
var trackingHandler: ((StrikerData) -> ())?
var beginHandler: (() -> Void)?
var stopHandler: (() -> Void)?
var substrate: OpponentStriker!
private var tracking = false
private(set) var data = StrikerData()
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
@objc func listen() {
if tracking {
trackingHandler?(data)
}
}
//MARK: - Overrides
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let striker = touch.location(in: self)
tracking = true
beginHandler?()
}
}
open override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
guard tracking else {
return
}
print("Stopped here FIX THIS!!!!!!")
}
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
resetStriker()
}
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
resetStriker()
}
// CustomStringConvertible protocol
open override var description: String {
return "OpponentStriker(data: \(data))"
print("OpponentStriker(data:\(data)")
}
// private methods
private func resetStriker() {
tracking = false
let moveToBack = SCNAction.move(to: SCNVector3(x:0, y:1, z: 0), duration: TimeInterval(0.1))
moveToBack.timingMode = .easeOut
data.reset()
stopHandler?();
}
}
typealias = OpponentStriker
然后,我在使用以下功能创建节点时从视图控制器发送数据:
guard let tableScene = SCNScene(named: "art.scnassets/table.scn"),
let strikerOne = tableScene.rootNode.childNode(withName: "Striker", recursively: false)
// let strikerTwo = tableScene.rootNode.childNode(withName: "Striker", recursively: false)
else { print("Cant find strikerOne node")
return
}
let nodeScale = SCNVector3(0.5,1.25,0.75)
strikerOne.position = SCNVector3(x,y,z)
strikerOne.physicsBody = SCNPhysicsBody(type: .kinematic , shape: SCNPhysicsShape(node: strikerOne, options: [SCNPhysicsShape.Option.scale: nodeScale]))
strikerOne.physicsBody?.categoryBitMask = BitMaskCategory.striker.rawValue
strikerOne.physicsBody?.contactTestBitMask = BitMaskCategory.puck.rawValue
self.strikerOneNode = strikerOne
if player == "One" {
self.selectedNode = strikerOne
}
self.sceneView.scene.rootNode.addChildNode(strikerOne)
let mat4 = strikerOne.transform
let f4x4 = simd_float4x4(mat4)
let anchor = ARAnchor(name: "StrikerOne", transform: f4x4 )
sceneView.session.add(anchor: anchor)
// Send the anchor info to peers, so they can place the same content.
guard let data = try? NSKeyedArchiver.archivedData(withRootObject: anchor, requiringSecureCoding: true)
else { fatalError("can't encode anchor") }
self.multipeerSession.sendToAllPeers(data)
print("Striker One added")
// guard let data = try? NSKeyedArchiver.archivedData(withRootObject: strikerOne, requiringSecureCoding: true)
self.sceneView.scene.rootNode.addChildNode(strikerTwo)
我正在尝试使用NSKeyedUnarchiver反序列化数据
if let movement = try NSKeyedUnarchiver.unarchivedObject(ofClass:MovementData.self, from: data) {
print(" movement DATA FROM \(peer) with data \(data)")
print(movement)
}
我收到的错误是:
can't decode data recieved from <MCPeerID: 0x28294b120 DisplayName = Montreaux’s iPhone>
我正在使用以下演示/自述文件来创建AR Multi用户体验:
非常感谢所有帮助,
干杯!
答案 0 :(得分:1)
如果您使用的是Apple提供的示例,则可以通过执行以下操作来使您的代码起作用。
首先,当两个设备都连接时,我使用以下功能发送一些测试数据:
/// Send A Movement Data Object To Our Peers
@IBAction func pressToSend(){
let shouldSend = MovementData(velocity: CGPoint.zero,
angular: Float(10),
position: "StackOverflow",
x:Float(10), y:Float(20),z:Float(30),
type:"BlackMirrorz")
guard let sendData = try? NSKeyedArchiver.archivedData(withRootObject: shouldSend, requiringSecureCoding: true) else { fatalError("can't encode movementData") }
cloudSession.sendDataToUsers(sendData)
}
在cloudSession sendDataToUsers(_ data: Data)
中调用Multipeer Class
函数:
//--------------------------
// MARK: - MCSessionDelegate
//--------------------------
extension ARCloudShare: MCSessionDelegate {
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) { }
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
receivedDataHandler(data, peerID)
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
fatalError("This Service Does Not Send Or Receive Streams")
}
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
fatalError("This Service Does Not Send Or Receive Resources")
}
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {
fatalError("This Service Does Not Send Or Receive Resources")
}
}
//---------------------------------------
// MARK: - MCNearbyServiceBrowserDelegate
//---------------------------------------
extension ARCloudShare: MCNearbyServiceBrowserDelegate {
public func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String: String]?) {
//Invite A New User To The Session
browser.invitePeer(peerID, to: session, withContext: nil, timeout: 10)
}
public func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) { }
}
//------------------------------------------
// MARK: - MCNearbyServiceAdvertiserDelegate
//------------------------------------------
extension ARCloudShare: MCNearbyServiceAdvertiserDelegate {
//----------------------------------------------------------
// MARK: - Allows The User To Accept The Invitation To Share
//----------------------------------------------------------
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
//Allow The User To Accept The Invitation & Join The Twunkl Session
invitationHandler(true, self.session)
}
}
class ARCloudShare: NSObject{
static let serviceType = "arcloud-share"
let myPeerID = MCPeerID(displayName: UIDevice.current.name)
var session: MCSession!
var serviceAdvertiser: MCNearbyServiceAdvertiser!
var serviceBrowser: MCNearbyServiceBrowser!
let receivedDataHandler: (Data, MCPeerID) -> Void
//-----------------------
// MARK: - Initialization
//-----------------------
init(receivedDataHandler: @escaping (Data, MCPeerID) -> Void ) {
self.receivedDataHandler = receivedDataHandler
super.init()
session = MCSession(peer: myPeerID, securityIdentity: nil, encryptionPreference: .required)
session.delegate = self
serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerID, discoveryInfo: nil, serviceType: ARCloudShare.serviceType)
serviceAdvertiser.delegate = self
serviceAdvertiser.startAdvertisingPeer()
serviceBrowser = MCNearbyServiceBrowser(peer: myPeerID, serviceType: ARCloudShare.serviceType)
serviceBrowser.delegate = self
serviceBrowser.startBrowsingForPeers()
}
//---------------------
// MARK: - Data Sending
//---------------------
func sendDataToUsers(_ data: Data) {
do {
try session.send(data, toPeers: session.connectedPeers, with: .reliable)
} catch {
print("Error Sending Data To Users: \(error.localizedDescription)")
}
}
//----------------------
// MARK: - Peer Tracking
//----------------------
var connectedPeers: [MCPeerID] { return session.connectedPeers }
}
然后在我们的主要ViewController中处理数据,如下所示:
//----------------------
// MARK: - Data Handling
//----------------------
/// Handles The Data Received From Our ARMultipeer Session
///
/// - Parameters:
/// - data: Data
/// - peer: MCPeerID
func receivedData(_ data: Data, from peer: MCPeerID) {
if let unarchivedData = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data){
if unarchivedData is MovementData, let data = unarchivedData as? MovementData{
print(data.orientation)
print(data.position)
}
else {
print("Unknown Data Recieved From = \(peer)")
}
}
}
产生如下内容:
在此处可以看到发送多种数据类型的示例:ARWorldMaps
希望它会为您指明正确的方向...