Dear all,
Happy Friday! 🎉
We are changing the pace of our coding challenges a little bit by entering the realm of video games. And as you can probably hint, this new challenge is all about creating a video game.
Now is a good time to join kids and also act on this advice from president Obama: “Don't just buy a new video game, make one!”
Challenge
In this coding challenge you take the role of a young bedroom coder that strives to implement a clone of (perhaps) the most influential game of all time: “Space Invaders”.
You played this game thousand of times at the mall arcade, and now you want to build your special version that you can share with your friends via the big world wide web.
Therefore you plan to write your game using JavaScript and HTML5 canvas!
Of course you plan to write a simplified version of the game. In your game a fleet of unidentified vessels are moving on the screen left and right ... then slowly go down one step before changing direction.
You need to destroy these vessels before they land using plasma bullets (see below). If you destroy all the vessels – you win. If they land – you lose. In either case, the game restarts and gives the player a new try.
How to work with the canvas?
Don’t worry – it is not difficult as this challenge comes with ‘training wheels’: in order to eliminate the intricacies of HTML5 canvas and therefore be able to focus only on the game, a tiny “pseudo-library” is provided to you as starting point.
The library implements a rudimentary game loop, together with a few other helper functions. The library API is inspired by the Processing API and in particular p5.js.
To use the library you either (1) copy it’s entire body in your code before the code you plan to write, or (2) save it in a .js file and include it in your HTML page before the code you plan to write as this:
<canvas id="canvas" tabindex="1" width="800" height="600"></canvas>
<script src="easycanvas.js"></script>
<script>
// Copy the library code here (if you don’t include the above script). Either way, works great!
// Then ... write your game code here, after the helper functions!!!
</script>
*** Note: The code of easyCanvas is provided towards the end of this article.
What’s inside easyCanvas?
There is no better way to see what’s inside easyCanvas than to inspect the code yourself. At a glance, after instantiation, easyCanvas populates the global space (e.g. window object) with a few helper constants and functions. You only need to use these to build your game!
Don’t even try to access the canvas directly... these functions are all you need for this game.
// Clear the canvas with the specified color
function background(color)
// Specify that the next shape won't be filled
function noFill()
// Specify that the next shaped should be filled with specified color
function fill(color)
// Specify that the next shape should not have a stroke stroke
function noStroke()
// Specify the stroke width for the next shape
function strokeWidth(n)
// Specify the stroke color for the next shape
function stroke(color)
// Draw a rectangle
function rect(x, y, width, height)
// Specify the text size of the next drawn text
function textSize(n)
// Write a text at specified coordinates
function text(txt, x, y)
// Returns true if key with specified code is pressed
function keyIsDown(code)
What about the game loop?
Did you pay attention to the statements above? For the implementation of your game you need to use the “game loop pattern”.
Robert Nystrom compares the game loop with the "best thing since slide bread".
He also explain what it is: “A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates the game state, and renders the game.” ...
Sounds fancy? ... don’t be discouraged. All you have to do is to write your logic inside the “loop” function and the easyCanvas “library” will call your function in a loop.
More hints please!
OK ... one more hint and now you should be ready to start working on the game.
Before you start working on the game, try to run and understand the following code.
The code shows how to implement the main mechanics of your game:
<canvas id="canvas" tabindex="1" width="800" height="600"></canvas>
<script src="easycanvas.js"></script>
<script>
// Note: Include the code of easyCanvas here if you don't include the above script
// ===============
// BEGIN USER CODE
// ===============
var xObject = 0;
var xPaddle = width / 2;
textSize(12);
// This function gets called automatically in a `loop` by the `engine`
function loop() {
// Clear the canvas
background("black")
// Draw the moving object
noFill();
strokeWidth(2);
stroke("white");
rect(xObject, 10, 30, 30);
// Draw the paddle
fill("red");
noStroke();
rect(xPaddle, height - 50, 100, 30);
// Display text
fill("white");
text("Use LEFT and RIGHT arrows to move", 10, 580);
// Update object position
xObject++;
// Update paddle on key press
if (keyIsDown(RIGHT_ARROW)) {
xPaddle += 3;
}
else if (keyIsDown(LEFT_ARROW)) {
xPaddle -= 3;
}
else if (keyIsDown(SPACE)) {
}
}
</script>
Bonus points
Try to get extra points in this game jam competition also do the following in your game:
- Separate the update logic from display logic inside your game loop
- Decorate the enemy vessels and your vessels in the most creative way possible (using of course only the rect function)
- Make the stars move
- Improve the game to wow the players!
Note: After you finish the coding, show the game to your kids or family... See what they think about it! Seek their opinion on how to improve the game mechanics or graphics!
Send solutions
Please post your solution (code) as well as screen captures / screencasts in the comments.
If your code is big... share just the main parts via the email and put the rest in an online playground.
Happy coding 👨💻👩💻 !!!
easyCanvas
And now, please see the code of easyCanvas
pseudo-library.
// ===========
// EASY CANVAS
// ===========
// This is an IIFE expression that will 'populate' the global space (e.g. window)
// with a few useful constants and functions to manipulate the canvas easily!
// Requirement: Use ONLY these global / public functions in your game!
(function(canvasId) {
// --- Begin boiler plate and private code for canvas manipulation
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const attributes = {
fill : "black",
stroke : "black",
strokeWidth : 1,
useFill : true,
useStroke : true,
textSize : 12
}
requestAnimationFrame(repeatOften);
function repeatOften() {
// If you define a function called `loop` in your progra
// the engine will call it automatically
if (window.loop)
window.loop();
requestAnimationFrame(repeatOften);
}
// --- Begin boiler plate and private code for keyboard manipulation
const keyPressed = new Map();
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
function handleKeyDown(eventArgs) {
if (!keyPressed.has(eventArgs.keyCode)) {
keyPressed.set(eventArgs.keyCode, eventArgs.keyCode);
}
}
function handleKeyUp(eventArgs) {
if (keyPressed.has(eventArgs.keyCode)) {
keyPressed.delete(eventArgs.keyCode);
}
}
// --- Begin public functions (e.g. added to the global window object)
// --- Feel free to use any of these global constants / functions in your program
// Put a few constants in the global scope
window.width = canvas.width;
window.height = canvas.height;
window.LEFT_ARROW = 37;
window.RIGHT_ARROW = 39;
window.SPACE = 32;
// Clear the canvas with the specified color
window.background = function(color) {
ctx.fillStyle = color;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// Specify that the next shape won't be filled
window.noFill = function() {
attributes.useFill = false;
}
// Specify that the next shaped should be filled with specified color
window.fill = function(color) {
attributes.useFill = true;
attributes.fill = color;
}
// Specify that the next shape should not have a stroke stroke
window.noStroke = function() {
attributes.useStroke = false;
}
// Specify the stroke width for the next shape
window.strokeWidth = function(n) {
attributes.useStroke = true;
attributes.strokeWidth = n;
}
// Specify the stroke color for the next shape
window.stroke = function(color) {
attributes.stroke = color;
}
// Draw a rectangle
window.rect = function(x, y, width, height) {
if (attributes.useFill) {
ctx.fillStyle = attributes.fill;
ctx.fillRect(x, y, width, height);
}
if (attributes.useStroke) {
ctx.lineWidth = attributes.strokeWidth;
ctx.strokeStyle = attributes.stroke;
ctx.strokeRect(x, y, width, height);
}
}
// Specify the text size of the next drawn text
window.textSize = function(n) {
attributes.textSize = n;
}
// Write a text at specified coordinates
window.text = function(txt, x, y) {
ctx.font = attributes.textSize + "px serif";
ctx.fillStyle = attributes.fill;
ctx.fillText(txt, x, y);
}
// Returns true if key with specified code is pressed
window.keyIsDown = function(code) {
if (keyPressed.has(code))
return true;
}
})("canvas");
Notes
This challenge is brought to you by codeguppy.com - the fun recreational coding platform for all ages.
Top comments (0)