Sessions is temporarily moving to YouTube, check out all our new videos here.

Making a Modern Version of Space Invaders Using TypeScript

Nikos Katsikanis speaking at Ember London in November, 2016
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

You will learn OOP game coding for Canvas using the strong Typing of TypeScript.


Right, let's talk about TypeScript. I discovered TypeScript back in 2012 and I actually started the code for this game back in the day. I came from a Flash background, ActionScript, strong typing background, and I got seriously into JavaScript 2012 and I just didn't really like it that much. [00:33] TypeScript was quite attractive to me because I was using Visual Studio at the time and the tooling was really good for this. It's quite close to JavaScript. TypeScript is doing quite well, especially the last year or so since Angular 2 are using it for their code and you can see it's really rising up here, then we had Brexit and the US elections. [00:59] [laughter] Nikos: [00:59] Cut that out. [laughs] It's a superset of JavaScript, which basically means that there's everything that JavaScript is plus the super stuff. It's not a clean break from JavaScript like Dart. Dart is, "JavaScript, we don't like you." TypeScript has really kept with the deal here. [01:20] It also keeps the syntax of JavaScript so it's not departing it even from the CoffeeScript, which keeps the same functionality but the syntax is way different. It has optional types so you can use strong typing at any point you like in your application or whenever you don't like, kind of like Flow, which does something similar. [01:37] It also has ECMAScript compatibility. TypeScript are doing quite well here. Dear me. We've got TypeScript and this is the ES6 compatibility. So it's lagging a little bit behind things like Babel, which you'd expect but they're making a good job of what they're doing. [01:58] One of the best things about TypeScript is that it catches bugs that you usually discover when your code's running because it has compile time checks. End of story. [02:07] [laughter] Nikos: [02:10] There's like this huge readme page, changelog of what's happened with TypeScript so I've tried to condense it but if you've got like 10 hours, you can read that in your own time. When I first starting using TypeScript, it was version .5 or something. In version 1.1, they got a four times faster compiler, which is really handy. [02:34] It just means that you can run the code quicker when you've changed something. They add Tuple types, which is...I've forgotten what it is. I think it's like you can say, "I want an array and I want the first item of the array to be an enter string [inaudible] protected, which is nice for people that came from a Java background. [02:57] Anybody in here from a Java background? Do you like protected? Yeah. Version 1.4, they have Type Guards. They have logic that will then do a check on the type and then if you some code in that F loop then it will throw errors based on whether it should never actually be that type. [03:20] Version 1.5, ES6 stuff, tsconfig, kind of like webpack-config, babel-config. You can define all your TypeScript settings. Destructuring, blah, blah, blah. JSX support, which was really controversial because a lot of the guys that don't do React really hated that. [03:37] Have you seen the pull request? Anyone seen that pull request? When TypeScript says, "We're going to support JSX," it's some funny reading. Intersection types. I've forgotten what that is. Local type, yeah. That's a third of the things that are covered in that document. Between 1.6 and 2.1, there's a whole bunch of stuff, which I will read when I'm on a beach or something like that. [04:04] Here's code that I'm using in my game. All this stuff that's moving around on my screen extends or implements this interface. Anyone used interfaces before? Most people. Interface is like a contract that your class must satisfy. If it doesn't satisfy then... [04:27] In my game, things like the space invaders and the player and the destructible scenery, which you won't see in this game, they all have to implement these things. Here, you can see there's a draw method, an update method and it has to have position and dimensions. [04:42] Don't worry, the game doesn't have a white background. This, after the canvas, this is the type. When you're writing your code then you must pass in a type of CanvasRenderingContext2D or whatever type you declare. That's my channel and this is the boring part. [05:03] Now I will need a volunteer to play my game and complete it. You have one chance. Who wants to do it? You have three lives. You just lost one. Hold in spacebar. Spacebar. That one. Yeah. If you want, I could do commentary here. [05:24] You know, he's got three space invaders left and one bullet's going to the next one and another bullet's going towards the space invader and earth is OK. Earth is still OK. Yeah, so now we have another row of space invaders. We have bullets going towards the space invaders and there's two bad guys, big bosses up there. He might be surprised when he hits it and it doesn't explode, which it will do if he hits it two more times. [05:47] He's got two more lives to lose, actually really well. You can go forward as well. It's kind of digressed a bit from the original Space Invaders. [05:54] [laughter] Nikos: [05:59] I really don't like using Photoshop. All these graphics are SVGs that I hand coded. That was character building. Yeah, I'm calling him Gandalf because he shoots out a whole bunch of stuff at once. That yellow thing, yeah. Whoa, yeah. He's actually doing really well. I'm really impressed. He might complete this without...The next level's the last level. [06:35] [audience sighs] Nikos: [06:35] There's no animation framework going on here. What I'm doing is I'm using...every object has a velocity and an update loop. The update loop is based on, when you're doing animations you can request when the next animation frame is ready. Before I was saying I wanted 30 frames per second or 60 frames per second and all this stuff but [inaudible] this update loop thing. [06:59] Collision detection is quite simple. It's just checking for intersection of rectangle. There's a collision rectangle around here so when any bullet hits it, then there's some checks. There's performance things that you can do later on, which I haven't done. Things like octrees and things like that. Anyone heard or octrees? Yeah. [07:22] Octrees are ways of saying, "Don't check collision unless your item is in a certain area." I'll stop talking about it because you'll realize how less I know about that thing. Let's look at the code for this game. [07:36] Do you want to see me complete it first. I'll just show you. One bit of health left. That's challenging but I bet I can do it. It used to be you could press spacebar and you'd get a bullet every frame, which had a nice...made it really easy because if you can imagine 30 bullets per second coming towards the space invaders... [08:01] There we are. OK. Hello. Na-na-na-na-na, you can't get me. La, la, la, la, la. [08:13] [laughter] Nikos: [08:13] That's all you got? Come on. Is that all you got? You do not shoot that stuff at me, man. Is that all you got? Is that all you got? Is that all you got? Yeah. [08:32] [applause] Nikos: [08:32] Any part of the code you guys particularly want to see or understand how it works? It's all vanilla TypeScript. I have webpack. Anyone used webpack? Webpack's a really important module, way of packaging code nowadays. Maybe people, frameworks are using it. Webpack-config is something like this. [09:09] You say, entry to your application, you have an output directory, you have loaders. Loaders look at different types of source and they apply different transforms to them. In this case, we're looking at TypeScript files and we're using a TypeScript loader, which has all the TypeScript compiler bundled into it. [09:27] By the way, how am I doing for time? Fine. We also have a CSS loader, which will then package as a CSS and actually bundles it within the actual JavaScript. There's ways that you can use webpack to bundle the CSS to load it first so you don't get a flash of unstyled content. Webpack then basically looks like this. Really messy but you don't have to worry about that. [09:53] It's just a code for loading things and then it loads all your code inside of itself. In the game, I have an index file, which loads my source. I'm using something that generates an index file and outputs the non-cached version of the JavaScript. This is a plugin that I've used with webpack to do that. I've called it HTMLWebpackPlugin. [10:23] In the game, we have a lot of imports, we have some types here, we have a reference to the canvas, which I get with getElementById and I assign it this type. So then it means I can apply this canvas anywhere in the code and have auto-completion for properties and things. [10:46] For example, in the game objects, I have game object here, which ticks draw method and has to have this CanvasRenderingContext2D. In my space invaders, I have the main class with invader as an abstract class called AbstractInvader, which implements IGameObject. [11:07] You can see another draw method here. If I, for example, change the type or remove the typing here, then it will complain. It should complain. It normally does. You can imagine it is, right? [11:36] All the different types of enemies in that game, they all extend this AbstractInvader, which means when I want to create different types of enemies, It's quite simple because the actual code for each...For example, the light invader, which is the one you saw here, these guys, they have a health of one and I load in the svg and I do something silly here. [12:11] This thing's called probabilityOfShooting. The heavier invaders have a greater probability of shooting and then the heaviest one has an extra method, called shootAhead. So every fourth bullet will have vectors that shoot out like this so you'll have to be really good at trigonometry. [12:28] Trigonometry is quite frustrating in development. When you go to school, X is that direction and all the angles start from there. When you go to game development, Y going up is down and you...yeah, long story. [12:43] Go try and make a game using maths. You have to get really good at radians. See game objects. We have these things called, on the invaders, we have directionVectors and facing degrees number. In the game I'm going to have ships moving around being able to shoot in one direction and move in another direction. [13:15] Vectors are a class that I made. A vector has an X number and a Y number. This public x is pretty cool in TypeScript. That's the same thing as having this.x and then having this.x=x inside that function. That's a TypeScript feature. There's some conversions I have to do between radians and degrees. This is my function for...Yeah, it's all maths. Anyone like maths? Audience Member: [13:46] No. Nikos: [13:47] One, two, three. What else can I teach you? The story mode. All the waves of the space invaders generating them like this. For the first level, we have four of them and then I assign them to this rectangle function. [14:06] I'm still alive. What's going on? These rectangles. The reason I'm using a formations class is that it's quite easy to create each individual space invader by themselves. This is another formation I'm using. It's called triangle formation. I could change to pyramid if somebody preferred. [14:28] You can just create them all like this and then assign it to the triangle function, which is kind of hairy because it is what it is. Audience Member: [14:41] Could you show us the mode where you're shooting a bullet every frame? Nikos: [14:46] Yes. Yes, I can. Where did I do it? In the player class, there's a shoot method and I check to see that the time difference is...Basically I have a rate of fire. I'm just going to delete that and do this. It's compiling. I've got it on watching. Will that compile? This is webpack compiling the source files and that outputs things. [15:38] Who wants to play it now? Here we go boys! [15:44] [laughter] Nikos: [15:44] If you want to go onto YouTube and see how things are made, this is my first coding video. I've got some...I paid for that animation. [16:00] [YouTube video plays] Nikos: [16:00] Something to do with animation. This is my garden out there. This was a rainy day in Scotland, which, if you like to film in rain then it's a good place. It's quite often guaranteed to. It's a good intellectual challenge. There's a lot of interesting algorithms you can come up with when you're making games. [16:25] I got pretty intimate with svg graphics. My images, I hand coded these svgs. Look at the heavy invader, the medium invader. I turned off spectacle. Makes it easier to zoom in. I don't have to worry about Photoshop. I just hand code the stuff using svg paths. [16:50] This is a svg graphic on canvas and these are the bullets. They're just primitive rectangles. Each frame, I wipe the canvas clean and then re-render it. I'm not using double buffering because I don't know if I actually have to do that with this canvas. [17:05] In Java, in games developed, you have to do double buffering. Audience Member: [17:07] So how do you make sure you're getting smooth images? Very smooth. Considering... [17:13] [crosstalk] Audience Member: [17:13] extremely smooth... Nikos: [17:13] [laughs] What I'm doing there is I'm using... [17:22] [laughter] Nikos: [17:27] This is very satisfying actually. Actually app is a JavaScript file and I'm loading in this TypeScript, which compiled. Audience Member: [17:33] Can you make it a bit bigger? Nikos: [17:36] Sorry, yeah. Every game loop, I request an animation frame and this happens when the browser's ready for it. That's how I'm doing it there. A lot of the stuff in the game, I could've done in TypeScript three or four years ago. I'm not actually using hardly any of the more advanced features of it yet. [17:56] Probably with the density wars game, the strategy game, it will hold me to some of the more advanced things because it's going to get really complicated. I couldn't imagine not using TypeScript for a complicated application like that. I just like to have strong typing. [18:14] [applause]