Page 1 of 2

Using a string to call another file's function

Posted: Sat May 17, 2014 11:31 am
by geleiademocoto
Hey all,
I looked for other questions similar to this one by searching "call function from another file", but I didn't find any that had this particular problem. It's a Lua problem. Here's the thing:

I have a series of rooms that I'm storing in a table. Inside game.lua, I create the table containing strings with the names of every room (which are also the names of the lua files for each room). I also create a variable called current_room to store the particular string with the name of the room that's supposed to be loaded. Initially, that's "room_1", which is rooms[1].

Now I want to call room_1.load() right here in game.load(). I know that it works if I write room_1.load(), but later on I may want current_room to be another room. So I want to basically do current_room.load(). I can't, because it's a string, right? So I looked around and found a few functions like loadstring() and assert(loadstring()). They didn't work, though. How do I do this?

Here's some code for the tl;dr folk:

Code: Select all

  --this code is inside game.load(). there is a file called room_1.lua and it contains the function room_1.load()
  rooms = {"room_1", "room_2"}
  current_room = rooms[1]

  -- Load the current room
  assert(loadstring(current_room)).load()
Thanks!

EDIT: I think I found out what wasn't working. I created a variable

Code: Select all

load_current_room = current_room..".load()" 
and then called

Code: Select all

assert(loadstring(load_current_room))
seems to have worked! Is this the best way to do this?

EDIT 2: Nope, didn't work. LOVE stopped accusing an error, but the code I put in room_1.load() doesn't get executed. Back to square one.

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 3:06 pm
by Robin
So what's wrong with:

Code: Select all

rooms = {room_1, room_2}
current_room = rooms[1]
current_room.load()
?

No loadstring needed.

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 4:06 pm
by micha
If you have the name as a string, you can also a access global variable like that:

Code: Select all

_G[name]
In your case this should work:

Code: Select all

_G.[current_room].load()
_G is the table of all global variables.

However, I think Robin's solution is better.

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 6:31 pm
by geleiademocoto
So what's wrong with:
CODE: SELECT ALL
rooms = {room_1, room_2}
current_room = rooms[1]
current_room.load()

?

No loadstring needed.
I get the blue screen with this error:
game.lua:21:attempt to call field 'load'(a nil value)

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 7:20 pm
by Robin
It's hard to tell without a .love, but it looks like you don't have access to the rooms there. Are they required? And how?

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 9:43 pm
by geleiademocoto
EDIT: I forgot to actually attach it the file. Sorry, fixed now.

It's hard to tell without a .love, but it looks like you don't have access to the rooms there. Are they required? And how?
Er, I'm a little embarassed to attach this because of how messy it looks, both the code and the game itself. Actually the game doesn't even have actual graphics, I'm just using random pics to be able to test the stuff. But I suppose you'll just be looking at the code, so it doesn't matter.

I'm attaching the .love, and for those who don't feel like DLing anytihing, here's just game.lua. As you can see, I am requiring room_1. My requirement of player.lua seems to be working fine, though.

Code: Select all

game = {}

require('room_1')
require('player')

function game.load()
  game.clock = 0

  -- Player init
  player.load()


  --Init rooms
  rooms = {"room_1", "room_2"}
  current_room = rooms[1]
  load_current_room = current_room..".load()"
  --update_current_room = current_room..".update(dt)"

  -- Load the current room
  _G[current_room].load()
end



function game.draw()
  -- Call the room's draw function
  if current_room == rooms[1] then
    room_1.draw()
  end
  if current_room == rooms[2] then
    room_2.draw()
  end

  -- Draw player
  player.draw()
end

function game.update(dt)
  game.clock = game.clock + dt

  -- Update player
  player.update(dt)

  -- Update the rooms
  if current_room == rooms[1] then
    room_1.update(dt)
  end

end

function game.keypressed(key)
  -- Call the room's keypressed function
  if current_room == rooms[1] then
    room_1.keypressed(dt)
  end
  if current_room == rooms[2] then
    room_2.keypressed(dt)
  end

  -- Restart game
  if key == "q" then
    love.load()
  end

end

function game.keyreleased(key)
  -- Call the room's keyreleased function
  if current_room == rooms[1] then
    room_1.keyreleased(dt)
  end
  if current_room == rooms[2] then
    room_2.keyreleased(dt)
  end
end

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 9:51 pm
by Robin
It looks like something went wrong, because there's no .love here, and I particularly need to see the contents of room_1.lua.

Re: Using a string to call another file's function

Posted: Sat May 17, 2014 10:59 pm
by geleiademocoto
Now that I've read your reply, I'm not sure how useful my .love file is going to be. I ended up deleting everything that was on room_1.lua except for the drawing of the background. The content of player.lua used to be inside of room_1, so the content of player.load() was what was in room_1.load(). So I'm afraid it won't be very useful, sorry.

Re: Using a string to call another file's function

Posted: Sun May 18, 2014 1:40 am
by ejmr
If you use Robin’s suggestion, that is…

Code: Select all

function game.load()
  game.clock = 0
  player.load()

  -- Use the tables created as a result of require("room_1")
  -- instead of using their names.
  rooms = {room_1, room_2}
  current_room = rooms[1]
  current_room.load()
end
…then you can simplify a lot of the functions in game.lua, e.g.:

Code: Select all

function game.draw()
  -- Call the room's draw function
  if current_room == rooms[1] then
    room_1.draw()
  end
  if current_room == rooms[2] then
    room_2.draw()
  end

  -- Draw player
  player.draw()
end

-- If current_room equals the actual room_1 or room_2 tables then the
-- if-statements are not necessary and the function can be like this:

function game.draw()
    current_room.draw()
    player.draw()
end

Re: Using a string to call another file's function

Posted: Sun May 18, 2014 9:11 am
by Robin
geleiademocoto wrote:Now that I've read your reply, I'm not sure how useful my .love file is going to be. [...] So I'm afraid it won't be very useful, sorry.
You underestimate how much information we can glean from a .love. Most non-trivial non-general questions here only get resolved once the person seeking help uploads a .love.

If you upload the .love, I can see the file structure, I can see whether room_1.lua creates a global called room_1, if it returns anything, if the current_room is ever changed in another module, etc. The answers to those questions mean I know what other questions to ask, and so on, until I get to the answer. If I have a .love of your game, I can read the answers to all my questions in seconds, and get back to you with an answer within minutes. Now, we have to play a game where I ask you things like "what does file_a look like?" or "change a into b here, what is the result?" which can easily go on for days.

tl;dr: please upload a .love, always, even if you don't think it'll help.