Code Monkey home page Code Monkey logo

ecsx's People

Contributors

apb9785 avatar hl avatar ruan-brandao avatar thefirstavenger 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

ecsx's Issues

Unable to restart application after renaming component names and/or value types

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?

LiveView Native Frontend tutorial

Pretty soon we can probably build the ship app in LVN and include the instructions in the tutorial as an advanced frontend section

Idea: Query System

In game development practice, it may be necessary to query the system. Mixed query and filter components.

Tick Shedding

Option to shed ticks if too many ticks are backed up in the managers message queue.

Multiple instances

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?

TODO: Admin tools/console

Search components
Show component table updates in real-time
Maybe expose component write API
General server stats - component quantities, system run times, player inputs

Support component type of tuple

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.

Support for turn-based apps

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.

Is there a way to delete an Entity?

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?

Time Dilation

An option when system gets overloaded to decrease tick rate (increase time per tick) until things get caught up. See EVE Online.

Generate ClientEventsHandler module

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.

Multiplayer guidance in docs and tutorial

There are a few multiplayer scenarios that I think would be fantastic to have documented patterns for.

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

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

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

How to run multiple instances?

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?

Remove phoenix layout from tutorial project

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

Component fields order matters.

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!

Question on handling collections

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:

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

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

Investigate game map/environment seeding

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.

Entity-less/Global Components?

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

Deprecate nonunique components

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 entity

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

Should ECSx implement Entities or leave it up to the user?

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?

`between` fails but `get_all` works for a numerical type.

  * 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?

the table identifier refers to an ETS table with insufficient access rights

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.

Idea: ECSx.ServerEvents

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.

Idea: Double index tables

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.

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.