// GDnD wiki example // Demonstrates: a shared base class that moves an actor smoothly cell-to-cell and asks subclasses which way to turn // Related pages: [[overview-arcade-classics-as-learning-projects]], [[csharp-inheritance]] using UnityEngine; // Both the player and the ghosts move the same way: glide to the next cell // centre, then decide a direction. That shared mechanism lives here; the // decision (read input vs run AI) is left abstract for subclasses. This is a // small, concrete use of [[csharp-inheritance]]. public abstract class GridMover : MonoBehaviour { [SerializeField] protected float speed = 4f; public Vector2Int CurrentCell { get; private set; } protected MazeGrid maze; protected Vector2Int currentDir = Vector2Int.zero; private Vector2Int targetCell; private Vector3 targetPos; private bool hasTarget; public virtual void Init(MazeGrid grid, Vector2Int startCell) { maze = grid; SnapTo(startCell); } public void SnapTo(Vector2Int cell) { CurrentCell = cell; transform.position = maze.CellToWorld(cell); currentDir = Vector2Int.zero; hasTarget = false; } private void Update() { if (maze == null) { return; } OnTick(); StepMovement(); } private void StepMovement() { if (!hasTarget) { // At a cell centre: ask the subclass which way to go next. Vector2Int dir = ChooseDirection(CurrentCell, currentDir); if (dir != Vector2Int.zero && maze.IsWalkable(CurrentCell + dir)) { currentDir = dir; targetCell = CurrentCell + dir; targetPos = maze.CellToWorld(targetCell); hasTarget = true; } else { return; // nowhere to go this frame — idle } } transform.position = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime); if ((transform.position - targetPos).sqrMagnitude < 0.0001f) { transform.position = targetPos; CurrentCell = targetCell; hasTarget = false; OnArrived(CurrentCell); } } // Runs every frame before movement — used by the player to buffer input. protected virtual void OnTick() { } // Decide the next grid direction from the current cell. Vector2Int.zero = stay. protected abstract Vector2Int ChooseDirection(Vector2Int cell, Vector2Int dir); // Called once each time the actor reaches a new cell centre. protected virtual void OnArrived(Vector2Int cell) { } }