Giter VIP home page Giter VIP logo

lovetoys's Introduction

lövetoys

GitHub release Build Status Coverage Status

lovetoys is an Entity Component System framework for game development with lua. Originally written for the LÖVE 2D game engine, it is actually compatible with pretty much any game that uses lua! It is inspired by Richard Lords Introduction to ECS. If you don't have any idea what this entity component stuff is all about, click that link and give it a read! It's totally worth it!

lovetoys is a full-featured game development framework, not only providing the core parts like Entity, Component and System classes but also a Publish-Subscribe messaging system as well as a Scene Graph, enabling you to build even complex games easily and in a structured way.

🚦 Status of the project

lovetoys is in maintenance mode. It works well and has no bugs known to us. We will not be adding new features, but will try to respond to issues and review any pull requests. If you open an issue, please have a little patience :)

Installation

The recommended way of installing lovetoys is by creating a submodule and cloning it right into your git repo. Another way is to just download a tarball and copy the files into your project folder. We also provide a luarocks package. To use this with LÖVE, check out loverocks.

To require lovetoys and initialize it with the default options, use the following:

local lovetoys = require('lovetoys')
lovetoys.initialize()

For an example on how to integrate the lovetoys with love2d, have a look at our example project.

Configuration

After requiring, configure lovetoys by passing a configuration table to the initialize function. For example, if you want debug output, pass the option debug = true:

lovetoys.initialize({
    debug = true
})

The following table lists all available options:

Name Type Default Meaning
debug boolean false Makes lovetoys print warnings and notifications to stdout.
globals boolean false If true, lovetoys will make all its classes available via the global namespace. (e.g. Entity instead of lovetoys.Entity)
middleclassPath string nil Path to user's copy of middleclass

⚠️ Once you've called initialize, the configuration will be the same every time you require('lovetoys').

Quickstart

-- Include the library.
local lovetoys = require('lovetoys')

-- Initialize:
-- debug = true will enable library console logs
-- globals = true will register lovetoys classes in the global namespace
-- so you can access i.e. Entity() in addition to lovetoys.Entity()
lovetoys.initialize({globals = true, debug = true})

function love.load()
    -- Define a Component class.
    local Position = Component.create("position", {"x", "y"}, {x = 0, y = 0})
    local Velocity = Component.create("velocity", {"vx", "vy"})

    -- Create and initialize a new Entity.
    -- Note we can access Entity() in the global
    -- namespace since we used globals = true in 
    -- the lovetoys initialization.
    local player = Entity()
    player:initialize()

    -- Add position and velocity components. We are passing custom default values.
    player:add(Position(150, 25))
    player:add(Velocity(100, 100))
    
    -- Create a System class as lovetoys.System subclass.
    local MoveSystem = class("MoveSystem", System)

    -- Define this System's requirements.
    function MoveSystem:requires()
        return {"position", "velocity"}
    end

    function MoveSystem:update(dt)
        for _, entity in pairs(self.targets) do
            local position = entity:get("position")
            local velocity = entity:get("velocity")
            position.x = position.x + velocity.vx * dt
            position.y = position.y + velocity.vy * dt
        end
    end

    -- Create a draw System.
    local DrawSystem = class("DrawSystem", System)

    -- Define this System requirements.
    function DrawSystem:requires()
        return {"position"}
    end

    function DrawSystem:draw()
        for _, entity in pairs(self.targets) do
            love.graphics.rectangle("fill", entity:get("position").x, entity:get("position").y, 10, 10)
        end
    end

    -- Finally, we setup an Engine.
    engine = Engine()
    engine:addEntity(player)

    -- Let's add the MoveSystem to the Engine. Its update() 
    -- method will be invoked within any Engine:update() call.
    engine:addSystem(MoveSystem())
    
    -- This will be a 'draw' System, so the
    -- Engine will call its draw method.
    engine:addSystem(DrawSystem(), "draw")
end

function love.update(dt)
    -- Will run each system with type == 'update'
    engine:update(dt)
end

function love.draw()
    -- Will invoke the draw() method on each system with type == 'draw'
    engine:draw()
end

API Reference

lovetoys primarily consists of a few classes that are implemented using middleclass. By default, they are available via the lovetoys object:

local lovetoys = require('lovetoys')
-- Example: using constructors
local entity = lovetoys.Entity()
local system = lovetoys.System()
local engine = lovetoys.Engine()
-- the middleclass `class` object
local class = lovetoys.class ()

Entity

The Entity is the basic building block of your game. You can loosely think of it as an object in your game, such as a player or a wall. From the technical side, it basically represents a collection of components.

Entity(parent)

  • parent (Entity) - Parent entity

This function returns a new instance of an entity. If you specify a parent entity, you can later access it via the .parent property. Also, the parent entity will get a reference to its newly created child, accessible by its .children table.

⚠️ If you add an entity without a parent to the engine, the engine will set the root entity as its parent.

Entity:setParent(parent)

  • parent (Entity) - Parent entity

Use this method to set a new parent on an entity. It will take care of removing itself from the children of its previous parent and registering as a child of the new parent.

Entity:getParent()

Returns the entities parent.

Entity:add(component)

  • component - (Component) Instance of a component.

Adds a component to this particular entity.

Entity:addMultiple(components)

  • components - (List) A list containing instances of components.

Adds multiple components to the entity at once.

Entity:set(component)

  • component - (Component) Instance of a component.

Adds the component to this particular entity. If there already exists a component of this type the previous component will be overwritten.

Entity:remove(name)

  • name (String) - Name of the component class

Removes a component from this particular entity.

Entity:has(Name)

  • name (String) - Name of the component class

Returns boolean depending on if the component is contained by the entity.

Entity:get(Name)

  • name (String) - Name of the component class

Returns the component or nil if the Entity has no component with the given name.

Entity:getComponents()

Returns the list that contains all components.

Component

Collection of functions for creating and working with Component classes. There is no Component class; As components are only 'data bags', you can just use standard middleclass classes to implement your components.

Creating a simple component

local Color = class('Color');

function Color:initialize(r, g, b)
    self.r = r
    self.g = g
    self.b = b
end

The Component.create() function can automatically generate simple component classes like these for you.

Component.register(componentClass)

  • class The component class as returned by a call to the class() function

Register the component for loading it conveniently with Component.load. Registered components are stored in a local table which stays the same across different require()s.

Component.load(components)

  • components A list containing component names

Load the specified components, sparing you lots of calls to require().

local Color, Transform, Drawable = Component.load({"Color", "Transform", "Drawable"})
-- Create a component for the color black
Color(0, 0, 0)

Component.create(name, [fields, defaults])

  • fields (Table) - A list of Strings specifying the property names of the new component. The constructor of the component class will accept each of these properties as arguments, in the order they appear in the fields list.
  • defaults (Table) - Key value pairs where each pair describes the default value for the property named like the pairs key.

Create a new component class. This will also call Component.register for you.

-- Create a Color component with the default color set to blue
local Color = Component.create("Color",
    {"r", "g", "b"},
    {r = 0, g = 0, b = 255})
-- Create a component for the color violet
Color(255)

System

Systems provide the functionality for your game. The engine manages all Systems and assigns all entities with the right components to them.

All your systems have to be derived from the System class. An example how to do this can be found below.

There are two types of Systems: "update" and "draw" Systems. Update systems perform logic operations, like moving a player and updating physics. Their update method is called by the engine. Draw systems are responsible for rendering your game world on screen. Their draw method is also called by the engine.

An example for a custom system

To implement functionality in your game, you create custom Systems. You inherit from the System class and override some methods to specify your System's behavior.

To create your own system, you use the class function provided by MiddleClass. The first argument is the name of your new System, the second is the Class you want to inherit from. The specific methods you can override are specified below.

local CustomSystem = class("CustomSystem", System)

function CustomSystem:initialize(parameter)
    System.initialize(self)
    self.parameter = parameter
end

function CustomSystem:update(dt)
    for key, entity in pairs(self.targets) do
        local foo =  entity:get("Component1").foo
        entity:get("Component2").bar = foo
    end
end

function CustomSystem:requires()
    return {"Component1", "Component2"}
end

return CustomSystem

System:requires() return {"Componentname1", "Componentname2", ...} end

This function defines what kind of entities shall be managed by this System. The function has to be overridden in every System or it won't get any entities! The strings inside the returned table define the components a entity has to contain, to be managed by the System. Those entities are accessible in self.targets.

If you want to manage different groups of entities just return a table that looks like this:

return {group1 = {"Componentname1", "Componentname2"}, group2 = {"Componentname3", "Componentname4"}}

The different entities are now accessible under system.targets.group1 and system.targets.group2. An entity can be contained by the same system multiple times in different groups if it matches the varying component constellations.

System:update(...)

  • ... (Varargs) - Parameters passed to the Engine update method, e.g. delta time

This function is going to be called by the engine every tick.

System:draw()

This method is going to be called by the engine every draw.

System:onAddEntity(entity, group)

  • entity (Entity) - The entity added
  • group (String) - The group the entity was added to

Overwrite this method in your system if you want to react when new entities are added to it. Override this method if you want to react to the addition of entities. This will get called once for each group the entity gets added to. If you return no groups from System:requires(), group will be nil and the callback will only get called once.

System:onRemoveEntity(entity, group)

  • entity (Entity) - The entity that was removed
  • group (String) - The group the entity was removed from

Override this method if you want to react to the removal of entities. This will get called once for each group the entity gets removed from. If you return no groups from System:requires(), group will be nil and the callback will only get called once.

Engine

The engine is the most important part of the lovetoys and the most frequently used interface. It manages all entities, systems and their requirements, for you.

Engine()

Creates a new engine object. Every engine creates a rootEntity which becomes parent of all entities that don't have a parent yet.

Engine:getRootEntity()

Returns the root entity. Modify it to your needs!

Engine:addSystem(system, type)

  • system (System) - Instance of the system to be added
  • type (String) - optional; Should be either "draw" or "update"

This function registers the system in the engine. The systems' functions will be called in the order they've been added. As long as the system implements either the update or the draw function, lovetoys will guess the type parameter for you.

⚠️ If a system implements both draw and update functions, you will need to specify the type and add the system twice, once to draw and once to update. Otherwise lovetoys couldn't know in what order to execute the update and draw methods.

Engine:stopSystem(system)

  • system (String) - the name of the system

If you want a system to stop, just call this function. It's draw/update function won't be called anymore until you start it again.

Engine:startSystem(system)

  • system (String) the name of the system

Call this to start a stopped system.

Engine:toggleSystem(system)

  • system (String) the name of the system

If the system is running, stop it. If it is stopped, start it.

Engine:addEntity(entity)

  • entity (Entity) - Instance of the Entity to be added

Adds an entity to the engine and registers it with all systems that are interested in its component constellation.

Engine:removeEntity(entity, removeChildren, newParent)

  • entity - (Entity) - Instance of the Entity to be removed
  • removeChildren - (Boolean) Default is false
  • newParent - (Entity) - Instance of another entity, which should become the new Parent

Removes the particular entity instance from the engine and all systems. Depending on removeChildren all Children are going to deleted recursively as well. If there is a new Parent defined, this entity becomes the new Parent of all children, otherwise they become children of engine.rootEntity.

Engine:getEntitiesWithComponent(component)

  • component (String) - Class name of the component

Returns a list with all entities that contain this particular component.

Engine:getEntityCount(component)

  • component (Number) - Returns the count of entities that contain this particular component.

Engine:update(...)

  • ... (Varargs) - Any variables you want to pass to the update methods of systems

Updates all logic systems. A typical use case would be to pass in the delta time you get from love2d:

function love.update(dt)
    engine:update(dt)
end

Engine:draw()

Updates all draw systems.

Example for a löve2d main.lua file

For a more detailed and commented version with collisions and some other examples check the main.lua file of the lovetoys example game.

-- Importing lovetoys
require("lib.lovetoys")

function love.load()
    engine = Engine()
    world = love.physics.newWorld(0, 9.81*80, true)
    world:setCallbacks(beginContact, endContact)
    eventmanager = EventManager()
end

function love.update(dt)
    -- Engine update function
    engine:update(dt)
    world:update(dt)
end

function love.draw()
    -- Engine draw function
    engine:draw()
end

function love.keypressed(key, isrepeat)
    eventmanager:fireEvent(KeyPressed(key, isrepeat))
end

function love.mousepressed(x, y, button)
    eventmanager:fireEvent(MousePressed(x, y, button))
end

Eventmanager

This class is a simple eventmanager for sending events to their respective listeners.

EventManager:addListener(eventName, listener, listenerFunction)

  • eventName (String) - Name of the event-class to be added
  • listener (Listener) - The first entry is the table/class that will is supposed to be passed as self to the called function.
  • listenerFunction (Function) - The function that should be called.

Adds a function that is listening to the Event. An example for adding a Listener: EventManager:addListener("EventName", listener, listener.func). The resulting function call will be func(table, event). We need to do this so we can work with self as we are used to, as lua doesn't provide a native class implementation.

EventManager:removeListener(eventName, listener)

  • eventName (String) - Name of the event-class
  • listener (String) - Name of the listener to be deleted

Removes a listener from this particular Event.

EventManager:fireEvent(event)

  • event (Event) - Instance of the event

This function pipes the event through to every listener that is registered to the class-name of the event and triggers listener:fireEvent(event).

Testing

You can find the tests in the spec folder. They are defined using the busted test framework.

To run the suite, install busted and simply execute busted in the lovetoys directory.


Copyright © 2016 Arne Beer (@Nukesor) and Rafael Epplée (@raffomania)

This Software is published under the MIT License.

For further information check LICENSE.md.

lovetoys's People

Contributors

brazorf avatar erasio avatar hamsterready avatar hewills avatar jkbz64 avatar jonnay avatar luminess avatar nickflexer avatar nukesor avatar raffomania avatar rosshadden avatar vaartis avatar xpol avatar yscik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lovetoys's Issues

Strange bug adding components

It has taken me several days to get this down to a minimal example, because for the longest time I thought it was just something in my own code. I have not figured out exactly what in lovetoys is causing this issue, but I was able to verify that it is a problem in lovetoys itself. Also I don't really think lovetoys is actually even usable in this state, so I don't know if people are just using old versions or using the same components on every entity to get around it or what.

I am going to explain through example. I cloned the example repo (to make sure it wasn't an issue in my own codebase), and made the following changes:

I added these functions to TestSystem:

function TestSystem:update()
    print(#self.targets)
    love.event.quit()
end

function TestSystem:requires()
    return { 'Position' }
end

And I changed the last block of code in the love.load function in main.lua to this:

    local foo = Entity()
    -- foo:add(Position(100, 100))
    engine:addEntity(foo)

    local bar = Entity()
    bar:add(Position(100, 100))
    engine:addEntity(bar)

    -- -- Creation and adding of some Entities
    -- for i = 1, 20, 1 do
    --     entity = Entity()
    --     local x, y = love.math.random(100, 900), love.math.random(150, 600)
    --     entity:add(DrawablePolygon(world, x, y, 100, 10, "static", wall))
    --     entity:add(Timing(love.math.random(0, 5000)))
    --     -- entity:add(Position(x, y))
    --     entity:get("DrawablePolygon").fixture:setUserData(entity)
    --     engine:addEntity(entity)
    -- end

The expected result is that the TestSystem would print 1, as one entity (bar) exists with Postion. But the act of adding an entity before it, foo, makes it instead print 2. Even though foo does not have the Position component.

The order here is very important (and why it took me so long to learn about the bug). If I flip them, and add Position to foo instead of bar, I get 1 printed as expected.

    local foo = Entity()
    foo:add(Position(100, 100))
    engine:addEntity(foo)

    local bar = Entity()
    -- bar:add(Position(100, 100))
    engine:addEntity(bar)

Docs for adding/starting systems

Is it the case that systems need to be manually started, using engine:startSystem? This was not the case in my previous lovetoys project from several months ago, so I assume it was a recent change.

I think this makes a lot of sense, because we really do need a way to add systems without starting them. However as this behavior does not match the documentation, I felt like I should bring it up.

Question: systems can only update or draw?

Hi there I'm new to ESC so maybe this is obvious but why can't I have a System that has both an update() and a draw() function?

For example I have an animation System that needs to both call update on the animation and draw the animation frame, it would be nice to do this in one system no? I could be designing this totally wrong

CI builds should not use Travis's legacy infrastructure.

TL;DR: Should use Travis-CI's container-based infrastructure instead of legacy infrastructure for the dramatically shorter build times from the increased available computing resources, better network speeds, build caching, and the shorter "VM" startup time.
Why using the legacy infrastructure is bad:

Using their container-based infrastructure as opposed to legacy provides missing key benefits to any CI build. Benefits include dramatically reduced build times from decreased build startup times and the 2 dedicated cores and 4GB of memory provided, vs 1.5 cores and 3GB on legacy; increased network performance backed by Amazon's network; and build caching with the ability to declare files to persist between builds. The only features the new infrastructure is missing is having sudo available and MySQL/PostgreSQL preconfigured to run off a RAM disk.

This project does not use MySQL or PostgreSQL for its build process and using sudo for installing LuaJIT and LuaRocks is unnecessary as Travis-CI supports, within a whitelist, defining sources and packages to install via apt-get by defining the addons.apt key in .travis.yml.

Suggestion for empowering the CI builds with the cache feature:

A replacement for using sudo to install LuaJIT and LuaRocks is to use the hererocks python script which installs both a user-specified version of Lua along with LuaRocks into $INSTALL_DIR with one command (hererocks $INSTALL_DIR -r^ --$LUA_VERSION). Using hererocks to install LuaJIT and LuaRocks ensures defining the files to cache between builds is as simple as including $INSTALL_DIR in the cache list of .travis.yml. hererocks and LuaRocks automatically cancels installation of packages if they exist locally. This default behavior works in our favor as the lengthy build process of certain packages would then be skipped; reusing the already built packages from the cache.

Don't use globals.

Can lovetoys not use globals.

eg.

local M = class('xxxx')

...

return M

module 'src.namespace' not found

After updating to the latest version, I get the following error when requiring lovetoys:

Error: vendor/lovetoys/lovetoys.lua:4: module 'src.namespace' not found:
        no field package.preload['src.namespace']
        no 'src/namespace' in LOVE game directories.
        no file 'src/namespace.so' in LOVE paths.
        no file './src/namespace.lua'
        no file '/usr/share/luajit-2.0.4/src/namespace.lua'
        no file '/usr/local/share/lua/5.1/src/namespace.lua'
        no file '/usr/local/share/lua/5.1/src/namespace/init.lua'
        no file '/usr/share/lua/5.1/src/namespace.lua'
        no file '/usr/share/lua/5.1/src/namespace/init.lua'
        no file './src/namespace.so'
        no file '/usr/local/lib/lua/5.1/src/namespace.so'
        no file '/usr/lib/lua/5.1/src/namespace.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
        no file './src.so'
        no file '/usr/local/lib/lua/5.1/src.so'
        no file '/usr/lib/lua/5.1/src.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
        [C]: in function 'require'
        vendor/lovetoys/lovetoys.lua:4: in main chunk
        [C]: in function 'require'
        main.lua:2: in main chunk
        [C]: in function 'require'
        [string "boot.lua"]:428: in function <[string "boot.lua"]:274>
        [C]: in function 'xpcall'

Note that I have lovetoys cloned as a submodule at vendor/lovetoys, and am thus requiring vendor/lovetoys/lovetoys. I have tried requiring it with dots as well. This used to work until v0.3.0.

Entity:remove() / Entity:add() crashes when not initializing with globals

It seems like removing a component from an entity crashes with with the following error:

lib/lovetoys/src/Entity.lua:58: attempt to call global 'ComponentRemoved' (a nil value)

I've fixed it for my own usage by simply changing the line in question from:

self.eventManager:fireEvent(ComponentRemoved(self, name))

to

self.eventManager:fireEvent(lovetoys.ComponentRemoved(self, name))

The same goes for Entity:add(). Naive fix is exactly the same. But I feel like this deserves a proper fix.

Docs outdated? Init code doesn't seem to work

This one is not working

local lovetoys = require("lovetoys.lovetoys")
lovetoys.initialize()

local entity = lovetoys.Entity()
local system = lovetoys.System()
local engine = lovetoys.Engine()
local component = lovetoys.Component()
local eventManager = lovetoys.EventManager()

Error: Error: main.lua:7: attempt to call field 'Component' (a table value) stack traceback:

Engine.systems["all"] is a unnecessary field.

In Engine.lua:157-158, I can see that the way the engine registers systems make self.systemRegistry (a hash table) and self.systems["all"] (an array) virtually identical its in usage.

The only time self.systems["all"] is used in the project is in Engine:stopSystem, Engine:startSystem, and Engine:toggleSystem. In those methods, the engine is iterating through self.systems["all"] to lookup the needed system when it could just access the needed system by key from its self.systemRegistry hash table, saving a pointless iteration.

Helps with #21

Should fail when calling addSystem(system, 'derp')

When calling it like addSystem(system, 'invalid') there should at least be a warning. What I did: addSystem(system, 'update') instead of addSystem(system, 'logic'). This causes weird and hard to debug behavior.

How do you manually create classes?

I'm using Lovetoys and I have a working project until I started to create component classes manually.

I have a simple sprite class:

local lovetoys = require('libs.lovetoys')
local Sprite = lovetoys.class("Sprite")

function Sprite:intialize(path)
    print("Sprite initialized")
    self.path = path
    self.image = love.graphics.newImage(self.path)
end

return Sprite

and I import it into my main.lua like this:

local Sprite = require('components.Sprite')

When I read through the documentation, I think I need to call Component.register() to make the component available so I write:

function love.load()

    -- Simplified version of my love.load()
    engine = Engine()
    Component.register('components.Sprite')
end

This triggers an error:
Error: libs/lovetoys/src/Component.lua:31: table index is nil

I know I can use Component.create() but ideally I would like to use the middleclass style of creating classes.

What am I doing wrong here?

The version on luarocks is missing `init.lua`

I'm using plain luarocks not loverocks (it dosen't seem to be compatible with my lua/rocks version) and I'm on Arch Linux with love and luarocks installed through my distro package manager
I run luarocks install --tree deps lovetoys to install it in the deps subdirectory of my working folder, which makes this file tree. If I then set my lua path to include ./deps and run love . with a main.lua that has require deps/lovetoys I get this traceback, which is looking for .../lovetoys/init.lua, which exists in the git repo. If I download the release version then I can get that importing but then I get #77 (but that indicates that lovetoys is importing properly)

I might have a kinda weird setup, as I haven't worked with Lua before and so I'm just now getting my whole lua environment set up.

Treating systems as objects does not make sense

By definition, a system in a Entity-Component System framework is a stateless processor for its declared components in an entity. This boils down to basically a function to process the entity along with some metadata. Treating systems as an object when you really are only going to instantiate a system once is unneeded.

Helps with #21

Entities are probably not added to System

If an entity is already added to an engine and it gets an additional component, there is a chance that a system that requires this component doesn't get it.
This depends on the registered Component. There has to be an refactoring in requirement checking!!

Best practice for removing entites based on some system logic?

I have a system that processes some entities, and then I would like to remove these entities once they have been processed.

Should I pass the engine as a parameter to my system so it can call engine.removeEntity, or should I use some other approach to removal? I think it's interesting that entities can deactivate themselves, but cannot remove themselves from the engine.

Error when initializing lovetoys

Hi, I'm getting the following error when initializing lovetoys. Using the latest .zip download, running with the latest love2d version.

Error:
Error: lib/lovetoys/src/events/ComponentAdded.lua:12: attempt to call field 'class' (a nil value)

minimal main.lua:

lovetoys = require('lib.lovetoys.lovetoys')
lovetoys.initialize({
    globals = true,
    debug = true
})

Did a bit of debugging, breaking on this line:

ComponentAdded.lua:12
local ComponentAdded = require(folderOfThisFile .. '.namespace').class("ComponentAdded")

It seems like it's trying to include the empty table from namespace.lua which was previously populated with various things (including 'class') in lovetoys.lua populateNamespace()

however it doesn't seem like it's actually referring to the same table:

>>> require(folderOfThisFile .. '.namespace')
{} --[[table: 0x0b3834c8]]

>>> lovetoys  -- This is supposed to be the same table as the one included from namespace.lua
{class = {Object = "class Object", _DESCRIPTION = "Object --  (TRIMMED) [[..skipped..]] end}} --
[[table: 0x08c47738]]

Error: lovetoys/init.lua:7: module 'src.namespace' not found:

Getting this with a fresh checkout and running:

local lovetoys = require("lovetoys")

lovetoys.initialize({
  globals = true,
  debug = true
})
Error: lovetoys/init.lua:7: module 'src.namespace' not found:
	no field package.preload['src.namespace']
	no 'src/namespace' in LOVE game directories.
	no file 'src/namespace' in LOVE paths.
	no file './src/namespace.lua'
	no file '/usr/share/luajit-2.0.5/src/namespace.lua'
	no file '/usr/local/share/lua/5.1/src/namespace.lua'
	no file '/usr/local/share/lua/5.1/src/namespace/init.lua'
	no file '/usr/share/lua/5.1/src/namespace.lua'
	no file '/usr/share/lua/5.1/src/namespace/init.lua'
	no file './src/namespace.so'
	no file '/usr/local/lib/lua/5.1/src/namespace.so'
	no file '/usr/lib/lua/5.1/src/namespace.so'
	no file '/usr/local/lib/lua/5.1/loadall.so'
...

New to Lua and love2d. What am I doing wrong?

Feature Request - System:excludes()

Hello there,
First of all, great work on lovetoys, I'm using it for a project and it works like a charm :)

I'd love to be able to add system requirements, but the other way around.
Something like

function mySystem:excludes()
  return {"ExcludedComponent"}
end

If an entity has any of the excluded components, then it is excluded from the system.

create abstract data structure for engine internals

We have two different sets of data that the engine manages:

  • A collection of entities that need to be filtered by their component constellations.
  • A collection of Systems that represent one or more constellations of required components.

To clean up the code it would be nice to create one or more specialized data structures to handle those two collections outside of the engine.

questions

  • do we create separate data structures for entities and systems or does one structure manage both?
  • should the structure be able to filter systems by activeness/inactiveness?

needed functionality

  • fast lookup of systems whose requirements a given entity meets
    • does not necessarily need to be exposed, could be handled automatically on entity adding, removing etc
  • usual methods: add, remove, getAll, hasEntity, hasSystem etc.

Refactor Engine:registerSystem

There are a few possibilities to get more performance, in case of multiple table requirements.
Besides systems are beeing added twice, if they implement update and draw function.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.