-
Notifications
You must be signed in to change notification settings - Fork 32
/
index.html
412 lines (306 loc) · 12.1 KB
/
index.html
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
<!doctype html>
<html>
<head>
<title>Coquette</title>
<link type="text/css" rel="stylesheet" href="resources/main.css" />
<link type="text/css" rel="stylesheet" href="resources/prettify.css" />
<script type="text/javascript" src="resources/prettify.js"></script>
<script src="resources/head.loader.js"></script>
<script type="text/javascript">
head.js("/coquette.js",
"/demos/simple/game.js",
"/demos/spinning-shapes/game.js",
function() {
new SimpleGame(false);
new SpinningShapesGame(false);
});
</script>
</head>
<body onload="prettyPrint()">
<a href="https://github.com/maryrosecook/coquette"><img style="position: absolute; top: 0; left: 0; border: 0;" src="/resources/forkme_left_darkblue_121621.png" alt="Fork me on GitHub"></a>
<h1>Coquette</h1>
<hr/>
<p>A micro framework for JavaScript games.</p>
<p>Handles collision detection, the game update loop, canvas rendering, and keyboard and mouse input.</p>
<h2>Get the code</h2>
<ul>
<li><a href='/coquette-min.js'>Minified</a></li>
<li><a href='/coquette.js'>Development version</a></li>
<li>
<a href='https://github.com/maryrosecook/coquette'>GitHub</a>
</li>
<li><a href='https://npmjs.org/coquette'>npm</a> <code>$ npm install coquette</code></li>
</ul>
<h2>Example</h2>
<div class="demo"><canvas id="simple-canvas"></canvas></body></div>
<p>A game where you, the valiant player, must find a person of indeterminate gender in distress so you can take them away from all this. Click on the game, then press the up arrow key to play.</p>
<p>The HTML below defines a canvas element and loads in Coquette and the game code.</p>
<pre class="prettyprint">
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="../../coquette.js"></script>
<script type="text/javascript" src="game.js"></script>
</head>
<body><canvas id="canvas"></canvas></body>
</html>
</pre>
<p>The game code:</p>
<pre class="prettyprint">
var Game = function() {
this.c = new Coquette(this, "canvas", 500, 150, "#000");
// paramour
this.c.entities.create(Person, { center: { x:250, y:40 }, color:"#099" });
// player
this.c.entities.create(Person, { center: { x:256, y:110 }, color:"#f07",
update: function() {
if (this.c.inputter.isDown(this.c.inputter.UP_ARROW)) {
this.center.y -= 0.4;
}
},
collision: function(other) {
other.center.y = this.center.y; // follow the player
}
});
};
var Person = function(game, settings) {
this.c = game.c;
for (var i in settings) {
this[i] = settings[i];
}
this.size = { x:9, y:9 };
this.draw = function(ctx) {
ctx.fillStyle = settings.color;
ctx.fillRect(this.center.x - this.size.x / 2,
this.center.y - this.size.y / 2,
this.size.x,
this.size.y);
};
};
window.addEventListener('load', function() {
new Game();
});
</pre>
<h2>Demos</h2>
<p>
Five demos are included in this repository:
</p>
<ul>
<li><a href="/demos/spinning-shapes/">/demos/spinning-shapes</a> - an example of collisions between rotated entities.</li>
<li><a href="/demos/racecar/">/demos/racecar</a> - a 2D racing game.</li>
<li><a href="/demos/box2d-physics/">/demos/box2d-physics</a> - a game that uses the Box2D physics engine.</li>
<li><a href="/demos/leftrightspace/">/demos/leftrightspace</a> - a complete game.</li>
<li><a href="/demos/simple/">/demos/simple</a> - the example at the top of the page.</li>
</ul>
<h3>Spinning shapes</h3>
<p>
Coquette handles collision detection for rotated entities.
It also handles mouse (and keyboard) input.
Try dragging a shape in the demo below.
</p>
<div class="demo"><canvas id="spinning-shapes-canvas"></canvas></body></div>
<h3>Racecar</h3>
<p>
A 2D racing game. Click to play.
</p>
<p><a href='/demos/racecar/' style="border:none;">
<img src="/resources/racecar.png" width="500" />
</a></p>
<h3>Box2D physics</h3>
<p>
A game that uses the Box2D physics engine. Click to play.
</p>
<p><a href='demos/box2d-physics/' style="border:none;">
<img src="resources/box2d-physics.png" width="500" />
</a></p>
<br/>
<h2>Reference</h2>
<h3>Instantiate Coquette</h3>
<p>Pass in:</p>
<ul>
<li>Your main game object.</li>
<li>The ID of the canvas element, e.g. <code>"canvas"</code>.</li>
<li>The desired width of the canvas element.</li>
<li>The desired height of the canvas element.</li>
<li>The background colour of your game, e.g. <code>"#000"</code>.</li>
</ul>
<pre class="prettyprint">
var YourGame = function() {
this.c = new Coquette(this, "canvas", 150, 150, "#000");
};
</pre>
<h3>Modules</h3>
<p>When you instantiate Coquette, you get an object that has five modules. You can use these modules in your game.</p>
<h4>Entities</h4>
<p>Keeps track of all the entities in the game: the player, enemies, obstacles.</p>
<h5>Define an entity</h5>
<p>Most entities will have these attributes:</p>
<ul>
<li><code>center</code>: The center of the entity, e.g. <code>{ x: 10, y: 20 }</code></li>
<li><code>size</code>: The size of the entity, e.g. <code>{ x: 50, y: 30 }</code></li>
<li><code>angle</code>: The orientation of the entity in degrees, e.g. <code>30</code></li>
</ul>
<p>And these methods:</p>
<ul>
<li><code>update(timeSinceLastTick)</code>: Called every tick. You should change the state of the entity in this method.</li>
<li><code>draw(canvasCtx)</code>: Called every tick. You should draw the entity upright in this method. The drawing will automatically get rotated to the orientation indicated by <code>angle</code>.</li>
</ul>
<p>For example:</p>
<pre class="prettyprint">
var Block = function(game, settings) {
this.game = game;
this.center = settings.center;
this.size = settings.size;
this.angle = 30;
};
Block.prototype = {
update: function(timeSinceLastTick) {
this.center.x += 0.02 * timeSinceLastTick;
this.center.y += 0.02 * timeSinceLastTick;
},
draw: function(canvasCtx) {
ctx.fillStyle = "black";
ctx.fillRect(this.center.x - this.size.x / 2,
this.center.y - this.size.y / 2,
this.size.x,
this.size.y);
}
};
</pre>
<p>See the Collider section for instructions on enabling collision detection.</p>
<h5>Create an entity</h5>
<p>Call <code>c.entities.create()</code> with:</p>
<ul>
<li>The constructor function of the entity you want to create, e.g. <code>Block</code>.</li>
<li>An optional settings object that will be passed into the constructor, e.g.<br/>
<code>{ center: { x: 5, y: 10 }, size: { x: 10, y: 30 } }</code>.</li>
</ul>
<p>Returns the created entity.</p>
<pre class="prettyprint">
var Block = function(game, settings) {
this.game = game;
this.center = settings.center;
this.size = settings.size;
this.angle = 0;
};
var myBlock = c.entities.create(Block, {
center: { x: 5, y: 10 },
size: { x: 10, y: 30 }
});
</pre>
<h5>Destroy an entity</h5>
<p>Call <code>c.entities.destroy()</code> with:</p>
<ul>
<li>The entity you want to destroy, e.g. <code>myBlock</code>.</li>
</ul>
<pre class="prettyprint">
c.entities.destroy(myBlock);
</pre>
<h5>Get all the entities in the game</h5>
<pre class="prettyprint">
var all = c.entities.all();
</pre>
<h5>Get all the entities of a certain type</h5>
<pre class="prettyprint">
var invaders = c.entities.all(Invader);
</pre>
<h4>Inputter</h4>
<p>Handles keyboard and mouse input from the player.</p>
<h5>Find out if a certain key or mouse button is down</h5>
<pre class="prettyprint">
var leftArrowDown = c.inputter.isDown(c.inputter.LEFT_ARROW);
var rightMouseDown = c.inputter.isDown(c.inputter.RIGHT_MOUSE);
</pre>
<h5>Find out if a certain key or mouse button is pressed</h5>
<p>This returns true for the tick following the key going down. In subsequent ticks, it returns false until the key is released and pressed down again.</p>
<pre class="prettyprint">
var leftArrowPressed = c.inputter.isPressed(c.inputter.LEFT_ARROW);
var rightMousePressed = c.inputter.isPressed(c.inputter.RIGHT_MOUSE);
</pre>
<h5>Run a function every time the mouse is moved</h5>
<pre class="prettyprint">
c.inputter.bindMouseMove(function(position) {
console.log("The mouse is at", position.x, position.y);
});
</pre>
<p><code>position</code> is relative to the game canvas. If the mouse pointer is in the top left corner, position will be <code>{ x: 0, y: 0 }</code>.</p>
<h5>Get the current mouse position</h5>
<pre class="prettyprint">
var position = c.inputter.getMousePosition();
</pre>
<p><code>position</code> is relative to the game canvas. If the mouse pointer is in the top left corner, position will be <code>{ x: 0, y: 0 }</code>.</p>
<h4>Renderer</h4>
<p>Holds the canvas drawing context. Calls <code>draw()</code> on the main game object and all the game entities.</p>
<h5>Draw an entity</h5>
<p>See the Define an Entity sub-section of the Entities section.</p>
<h5>Get the canvas drawing context</h5>
<pre class="prettyprint">
var ctx = c.renderer.getCtx();
ctx.fillStyle = "#f00";
ctx.fillRect(0, 0, 10, 10);
</pre>
<h5>Set the order that entities are drawn</h5>
<p>
When you create your entities, set an integer <code>zindex</code> attribute on them. An entity with a higher <code>zindex</code> will get drawn on top of an entity with a lower <code>zindex</code>. The default <code>zindex</code> is <code>0</code>.
</p>
<pre class="prettyprint">
var BackgroundTile = function() {
this.zindex = -1;
};
var Player = function() {
this.zindex = 0;
};
c.entities.create(BackgroundTile, {});
c.entities.create(Player, {}); // drawn on top
</pre>
<h5>Move the view</h5>
<p>
You can use <code>c.renderer.setViewCenter()</code> to move the view around the world. For example, to make the view follow a specific object, you could call <code>setViewCenter(specificObj.center)</code> in the <code>update()</code> function of your game:
</p>
<pre class="prettyprint">
var Game = function() {
var c = new Coquette(this, "canvas", 500, 500, "#000");
var specialObject = c.entities.create(SpecialObject, {});
this.update = function() {
c.renderer.setViewCenter(specialObject.center);
};
};
</pre>
<h4>Collider</h4>
<p>Reports when entities collide.</p>
<h5>Entity setup</h5>
<p>To make an entity support collisions, put these attributes on it:</p>
<ul>
<li><code>center</code>: The center of the entity, e.g. <code>{ x: 10, y: 20 }</code>.</li>
<li><code>size</code>: The size of the entity, e.g. <code>{ x: 50, y: 30 }</code>.</li>
<li><code>boundingBox</code>: The shape that best approximates the shape of the entity, either <code>c.collider.RECTANGLE</code> or <code>c.collider.CIRCLE</code>.</li>
<li><code>angle</code>: The orientation of the entity in degrees, e.g. <code>30</code>.</li>
</ul>
<p>And, optionally, this method:</p>
<ul>
<li><code>collision(other)</code>: Called when the entity collides with another entity. Takes <code>other</code>, the other entity involved in the collision.</li>
</ul>
<p>For example:</p>
<pre class="prettyprint">
var Player = function() {
this.center = { x: 10, y: 20 };
this.size = { x: 50, y: 50 };
this.boundingBox = c.collider.CIRCLE;
this.angle = 0;
};
Player.prototype = {
collision: function(other) {
console.log("Ow,", other, "hit me.");
}
};
</pre>
<h2>Licence</h2>
<p>
The <a href='http://github.com/maryrosecook/coquette'>code</a> is open source, under the <a href='http://en.wikipedia.org/wiki/MIT_License'>MIT licence</a>.
</p>
<hr/>
<div class="footer">
<a href="http://maryrosecook.com">Mary Rose Cook</a>
</div>
</body>
</html>