I'm trying to define a new function for my Player
class which was defined in C#. The purpose of Lua in my project (a game engine) is to define custom behavior for entities such as players.
However, when I do DoFile(fileName)
on the Lua file, it crashes with this exception:
"field or property 'Idle' does not exist"
It specifically points to the first line in this chunk of code:
function Player:Idle()
self:Turn()
self.StateType = StateType.Stand
self.MoveType = MoveType.Idle
self.Vel = Vector2.Zero
if self.Anim.Number ~= 0 and (self.Anim.Number ~= 5 or self:GetAnimTime() == 0) then
self:ChangeAnim(0)
end
end
It seems to have a problem with writing Player:Idle
. However, I also tried writing it as Player.Idle
and I get the same issue. Here's how I handle loading the scripts for the player in C#:
state["Player"] = this;
// Load the states
for (int j = 0; j < stateFiles.Length; j++)
{
string fp = filePath + @"\" + stateFiles[j];
// If it's common, then if it doesn't exist, use the default.
if (stateFiles[j] == "common.lua" && !File.Exists(fp))
fp = Path.Combine("Content", "common.lua");
// Now load it
var f = state.DoFile(fp);
}
I'm setting the Player global to this
because this is the player class, so any new functions need to be declared in the context of Player
. What am I doing wrong?
Edit
I've solved the error from earlier, but I'm still not getting the results I want. It seems it's not possible to directly do this; however I've read up and it seems in Lua 5.2, there's a way to do something like this by associating a table with the userdata object through debug.setuservalue
. However, when I tried using it, the table was still empty (even though the userdata was not).
This is what I tried (C#):
state.NewTable("Player");
state["tmp"] = this;
state.DoString("a = debug.setuservalue(tmp, Player)");
var t = state["Player"]; // Shows that Player is an empty table
var a = state["a"]; // Shows that a was indeed set.
In other words, I want to be able to use self
in the script to be able to refer to the userdata, as well as custom functions, such as Idle()
and Turn()
.
How can I achieve the behavior I desire?
From the Lua reference manual: https://www.lua.org/manual/5.3/manual.html#2.1
Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.
So you cannot add functions to userdata but you write your own, extended interface by wrapping the userdata in your own Lua table.
Simple example, assuming you can create a Player userdata value by calling Player().
WrappedPlayer = {}
WrappedPlayer.usrdata = Player()
function WrappedPlayer:Idle()
self.usrdata:Turn()
self.usrdata.MoveType = MoveType.Idle
end
Then you can simply call WrappedPlayer:Idle()
Of course you can further improve this and after overwriting the Player table with your own and adding some metatable magic you could simply create your very own Player object:
local myPlayer = Player()
myPlayer:Idle()
Just read some Lua OOP tutorials to find out how.
Not to forget a very simple solution:
function SetPlayerIdle(player)
player:Turn()
-- and so forth
end