Re: ËNVY (LÖVE Framework)
Posted: Wed Jan 21, 2009 11:48 am
I like this framework, it removes an additional good deal coding from my back. I especially like the hooks. Implementing an experimental game with ENVY, I had to make a few changes to the framework files though. Some suggestions:
Use tables more efficiently. We do not wish to iterate through a large table each frame. To get the number of entities, for instance, you just have to use
Instead of using values and looking for the value, you can use it as a key. Set the value of the key to nil and the object is removed from the table. What the value is does not matter, the important aspect is that the key is easy to access. Is the object in the table? - check table[object]! The value can be used though, as in the example below.
I think entity initialize should take a table as input. That way, you can pass arguments to your entities. It is fairly, easy, just change onIntialize to onInitialize(params) and envy.entity.add(class) to envy.entity.add(class, params). I think your current method is to set variables in the classes. This is a bit simpler as one can then pass the params from one object to another (e.g. from a player to a map to an object that is created to an object that the created object creates)
Sorted drawing and/or drawing to layers would be great. The simplest would be to just call onDraw(phase) for some number of phases. A neater system would allow the user to set the draw order of objects and call the functions in this order. Perhaps hooks with priority arguments, something that would also be useful for having a main file draw before the map draw before entities? An example would be to add a addDrawPhase(object, identifier, layer, order) to the draw system (and remove and clear) (perhaps passing the calls upwards, entity -> map -> main). The tuples (layer, order, entity, identifier) would be sorted first by order, then by layer (i.e. (1,10), (3,4), (1,4) becomes (3,4), (1,4), (1,10) becomes (1,4), (1,10), (3,4)). You only have to put the triples in the right place when 'addDrawPhase' is called, you do not have to sort each frame. You could use table.sort and duplicate the results so you know what to remove, but it will be faster to update incrementally.
Example:
I changed collision to the following. In my system, objects can be destroyed when colliding with each other. If the first object is destroyed, then the second object's collision method won't be called in the current system.
Things that would be nice to add: Model-View-Controller ideology and encouragement thereof.
Thanks for your hard work (and to the LÖVE staff)!
Use tables more efficiently. We do not wish to iterate through a large table each frame. To get the number of entities, for instance, you just have to use
Code: Select all
table.getn(envy.entity.spawned)
Code: Select all
objectsInBox = {}
function addObject(obj, count)
count = count or 1
objectsInBox[obj] = (objectsInBox[obj] or 0) + count
end
function removeObject(obj, count)
count = count or 1
if (objectsInBox[obj] < count) then return false; end
objectsInBox[obj] = (objectsInBox[obj] or 0) - count
if (objectsInBox[obj] == 0) then objectsInBox[obj] = nil: end
end
function printObjects()
for k, v in pairs(objectsInBox) do
print(k..": "..v) -- Only objects we have more than 0 of will be printed
end
end
Sorted drawing and/or drawing to layers would be great. The simplest would be to just call onDraw(phase) for some number of phases. A neater system would allow the user to set the draw order of objects and call the functions in this order. Perhaps hooks with priority arguments, something that would also be useful for having a main file draw before the map draw before entities? An example would be to add a addDrawPhase(object, identifier, layer, order) to the draw system (and remove and clear) (perhaps passing the calls upwards, entity -> map -> main). The tuples (layer, order, entity, identifier) would be sorted first by order, then by layer (i.e. (1,10), (3,4), (1,4) becomes (3,4), (1,4), (1,10) becomes (1,4), (1,10), (3,4)). You only have to put the triples in the right place when 'addDrawPhase' is called, you do not have to sort each frame. You could use table.sort and duplicate the results so you know what to remove, but it will be faster to update incrementally.
Example:
Code: Select all
-- Users can easily add their own layers.
LAYER_PRE = -1100
LAYER_BACKGROUND = -100
LAYER_GROUND = 0
LAYER_SHADOW = 75; LAYER_MAIN = 100; LAYER_HIGHLIGHT = 125
LAYER_CLOUDS = 200 --name?
LAYER_GUI = 1000
LAYER_POST = 1100
function envy.entity:new()
...
entity.t_DrawPhases = {}
...
end
envy.entity.class:defaultDrawOrder()
return self:getY() -- + self:getZ() + self:getZHeight() / 2
end
envy.entity.class:addDrawOrder(identifier, layer, order)
layer = layer or LAYER_MAIN
order = order OR self:defaultDrawOrder()
self.t_DrawPhases[identifier] = {layer, order}
-- Add to draw system
end
--envy.entity.class:changeDrawOrder(identifier, layer, order)
envy.entity.class:removeDrawOrder(identifier)
self.t_DrawPhases[identifier] = nil
-- Remove from draw system
end
envy.entity.class:clearDrawOrder(identifier, layer, order)
for k, v in pairs(self.t_DrawPhases) do
self:removeDrawOrder(k)
end
end
myBurningTree.lua:
ENTITY.i_Z = 0
ENTITY.i_ZHeight = 0.9 * 137
function ENTITY:onInitialize(params)
self:addDrawPhase("shadow", LAYER_SHADOW)
self:addDrawPhase("main", LAYER_MAIN)
self:addDrawPhase("highlight", LAYER_HIGHLIGHT)
end
function ENTITY:onDraw(identifier)
if identifier == "shadow" then
self:drawShadow()
elseif identifier == "main" then
...
elseif identifier =="highlight" then
...
else
--error
end
end
Code: Select all
envy.hook.add("onCollision", function(first, second, contact)
local bFirstSecond, bSecondFirst = false, false
if (type(first) == "entity") then
if (type(second) == "entity") then
if ( first:getValid() and second:getValid() ) then
bFirstSecond = true
bSecondFirst = true
end
elseif ( first:getValid() ) then
bFirstSecond = true
end
elseif (type(second) == "entity" and second:getValid() ) then
bSecondFirst = true
end
if (bFirstSecond) then first:onEntityCollision(second, contact); end
if (bSecondFirst) then second:onEntityCollision(first, contact); end
end);
Thanks for your hard work (and to the LÖVE staff)!