2014-07-08 149 views
1

在大多數情況下,我很高興通過SWIG處理數據的方式,但是我遇到問題並且無法在文檔中找到答案。SWIG擴展變量

的所有IM使用痛飲和Lua的第一和具有以下結構包裹:

typedef struct 
{ 
    %mutable; 
     float x,y,z; 
    ... 
    ... 

} Vector3; 


typedef struct 
{ 
    ... 
    ... 

    %immutable; 
     Vector3 gravity; 

    ... 
    ... 

    %extend 
    { 
     void SetGravity(Vector3 gravity) 
     { 
      WorldSetGravity($self,gravity); 
     } 
    }; 
} World; 

正如你所看到的嚴重性XYZ可以通過調用SetGravity功能受到影響,它的工作很大。

然而,爲了更直觀,更易於使用,我想給的機會,用戶設置組件(XY或Z)獨立,如:

world.gravity.x=-10; 

但我需要調用在後臺SetGravity中,以便能夠將適當的值發送給物理引擎(未暴露給Lua)。

我想知道是否有方法%extend變量,這將允許我調用world.gravity.xy or z調用SetGravity

或者能夠爲每個組件實現我自己的wrap功能版本,如:_wrap_World_gravity_set_x這將分配我在後臺調用SetGravity

+1

如果你想'world.gravity.x'是可變的,那麼爲什麼'world.gravity'標記爲不可變?如果一個對象被標記爲不可變,那麼你不應該設計使它的一部分變爲可變的黑客。有些事情是不對的,也許描述你想如何使用重力和約束。 – Schollii

+0

需要注意的一點是:如果您展示說明問題所需的最少但仍然完整的代碼量,則可以更輕鬆地回答這樣的問題。當我開始回答時,我不得不重新發明你已經得到的東西。一般來說,如果你堅持這一點,你會得到更多更好的答案。 – Flexo

回答

1

首先值得注意的是,這個問題比使用%extend製作一個「虛擬」成員變量更難,當有人修改它時會自動調用一個額外的函數。這是因爲你想要它是另一個類的成員來改變行爲。

我可以看到幾個基本的方法,你可以拿得到這個行爲:

  1. 注入目標腳本語言的一些額外的代碼勾集
  2. 注入一些額外的東西在痛飲接口透明地將World中的Vector3轉換爲仍然看起來和感覺相同的東西,但具有您想要的行爲。
  3. Vector3的memberin類型映射注入一些額外的代碼,該代碼檢查從中調用的上下文並相應地修改行爲。

這些#2是我首選的解決方案,因爲#1是特定語言(我不知道Lua的不夠好做!)和#3從軟件工程的角度看感覺很髒。

爲了實現#2我做了以下內容:

%module test 

%{ 
#include "test.h" 
%} 

typedef struct 
{ 
    %mutable; 
    float x,y,z; 
} Vector3; 

%nodefaultctor Vector3Gravity; 

%{ 
// Inside C this is just a typedef! 
typedef Vector3 Vector3Gravity; 
// But we have magic for sets/gets now: 
#define MEMBER_VAR(ct,vt,rt,n)          \ 
    SWIGINTERN void ct##_##n##_set(ct *self, const vt val) {   \ 
    self->n = val;             \ 
    /* Need to find a way to lookup world here */     \ 
    WorldSetGravity(world, self);         \ 
    }                 \ 
    SWIGINTERN vt ct##_##n##_get(const ct *self) { return self->n; } 

MEMBER_VAR(Vector3Gravity, float, Vector3, x) 
MEMBER_VAR(Vector3Gravity, float, Vector3, y) 
MEMBER_VAR(Vector3Gravity, float, Vector3, z) 
%} 

// Inside SWIG Vector3Gravity is a distinct type: 
typedef struct 
{ 
    %mutable; 
    %extend { 
     float x,y,z; 
    } 
} Vector3Gravity; 


%typemap(memberin,noblock=1) Vector3Gravity gravity %{ 
    $1 = *((const Vector3*)$input); 
    WorldSetGravity($self, $1); // This gets expanded to automatically make this call 
%} 

typedef struct 
{ 
    // This is a blatant lie! 
    Vector3Gravity gravity; 
} World; 

本質上講,我們是在撒謊,並聲稱世界gravity成員是一個「特殊」的類型,而實際上它只是一個Vector3。我們特殊的類型有兩個明顯的特點。首先設置/獲取其成員由我們實現一個C代碼。其次,當我們設置這個成員時,我們會自動進行額外的調用,而不僅僅是傳遞值。

有兩件事情可能是從這個例子裏缺了,你可能想:

  1. 透明轉換從Vector3GravityVector3。 (因爲它的立場除了重力集以外的任何東西都會拒絕接受Vector3Gravity實例)。如果需要,可以通過使用SWIG/Lua的重載解析機制來實現透明。
  2. 對於Vector3Gravity的設置者,我們不知道這個引力屬於哪個世界。

    我們可以通過幾種方式解決這個問題,最簡單的就是每次創建一個Vector3Gravity就隱式設置一個靜態指針。如果只有一個世界,這是有道理的。

    另一種方法是將Vector3Gravity實例的全局地圖用於自動維護的世界。

    最後,而是採用了typedefVector3Gravity類型,我們可以做一個真正獨特的類型,與兼容的佈局,但添加到World它來自一個指針。雖然這是更多的工作。

+0

Humm ...在某些時候,我正在玩類似的東西,通過創建一個「假的」Gravity結構來保存XYZ,並在每個組件被調用時擴展它以便SetGravity是觸發器。它可以工作,但問題是重力不再是Vector3,不能使用任何Vector3功能。有沒有一種方法來保持Vector3的重力,並且只有%擴展了XYZ set方法才能觸發SetGravity?當然,在引力的情況下,它不會有多大意義,但在ie:Object.location.xyz的情況下,它會調用ie:ObjectSetTransform它會... – user3192607

+1

因此,您需要一種機制,通過這種機制,所有矢量可以關聯一些其他功能的變化。我將不得不多想一想。我會做的是讓矢量不可變(然後通過總是創建新的來改變),然後使用我的示例的成員部分將修改修改到正確位置的變量。 – Flexo

+0

@Flexo:Im與這個用戶有幾乎相同的問題。你介意發表一個最後一種方法的例子(你必須考慮更多的方法) – McBob