A browser-based TypeScript implementation of the classic retro game, Snake (Wikipedia)
Game features implemented so far are:
- Mobile responsive layout
- Keyboard / mouse / touch controls
- Persistent high scores
A non-UML class diagram for the Snake game is as follows:
Class | Description |
---|---|
Apple | Is given a location on the board and remains static until the snake eats it by running into the same square. The user's score is incremented and another apple placed on the board for the snake to eat. |
Snake | Moves around the board 'eating' apples. Each apple eaten results in the snake growing in length, making it harder to remain in the game because the snake cannot run across itself or hit the edge of the board. |
Game | A container for holding the Apple and Snake objects. Also responsible for handling user events (keyboard / mouse / touch), snake events (snake has eaten an apple, snake has run into itself, snake has fallen off the board) and game events (Game Over). |
GameRenderer | Responsible for rendering the game state at point of redraw. Converts the relative locations of Snake and Apple into pixel coordinates for rendering to an Html canvas element it contains a reference to. |
HighScoresProvider | An interface defining the high scores functionality required by the Game class, primarily concerned with getting and saving game scores. |
The game was implemented in HTML, CSS and TypeScript using Visual Studio 2019 as the development IDE.
The HighScoresProvider interface has been implemented twice, namely an in-memory (non-persistent) provider and also a (persistent) webservice provider.
The in-memory provider has been configured as the default provider in the checked-in codebase. This allows the Snake game to be standalone and work 'out of the box' should you build and run a forked / cloned repo.
You will need to implement your own webservice implementation (or similar) should you want persistent high scores between games and between users.
The specific provider to use is defined in code through a poor man's DI located in the app.ts file, namely:
//Load the correct high scores provider here:
const highScoresProvider: HighScoresProviderInterface = new HighScoresMemoryProvider(
[
new HighScore("FDR", 10),
new HighScore("HGR", 7),
new HighScore("SRR", 2)
]
);
//const highScoresProvider: HighScoresProviderInterface = new HighScoresWebServiceProvider(
// 'http://localhost/SnakeWebAPI/api/Snake/GetHighScores',
// 'http://localhost/SnakeWebAPI/api/Snake/SaveHighScore'
//);
A comprehensive suite of unit tests have been written against the materially important classes to validate a lot of the game logic. Classes have been split out into separate TS files and loaded when needed through the RequireJS framework. The use of separate type files have allowed unit tests to be easily written against individual classes. Jest unit test framework was selected and remains a good choice due to ease of use and breadth of functionality. Both RequireJS and Jest were installed with NPM (Node Package Manager).
Make the Snake's length grow upon eating each apple[Done - 21 January 2021]Collision detection of the snake upon itself[Done - 21 January 2021]Unit testing (of TypeScript classes)[Done - 20 January 2021]- GitHub post commit hook to execute unit tests
Persist high scores in a database with the help of a ASP.Net Web API service[Done - 22 February 2021]- Give the snake a timer and make it autonomous; redraw the Html canvas on browser screen refresh event
- Implement a proper config file option (example)
The following resources came in handy when implementing the game:
- Tutorial: Create an ASP.NET Core app with TypeScript in Visual Studio
- Getting the Right Set Up for TypeScript
- Multiple files making up Type Script project
- Can you create Typescript packages? like c# dlls
- Canvas Animations in TypeScript
- Using Touch Events with the HTML5 Canvas
- Event Creation and Handling Techniques in TypeScript
- HOW TO GET STARTED WITH REQUIREJS
- Using RequireJS with Visual Studio
- What's the correct way to use requireJS with typescript?
- How to use npm installed requireJS for browser
- The TypeScript Handbook
- Using ESLint with TypeScript in 2019
- How to upgrade the version of ESLint used in Visual Studio 2019?
- Custom error class in TypeScript
- How do I cast a JSON Object to a TypeScript class?
- JavaScript Obfuscator Tool
Royalty free Snake logo courtesy of CLEANPNG