【问题标题】:Any proper way of sending byte data to Unity3D from a C plugin?从 C 插件向 Unity3D 发送字节数据的任何正确方法?
【发布时间】:2012-09-05 13:22:10
【问题描述】:

这里只是一个好奇的问题。

当您在 iOS 平台上为 Unity 编写插件时,插件具有有限的本地到托管回调功能(从插件到 Unity)。基本上这个文档: iOS plugin Unity documentation

声明您可以回调的函数签名是这样的:

只有符合以下签名的脚本方法才能从本机代码中调用:function MethodName(message:string)

C 中定义的签名如下所示:

void UnitySendMessage(const char* obj, const char* 方法, const char* msg);

所以这几乎意味着我只能将字符串发送回 Unity。

现在在我的插件中,我使用 protobuf-net 来序列化对象并将它们发送回 unity 进行反序列化。我已经让这个工作了,但是通过一个我觉得很丑陋而且一点也不优雅的解决方案:

Person* person = [[[[[Person builder] setId:123]
                    setName:@"Bob"]
                   setEmail:@"bob@example.com"] build];
NSData* data = [person data];

NSString *rawTest = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

UnitySendMessage("GameObject", "ReceiveProductRequestResponse", [rawTest cStringUsingEncoding:NSUTF8StringEncoding]);

基本上我只是将字节流编码成一个字符串。然后在 Unity 中获取字符串的字节并从那里反序列化:

System.Text.UTF8Encoding encoding=new System.Text.UTF8Encoding();
Byte[] bytes = encoding.GetBytes(message);

这确实有效。但是真的没有别的办法了吗?也许有人知道如何以其他方式完成它?

【问题讨论】:

  • 这种方法绝对没有错。如果您必须将数据作为字符串传输,则将其编码为字符串。也就是说,UTF8 不是一个好的选择; UTF8 旨在将字符串编码为二进制,反之亦然。我会使用 base64。
  • 或者,使用生成文本的序列化机制而不是协议缓冲区,例如 JSON 或 XML。
  • 哈哈有趣 :) 我会尝试使用 Base64 编码。感谢您的建议:D 我不确定这是否是一种可接受的方式。
  • 一个很好的问题,但它不应该在 UnityAnswers 上而不是堆栈溢出上吗?

标签: c# objective-c c unity3d protobuf-net


【解决方案1】:

Base-64(或其他类似的基础)是执行此操作的正确方法;您不能在此处使用编码(例如 UTF8) - 编码旨在转换:

arbitrary string <===encoding===> structured bytes

即其中字节具有定义的结构; protobuf 不是这种情况;你想要的是:

arbitrary bytes <===transform===> structured string

在大多数情况下,base-64 是最方便的实现。严格来说,你有时可以比 64 高一点,但你可能不得不手动滚动它 - 不漂亮。 Base-64 易于理解且支持良好,是一个不错的选择。我不知道你是如何在 C 中做到这一点的,但在 Unity 中应该是这样的:

string s = Convert.ToBase64String(bytes);

通常,您还可以在此处避免额外的缓冲区,假设您将内存中序列化为MemoryStream:

string s;
using(var ms = new MemoryStream()) {
    // not shown: serialization steps

    s = Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
}

【讨论】:

  • 是的,在上面 cmets 的提示之后,我尝试切换到 Base64 并发现它对我的代码中的功能产生了奇迹 :) 它有助于消除无法解释的行为。现在我终于可以让我的功能在同一个缓冲区下读取 protobuf 消息的集合,以减少非托管到托管的调用量。
  • 啊哈有趣!如果我可以减少使用的缓冲区数量,那就太棒了:)谢谢你的额外提示!
【解决方案2】:

基于 Marc Gravell 回答的示例:

在ios端:

-(void)sendData:(NSData*)data
{
    NSString* base64String = [data base64Encoding];
    const char* utf8String = [base64String cStringUsingEncoding:NSUTF8StringEncoding];
    UnitySendMessage("iOSNativeCommunicationManager", "dataReceived", utf8String);
}

在团结方面:

public delegate void didReceivedData( byte[] data );
public static event didReceivedData didReceivedDataEvent;

public void dataReceived( string bytesString )
{
    byte[] data = System.Convert.FromBase64String(bytesString);

    if( didReceivedDataEvent != null )
        didReceivedDataEvent(data);
}

【讨论】:

  • 很棒的例子。像冠军一样工作。
猜你喜欢
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
  • 2016-06-16
  • 2016-12-27
  • 2014-07-16
  • 2010-10-02
  • 1970-01-01
相关资源
最近更新 更多