Room
Game room is your entry point. When first player connects to your server, a new game room will be created.
import { defineRoom } from "@cardsgame/server"
import { actions } from "./actions.js"
import { setupState } from "./setupState.js"
import { MyGameState } from "./state.js"
export default defineRoom<MyGameState>("MyGame", {
stateConstructor: MyGameState,
maxClients: 4,
possibleActions: actions,
onStartGame(options) {
return new commands.Broadcast("Let's start!")
},
})
A functioning game room require at the very least:
stateConstructor
- reference to game State constructor, will be used to start fresh game state when creating new Room,possibleActions
- a list of actions players can make in a game,- any of the lifecycle methods, to react for example on game start, player's turn end etc
Lifecycle hooks
API for these: RoomDefinition lifecycle-methods
onInitGame(options?)
Will be called right after the game room is created, and game state is setup.
onInitGame(options) {
const { state } = this
const deck = new Deck(state, { name: "mainDeck" })
standardDeckFactory().forEach(
({ suit, rank }) =>
new ClassicCard(state, {
parent: deck,
suit,
rank,
})
)
}
canGameStart(): boolean
State your own conditions of whether the game can be started or not.
onStartGame(state): void | Command[]
Will be called when clients agree to start the game. At this stage state.players
is already populated with all joined players (including bots).
After this function, the game will give turn to the first player.
You can make this function return an array of commands to execute:
onStartGame() {
const { state } = this
// Create a "Hand" container for each player
const hands = state.players.map(
(player, idx) =>
new Hand(state, {
owner: player,
ownersMainFocus: true,
name: `player${idx}`,
})
)
return [
new commands.ShuffleChildren(state.deck),
new commands.DealCards(state.deck, hands, { count: 5 }),
]
}
onRoundStart(): void | Command[]
and onRoundEnd(): void | Command[]
Both invoked when executing NextRound command, in order:
onRoundEnd()
state.round
number is bumped uponRoundStart()
.
Return an array of commands if needed.
This example just illustrates the usage of onRoundStart
hook. In reality, it would be much better to rely on client-side state.round
updates to show a round change in UI.
onRoundStart() {
const { state } = this
return [
new commands.Broadcast("announcement", `Round ${state.round} begins!`)
]
}
onPlayerTurnStarted(player): void | Command[]
and onPlayerTurnEnded(player): void | Command[]
This happens when executing NextPlayer command, which will:
- Call
onPlayerTurnEnded(player)
with a reference to player whose turn just ended - Call
onPlayerTurnStarted(player)
with the next player to play.
Return an array of commands if needed.