I'm learning game development with LÖVE2D and Lua and lately I've been using a state machine class. I haven't coded the class myself, but I've went through the code and I think I pretty much got it, besides this one problem.
The thing is, I'm trying to prompt the class for its current state, just so I can use it inside an if, but no matter what, I cannot get it right.
Here's the relevant code of the class:
StateMachine = Class{}
function StateMachine:init(states)
self.empty = {
render = function() end,
update = function() end,
enter = function() end,
exit = function() end
}
self.states = states or {} -- [name] -> [function that returns states]
self.current = self.empty
end
function StateMachine:change(stateName, enterParams)
assert(self.states[stateName]) -- state must exist!
self.current:exit()
self.current = self.states[stateName]()
self.current:enter(enterParams)
end
What I'm basically trying to do is:
function StateMachine:is(stateName)
if self.current == self.states[stateName] then
-- this never executes
return true
end
return false
end
I've tried changing self.states[stateName] to other things to test it out and also tried printing stuff to the console to see why the comparison is never true. It seems self.current returns a pointer to a table and thus never matches whatever is on the other side of the comparison operator.
Thanks for your help!
self.current is set to the return value of self.states[stateName] in StateMachine:change
function StateMachine:change(stateName, enterParams)
...
self.current = self.states[stateName]() -- note the () indicating the call
This means, unless the return value is self, self.current will not be equal to the function or object self.states[stateName] that it is compared to in StateMachine:is
function StateMachine:is(stateName)
if self.current == self.states[stateName] then -- here we are comparing the function to the return value
I would suggest expanding your state object to have a :getName function that would return the stateName or to store the name in your StateMachine under a key such as currentStateName.
I had the exact same question & I'd like to add--perhaps some of the comments explain this in language I just didn't understand :D--but in the getCurrentState function I created I had to do this:
function StateMachine:getCurrentState()
variable = self.currentStateName
return variable
where ofc variable is just some placeholder. but I had to grab the reference that self.currentStateName was pointing to, otherwise the comparison always failed.
Related
Edited for more details:
I'm trying to have a turtle that is sitting in front of a sapling wait for it to grow before cutting it down. It compares the log to the item in front until it matches. The system I'm currently using works, but I was hoping there was a slightly more minimal way to write it.
checkTarget = {
forward = function(tgt)
check = {turtle.inspect()} --creates table with first as boolean, second as information table
local rtn = {false, check[2]}
if type(tgt) == "table" then
for k, v in pairs(tgt) do
if check[2].name == v then
rtn = {true, v}
break
end
end
elseif tgt == nil then
return check[1]
elseif check[2].name == tgt then
rtn[1] = true
end
return rtn
end,--continued
This takes an argument, either a string or an array of strings, to compare against. When it checks the block in front it saves the detailed information to the second element in rtn and the first to a default of false. If the string matches the checked block's name, then it changes rtn[1] to true and returns all of it, which is the table at the bottom when doing checkTarget.forward("minecraft:log").
My question was, I am currently making a disposable variable to store the array that is returned from checkTarget, and then calling the variable's first element to get if it's true or not. I was hoping there was a way to include it in the if statement without the disposable variable (tempV)
repeat
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
cut()
fox.goTo({x = 0, y = 0, z = 0})
fox.face(0)
end
tempV = fox.checkTarget.forward("minecraft:log")
until not run
{
false,
{
state = {
stage = 0,
type = "birch",
},
name = "minecraft:sapling",
metadata = 2
}
}
Instead of
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
end
You can do
if fox.checkTarget.forward("minecraft:log")[1] then
end
and then calling the variable's first element to get if it's true or
not.
With tempV[1] you're not calling the first element, you're indexing it.
To call something you have to use the call operator () which doesn't make sense as a boolean is not callable.
My goal
Get getmetatable to return the return value of the function assigned to the __metatable field.
Code:
local x, m = {}, {__metatable = function() return nil end};
setmetatable(x, m);
io.write("Let's get the metatable:", tostring(getmetatable(x)), "\n");
But I'm getting the actual function rather than return.
So how do I get it to be called so I can get nil? So it seems like it has no metatable?
Just rewrite getmetatable to work the way you want it to ;)
do local getmetatable = getmetatable
function _G.getmetatable(tab)
local meta = getmetatable(tab)
if type(meta)=='function' then
return meta(tab)
else
return meta
end
end
end
Alternatively, you could just set __metatable to false. This would work for code written like if getmetatable(foo) then, but would break to code like if getmetatable(foo) == false. Arguably, the first is the one you should use, but there's likely someone out there doing the second one.
That'd also hint to the user that there is a metatable, it's just none of their busyness to mess with it.
For some reason it doesn't appear to work to pass in a table key as a function argument, what is the trick to do this?
I'm trying to wrap the for loop iteration technique in vanilla Lua into a function that has three arguments: (1) the table to iterate, (2) the table_key to check each time, and (3) the value to find. If a match is found, return it, otherwise return nil.
function table_find_match(table, table_key, match_value)
for i=1, #table do
local this = table[i]
if this[table_key] == match_value then
return this[table_key]
end
end
return nil
end
local table_example = {
{
key_example = "string_value_1"
},
{
key_example = "string_value_2"
}
}
local result = table_find_match(table_example, key_example, "string_value_1")
print(result)
Found a solution, if I pass in the table key as a string it works, such as
table_find_match(table_example, "key_example", "string_value_1")
but I really dislike having to convert it into a string, if anyone knows any other workaround to this please share
If you pass it like table_find_match(table_example, key_example, "string_value_1")
the key_example is now considered as a (nil) variable if not defined before executing, so it has to be like
local key_example = "key_example"
local result = table_find_match(table_example, key_example, "string_value_1")
print(result)
Can you alias a function (not in a class) in LUA in a similar way to Ruby? In ruby you would do something like this:
alias new_name_for_method method()
def method()
new_name_for_method() # Call original method then do custom code
i = 12 # New code
end
I'm asking because I'm developing for a program that uses LUA scripting and I need to override a function that is declared in a default file.
In Lua, functions are values, treated like any other value (number, string, table, etc.) You can refer to a function value via as many variables as you like.
In your case:
local oldmethod = method
function method(...)
oldmethod(...)
i = 12 -- new code
end
keep in mind that
function method() end
is shorthand for:
method = function() end
function() end just creates a function value, which we assign to the variable method. We could turn around and store that same value in a dozen other variables, or assign a string or number to the method variable. In Lua, variables do not have type, only values do.
More illustration:
print("Hello, World")
donut = print
donut("Hello, World")
t = { foo = { bar = donut } }
t.foo.bar("Hello, World")
assert(t.foo.bar == print) -- same value
FYI, when wrapping a function, if you want its old behavior to be unaffected for now and forever, even if its signature changes, you need to be forward all arguments and return values.
For a pre-hook (new code invoked before the old), this is trivial:
local oldmethod = method
function method(...)
i = 12 -- new code
return oldmethod(...)
end
A post-hook (new code invoked after the old) is a bit more expensive; Lua supports multiple return values and we have to store them all, which requires creating a table:
local oldmethod = method
function method(...)
local return_values = { oldmethod(...) }
i = 12 -- new code
return unpack(return_values)
end
In lua, you can simply override a variable by creating a new function or variable with the same name.
function name_to_override()
print('hi')
end
If you still want to be able to call the old function:
local old_function = name_to_override
function name_to_override()
old_function()
print('hi')
end
I need to create a structure. The structure must contain an array of "boolean conditions". Something like this:
function ReturnStructure ()
local structure = {
{A < 10},
{B == "smth"},
{FunctionReturnsTrueOrFalse(params)},
--...
}
return structure
end
structure = ReturnStructure()
print(structure[1][1]) -- prints true or false depending on the value of A
In fact these tables contain true or false, not conditions, because when we call function ReturnStructure and it creates a local table structure, all conditions in the fields will be executed. I want to create a structure whose fields will contain not boolean values, but something that I can execute (when I want to do it) and get a boolean value. I can achieve this by using anonymous functions:
function ReturnStructure ()
local structure = {
{function() return A < 10 end},
{function() return B == "smth" end},
{FunctionReturnsTrueOrFalse, params}, -- I don't call function in this line, a just put its adress and parameters to table.
--...
}
return structure
end
structure = ReturnStructure()
print(structure[1][1]) -- prints function: 0x109bdd0
print(structure[1][1]()) -- prints true or false. I execute condition in this string.
So, there is a code which works as I want it to, but it seems very ugly.
I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field. I think that I should use a simple OOP implementation to create my structure as an object, but I don't know how to do it. I also will be happy to get some references to methods, implementations, articles etc., which can help me to find some ideas.
I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field.
There aren't. If Lua had C#'s lambda syntax, you could write:
local structure = {
() => A < 10,
() => B == "smth",
() => FunctionReturnsTrueOrFalse(params),
But Lua likes to keep things small and simple, to avoid adding size and complexity to the language and its implementation, so we have one syntax for one function type.
You could store them as strings, then compile and run them later, but that's choosing form over function. You don't want to be invoking the compiler unnecessarily.
local structure = {
'A < 10',
'B == "smth"',
'FunctionReturnsTrueOrFalse(params)',
So your original solution is better. I don't particularly like the way that the first two items defer evaluating their arguments, while your third example evaluates the parameters at compile time. It would be more consistent to treat the FunctionReturnsTrueOrFalse the same
local structure = {
function() return A < 10 end,
function() return B == "smth" end,
function() return FunctionReturnsTrueOrFalse(param1) end,
This also means you don't need to put them in tables. Each is just a function you call, which simplifies the calling code as well.
If you really wanted to evaluate FunctionReturnsTrueOrFalse's arguments at compile time, I'd write a utility routine to build a closure from a function and its arguments:
local function bind(f, ...)
local args = {...}
return function() f(unpack(args)) end
end
Then use that to bind the function to its args:
local structure = {
function() return A < 10 end,
function() return B == "smth" end,
bind(FunctionReturnsTrueOrFalse, param1, param2, param3),
Then everything in your table is simply a function so you don't need special handling
function ReturnStructure ()
local structure = {
{'A < 10'},
{'B == "smth"'},
{FunctionReturnsTrueOrFalse, 'parameter'},
}
local function call_me(f, ...)
return (type(f)=='function' and f or
assert((load or loadstring)('return '..f)))(...)
end
return setmetatable({}, {
__index =
function(t,k)
if structure[k] then
return call_me((table.unpack or unpack)(structure[k]))
end
end,
__newindex = function(t,k,v) structure[k] = v end
})
end
A = 2
B = "anything"
function FunctionReturnsTrueOrFalse(par)
return #par > 5
end
structure = ReturnStructure()
print(structure[1]) -- true
print(structure[2]) -- false
print(structure[3]) -- true
structure[4] = {'1==0'}
print(structure[4]) -- false