Skip to main content

Crate falling_tetromino_engine

Crate falling_tetromino_engine 

Source
Expand description

§Falling Tetromino Engine

A tetromino stacker engine in Rust, with the goals of being featureful, efficient and elegant.

use falling_tetromino_engine::*;

// Initialize a game. In-game time starts at 0s.
let mut game = Game::builder()
    .seed(1234)
    /* Further customization possible here. */
    .build();

// Update the game with info that 'left' is activated at second 4.2 (i.e. piece starts moving left).
let input = Input::Activate(Button::MoveLeft);
game.update(InGameTime::from_secs_f64(4.2), Some(input));

// Update the game with info that no input changes up to second 6.79 (e.g. piece falls).
game.update(InGameTime::from_secs_f64(6.79), None);

// Read game state (for rendering etc.)
let State { board, .. } = game.state();

§Features Overview

Fundamental points to note:

  • The engine implements the pure game logic/backend, i.e. it accurately and only simulates a virtual board with tetromino pieces spawning/moving/locking, lines clearing etc.
  • The engine is frontend-agnostic and by itself does not prescribe how to interact with the real world player (it does not know about the keyboard, refresh-/framerate etc.)

Internally, the game processes a pure timeline like so:

Piece spawns              e.g. Game state viewed here
|        Piece falls                  |
|        |       Piece falls          |
v        v       v                    v
|--------¦--|----¦-------¦-------¦----+--¦------->
            ^
            |
            "RotateLeft" player input:
             Piece rotates

I.e. running a game at 60 Hz just means that Game::update is called 60 times in one second to determine the state in the timeline and show it. (The precision used internally is currently based on std::time::Duration which goes down to nanoseconds.)

Depending on configuration, calls to Game::update and Game::forfeit can return additional information (Notification) which can facilitate frontend implementation (e.g. hard drop, piece lock, line clears and other visual feedback).

The engine provides possibilities for compile-time modding. Mods may arbitrarily access and modify game state when called on given engine hooks.

In terms of advanced game mechanics the engine aims to compare with other modern tetromino stackers. It should already incorporate many features desired by familiar/experienced players, such as:

  • Available player actions:
    • Move left/right,
    • Rotate left/right/180°
    • Drop soft/hard
    • Teleport down(=‘Sonic drop’) and left/right
    • Hold piece,
  • Tetromino randomizers: ‘Uniform’, ‘Stock’ (generalized Bag), ‘Recency’ (history), ‘Balance-out’,
  • Piece preview (arbitrary size),
  • Spawn delay (ARE),
  • Spawn actions (IRS/IHS; by keeping rotate/hold pressed during spawn),
  • Rotation systems: ‘Ocular’ (engine-specific, playtested), ‘Classic’, ‘Super’,
  • Delayed auto-move (DAS),
  • Auto-move rate (ARR),
  • Soft drop factor (SDF),
  • Customizable gravity/fall and lock delay curves (exponential and/or linear; also, ‘20G’ (fall rate of ≥1200 Hz) just becomes ≤00083s fall delay),
  • Ensure move delay less than lock delay toggle (i.e. DAS/ARR are automatically shortened when lock delay is very low),
  • Allow lenient lock-reset toggle (i.e. reset lock delay even if rotate/move fails),
  • Lock-reset cap factor (i.e. maximum time before lock delay cannot be reset),
  • Line clear duration (LCD),
  • Customizable win/loss conditions based on the time, pieces, lines, points,
  • Score more points for larger lineclears, spins (‘allspin’), perfect clear, combo,
  • Game reproducibility (PRNG/determinism).

The basics seem to have been figured out through many iterative improvements. Ongoing areas of investigation (to improve generalization) are:

  • Choice of Notifications provided to frontend clients;
  • Choice of update Hooks for modding clients;
  • Choice of Stats to query game with or make game automatically halt;
  • Various engine generalizations for engine clients that want to plug custom behavior for currently-hardcoded structures.

§Implementation Idea

The game keeps:

  • Configuration to read from, which determines game behavior.
  • State values which persist throughout the game.
  • A dedicated ‘phase’-state field:
    • This represents the macro-scale state machine and can store values specific to separate stages during the game.
    • E.g., ‘Spawning’ (no piece) vs. ‘Piece-is-in-play’ (with piece data to keep track of).

During each update, the game looks at the (very limited) number of upcoming in-game ‘events’ and processes them. The only complicated phase is Phase::PieceInPlay { .. }, which encapsulates several types of upcoming events (priority in the given order):

  • Action by player: Player input which causes e.g. the piece to move, makes it lock immediately or cancels auto-movement.
  • Autonomous movement: While move buttons are active (‘held down’), the piece may move autonomously.
  • Falling or locking: Whenever the piece is airborne or grounded, there is an upcoming fall or lock scheduled.

§FIXME

Current documentation is lacking and sometimes slightly outdated. All features should be commented in detail (including IRS, etc., cargo feature serde etc.)]]

Re-exports§

pub use extduration::ExtDuration;
pub use extnonnegf64::ExtNonNegF64;
pub use modding::GameAccess;
pub use modding::GameModifier;
pub use randomization::TetrominoGenerator;
pub use rotation::RotationSystem;

Modules§

extduration
Supertype of Duration where dur may be Infinite.
extnonnegf64
Subtype of f64 where +0.0 ≤ value ≤ +∞.
modding
Modding facilities for the engine.
randomization
Random generation of Tetrominos.
rotation
Rotation of tetromino Pieces.

Structs§

Configuration
Configuration options of the game.
DelayParameters
A struct describing how certain time ‘delay’ values progress during a game’s lifetime.
Game
Main game struct representing a round of play.
GameBuilder
This builder exposes the ability to configure a new Game to varying degrees.
GameLimits
Certain statistics for which an instance of Game can be checked against.
Piece
An active tetromino in play.
State
Struct storing internal game state that changes over the course of play.
StateInitialization
Some values that were used to help initialize the game.

Enums§

Button
Represents an abstract game input.
GameEndCause
Represents how a game can end.
Input
A signal about button activation or deactivation.
Notification
A number of feedback notifications that can be returned by the game.
NotificationLevel
The amount of feedback information that is to be generated.
Orientation
Represents the orientation an active piece can be in.
Phase
An event that is scheduled by the game engine to execute some action.
Stat
Certain statistics for which an instance of Game can be checked against.
Tetromino
Represents one of the seven “Tetrominos”;
UpdateGameError
An error that can be thrown by Game::update.

Traits§

CoordAdd
Trait to enable adding 2D coordinates together.

Type Aliases§

Board
The type of the entire two-dimensional playing grid.
ButtonsState
Type describing the state that is stored about buttons.
Coordinate
Coordinates conventionally used to index into the Board, starting in the bottom left.
GameRng
The internal RNG used by a game.
InGameTime
The type used to identify points in time in a game’s internal timeline.
Line
The type of horizontal lines of the playing grid.
NotificationFeed
Type alias for a stream of notifications with timestamps.
Offset
Coordinate offsets that can be CoordAdd::added to Coordinates.
TileID
Abstract identifier for which type of tile occupies a cell in the grid.