ËNVY (LÖVE Framework)

Showcase your libraries, tools and other projects that help your fellow love users.
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: ËNVY (LÖVE Framework)

Post by osuf oboys »

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

Code: Select all

table.getn(envy.entity.spawned)
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.

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
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:

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
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.

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);
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)!
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: ËNVY (LÖVE Framework)

Post by osuf oboys »

A small bug: the line in set_parent in control.lua that says

Code: Select all

table.insert(control:getChildren(), self)
should be

Code: Select all

control:getChildren()[self.i_Index] = self
since you are using control:getChildren()[self.i_Index] in the destroy() function.

Otherwise, adding and removing controls will still keep the controls in memory and causes checks from the parent (e.g. hover) to react to the nonexistent controls.
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
User avatar
Kuromeku
Party member
Posts: 166
Joined: Sun Jul 20, 2008 5:45 pm

Re: ËNVY (LÖVE Framework)

Post by Kuromeku »

Thank you, glad to see somebody actually cares about ËNVY.
User avatar
Kuromeku
Party member
Posts: 166
Joined: Sun Jul 20, 2008 5:45 pm

Re: ËNVY (LÖVE Framework)

Post by Kuromeku »

Image

Version: Phase 13a.
Download:http://kudomiku.com/dump/lua/envy/envy.love.
Changelog:

Code: Select all

[Phase 13a]
	* Added envy.control.class:stretchToParent(spacing).
	* Added envy.util.drawRoundedBox(x, y, width, height, radius, drawType).
	* Added envy.util.round(number).
	* Added envy.vector:newFromRandom().
	* Added envy.entity:onInitialize() is now envy.entity:onInitialize(arguments).
	* Added envy.control:onInitialize() is now envy.control:onInitialize(arguments).
	* Added envy.map:onInitialize() is now envy.map:onInitialize(arguments).
	* Added the ability to parse arguments to an entity's onInitialize callback with envy.entity.add(s_Class, t_Arguments, b_World).
	* Added the ability to parse arguments to a control's onInitialize callback with envy.control.add(s_Class, t_Parent, t_Arguments).
	* Added the ability to parse arguments to a map's onInitialize callback with envy.map.load(s_Class, t_Arguments).
	* Changed the style of the GUI.
	* Changed the control's onDraw function to have position, width and height arguments.
	* Changed the type()'s of Controls, Entities, etc to proper ones.
	* Changed envy.defaultFont to ENVY_FONT.
	* Fixed a bug that osuf oboys pointed out to me, thanks osuf oboys.
If you give me an example, (or a modified ËNVY) of how you'd best like to see layers implemented and the location of each place I loop unneccessarily I'll go about fixing/adding them.

Thanks for your help.
User avatar
osgeld
Party member
Posts: 303
Joined: Sun Nov 23, 2008 10:13 pm

Re: ËNVY (LÖVE Framework)

Post by osgeld »

osuf oboys wrote:

Code: Select all

table.getn(envy.entity.spawned)
table.getn has been depreciated

#envy.entity.spawned
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: ËNVY (LÖVE Framework)

Post by osuf oboys »

osgeld wrote:
osuf oboys wrote:

Code: Select all

table.getn(envy.entity.spawned)
table.getn has been depreciated

#envy.entity.spawned
Thanks
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: ËNVY (LÖVE Framework)

Post by osuf oboys »

Kudomiku wrote: ...

If you give me an example, (or a modified ËNVY) of how you'd best like to see layers implemented and the location of each place I loop unneccessarily I'll go about fixing/adding them.

Thanks for your help.
Hi, thanks for the kind comments.

The latest version of ËNVY crashes occasionally when you die or take items. You can test it by running around and picking up some 15 item boxes. It seems to stem from destroy()ing a body in the collision callback. I also had this problem and instead chose to set a flag and destroy the item in the update loop instead. I do believe, however, that destroy() should make a safefty check to getValid() and that there actually are shapes and bodies to destroy. Preferably also having getAlive() making a check to getValid() for convenience.

There's also a bug that remains from an earlier version which causes the walls to become passable after dying.

I'll get back to you about the layers shortly.
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
User avatar
Kuromeku
Party member
Posts: 166
Joined: Sun Jul 20, 2008 5:45 pm

Re: ËNVY (LÖVE Framework)

Post by Kuromeku »

Image

Version: Phase 14.
Download:http://kudomiku.com/dump/lua/envy/envy.love.
Changelog:

Code: Select all

[Phase 14]
	* Changed envy.entity.class:destroy() to envy.entity.class:destroy(force).
	* Fixed a bug in the example gamemode where dying would allow you to pass through walls (didn't destroy the border entity correctly).
	* Added getValid() checks in envy.entity.class:getAlive() and envy.entity.class:destroy(force);
	* Added envy.entity.class:getDestroyed().
	* Added unless an entity is forcefully destroyed, it'll be destroyed at the end of the frame to avoid crashes.
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: ËNVY (LÖVE Framework)

Post by osuf oboys »

Hi, I've been playing around with the phases for drawing and find that I'm not satisfied with the current ËNVY design in the sense that the best solution to my problem depends a great deal on ËNVY's design. I would like the drawing scheme to be separated from the world - like in the Model-View-Controller model - and with message passing to discern what exists and what does not. I would like to hear your take on this.

Something unrelated that would be useful would be two higher levels above entity - a general class system for an object or property that does not necessarily have a physical manifestation and therefore not restricted to a particular map or world, the higher of the two an object that is not in the world and the other for objects which are in the world. An example of the former category would be a 'game session', which could store how long someone has been playing this particular execution, and example of the latter category would a character class recording the current items and points. (Perhaps you could also add 'super' as a standard function - call the base class' function of the same/the given name and arguments.)

To give a concrete example of what I want the system to achieve - it should be seamless for a well-designed system to feature any number of players and the clients need not even be at the same PC. In other words, one should be able to write a network client for the game if one has already written a GUI client simply by calling the same methods as the GUI does to achieve the desired results. If there are several players and one of them sees zombies glowing red, then it should be seamless to achieve this effect. I don't know how to go about this with the current system.

And a concrete way to go about this - Publishers and Listeners. Sort of like the hooks that you are using but where messages are sent from a particular object and only to those who are registered listeners. The listeners who receive messages can however pass them along etc. Create an Agent/Controller/Player instance for each agent in the game (humans + AIs) (this is an out-of-game object but nevertheless saved) and add a Client/View/GUI to some (local human players) (this is an out-of-game object which would not be stored when saving a game). In particular, there only needs to be one Agent subclass, HumanAgent, and one Client class, SharedWindowClient (or similar). Out-of-game objects and subclassses should be publishers and listeners. In particular, when an agent gains control of or loses a animate, or if an animate is moved to another map, then the agent should be informed - which in turn informs the attached clients. When the system calls for a draw, any clients attached to the game gets to loop through the events that they know exist (i.e. maps they control characters on) and draws appropriately. This is just the basic foundation but it would have as an effect that you immediately get the functionality of multiple players and dynamic control of more than one character on the same or on different levels (i.e. if you gain control of the second char, the view would simply in the next frame split the part of the screen designated to it).

I can take on to implement these features but would like to hear how you feel about it and how you would like it. In particular, extending the system in the above way might provide a lot of functionality but also make it more complicated and slower. In either case, I would like you to design the the features of the second paragraph according to your philosophy. I personally would like game to be an out of game object, a universe in-game object, and then maps as in-game objects.

On a different point - some entities may use more than one shape for the same body and some may want to use none at all.

Thanks!
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
User avatar
Skofo
Party member
Posts: 146
Joined: Mon Dec 22, 2008 10:55 pm

Re: ËNVY (LÖVE Framework)

Post by Skofo »

Kudomiku wrote:
qubodup wrote:
Kudomiku wrote:License? BTW, LÖVE uses Lua and Lua is an interpreted language and compiled at run-time so it is open-source. So, yes, I did include the source actually; and, no license was specified so it is free to use, modify, and redistribute providing that I am credited and that is out of respect and not force.
Pardon please. I was unclear once more.

I was referring to the image source (lossless image, for example png or svg or bmp).

Oh, I think you have an incorrect understanding of how licensing works. If you don't specify a license, then you automatically own all copyright and give no right to anyone to do anything. You don't have to put "copyright by me" on stuff so that it is copyrighted.

For better info on this topic, I recommend section one of 10 Big Myths about copyright explained
I don't like you, no offense or anything, you just seem like we aren't going to get on in the future.

Thanks.
Don't be an ass, he tried to help you. Also, he was correct that if you don't distribute your work with a license, it is all copyrighted to you by default. Releasing the source code does not make the source open.

Also, in the demo the boxes always move to the right when you shoot them.
Working on: Viator
Need a 64-bit Debian package for LÖVE? Here it is!
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 204 guests