This will be a post on a cannon shoot type game that will be the subject of yet another one of my canvas example posts. The idea here is to just keep making one canvas example after another until I manage to make one or two that might prove to be worth a higher investment of time if people show an interest in one. There are many games like this on the open Internet such as kitten cannon where the basic mechanics are than the player sets an angle and initial power value and then that is used to determine how far the object will go in a game map.
Anyway so this kind of game is just one of many different types of games that come to mind, and I figured that I should make at least one cannon shoot type game for this series of posts. Keep in mind that I rushed with this one, and there is much about it that I am not happy with, at least at the time of this writing anyway. I have a lot of these examples and thus far there are a few others that I would say have higher priority when it comes to improving the quality of the example.
Still I do have the basic idea of this kind of game working for what it is worth. There is just having a display object shoot off from a starting location and the initial heading and power can be set by a simple user interface. There is much more that could be added in terms of additional features beyond that, but I think the code could use some major clean up first.
1 - The Utils module of this canvas example
To start off with in this section I will be going over the custom utility library that I worked out for this canvas example. This module contains a custom tailor set of copy and past usual suspects for these kinds of projects. Considering the nature of the project, I am going to want methods like the distance formula and some methods that have to do with angles. I also want some additional methods that I will be using in the game module, but also potential outside of it as well if I where to continue working on this example.
1.1 - The start of the module, and the get canvas relative method.
I went with just an object literal pattern rather than an IIFE for the utils module. This will more or less work out okay with this module as all of the methods here are public.
The first method I added to my utils module is a method that is a usual copy and past suspect that has to do with getting a canvas relative position when a canvas is clicked or touched. This is of course something that I am going to want to do one way or another when to comes to any kind of canvas project that works with input from a user in the from of mouse or touch events.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// UTILS
var utils = {};
utils.getCanvasRelative = function (e) {
var canvas = e.target,
bx = canvas.getBoundingClientRect();
var x = (e.changedTouches ? e.changedTouches[0].clientX : e.clientX) - bx.left,
y = (e.changedTouches ? e.changedTouches[0].clientY : e.clientY) - bx.top;
return {
x: x,
y: y,
bx: bx
};
};
1.2 - Bounding box collision detection
This project is going to involve at least maybe one or two areas in the canvas that will act as a fire button of sorts. I could just use the distance formula if it is a circle like area, but I desired to make bounding box part of the utility library so I will use that for the fire button at least if not elsewhere.
I added the distance formula as part of the module. This is what I will be using to just find the distance between two points. This can be used with a little additional code to set the initial power of the cannon and therefor the shot by comparing the distance from a certain point to a certain max length.
I also have a few methods that have to do with mathematical modulo and working with angles. The modulo method is just another way of getting a remainder that compared to what is used in the core javaScript syntax. The other methods here have to do with normalizing angles and angular distance that are from a project called angles.js.
2 - The Game module for this cannon shoot canvas example
Now that I got the utility module out of the way it is not time to go over the game module for this cannon shoot canvas game example. This module is what I will be using in my main JavaScript file to create a game state, update it, as well as attaching some event handers to mutate state that way.
In addition to methods and a state object it is also worth mentioning that there is more than one mode for this game module. That is that I made a state machine of sorts as part of this module where there three modes, and there are update methods and or event handlers for each o them. There is the aim mode where the player can set the heading and power level of the cannon. Then there is the fired mode where the shot is currently in motion, and finally there is the over mode that the game state will be in when the shot hits the ground.
2.1 - The start of the module and create new state method
So I start off the module with an IIFE, and at the top of the function expression there is my create new state method. This methods creates and returns a new game state that can then be passed to other public methods of this module that are used to mutate and update that state, by way of user input and update methods.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// GAME
var game = (function () {
var createNewState = function (opt) {
var state = {
canvas: canvas,
ctx: ctx = canvas.getContext('2d'),
mode: 'aim', // 'aim', 'fired, and 'over' modes
userDown: false,
lastTick: newDate(),
time: 0,
offset: {
x: 0,
y: 0
},
shot: {
x: 0,
y: 0,
pps: 64, // pixels per second
power: 1,
plps: 1 / 10, // power loss per second
startHeading: 0,
heading: 0
},
cannon: {
heading: 0,
power: 1,
sx: 0,
sy: 0,
len: 100
}
};
setCannon(state, -1, 1);
return state;
};
2.2 - Set cannon and set shot method.
These methods are used to set the values of the cannon object, and shot object of a game state object created with the create new state method. The set cannon method just sets the given heading in radians and power level between 0 and 1. However it also sets the current sx and sy position based on the current heading that was just set. This position and other values are then what is used to set the starting position, heading, and power of the shot object when fired.
I then have a set shot method that will set the heading and pixels per second based n the start heading and power of the shot. The start heading as you might expect is set
1
2
3
4
5
6
7
8
9
10
11
12
13
var setCannon = function (state, heading, power) {
2.4 - Events attachment and user action methods for each mode that uses one
So here I have my user action method that when called will return an event hander that can then be passed to add event listener in the main.js file. When calling the user action method a state object can be passed as the first argument that will be used inside the body of the event handler thanks to closure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Events
var eventTypeMaps = {
mousedown: 'start',
mousemove: 'move',
mouseup: 'end',
touchstart: 'start',
touchmove: 'move',
touchend: 'end'
};
var userAction = function (state) {
returnfunction (e) {
var pos = utils.getCanvasRelative(e),
myType = eventTypeMaps[e.type];
if (myType === 'start') {
state.userDown = true;
}
if (myType === 'end') {
state.userDown = false;
}
var userActionMode = userAction[state.mode] || {},
modeAction = userActionMode[myType];
if (modeAction) {
modeAction(pos, state, e);
}
};
};
userAction.aim = {
start: function (pos, state, e) {},
move: function (pos, state, e) {
var cannon = state.cannon,
canvas = state.canvas;
if (state.userDown) {
var d = utils.distance(pos.x, pos.y, 0, canvas.height);
2.5 - The main update method, mode update methods, and the public API.
So I have my user action method that can be used to attach event handers for mouse and touch events that are used to mutate the state object by way of user interaction. Now I need a similar kind of structure to do the same by way of a repeating update loop.
Now that I have a utility library and a module that has my game logic I now want another module that has methods that can be used to draw to the canvas with the current state of a state object created and mutated by the game module. I find that it is important to separate this from the game logic as a way to separate concerns and reduce the complexity of the game module.