I am just starting with MOAI and I am trying to create a traditional game loop using MOAICoroutine. The problem is that when I pass it the function that is part of a "class" that is built using 30log, it returns an error. It seems to continue to function, but I would like to fix the error. My guess is that the MOAICoroutine is calling the function using the dot notation rather than the syntactical sugar method with a colon. Here is the code:
class = require "30log.30log"
GameSystem = class ()
function GameSystem:__init(Name, Title)
self.Name = Name
self.Title = Title
self.Ready = false
end
function GameSystem:Run()
if self:Init() then
self.Thread = MOAICoroutine.new ()
self.Thread:run(self.Start)
--self:Start()
return true
else
print("Init failed.")
return false
end
end
function GameSystem:Init()
print("Initializing Game System")
if not self:InitTimer() then return false end
if not self:InitWindow(640,480) then return false end
if not self:InitViewport() then return false end
if not self:InitGraphics() then return false end
if not self:InitSound() then return false end
if not self:InitInput() then return false end
self.Ready = true
return true
end
function GameSystem:Start()
print("Starting Game System")
while self.Ready do
self:UpdateTimer()
self:UpdateGraphics()
self:UpdateSound()
self:UpdateInput()
coroutine.yield()
end
end
function GameSystem:InitTimer()
return true
end
function GameSystem:InitWindow(width, height)
print("Initializing Window")
return true
end
function GameSystem:InitViewport()
print("Initializing Viewport")
return true
end
function GameSystem:InitGraphics()
print("Initializing Graphics")
return true
end
function GameSystem:InitSound()
print("Initializing Sound")
return true
end
function GameSystem:InitInput()
print("Initializing Input")
return true
end
function GameSystem:UpdateTimer()
--print("Updating Timer")
return true
end
function GameSystem:UpdateGraphics()
--print("Updating Graphics")
return true
end
function GameSystem:UpdateSound()
--print("Updating Sound")
return true
end
function GameSystem:UpdateInput()
--print("Updating Input")
return true
end
Is the 30log class code causing this problem? I have tried various things. I am pretty sure the self it is trying to access is the first argument i.e. mytable.myfunction(self, myarg). Any ideas to fix this nil value reference. The error actually occurred on the second line inside the Start function (while self.Ready do).
function GameSystem:Run()
if self:Init() then
self.Thread = MOAICoroutine.new ()
self.Thread:run(self.Start)
My guess is that the MOAICoroutine is calling the function using the dot notation rather than the syntactical sugar method with a colon.
How would it be calling the function using dot notion (or colon notation)? What would be on the left side of the period or colon? You haven't passed it an object, only a function. The fact that it's caller was storing that function in a table is completely unknown to it. It just receives a function, and calls it.
If you want your coroutine to start with a method call, do that in the function you pass to coroutine.start:
self.Thread = MOAICoroutine.new ()
self.Thread:run(function() self:Start() end)
The point is that:
function GameSystem:Start()
end
Is exactly equivalent to:
function GameSystem.Start(self)
end
Is exactly equivalent to:
GameSystem.Start = function(self)
end
Is equivalent to:
function Foobar(self)
end
GameSystem.Start = Foobar
If I call:
print(Foobar)
print(GameSystem.Start)
print(someGameSystemInstance.Start)
print receives the same value. In Lua, a function is a function is a function, it's not "tainted" in some way by being stored in a table, such that a third party with a reference to the function can know that you want it to be called as a method to some particular 'class instance.
Related
Here is a sample code:
local function name()
startingAction()
if trigger() then
endingAction()
return true
else
resetAction()
startingAction()
if trigger() then
endingAction()
return true
else
resetAction()
startingAction()
if trigger() then
endingAction()
return true
else
return false
end
end
end
Basically its a function that does something, but if in between it fails to do it, I would like to repeat this function by prefixing it with another action. The sample is 3 levels deep, but I would like to be able to control number of repeats.
Any suggestions?
You could use a basic while loop for this:
local MAX_RETRIES = 3
local
function name ()
local tries_remaining = MAX_RETRIES
while tries_remaining > 0 do
startingAction()
if trigger() then
endingAction()
return true
end
-- Implies else due to early return above.
resetAction()
tries_remaining = tries_remaining - 1
end
return false
end
If getting rid of the last resetAction call is necessary then you can modify the whole loop a little bit, although it is less readable and not-so-standardized:
local
function name2 ()
local tries_remaining = MAX_RETRIES
while true do
startingAction()
if trigger() then
endingAction()
return true
end
if tries_remaining > 0 then
resetAction()
tries_remaining = tries_remaining - 1
else
return false
end
end
end
Of course you can also do it with e.g. numeric for, labels or nice recursive calls. I'll leave these cases to you.
In general I encourage you to read Lua Reference Manual - 3.3.4 - Control Structures ff.
I get the error: source_file.lua:5: attempt to call a nil value (global 'getCard')
i try to catch the right table in questCards which Index=name is the same as the given string from objName
questCards={{['name']='test1',['creatureName']='test3'},{['name']='test2',['creatureName']='test4'}}
obj='test1'
card=getCard(obj)
card['creatureName']=nil --Only for test purpose
if card['creatureName']==nil then
--do Somthing
end
function getCard(objName)
for k,v in pairs(questCards) do
if v['name']==objName then
return v
end
end
end
The error message is telling you that getCard is not defined at the point where it is called.
You need to define getCard before calling it.
I'm trying to create a plugin but I can't seem to access the returned player class from outside the GetPlayer() function.
This is the GetPlayer Fuction:
function GetPlayer(Player_To_Find) -- This is the function we use to verify the user exists, It will return the user class if the user exists
LOG("Finding " .. Player_To_Find) --False if they do not exist
local Found = false
local FindPlayer = function(TargetPlayer)
if (TargetPlayer:GetName() == Player_To_Find) then
Found = true
print("Found " .. TargetPlayer:GetName())
return TargetPlayer
end
end
cRoot:Get():FindAndDoWithPlayer(Player_To_Find, FindPlayer)
if Found == true then return TargetPlayer else return false end
end
If I try to call the TargetPlayer class after it has returned using this snippet:
TargetPlayer=GetPlayer(Target)
if TargetPlayer ~= false then
LOG(TargetPlayer:GetName())
It will fail with the error:
attempt to index global 'TargetPlayer' (a nil value)
Can anyone point me in the right direction, It's taken me a long time and I've come up blank.
The parameter TargetPlayer is only in scope in the function body. The TargetPlayer in the last line of GetPlayer refers to a global variable, which is presumably nonexistent and therefore nil.
Declare a local variable in the GetPlayer function, set it in the body of the FindPlayer function, and return it at the end of the of GetPlayer (also don't return false if a player can't be found, return nil, which semantically means "nothing").
I have a ComputerCraft program set to turn on a siren when any non-whitelisted players are near:
sensor = peripheral.wrap("top")
function arraysubset(a, b)
local s = set(b)
for _, el in pairs(a)
if not s[el] then
return false
end
end
return true
end
function sirenOn() rs.setBundledOutput("back",colors.blue) end
function sirenOff() rs.setBundledOutput("back",0) end
while 1 do
playersNear = sensor.getPlayerNames()
allowedPlayers = {"VirtualDXS","jettrom","Shad0wlurker16","Demonicmobster","FireFang0113","riggs135","DaisySnow123","MasterAlex930"}
if playersNear[1] ~= nil then
if arraysubset(playersNear,allowedPlayers) then sirenOff() else sirenOn() end
else sirenOff() end
end
However, on line 3 I get an attempt to call nil. This makes me think that the set() function is not present on computercraft. I'm wondering:
Is there another (maybe better) way to find if array a is a subset of array b and
If not where can I get an API with the set() function?
Rereading the source for the subset() code, I am seeing that the code I used required more code from earlier in the answer:
function set(list)
local t = {}
for _, item in pairs(list) do
t[item] = true
end
return t
end
I'm trying to write a unit test against a single module function. This module collaborates with a few other modules, so I'd like to mock those modules out to isolate my system under test. Here's some simplified pseudo code:
local moduleFoo={}
local moduleBaz= require("moduleBaz")
moduleFoo.doSomething = function (arg)
if moduleBaz.bar.neatMethod(arg) then
--does something interesting
end
end
return moduleFoo
And here's the code for moduleBaz
local moduleBaz={}
moduleBaz.bar= {}
moduleBaz.bar.neatMethod=function(arg)
--does something neat
end
return moduleBaz
I'm trying to use the package.preload function to inject a mock instance of moduleBaz before my tests run, but it doesn't appear to work (i.e. the real instance of the moduleBaz is used in the test, not my mock)
Here's some psueudo test code:
package.loaded.moduleBaz= nil
local moduleBaz = {}
moduleBaz.bar = {}
moduleBaz.bar.neatMethod= function(guid) return true end
package.preload['moduleBaz'] = function ()
return moduleBaz
end
local foo= require("moduleFoo")
foo.doSomething('asdasdasda')--real moduleBaz is called, not my mock!
Any ideas what I'm doing wrong? I'm very new to Lua, and not at all comfortable with how scope is handled in the language!
You seem to be missing a return statement in your moduleBaz code
return moduleBaz
Why not use package.loaded as it gives you a simpler interface? package.loaded.moduleBaz would simply need to include whatever you'd want to return from your moduleBaz code. Something like this should work or give you an idea:
package.loaded.moduleBaz = {
bar = {
neatmethod = function(arg)
-- your mock code here
end,
}
}
Then require('moduleBaz') would simply return that object you just created.
I cannot reproduce the issue with your setup either. The files I used are below; notice that I added return moduleBaz as I described above, but this is the only change I made:
file moduleBaz.lua:
local moduleBaz={}
moduleBaz.bar= {}
moduleBaz.bar.neatMethod=function(arg)
print "baz"
return true
end
return moduleBaz
file moduleFoo.lua:
local moduleFoo={}
local moduleBaz= require("moduleBaz")
moduleFoo.doSomething = function (arg)
if moduleBaz.bar.neatMethod(arg) then
print "foo"
end
end
return moduleFoo
file testFoo.lua
package.loaded.moduleBaz= nil
local moduleBaz = {}
moduleBaz.bar = {}
moduleBaz.bar.neatMethod= function(guid) print "mock" return true end
package.preload['moduleBaz'] = function ()
return moduleBaz
end
local foo= require("moduleFoo")
foo.doSomething('asdasdasda')--real moduleBaz is called, not my mock!
When I run this, I get mock\nfoo\n printed as expected.