1. 程式人生 > >Unity與c++ 結構體中帶陣列引數傳遞

Unity與c++ 結構體中帶陣列引數傳遞

在unity與c++ 進行互動中往往會有結構體的資料傳遞,如果在結構體中定義了陣列,那麼在unity中需要怎樣去定義結構體從而對應c++中定義的帶有陣列的結構體呢.

請看程式碼:

#ifndef TRACK_H_H_
#define TRACK_H_H_

#define TRACK_POINT_SIZE 68
#define TRACK_MOUNT_POINT_SIZE 11

#ifdef __cplusplus
extern "C" {
#endif
typedef struct TrackPointCoord{
	float x;
	float y;
}TrackPointCoord;

typedef struct TRACK2DRET{
	TrackPointCoord allTrackPoints[TRACK_POINT_SIZE];
	TrackPointCoord mountTrackPoints[TRACK_MOUNT_POINT_SIZE];
    float  scale;
    float  angle;
    float  rendering_paramsy;
    float  rendering_paramsx;
}TRACK2DRET;

bool Track2DForUnity3D(unsigned char* rgba, TRACK2DRET* track2dRet);

#ifdef __cplusplus
}
#endif

#endif
在c++程式碼中定義了一個結構體,結構體中還定義了兩個陣列物件。那麼c#該怎樣定義呢

請看程式碼:

using System.Runtime.InteropServices;
using UnityEngine;
public struct TrackPointCoord
{
    public float x;
    public float y;
    public TrackPointCoord(float _x, float _y)
    {
        this.x = _x;
        this.y = _y;
    }
};

public struct TRACK2DRET
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 68)]
    public TrackPointCoord[] allTrackPoints;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
    public TrackPointCoord[] mountTrackPoints;
    public float scale;
    public float angle;
    public float rendering_paramsy;
    public float rendering_paramsx;

    public TRACK2DRET(TrackPointCoord[] _allTrackPoints, TrackPointCoord[] _mountTrackPoints, float _scale, float _angle, float _rendering_paramsy, float _rendering_paramsx)
    {
        this.allTrackPoints = _allTrackPoints;
        this.mountTrackPoints = _mountTrackPoints;
        this.scale = _scale;
        this.angle = _angle;
        this.rendering_paramsy = _rendering_paramsy;
        this.rendering_paramsx = _rendering_paramsx;
    }
};

public class TrackTool: Manager
{
  #region Android
#if UNITY_ANDROID
    [DllImport("TrackToolForUnity3D")]
    private static extern bool Track2DForUnity3D(byte[] rgba, ref TRACK2DRET track2dRet);
#endif
    #endregion

    /// <summary>
    /// 初始化結構體
    /// </summary>
    public TRACK2DRET InitStruct()
    {
        TrackPointCoord[] _allTrackPoints, _mountTrackPoints;
        TrackPointCoord _TrackPointCoord = new TrackPointCoord(0, 0);
        _allTrackPoints = new TrackPointCoord[68];
        _mountTrackPoints = new TrackPointCoord[11];
        for (int i = 0; i < _allTrackPoints.Length; i++)
        {
            _allTrackPoints[i] = _TrackPointCoord;
        }
        for (int i = 0; i < _mountTrackPoints.Length; i++)
        {
            _mountTrackPoints[i] = _TrackPointCoord;
        }
        TRACK2DRET track2dret = new TRACK2DRET(_allTrackPoints, _mountTrackPoints, 0, 0, 0, 0);
        return track2dret;
    }

//呼叫so
    public bool GetTarck2d(Color32[] Pixels,ref TRACK2DRET track2dret)
    {
        return Track2DForUnity3D(Color32ArrayToByteArray(Pixels), ref track2dret);
    }

/// <summary>
    /// color32 array to byte array
    /// </summary>
    /// <param name="colors"></param>
    /// <returns></returns>
     byte[] Color32ArrayToByteArray(Color32[] colors)
    {
        if (colors == null || colors.Length == 0)
            return null;
        int length = Marshal.SizeOf(typeof(Color32)) * colors.Length;
        byte[] bytes = new byte[length];
        GCHandle handle = default(GCHandle);
        try
        {
            handle = GCHandle.Alloc(colors, GCHandleType.Pinned);
            Marshal.Copy(handle.AddrOfPinnedObject(), bytes, 0, length);
        }
        finally
        {
            if (handle != default(GCHandle))
                handle.Free();
        }
        return bytes;
    }
}
在c# 可以看到
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 68)]
MarshalAs屬性指示如何在託管程式碼和非託管程式碼之間封送資料

[MarshalAs(UnmanagedType unmanagedType, 命名引數)]

實際上相當於構造一個MarshalAsAttribute類的物件

常用的UnmanagedType列舉值:

BStr   長度字首為雙位元組的 Unicode 字串;

LPStr  單位元組、空終止的 ANSI 字串。;

LPWStr  一個 2 位元組、空終止的 Unicode 字串;

ByValArray用於在結構中出現的內聯定長字元陣列,應始終使用MarshalAsAttribute的SizeConst欄位來指示陣列的大小。

SizeConst值對應著c++中定義的結構體中陣列大小.。

-----------------------》

在c#中想要獲取c++中返回的結構體值需要使用ref方法。

[DllImport("TrackToolForUnity3D")]
    private static extern bool Track2DForUnity3D(byte[] rgba, ref TRACK2DRET track2dRet);
c++中:
bool Track2DForUnity3D(unsigned char* rgba, TRACK2DRET* track2dRet);
-----------------------------》

說下unsigned char* rgba引數

在c# 中需要定義物件為byte[]形式進行傳值。上面程式碼中提供一個簡便的將Color32[]轉為byte[]方法。