Page 1 of 4

What am I doing wrong here?

Posted: Thu Apr 14, 2011 12:41 am
by Jasoco

Code: Select all

enemyType["blob"] = {
  hp = 1
}
function enemyType.blob:update()

end
I want to be able to create enemies from enemy types so that when I say enemy[#enemy+1] = enemyType["blob"] it transfers all the variables from the enemy type into the enemy. And I want each type to have its own onLoad(), update(), draw() and onDeath() functions attached that are different for each one.

I know that:

Code: Select all

function enemyType:update()

end
Works, but then it wouldn't be attached to the type.

When I try to create an enemy using that enemy[#enemy+1] = enemyType["blob"] code, it gives me an error.

Am I going about it wrong???

Could I do this?

Code: Select all

enemyType["blob"] = {
  hp = 1,
  update = function()

  end
}
But then how do I pass the ID of the enemy to the update() function? Just lost here.

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 1:37 am
by Taehl
Jasoco wrote:

Code: Select all

enemyType["blob"] = {
  hp = 1
}
function enemyType.blob:update()
end
Well, for starters, in this code, enemyType.blob doesn't have an update() function (it only has one variable, hp).
Jasoco wrote: I want to be able to create enemies from enemy types so that when I say enemy[#enemy+1] = enemyType["blob"] it transfers all the variables from the enemy type into the enemy. And I want each type to have its own onLoad(), update(), draw() and onDeath() functions attached that are different for each one.
Doing OOP-style stuff like that is easily handled by Lua's metatable feature. I suggest researching it. I'm afraid that I'm not too familiar with them myself, so I can't tell you the code you'd need.
Jasoco wrote: I know that:

Code: Select all

function enemyType:update()

end
Works, but then it wouldn't be attached to the type.

When I try to create an enemy using that enemy[#enemy+1] = enemyType["blob"] code, it gives me an error.

Am I going about it wrong???
One thing you need to be careful about is to make sure that your new enemy doesn't equal enemyType.blob directly, but rather, contains copies of its data. If you don't, then each enemy will point at the same set of data, so moving one will move all of them, for instance.

Oh, and for the record, you don't need to say enemyType["blob"] - you can just say enemyType.blob

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 1:46 am
by Jasoco
But that's what I'm trying to do. Create an enemy from a set of enemy types. Each type needs to have its own functions for stuff. I don't know how to use metatables. Even after reading the official documentation on Lua.org.

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 2:53 am
by Taehl
Basically, metatables handle when a table is asked for a key it doesn't contain. Generally, people will tell it to refer to a OOP-style "prototype" table which contains shared functions and such, so that when calling something like enemy:init(), enemy says "I don't have init, let's use my prototype's init". It can also be used for inheritance and other neat things.

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 3:50 am
by Jasoco
Do you have an example of how it can be used?

For example, I'm looking at the code for "Fist Full of Beef" and see that it has bulls in their own class. But I don't know how it's doing it with the whole "self" thing.

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 4:22 am
by EmmanuelOga
Here is one way to do it:
http://pastie.org/1793974

I'm using a metatable there to tell all enemies that they should look for properties in the enemies table when they cannot find one (__index property of the metatable). Each time you call the setupEnemy function it creates a factory function and saves it in the same table that we are using as go-to in the setmetatable call. The setupFactory also initializes some properties for any enemy. You can mix and match where you want to initialize stuff: in the enemy itself, or in its metatable.

Hopefully that "explanation" is not very confusing. :oops:

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 4:30 am
by Robin

Code: Select all

enemyType["blob"] = {
  hp = 1
}
function enemyType.blob:update()

end
This is essentially correct. But you cannot just add that to your enemy list, our you will have an army of clones --- which isn't as cool as it sounds.

At the very basic, you need to do something like:

Code: Select all

et_meta = {__index = enemyType.blob }

Code: Select all

enemy[#enemy+1] = setmetatable({}, et_meta)
That, in fact is the basis of all OOP in Lua.

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 5:29 am
by BlackBulletIV
You're probably best off going with an OOP library to handle this for you. I, as usual, suggest MiddleClass, but you could use something like Slither, SECS, or one of the many others out there.

As for metatables, I think of them like tables which specify information about how a table should operate. Think of it like a program which tells a robot how to operate. Here's the two key functions:

* setmetatable(t, mt) sets the metatable of table 't' to be the table 'mt'.
* getmetatable(t) gets the metatable of 't'.

Metatables can contain a number of different functions. The two key ones are called __index and __newindex. __index is called when you try to access something in a table that doesn't exist. For example:

Code: Select all

t = { foo = 3 }
t.foo -- exists, so we get 3
t.bar -- doesn't exist, so Lua looks for __index in the metatable, it doesn't find it in this case, so nil is returned
If we had specified __index, we could do this:

Code: Select all

t = setmetatable({ foo = 3}, { __index = function(self, key) print('The key' .. key .. 'doesn't exist!') end }) -- yes, setmetatable returns the first parameter

t.foo -- exists, so we get 3
t.bar -- Lua fins __index, and so 'The key bar doesn't exist!' is printed
The self parameter is the table which got indexed. The key parameter is the non-existent key inside the table.

__newindex is called whenever you try to set the value of something in table which doesn't already exist. For example:

Code: Select all

t = { foo = 3 }
t.foo = 4 -- all well and good
t.bar = 5 -- Lua looks for __newindex, doesn't find it, so it just sets the value in t
If we had specified __newindex, we could do this:

Code: Select all

t = setmetatable({ foo = 3}, { __newindex = function(self, key, value) print('We're not setting anything!') end })

t.foo = 4 -- all good
t.bar = 5 -- "We're not setting anything!"
Hope that helps!

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 7:01 am
by Wulfie
Only mildly off topic, however relevant. I am trying to sort out doing something similar. My idea was to create each enemy type in an SQLite table, then have the lua code pull it from there. My reasoning behind this was to be able to code less and pull most of the content for items and enemies from the SQLite tables. As I am still learning Lua, I am not sure if the over head in doing something like this would be worth it or not.

I could always start with storing basics in text... Though the Idea I have for a game is a full fledged RPG/Adventure game with quests loot crafting and achievements.. Yes I know big task for a newbie. This is the way I learn, I'm not out to create the next big great game. I am more at it to learn and have fun programing.

-- back on topic

Which way would be best for this metatables (middleclass), text storage, sql??

Re: What am I doing wrong here?

Posted: Thu Apr 14, 2011 7:48 am
by BlackBulletIV
Wulfie wrote:Only mildly off topic, however relevant. I am trying to sort out doing something similar. My idea was to create each enemy type in an SQLite table, then have the lua code pull it from there. My reasoning behind this was to be able to code less and pull most of the content for items and enemies from the SQLite tables. As I am still learning Lua, I am not sure if the over head in doing something like this would be worth it or not.
My first thoughts are overkill - unless you want to persistently store information about individual entities, like how much gold you have, your inventory, and so on. But don't store attributes of enemies in SQL, that's going to be slow, and totally not worth it.
Wulfie wrote:I could always start with storing basics in text... Though the Idea I have for a game is a full fledged RPG/Adventure game with quests loot crafting and achievements.. Yes I know big task for a newbie. This is the way I learn, I'm not out to create the next big great game. I am more at it to learn and have fun programing.
If you haven't made a few simpler games before, I suggest stopping now, and going for something a lot simpler. Try creating PacMan, or Pong to get some experience of real game development under your belt. Then, if your still confident, you might want to venture into actually created an RPG. But keep it simple to start with!
Wulfie wrote:Which way would be best for this metatables (middleclass), text storage, sql??
For creating enemy types and such? Tables, and even better, an OOP system (like MiddleClass, as you mentioned).