ecsx-framework / ecsx Goto Github PK
View Code? Open in Web Editor NEWAn Entity-Component-System framework for Elixir
License: GNU General Public License v3.0
An Entity-Component-System framework for Elixir
License: GNU General Public License v3.0
After some manual edits to some components my app fails on start up with:
[error] GenServer #PID<0.728.0> terminating
** (ArgumentError) errors were found at the given arguments:
* 1st argument: the table identifier does not refer to an existing ETS table
(stdlib 4.2) :ets.match_object(Cid.Components.PlayerSpawned, :_)
(stdlib 4.2) ets.erl:771: :ets.tab2list/1
(ecsx 0.5.0) lib/ecsx/base.ex:96: ECSx.Base.get_all_keys/1
(cid 0.1.1) lib/cid_web/channels/game_channel.ex:37: CidWeb.GameChannel.handle_info/2
(phoenix 1.7.10) lib/phoenix/channel/server.ex:358: Phoenix.Channel.Server.handle_info/2
(stdlib 4.2) gen_server.erl:1123: :gen_server.try_dispatch/4
(stdlib 4.2) gen_server.erl:1200: :gen_server.handle_msg/6
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
```
I already tried to fix it be deleting the persistance file and _build folder, with no luck.
I wonder how to recover from this state?
Pretty soon we can probably build the ship app in LVN and include the instructions in the tutorial as an advanced frontend section
After the comment, so vscode won't complain
In game development practice, it may be necessary to query the system. Mixed query and filter components.
Option to shed ticks if too many ticks are backed up in the managers message queue.
Hi there!
I was wondering if there was a way to create some kind of lobbies, or parallel "game state", so instead of having one lobby with every player we could have smaller, unrelated lobbies players could join.
As far as I can tell the Manager is common for everything and we can't really have a multitude of smaller managers?
Search components
Show component table updates in real-time
Maybe expose component write API
General server stats - component quantities, system run times, player inputs
Hi, nice talk at the 2023 conference, I haven't tried this out yet but was looking over the library source and tutorial project and noticed that the valid component value types are all scalars. My first impulse was to have one component for position as a tuple {x, y} and another for velocity. Then I thought one often wants them both, so a tuple {x, y, dx, dy} might be more efficient.
You may have tried this already, perhaps the scalar types you support skip de/serialization in ETS and so they are faster and generate less garbage.
An idea which came up was the option to remove automatic tick events, while exposing a function to manually trigger a tick at the end of the turn.
The current method is to use component removal.
def destroy(entity) do
ArmorRating.remove(entity)
AttackCooldown.remove(entity)
...
end
Is there a way to remove an entity so that all its associated components are removed?
An option when system gets overloaded to decrease tick rate (increase time per tick) until things get caught up. See EVE Online.
Let's allow this to return any()
since the result is not used. It could also make it easier to test Systems.
Since this is a pretty important feature, it might make sense to generate this module in the setup generator with a really basic default like inspecting the event and putting it to the terminal.
After you generate a component, e.g. Legendary
, and it's added to the components
list in the manager you are unable to generate any new components due to the mix task breaking on https://github.com/ecsx-framework/ECSx/blob/master/lib/mix/tasks/ecsx/helpers.ex#L50
There are a few multiplayer scenarios that I think would be fantastic to have documented patterns for.
One Big World - in this scenario, there's a single giant living space for all players. So the things that we'd need guidance on here are how to center the frontend (live)view on only the current player entity and only within the player's limited view radius.
Multiple shards (aka the "Animal Crossing" world pattern) - in this scenario each player is given their own isolated world, and then other players can visit (creating a small version of 1). There are a couple of ways I can think of to implement this. The easiest that comes to mind is giving each player space in a giant shared world, and then just enforcing rules to prevent players from crossing the boundary (kind of similar to how world tilemaps used to be laid out in games with little space on a cartridge). In a situation like this, I worry about the cost of querying for entities. I think even with using the range query on something like XPosition
and YPosition
, if there's a large number of players online, it could get slow... and would continue to degrade over time as more and more players logged in.
Zones, which might be "shards". We might have a single overland map (e.g. 1) but then if a team decides to do an instanced dungeon, it would be ideal to get a separate manager for just that dungeon. Zones could also be used to logically (and data-wise) segment a large overland map.
The necessary backend infrastructure to support multiplayer is right up Elixir/Erlang's alley, and I'd love to be able to build a multiplayer ECS backend.
It doesn't look like it's currently supported, but if the manager could be sharded/instanced, then the set of systems and components in player1
's world and those in player2
's world would be different data, different indexes, and so we'd likely be able to scale out the "private world" model without degrading performance. We could even choose which node in the BEAM cluster got to run the new world instance.
live_session stuff is missing and could cause confusion about which scope to add the route to.
Really a cool project, I like it very much!
I wonder if it would be possible to run multiple instances in one application?
Is that possible? Or how would you implement for example a platform where players could create and play their (own) games? In this scenario I would have to launch an own server/node for each game, right? Or is there an other way to do it?
In a previous version, the tutorial project GUI would fill the whole browser window. Currently it is rather small inside the default Phoenix layout. Ideally we get rid of the layout and return to the full-size display
Could allow performance improvements for Component.search/2
and possibly comparison functions for integer types
Hi Andrew! @APB9785
Having a blast trying this out.
I'm trying to make a little factory simulator, and I noticed that the order of atoms in the fields
param for Component.add/3
seems to matter.
For example, I have a Producing
aspect.
defmodule Factory.Aspects.Producing do
@moduledoc """
Documentation for SampleAspect components.
"""
use ECSx.Aspect,
schema: {:entity_id, :type, :per_minute, :to}
end
Then when I add a component.
ECSx.Component.add(Producing, [id: id, to: to, type: :iron, per_minute: 30], [
:type,
:id,
:per_minute,
:to
])
The order of fields
changes which values are stored in which field. For example I'm logging all Producing
components:
ECSx.Component.get_all(Factory.Aspects.Producing, [:id, :type, :per_minute, :to])
|> IO.inspect()
Which prints the following. Notice my fields and values are incorrect.
[%{id: :iron, per_minute: 30, to: 4, type: 1}]
Perhaps I'm doing something wrong, or maybe this is a bug? Either way, I wanted to get your input on the fields
params. I wonder if it would be cleaner to exclude fields
from the function signature entirely?
i.e.
ECSx.Component.add(:aspect, [key: "value"])
Or am I misunderstanding, and there's a reason to include the fields
param?
Thank you again for making this and letting me try it out!
Search numerical values, return a list
Hi,
sorry for what may not be the most appropriate way to ask library questions (opening an issue). Please feel free to close it if it's not relevant.
As somebody working also on an ECS library with Elixir (https://github.com/iacobson/ecspanse, still WIP and not well documented ) I immediately read your article and much of the docs of the library.
BTW, congrats! Such a nice and clean API.
However, one of my most significant issues with ECS in general is handling collections.
For example, let's say in the Ship game, the ship has a ridiculous amount of cannons, eg. 50. Each cannon can fire individually, and each cannon has a cooldown (as in your game).
What I'm thinking:
Create multiple (50) Components.Cannon
and Components.AttackCooldown
components for the same entity.
I saw the unique: false
option in the Components.
But how to know which one of them fired or is reloaded?
More than this, let's assume that each cannon damage can be upgraded, so it is important that cannon 15 is reloading but cannon 23 is available, for example.
Cannons are their own entities
They will hold components like Components.AttackCooldown
and Components.CannonDamage
.
But in this case, how to link the cannon entities with the ship entity.
Thank you! And looking forward to the future of this library.
We want to find a convenient way for the game developer to design layouts for game levels including pieces of environment, boundaries, spawn points, etc.
These could be either publicly exposed for use in the initial setup
block, or automatically set up by the library somehow.
This would basically be some kind of global key/value store included in ECSx. Could remove some cases where users would have to reach outside ECSx for pure OTP solutions, and allow them to keep using the Components API for it too
Nonunique components don't seem necessary anymore and will create difficulty implementing some future features
one-to-many
relationships should be refactored to many-to-one
instead. search/2
can be used to replicate the functionality which is sought via the one-to-many
approach. Upcoming optimization of search/2
via reverse indexing will make many-to-one
equally performant.many-to-many
relationships indicate that the relationship itself should be modeled as an entityThis change should be accompanied by documentation which guides developers in using the proper patterns. Common use cases for one-to-many
and many-to-many
should be shown, with instructions on how to refactor these into unique components.
Right now the tutorial advises users to create new Entities with Ecto.UUID.generate()
but leaves it up to them in the end. Would it be helpful to instead have something like ECSx.new_entity()
with various options such as erlang unique refs, unique integers, uuids, etc?
* 1st argument: the table identifier does not refer to an existing ETS table
(stdlib 5.1) :ets.select(Rotb.Components.Zone, [{{:"$1", :"$2", :_}, [{:>=, :"$2", -1}, {:"=<", :"$2", 1}], [{{:"$1", :"$2"}}]}])
(ecsx 0.5.1) lib/ecsx/base.ex:114: ECSx.Base.between/3
When I use get_all/0 it works but when I use between
it complains
{player, _zone} <- Zone.between(zone_id - 1, zone_id + 1)
Is this a bug or am I doing something wrong?
I'm experimenting with this lib and when I try to add directly from my channel I run into this error.
Not sure if only systems are supposed to be able to do things like ZPosition.add(socket.id, starting_z)
But I need to do it when a socket connects. So I'm wondering what the correct approach is here.
Just offering words of encouragement!! Keep going!! You're the best!!
This feature isn't as useful as previously thought. Just run the systems every tick!
When the client is sensitive to network traffic, or the game state is very large, the cost of synchronizing all states each time is very high.
Is it possible to add an event list, just like client events, you can add events yourself every time you update the component, and only synchronize events to the client.
Only need to refresh all status at optional times.
In this way, the client can distinguish modifications based on events and synchronize the differences with the server.
When reverse index tables are introduced into ECSx, there might be a desire for functionality where two or more index tables are searched, to get a list of entities which are common to all search results.
For example:
Entity 123 has XCoord 10 and YCoord 5
We want to search a list of all entities found at location {10, 5}
With standard index tables, we need to XCoord.search(10)
and YCoord.search(5)
and then somehow get the intersection of those two lists
Ideally we would like to have an index table where the key is {10, 5}
, so a single search
returns exactly the results we want
It could also be worth testing out an intermediate approach where two searches and a MapSet.intersection
is used under-the-hood while we work on a more performant implementation.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.