2011-06-09 63 views
6

我正在用C++使用Lua來定義NPC的遊戲引擎。如何直接將Lua變量映射到C++變量?

我可以定義一個原型的NPC是這樣的:

orc = 
{ 
    name = "Generic Orc", 
    health = 100 
} 

function orc:onIdle() 
    print("Orc idles...") 
end 

,然後產卵「獸人」的實例,該entitySpawn(orc)。這是一個C++函數,它從給定表中讀取健康和名稱等值,使用給定值在C++中創建實體對象,併爲特定NPC創建一個Lua表。

現在,我想直接連接在Lua中的orc.health變量和C++中相應實體對象的mHealth成員變量,所以我可以在Lua中分配一個值並立即在C++中使用它,反之亦然。

這甚至可能嗎?或者我必須使用setter/getter函數?我看了一下light userdata,並在Lua中存儲了一個指向C++變量的指針,但無法賦值。

回答

6

這是可能的。我假設entitySpawn返回C++爲實體創建的表。我還假設您可以公開從C++函數接受一個實體的表,然後返回當前的健康,同樣的設置。 (您可以使用光用戶數據指向C++對象作爲此表的成員來實現這一點。)

因此,醜陋的方式是這樣的:

local myOrc = entitySpawn(orc) 
local curHealth = getEntityHealth(myOrc) 
setEntityHealth(myOrc, curHealth + 10) 

爲了使這個漂亮,我們可以與metatables有一些樂趣。首先,我們將爲我們關心的所有屬性添加訪問器。

entityGetters = { 
    health = getEntityHealth, 
    -- ... 
} 
entitySetters = { 
    health = setEntityHealth, 
    -- ... 
} 

然後我們將創建一個使用這些函數處理屬性分配的metatable

entityMetatable = {} 

function entityMetatable:__index(key) 
    local getter = entityGetters[key] 
    if getter then 
     return getter(self) 
    else 
     return nil 
    end 
end 

function entityMetable:__newindex(key, value) 
    local setter = entitySetters[key] 
    if setter then 
     return setter(self, value) 
    end 
end 

現在您需要爲entitySpawn賦值metatable。你可以用lua_setmetatable函數來做到這一點。

int entitySpawn(lua_State* L) 
{ 
    // ... 
    // assuming that the returned table is on top of the stack 
    lua_getglobal(L, "entityMetatable"); 
    lua_setmetatable(L, -2); 
    return 1; 
} 

現在,你可以把它寫的很好的方式:

local myOrc = entitySpawn(orc) 
myOrc.health = myOrc.health + 10 

注意,這需要由entitySpawn返回餐桌的現象確實有一個健康的屬性集。如果是這樣,那麼該物業將永遠不會諮詢metatable。

可以創建entityGettersentitySettersentityMetatable表,以及在__index__newindex元方法,在C++而不是Lua中如果感覺清潔給你,但總的想法是一樣的。

+0

謝謝,這就是我需要的!似乎我的研究走向了完全錯誤的方向:) – Daerst 2011-06-09 20:11:42

2

我沒有時間給你的任何代碼,但請記住orc.health是一樣的orc["health"];即orc是表格,"health"是一個元素。

考慮到這一點,您可以更改表格的indexnewindexmetamethods以擁有自己的特定行爲。將您的「真實」orc實例存儲爲一些私有元數據,然後用它來更新。