TQ
dev.com

Blog about software development

Subscribe

Writing games in TypeScript

30 Aug 2023 - by 'Maurits van der Schee'

I loved programming in Actionscript (for Flash) and I have tried Haxe and other languages when Flash was widely abandoned. I felt JavaScript was lacking features for better structural programming. Typescript and Visual Studio Code provide a great development experience for creating (well performing) cross-platform games. I have rewritten my AceCardGames.com solitaire card games in TypeScript. In this post I will share my development setup and some of my lessons learned.

Canvas or DOM?

Although one can create Canvas based games, one can also create DOM based games (as I did). This is especially suitable for board games as these tend to have a fairly static layout. The advantage of DOM based games is that your sprites can move over and under each other by means of the "z-index", without having to do programmatic redraws. I also like the SVG support and that I can create my graphics using either Inkscape or hand-written SVG.

History

AceCardGames.com is a hobby project of mine that is online since 2003 and offers a collection of 12 solitaire card games. I originally wrote the games in ActionScript 2 (Flash MX) for the Motion-Twin ActionScript Compiler (MTASC). In 2009 I rewrote the games in ActionScript 3 for the Flex 3 open source SDK. In 2017 I rewrote the games again in JavaScript and Scalable Vector Graphics (SVG). And now in 2023 I am rewriting the JavaScript code in TypeScript.

IDE and TypeScript compiler

I've installed the TypeScript compiler using "nvm" (Node Version Manager):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
nvm install node
npm install typescript live-server

I use the following file and folder structure:

To run the compiler I typed:

node_modules/typescript/bin/tsc -w

To run the live server I ran:

node_modules/live-server/live-server.js --mount=/src:src web

I have found that this command can be configured in "scripts" section of the "package.json". I have also configured the "tsconfig.json" using:

{
  "compilerOptions": {
    "strict": true,
    "sourceMap": true,
    "target": "ES5",
    "module": "AMD",
    "outFile": "web/js/solitaire.js",
  },
  "compileOnSave": true
}

And loaded the "require.js" library, finally having to just add one line to my HTML to get started:

<script type="text/javascript">require(["index"]);</script>

Corresponding to the startup code in the "index.ts" file in the "src" directory. I have found that Visual Studio Code and it's TypeScript extension by Microsoft provides a very nice developer experience.

Circular dependencies

I use the factory pattern with an abstract base class with a static create function returning a class extending the base class. The Typescript compiler gave the following cryptic error message:

TypeError: Class extends value undefined is not a function or null

According to this StackOverflow post the error is caused by a circular dependency. The classes extend the base class and the base class imports the classes to call their constructor in the static create method.

I'm running into the same problem. The Factory Pattern is causing a circular reference. It seems that moving the factory to another file (and not a static method inside of a class that gets inherited) is the way to go. – Johnny Oshika

This pattern is quite common and the error was not very descriptive. According to this Medium post you can fix the problem by adding all classes to the same typescript file (in different ways), but most people suggest to avoid circular dependencies, which is what I've chosen to do.

Getting started?

Do you want to start writing your own games? Check out my next post: TicTacToe in TypeScript, which can serve as a simple starter project. You can find the source code of the starter project on my Github account:

Source: https://github.com/mevdschee/typescript-tictactoe

Links


PS: Liked this article? Please share it on Facebook, Twitter or LinkedIn.