在大多数情况下,我对SWIG处理数据的方式感到高兴,但我遇到了一个问题,在文档中找不到答案。
首先,我将SWIG与Lua一起使用并包含以下结构:
typedef struct
{
%mutable;
float x,y,z;
...
...
} Vector3;
typedef struct
{
...
...
%immutable;
Vector3 gravity;
...
...
%extend
{
void SetGravity(Vector3 gravity)
{
WorldSetGravity($self,gravity);
}
};
} World;
正如您所看到的那样,通过调用SetGravity
函数可以影响XYZ的重力,并且效果很好。
但是,为了更直观和易于使用,我想让用户有机会独立设置组件(XY或Z),如:
world.gravity.x=-10;
但我需要在后台SetGravity
调用,以便能够将正确的值发送到物理引擎(不会暴露给Lua)。
我想知道是否有%extend
个变量可以让我在调用SetGravity
时调用world.gravity.xy or z
?
或者能够为每个组件实现我自己的wrap函数版本,例如:_wrap_World_gravity_set_x
,它将分配给我在后台调用SetGravity
。
答案 0 :(得分:1)
首先,值得注意的是,这个问题比简单地制作虚拟"更难。使用%extend
的成员变量,当有人修改它时会自动调用额外的函数。这是因为您希望它是另一个类的成员来改变行为。
我可以看到您可以采取的几种基本方法来实现此行为:
Vector3
内部World
内容转换为看起来和感觉相同但仍具有您想要的行为的内容。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代码。其次,当我们设置此成员时,我们会自动进行额外调用,而不是仅传递值。
此示例中可能缺少两件您可能想要的东西:
Vector3Gravity
到Vector3
的透明转换。 (因为除了重力集之外的其他任何东西都会拒绝接受Vector3Gravity
个实例)。如果需要,可以使用SWIG / Lua的重载解析机制使其透明。在Vector3Gravity
的制定者中,我们不知道这个引力属于哪个世界。
我们可以通过多种方式解决这个问题,最简单的方法是每次创建Vector3Gravity
时隐式设置静态指针。如果只有一个世界,这将是有意义的。
另一种方法是将Vector3Gravity
个实例的全局地图用于自动维护的世界。
最后,我们可以将typedef
用于Vector3Gravity
类型,而不是使用World
类型,而是使用兼容的布局,但是添加一个指向它的{{1}}的指针。但是,这还有更多的工作。