Key technical results and performance observations from development.
Performance observations gathered during development with Visual Studio diagnostics. The fixed-timestep loop runs at 60Hz. NPC count and behaviour type are the primary variables affecting CPU load during gameplay.
All entity updates run at a fixed 60 updates per second. The game loop decouples update from render, ensuring consistent behaviour tick rates regardless of frame time variation.
Swapping NPC behaviour via setBehaviour(unique_ptr) is a pointer assignment. No iteration, no allocation during runtime swap. Ownership transfer is immediate via move semantics.
Exclusive use of std::unique_ptr throughout - NPCBehaviour, SpecialEntity, Player, Menu, PhaseManager. Automatic cleanup on all ownership paths. No raw owning pointers.
The current implementation is well-suited to the game's NPC population. The two areas that would not scale are the proximity checks and the texture-swap animation system.
checkNPCsNearHatWearers() and checkNPCsNearSpecialEntity() both iterate all NPCs each frame. At current counts this is fine. At 500+ NPCs a spatial grid partitioning approach would be required to maintain performance.
Visual state changes (default → hat → scared → angry → screaming) are handled by reloading a texture from disk and reinitialising the Animation object. Acceptable at current NPC count, but a single sprite sheet with row selection would eliminate disk reads entirely.
Current: disk reload per state change · Fix: multi-row sprite sheetPhase-specific logic like applyHatsToNPCs() currently lives in Game.cpp. As noted in the project report, this logic should be delegated to the PhaseManager or a dedicated phase handler to keep the game class clean regardless of how many phases are added.