🚧 Work in Progress 🚧
You can test it on the Studio, but not yet deploy it to production.
State classes allow to create a PHP class for each game state. It allows to split the code in multiple files, without using Traits. The advantage is that the IDE understands the structure and can provide auto-completion and error highlights, that are lost in Traits.
State classes declared this way do not need to be declared in states.inc.php (in fact they must not be declared, as the game state engine will consider them 2 different states and detect a conflict of id).
Structure
The State class in modules/php/States/PlayerTurn.php
will have this structure:
namespace Bga\Games\<MyGameName>\States; use Bga\GameFramework\StateType; use Bga\GameFramework\States\GameState; use Bga\GameFramework\States\PossibleAction; use Bga\Games\<MyGameName>\Game; class PlayerTurn extends GameState { function __construct( protected Game $game, ) { parent::__construct($game, id: 2, type: StateType::ACTIVE_PLAYER, // optional description: clienttranslate('${actplayer} must play a card or pass'), descriptionMyTurn: clienttranslate('${you} must play a card or pass'), transitions: [], updateGameProgression: false, initialPrivate: null, ); } public function getArgs(): array { // the data sent to the front when entering the state return []; } function onEnteringState(int $activePlayerId) { // the code to run when entering the state } #[PossibleAction] public function actPlayCard(int $cardId, int $activePlayerId, array $args): string { // the code to run when the player triggers actPlayCard with bgaPerformAction } function zombie(int $playerId): string { // the code to run when the player is a Zombie } }
The state must extends Bga\GameFramework\States\GameState
and follow the same __construct
function as the example. Only $game, id and type are mandatory, other parameters are optional. name can be specified, by default it will be the class name.
In non GAME states, the zombie
function is also mandatory.
Differences with states declared in states.inc.php
Moved elements
The function getArgs
replaces the function that was declared as "args" => "argXXX"
on states.inc.php. Same for the function onEnteringState
that was "action" => "stXXX"
on states.inc.php. The zombie
function doesn't have the state as first parameter anymore, because it's not needed in this context.
The possible actions for this states don't need to be declared as an array, they will be found with the tag #[PossibleAction]
over each possible action.
The functions declared in Game.php will be accessible with $this->game
instead of $this
. The Game sub-objects are available on the State class too, so you can write $this->notif->all
without needing to pass through the game variable.
New elements
In the new class
The getArgs
function can set some predefined parameters that will be automatically filled:
int $activePlayerId/$active_player_id
will be filled by the result of getActivePlayerId. To be used on ACTIVE_PLAYER states only.int $playerId/$player_id/$currentPlayerId/$current_player_id
will be filled by the player id of the current PRIVATE state. To be used on PRIVATE states only.
The onEnteringState
function can set some predefined parameters that will be automatically filled:
array $args
will be filled by the result of$this->getArgs()
.int $activePlayerId/$active_player_id
will be filled by the result of getActivePlayerId. To be used on ACTIVE_PLAYER states only.int $playerId/$player_id/$currentPlayerId/$current_player_id
will be filled by the player id of the current PRIVATE state. To be used on PRIVATE states only.
The actXXX
functions (auto-wired functions) can set some predefined parameters that will be automatically filled:
array $args
will be filled by the result of$this->getArgs()
.int $activePlayerId/$active_player_id
will be filled by the result of getActivePlayerId. To be used on ACTIVE_PLAYER states only.int $currentPlayerId/$current_player_id
will be filled by the result of getCurrentPlayerId.
For all those functions, and also the zombie
function, they can now send a redirection to a game state as a returned result. The allowed writings are:
return NextPlayer::class
will redirect to the state declared in that class.return ST_END_GAME;
=return 99;
will redirect to the state of that id. It must be typed as int, numbers in a string won't work.return 'nextPlayer';
will redirect to the transition of that name (requirestransitions
to be declared in the constructor).
If you use this writing, remove $this->gamestate->nexState
to avoid double redirection!
The initialPrivate parameter of the constructor can be null or an int as before, but can now also accept a class name as value initialPrivate: PlaceCard::class
Outside the new class
You can now pass a state class as the parameter of GameStateBuilder::gameSetup(PlayDisc::class)->build()
, and on some function that previously only accepted transitions, like $this->gamestate->nextPrivateState(ConfirmTurn::class)
or $this->gamestate->setPlayerNonMultiactive($currentPlayerId, EndRound::class)
If all your classes are migrated to State classes, your states.inc.php file will look like this:
$machinestates = [ 1 => GameStateBuilder::gameSetup(PlayDisc::class)->build(), ];
Or even an empty array if your first state has id 2.
Zombie
Some utilities function has been added for Zombie Mode, so the example you can see in Zombie Mode can be simplified to :
Example of Zombie level 0
function zombie(int $playerId): void { return NextPlayer::class; }
Example of Zombie level 1
function zombie(int $playerId): void { $args = $this->getArgs(); $zombieChoice = $this->getRandomZombieChoice($args['playableCardsIds']); // random choice over possible moves return $this->actPlayCard($zombieChoice, $playerId, $args); // this function will return the state to go to, so we return it to end the zombie function }
Example of Zombie level 2
function zombie(int $playerId): void { $args = $this->getArgs(); $possibleSpaces = $args['possibleSpaces']; $playerCards = $this->getPlayerCards($playerId); $possibleAnswerPoints = []; foreach ($possibleSpaces as $choice) { $possibleAnswerPoints[$choice] = $this->getPointsFromState3Choice($playerCards, $choice); // for each possible choice, compute the points the player/Bot would immediately gain } $zombieChoice = $this->getBestZombieChoice($possibleAnswerPoints); // get top choice over possible moves return $this->actPlayCard($zombieChoice, $playerId, $args); // this function will return the state to go to, so we return it to end the zombie function }