So this post might be the first of several canvas examples, this one will be on a basic space shooter game. This is a project that I threw together in just a few hours, so it is not really a complete game at the time of this writing at least. Still I had some fun with this one, and I might get around to putting more time into the project at some point in the future if this new collection of posts gets some traction.
So then in this canvas example display objects are things like this player ship, enemy ships, and shots that are being fired from the player or enemy ships. So these objects have values like x and y that represent the current location of the object in the canvas matrix, but also values like the current heading.
So the file starts off with the Base Display Object class. Here I define a constructor function that will be used for all Display Objects in the canvas example.
The base display object class of course has properties like x and y but also a heading in radians, and a value that reflects the current pixels per second rate of movement. This kind of game is a real time rather than turn base system game so it is best to move the display objects by way of the system clock rather than just stepping by a delta each frame tick.
So in this canvas example all display objects have these properties they have a 2d position in the canvas as well as a heading and speed in pixels per second. This class also has many methods that are common for all display objects such as the move object method that accepts a time arguments and then moves the object by its current heading and pixels per second value.
The Shot class is one of two classes that I have that extend the functionality of the Disp Class. A Shot Class is used with A Ship Class an as the name implies represents a shot from a ship that can hurt another ship.
For now there is not much to this class I am just adding a damage property that is the amount of damage that the shot will cause to a ship, and a lifespan property that will serve as away to flag the shot for removal if it has just been around for to long.
Here I have the Ship Class that is used for both the Player Ship as well as enemy ships. Here I add a lot of properties that have to do with shooting shot and getting hit by a shot, as well as a custom draw method that overrides the main generic draw method used for other display objects that just displays a white square.
For now I am using this class as a way to also deal with a collection of shots. I am doing this as a way to help keep things simpler, but if I where to continue working on this example I might want to have a shot collection class, as well as a similar class for collections of ships. However for this example at least I decided to have an updateShots method in the Ship class, and for the Ship class to also work as a shot collection class by storing an array of Shot Class instances.
The update method of the ship class supersedes the Disp class update method so it is called first, but within the body of that update method I am still calling the main Disp class update method. The reason why is I still want the same rules to apply for all display objects when it comes to movement. Alter that I call the update shots method.
A state machine is a way to break an application such as this space shooter game into separate states, where each state is a method or collection of methods that define a set of logic that is to run for different states of the application or game play. For example A game might have a loading state, title screen state, menu state, game state, pause state, and game over state and it might not end there.
In this canvas example there is a main game state, as well as an initialization state, and a game over state. I did not put an awful lot of time into this canvas example, but if I where to continue working on this there would be a title state, as well as several other states that have to do with various menus to say the least.
In here I also parked some logic that has to do with what might eventually be a Ship Collection class. I needed at least some logic for that, and it had to be parked somewhere.
In the events.js file I worked out a few event handlers for moving the player ship and continuing when the game is over. Nothing major for this canvas example just a crude yet functional solution for accepting user input and using it to move the player ship.
So then there is also the renderer.js file. Here I have the code that will draw to the canvas. This returns a main draw method that will render one of many other draw methods depending on the current state of the game.
It also have one helper draw method of sorts that is called just once in the main draw method, but methods like that could be used in many such draw method. So for now it is just an example of keeping this a little more fine grain by pulling it into a stand alone method.
There is more that comes to mind, such as pulling the draw methods that I have in the classes out of the classes and place it here. Making the method at least a little more functional by making it so that the state object is passed as an argument to the factory function and make it so the factory function needs to be called in the state machine. However when it comes to making a first alpha state of a project those kinds of things take a back seat. The real concern here is if i am starting to make something that people will actually want to play or not.
Then there is the main app of the canvas game example. Here I am using requestAnimatuonFrame to create the loop, and call the States tick method and the draw method for each frame over and over again.
It goes without saying that I made this very basic, and it seems to work okay this way. The reason why is that I am figuring how much time has went by in the state machine, and then passing that value to the update methods that I am using for the display objects.
I would design this kind of loop all kinds of different ways. Ways where I would move display objects by just steeping by deltas each frame. Ways where I would use some other means to go about limiting the frame rate, but testing if a certain amount of time has elapses here in the main app loop, and then call my update and draw methods. However I have come to find that this kind of approach seems to work good when it comes to a real time space shooter type game.
Other games could be event driven and when it comes to that kind of game I might not need a main app loop at all, however that f course is not the case here, so no matter what i am always going to need something like this, at least for the game state anyway.
This canvas example is still pretty basic, If I get around to it I might put a little more time and effort into it. I often create projects like this where I get to the point where it is just starting to feel like a finished product, but stop and move on to the next thing. I would like to break that cycle some time, but only with something that is worth the investment.
A better user interface would be nice, and some animations, transitions and sound would be a nice touch. Still this was a good exercise for me, when it comes to working out how to structure a canvas example that is something not so basic. I think I will like to make a few more posts like this one, and put a great deal more effort into canvas examples that are worth more time and energy.