Hello everyone,
I am working on a little 2-player game to help me learn elixir/phoenix. Before starting to code (and re-read some documentation), I would be glad to have some feedback about this scenario:
1- Players join their own “user:#user_id” private topic to receive/send private events (see why below). On join/2("user:" <> user_id,...)
:
- check the user_id maps the one assigned on the socket during initial connection
2- Then they join a “match:lobby” channel where they can meet. On join/2("match:lobby",...)
:
- enable Presence in a
handle_info/2
callback
3- Players invite each other to start a match: client 1 sends an invitation event to client 2. On handle_in/3("invite", %{"dest_id" => dest_id}, socket)
:
- check
dest_id
player is still available - then send invitation through the “user:#dest_id” topic
4- Let’s say player 2 accepts the challenge. On handle_in/3("accept", %{"match_id" => match_id}, socket)
:
- push an event for both players so that they ask back to leave “match:lobby” (till the end of the game when they will join again)
- create a Game (module agent) that implements the gameplay and is added to a GameSupervisor (through
start_child/2
?).
5- Depending on user input and game events, the Game agent dispatch events to users until the match ends.
- here a specific channel with a topic “match:#match_id” could be used, or we could rely on the user channels (“user:#user_id” topics) previously created to send invitations
- a bit off-topic: maybe I need to persist the Game state to the DB, and retrieve it if the agent crashes and is respawned
Regarding the communication between the Game agent and clients:
-
Game agent->players: the Game agent holds the relevant topics in its state (let it be “user:#user_id” or “match:#match_id”) and can send event to players thanks to the endpoint’s
broadcast/3
-
Players->Game agent: on
handle_in/3("game_event",...)
: we need to find the Game agent corresponding to the given user_id or match_id. I guess this is when Registry is useful, but for the moment I feel that implementing my own GameIndex agent, mapping user_id keys to process names would be simpler. Or I could use the socket assigns to store the Game agent process name. This is where I would really appreciate some feedback, I am a bit lost here.
6- When the game ends:
- the result of the game is persisted to the DB
- the Game agent is terminated and specific properties are reset (for instance if the Game agent process name was assigned to the socket)
- players get back to “match:lobby”
In case of a client side reboot (a page refresh for instance) and if the user is currently in a game, we could jump directly from step 1 to 5, using the GameIndex.
Do you see any drawback/oversight in this scenario? Many thanks, Guillaume