Skip to content

MoveHistory

namespace Griff.Modules.Puzzles;
public sealed class MoveHistory : Component

Undo and restart for grid puzzles, with no code: each step a grid player takes (with any crates it pushes) is a move. The UndoAction (Z, U or the gamepad’s left shoulder) puts everything back where it was before the last move, and the RestartAction (R or the left trigger) back where the level started, which Undo takes back too. One in the scene is enough: put it on the player or on the level. A Counter counting its Output “Moves” shows how many moves have been taken. With Within, it covers only part of the scene (a puzzle room in a bigger game): only steps there count, and only what’s there goes back; give each puzzle its own.

It puts back every grid mover it covers: players, crates, and chasers and patrols (where they were on their routes), each facing the way it did. Things collected or destroyed since stay gone, and the rest (counters, switches, inventories, whose turn it is) stays as it is; tick RestartReloads for a restart that starts the whole scene over. In a network game there’s no undo, and a restart starts the scene over for everyone.

This is a component: its saved properties are on its component page.

public bool CanUndo { get; }

True while there’s a move (or a restart) to take back.

public float Fade { get; set; }

Seconds to fade out (and back in) as a restart reloads the scene. 0 cuts straight there.

public bool HoldToRepeat { get; set; }

Holding Undo keeps taking moves back, one after another.

public int Limit { get; set; }

The most moves it remembers, dropping the oldest. 0 remembers them all.

public int Moves { get; }

How many moves have been taken: one more with each, one fewer with each undo, 0 after a restart.

public string? RestartAction { get; set; }

The input action that starts the level over: “Restart” is R or the gamepad’s left trigger. Empty only restarts from scripts.

public string? RestartMessage { get; set; }

A message sent with Game.Send as the level starts over.

public bool RestartReloads { get; set; }

Restart reloads the scene from its file, so everything starts over (pickups, counters, scripts too), and Undo can’t take it back. Off, it puts the grid movers back where they started, as one more move Undo can take back.

public string? RestartSound { get; set; }

A sound played as the level starts over.

public string? UndoAction { get; set; }

The input action that takes the last move back: “Undo” is Z, U or the gamepad’s left shoulder. Empty only undoes from scripts.

public string? UndoMessage { get; set; }

A message sent with Game.Send as a move is taken back, with the moves now taken as its data.

public string? UndoSound { get; set; }

A sound played as a move is taken back, e.g. “Sounds/undo.wav”.

public string? Within { get; set; }

The part of the scene it covers, by an entity’s name: the grid movers inside that entity or standing in its area (a Room’s, a tilemap’s, a collider’s), e.g. “Puzzle Room”. Only their steps are moves, only they go back, and Undo and Restart work while a grid player with the input stands there. Empty covers the whole scene.

public Scope Covering()

The part of the scene it covers (see Within).

public void Record()

Counts a move now, remembering where every grid mover is so Undo can put them back here: for a script’s own moves (a lever pulled, a block teleported). Grid players’ steps count by themselves.

public void Restart()

Starts the level over at the start of the next frame, as pressing Restart does.

public void Undo()

Takes the last move back at the start of the next frame, as pressing Undo does.

public event Action<MoveHistory>? Restarted

Raised after the level starts over (or as it starts to reload, with RestartReloads).

public event Action<MoveHistory>? Undone

Raised after a move is taken back.