class 객체의 멤버에서 또 다른 class의 instance를 return 하려면 어떻게 하나요?

27 views
Skip to first unread message

odyssey

unread,
Nov 15, 2007, 3:56:53 AM11/15/07
to squirrelusers-kr
안녕하세요. squirrel을 엔진에 붙여서 엔진의 Entity 구성요소를 제어하려고 합니다.

아래의 간략한 소스를 통해 구조를 보여드리고 먼저 시도해 보신 분들의 의견 부탁드립니다.
Engine 내부에서 GameEntity를 모두 생성한 후에 script에서는 GameEntity의 포인터 참조로
멤버를 리턴받아 사용하고자 합니다.


// c++, 엔진 소스 코드
// GameEntity ======================
class GameEntity {
GameField* GetField(const char* name); // 이름으로 멤버 필드를 찾아서 리

};








// c++, 스크립트 제어 인터페이스
// CVector3 ======================
struct CVector3 {
float x;
float y;
float z;
CVector3() { x = y = z = 0.f; }
CVector3(float _x, float _y, float _z) { x = _x; y = _y; z =
_z; }
};

_MEMBER_FUNCTION_IMPL(Vector3,_get) {
StackHandler sa(v);
_CHECK_SELF(CVector3,Vector3);
const SQChar *s = sa.GetString(2);
if(s && (s[1] != 0)) return SQ_ERROR;
int index = s && (s[1] == 0)?s[0]:sa.GetInt(2);
switch(index) {
case 0: case 'x': case 'r': return sa.Return(self->x); break;
case 1: case 'y': case 'g': return sa.Return(self->y); break;
case 2: case 'z': case 'b': return sa.Return(self->z); break;
} // switch
return SQ_ERROR;
}




// EntityRef ===================
class EntityRef {
GameEntity* entity;
};

_MEMBER_FUNCTION_IMPL(EntityRef,_get) {
StackHandler sa(v);
_CHECK_SELF(CEntityRef,EntityRef);
const SQChar *s = sa.GetString(2);
if (! s) return SQ_ERROR;

GameEntity* pEntity = self->entity;
if (! pEntity) return SQ_ERROR;

GameField* pField = pEntity->GetField(s);
if (! pField) return SQ_ERROR;

switch (pField->type)
{
. . .
case EGTF_VEC3F :
{
float* pVal = ((float*) pField->ptr); // 필드에 저장된 ptr
는 객체의 vec3 형 멤버 변수임.

// 아래의 방법으로는 sa.Return()에서 User Pointer로 등록되어 버립니다.
// class instance 형식으로 return 되어야 script에서 사용가능할 것으로 보이는 데 방법
을 모르겠네요.

CVector3* newv = new CVector3(pVal[0], pVal[1],
pVal[2]);
return sa.Return(newv);
}
. . .
}
return SQ_ERROR;
}




// main.cpp, 스크립트 초기화 부분

SquirrelProcessor::Init();
SquirrelProcessor::RegistOutputStr( m_strOutput,
MAX_OUTPUT_LENGTH );

// VM 초기화 후에 스크립트 class를 등록했습니다.
_INIT_CLASS(EntityRef);
_INIT_CLASS(Vector3);





// squirrel, 스크립트 소스

local my_avt = EntityRef("my_avt");

local vec = Vector3(1,2,3); // 이 경우는 스크립트에서
vector3를 직접 생성하기 때문에 제대로 동작함.
print(vec.x);

local pos = my_avt.position; // EntityRef의 get()
함수에서 return 되는 객체가 UserPointer로만 인식되어 '.x' 을 index로 인식하지 못함.
print(pos.x); //
ERROR !!!







이렇게 스크립트 소스의 내부에서 생성하면 동작하는 데, c++ 함수에서 생성하면 인식되지 않는 문제를 어떻게 해결해야 할까요?

의견 주시면 감사하겠습니다.

yagur

unread,
Nov 15, 2007, 5:15:10 AM11/15/07
to squirrelusers-kr

On 11월15일, 오후5시56분, odyssey <vrdevelo...@paran.com> wrote:
>
> CVector3* newv = new CVector3(pVal[0], pVal[1],
> pVal[2]);
> return sa.Return(newv);
> }
> . . .
> }
> return SQ_ERROR;

포인터를 리턴하게되면 VM이 유저포인터로 인식을 합니다. 인스턴스로 만들어 주셔야하는데,

_IMPL_NATIVE_CONSTRUCTION(Vector3, CVector3);

를 먼저 해주신후.

CVector3* newv = new CVector3(pVal[0], pVal[1], pVal[2]);
return construct_Vector3(newv);
}
. . .
}
return SQ_ERROR;

이렇게 바꾸면 인스턴스로 인식할것입니다.

yagur

unread,
Nov 15, 2007, 5:39:58 AM11/15/07
to squirrelusers-kr
잘못쓴 부분이 있습니다.
return construct_Vector3(newv); <= 이 부분을 아래와 같이 고치면 동작합니다.

return push_Vector3(newv);

odyssey

unread,
Nov 15, 2007, 8:24:00 PM11/15/07
to squirrelusers-kr
답변 주셔서 감사합니다.

처음 질문을 올리고 나서 인터넷을 여기저기 뒤져보니

SquirrelObject root = SquirrelVM::GetRootTable();
SquirrelObject vector3class = root.GetValue("Vector3");
SquirrelObject so =
SquirrelVM::CreateInstance(vector3class);
CVector3* newv = new CVector3(pVal[0], pVal[1],
pVal[2]);
so.SetInstanceUP(newv);
return sa.Return(so);

이런 방법이 있어서 우선 해보았더니 동작하길래 그렇게 두기로 했었습니다.

그런데, 답변 주신 방법데로 해보았더니 역시 동일하게 동작하고 코드도 훨씬 간결하군요.
push_Vector3()의 내부를 trace 해보니 위와 같은 원리로 더 안전하게 코드가 구성되어 있어서
이 방법이 정답인 것 같습니다.

감사합니다.
Reply all
Reply to author
Forward
0 new messages