Coding hints IV: JavaScript Game Development with codeguppy.com
Game development is extremely easy and fun with codeguppy.com. The system comes with built-in background images, sprites, music and sound effects to allow you to focus on the code rather than searching for assets.
Layers and Background Images
Sprites
- Loading built-in sprites
- Loading custom sprites
- Loading animated custom sprites
- Set sprite position
- Moving sprites automatically
- Mirroring Sprites
- Sprite rotation
- Rotate sprites automatically
- Drawing depth
- Changing animations
- Mouse events on sprites
- Hiding sprites
- Removing sprites
- Sprite Collisions
- Sprite Groups
Music and Sound Effects
Other
Multi-scene games
Drawing Layers
codeguppy.com has a layered drawing architecture. There are up to 5 drawing layers on top of the canvas at any time as shown in the following diagram:
The engine combines automatically all the layers and displays the final image on the screen.
Setting Background Images
The background
command was also presented in the "Drawing" section as a way to set the background color of the canvas, like this:
background('LightBlue');
However, background command can do more than just setting a plain color as a background.
Using the same function, you can set any image from the codeguppy.com library as background:
background('Summer');
💡 To set the background to an image, open the "Backgrounds" palette, and drag and drop an image in the code area. The system will write the appropriate code for you.
The
background
commands sets the image in the Background layer as presented in the above diagram. In this way the background image won't be erased or altered byclear()
instruction or shape drawing instructions or even sprites.
Sprites
Sprites are small images, often animated, that you can load and manipulate through the code. Sprites are an essential ingredient of a succesful game.
codeguppy.com contains a big library of built-in sprites, and in the same time it offers the user the ability to define custom sprites.
Loading Built-in Sprites
You can load any sprite from the built-in library using the sprite
command.
Loading a sprite
The sprite
instruction will load the built-in sprite plane
and place it in the middle of the screen.
background('Summer');
sprite('plane');
💡 Open the Sprites palette and browse all the included built-in sprites. When you find one that you like, drag and drop it in the code editor and the system will write the code automatically.
Loading and positioning a sprite
background('Summer');
sprite('plane', 400, 200);
Loading and scaling a sprite
In the following code snippet, the sprite plane
is scalled to 0.5
before being placed in the middle of the screen
background('Summer');
sprite('plane', 0.5);
Loading, positioning and scaling of a sprite
In the following code snippet, the sprite plane
is scalled to 0.5
before being placed in the middle of the screen
background('Summer');
sprite('plane', 400, 150, 0.5);
Loading a particular animation of a sprite
For multi-animation sprites, you can specify the default animation at load time by including it in the same string as the sprite name using a .
symbol (e.g. plane.shoot
)
💡 You can discover what animations are supported by each sprite, by hovering the mouse over sprites in the "Sprites" palette. Check the information provided in the tooltip.
background('Summer');
sprite('plane.shoot', 400, 150, 0.5);
Note: For sprites with multiple animations, you can also change the displayed animation later-on using the sprite
.show()
method.
Loading custom sprites
For games that required custom graphics, users can define additional custom sprites directly in the code. codeguppy.com uses the Microsoft MakeCode Arcade format for custom sprites with up to 16 colors.
From text to images
Use img
in a string template, or as a function, to convert a custom-sprite text to an image:
From images to sprites
Custom sprites can also be loaded using the sprite
command. In this way you can manipulate them like the rest of built-in sprites:
Animated custom sprites
A custom sprite can also be animated. If you need animated sprites, then you need to create multiple frame images for each sprite:
Custom sprites with multiple animations
You can even pack multiple animations in a custom sprite. This help you change later on the animations using the sprite .show()
method:
Custom palette for custom sprites
If your program required different colors, you can define a custom palette using setPalette
.
Note: You can obtain the current palette at any time using the getPalette()
function.
Manipulating sprite properties
At runtime, the custom sprites are indistinguishable from the built-in sprites. No matter how you loaded / created the sprite, you can manipulate it in the same way through the code.
The sprite
command is returning a reference to an object on which you can invoke methods and properties.
Set sprite position
The sprite
command is returning a reference to a sprite object. Use the .x
and .y
properties to update the sprite position on the screen.
let player = sprite('adventure_girl.idle', 400, 300, 0.5);
player.x = 100;
player.y = 100;
Moving sprites automatically
Instead of changing the .x
and .y
coordinates yourself, you can let the engine move the sprite automatically on x or y axes by specifying a value for the appropriate .velocity
.
let plane = sprite('plane.fly', 0, 100, 0.5);
plane.velocity.x = 1;
Mirroring Sprites
Sometimes you need to flip a sprite on either .x
axis or .y
axis.
To mirror a sprite use the .mirror
method with -1
as argument. To mirror it to the original direction use 1
as argument.
plane.mirrorX(-1);
Sprite rotation
In certain games and programs, you may want to rotate your sprites at an arbitrary angle. You can do this using the .rotation
property which allow you to specify a rotation angle.
Rotate sprites automatically
If you want the sprite to rotate automatically for an indefinite time, you can put it on autorotate by giving a greater than zero value to .rotationSpeed
property:
Drawing depth
Normally, newly added sprites are drawn on top of the previous ones.
To control which sprite is drawn on top, and which one is drawn behind, you can make use of the .depth
property. Sprites with lower depth are drawn behind the ones with higher depth.
You can also combine sprites with classical shaped drawn using graphical APIs (circle
, rect
, etc.).
If you want sprites to appear behind the graphical plane, make sure you give sprites a negative depth, otherwise they will be drawn on top of the graphical plane.
Changing animations
If the sprite you selected contains multiple animations, you can specify what animation you want to display initially by adding the animation name with a .
in the string of the first parameter:
let player = sprite('adventure_girl.idle', 400, 300, 0.5);
However, later one, you can change the animation of that sprite using the .show
method:
player.show('run');
💡 Please check carefully the animations supported by a sprite by hovering over the sprite thumbnail in the Sprites palette.
Mouse events on sprites
You can detect mouse clicks on sprites by assigning an event handler (e.g. function) to the following sprite properties:
.onMousePressed
.onMouseReleased
.onMouseOver
.onMouseOut
Hiding sprites
You can hide a sprite in two ways:
- Setting the
.visible
property to false - Setting the
.x
and / or.y
coordinates outside of the visible canvas
let p = sprite('adventure_girl.idle', 400, 300, 0.5);
function mouseClicked()
{
p.visible = !p.visible;
}
Removing sprites
To permanently remove a sprite from the program, use the .remove()
method on the sprite. This is useful for sprites just as destroyed enemies, collected items, etc.
You can also make a sprite auto-remove after a certain number of frames using the .life
property. This is useful for objects such as bullets, rockets, etc. that you shoot and forget about them. Collectibles can make use of this property. By default this property has value -1
(disabled).
Sprite Collisions
There are 4 different methods to verify if sprites are colliding:
sprite.collide(target, callback);
sprite.displace(target, callback);
sprite.overlap(target, callback);
sprite.bounce(target, callback);
When called, some of these methods are automatically displacing the sprites, others are impacting their trajectories. They all return a Boolean indicating if the collision happened.
Experiment with these methods to discover their behaviors!
Parameters:
target
– this is a reference to the other sprite or group of sprites (more about groups later)callback
– this is optional, but useful in some cases. Callback is a function with the following signature, that gets called automatically in case of collision:
function onCollide(spr, target)
{
score++;
}
Note: Another way to check collisions between sprites, or between sprites and other shapes is by using the following shape collision functions.
Sprite groups
In games with multiple sprites of the same kind, it is sometimes useful to group various sprites in a single group created with new Group()
Main methods of a group are:
.add(sprite)
- Add a sprite to the group.remove(sprite)
– Removes a sprite from the group.clear()
- Removes sprites from group. Does not remove sprites from program..contains(sprite)
- Check if the specified sprite is in the group
Note: Certain methods, such as sprite collision methods can operate on an entire group of sprites, rather than on a single sprite (as explained on the previous page).
Background Music
Play music named Rainbow
music('Rainbow');
Note: If any music was playing before, the music
instruction interrupts that before playing the new music.
Play music named "Fun Background" at volume 0.1
music('Fun Background', 0.1);
💡 Use the "Music and Sounds" palette to discover music. When you find something that you like, drag and drop the song in the code area. The system will write the appropriate code for you.
Sound Effects
Play sound zap1
sound('zap1');
Note: The system plays in parallel all sounds triggered with the sound
command.
💡 Use the "Music and Sounds" palette to discover sound effects. When you find something that you like, drag and drop the song in the code area. The system will write the appropriate code for you.
Collisions between shapes
💡 If your game is using only sprites, then we recommend you to use sprite collision methods.
However, if you are not using sprites, or if you use sprites in combination with regular shapes, you can use the following methods to detect collisions. They take as arguments the parameters of the two shapes and return true
if the two shapes collide.
Note: For convenience, some instructions are define twice, with the arguments describing the shaped inversed.
Detect collision between point and circle
Use any of these instructions to detect the collision between a point and a circle:
collisionPointCircle(pointX, pointY, circleX, circleY, circleR)
collisionCirclePoint(circleX, circleY, circleR, pointX, pointY)
Detect collision between point and line
Use any of these two instructions to detect the collision between a point and a line:
collisionPointLine(pointX, pointY, lineX1, lineY1, lineX2, lineY2)
collisionLinePoint(lineX1, lineY1, lineX2, lineY2, pointX, pointY)
Detect collision between a point and a rectangle
Use any of the following two instructions to detect collisions between a point and a rectangle:
collisionPointRect(pointX, pointY, rectX, rectY, rectWidth, rectHeight)
collisionRectPoint(rectX, rectY, rectWidth, rectHeight, pointX, pointY)
Detect collision between two circles
Use the following instruction to detect collisions between two circles:
collisionCircleCircle(circle1X, circle1Y, circle1R, circle2X, circle2Y, circle2R)
Detect collision between a circle and a rectangle
Use any of the following two instructions to detect collisions between a circle and a rectangle:
collisionCircleRect(circleX, circleY, circleR, rectX, rectY, rectWidth, rectHeight)
collisionRectCircle(rectX, rectY, rectWidth, rectHeight, circleX, circleY, circleR)
Detect collision between two rectangles
Use the following instruction to detect collision between two rectangles:
collisionRectRect(rect1X, rect1Y, rect1Width, rect1Height, rect2X, rect2Y, rect2Width, rect2Height)
Detect collision between two lines
Use this instruction to detect collisions between two lines:
collisionLineLine(x1, y1, x2, y2, x3, y3, x4, y4)
Detect collision between a line and a rectangle
Use any of the following two instructions to detect collisions between a line and a rectangle:
collisionLineRect(x1, y1, x2, y2, x3, y3, w, h)
collisionRectLine(x3, y3, w, h, x1, y1, x2, y2)
The Game Loop
In virtually all games, you have to define a "game loop" - a special function that continously gets the user input, updates the game state and renders the game graphics.
In codeguppy.com you can easily implement the "game loop" using the loop()
function. This is the same function described on the "Drawings" page in the "Animations" section. All you have to do is to define this function in your code, and the codeguppy.com engine will run it for you up to 60 times per second! There is no need to call it yourself.
If your game is using only sprites
To make your character move on the screen, read the keyboard and update character state (e.g. position) inside the loop()
If your games is using sprites and shapes
If your game uses also classical shapes, then you need to re-render those inside the loop
function. Sprites are rendered automatically when you change their properties.
Think of your games as a series of frames! Start by drawing the first frame, then erase it and draw the second frame in a slightly different position, and so on!
Preloading Assets
codeguppy.com engine automatically scans your code prior to execution to identify what assets (e.g. background, sprites, music, sound effects) need to be loaded. The engine identify these by looking into the corrsponding background
, sprite
, music
and sound
commands you used.
If these commands don't specify the asset as a constant, then you need to preload the required assets using the preload
function. Just list all required assets comma separated:
preload("adventure_girl", "knight", 'Fun Background');
myMusic = "Fun" + " " + "Background";
music(myMusic);
createPlayer("adventure_girl");
createPlayer("knight");
function createPlayer(spriteName)
{
return sprite(spriteName, random(width), 300, 0.5);
}
Multi-Scene Games
Support for building multi-scene games is one of the main highlight of codeguppy.com environment!
By adding more scenes to a game, you're game will appear more polished. In the typical game, you may want to create an "Intro" scene to explain how to play the game, the actual "Game" scene and the "Congrats" scene that shows the congratulations / score after you finish the game.
Each scene is created in a new code page. Make sure you name the code pages appropriately since we need to refer to them later.
Showing a scene
When the program starts it will always run the first scene you define. To show other scene you need to use the showScene
method:
function mouseClicked()
{
showScene("Game");
}
The enter event
If your scene contains a function named enter
, then the engine will automatically run this function when a scene is entered / shown. In a typical game a scene may be shown more than once during the game. For instance the "Game" scene will be shown each time the user restarts the game from the "Intro" scene.
This gives you the ability to set the scene state appropriately.
Note: The loose code outside functions is executed just once per scene. Successive displays of the scene won't trigger that code anymore.
background("Red");
let score;
function enter()
{
score = 0;
}
Passing data to a scene
In certain cases, it is useful to pass data to a scene via the showScene
method. For instance you can pass the game options from the "Intro" scene to the "Game" scene, or the player score from the "Game" scene to the "Congrats" scene.
Passing a number (e.g. score) to "Congrats" scene
showScene("Congrats", 1000);
Inside the "Congrats" scene, you can retrieve this passed data in the following way:
function enter()
{
let score = sceneArgs;
text(score, 400, 300);
}
Passing a complex structure to "Congrats" scene
let data = {
score : 1000,
time : 10,
bonusPoints : 100
}
showScene("Congrats", data);
Inside the "Congrats" scene, you can retrieve this passed data in the following way:
function enter()
{
let data = sceneArgs;
text("Score: " + data.score, 400, 300);
text("Time: " + data.time, 400, 320);
text("Bonus Points: " + data.bonusPoints, 400, 340);
}
Further reading
For a deeper understanding on how to work with sprites in codeguppy.com, please consult these tutorials:
- Working with built-in sprites playground and tutorial
- Working with custom sprites playground and tutorial
This article is part of a series of mini-articles containing JavaScript coding hints applicable to codeguppy.com environment:
- Coding Hints. Part I: JavaScript syntax
- Coding Hints. Part II: Drawing
- Coding Hints. Part III: User Input
- Coding Hints. Part IV: Game Development
- Coding Hints. Part V: Other hints
About codeguppy
CodeGuppy is a FREE coding platform for schools and independent learners. If you don't have yet an account with codeguppy.com, you can start by visiting the registration page and sign-up for a free account. Registered users can access tons of fun projects!
Follow @codeguppy on Twitter for coding tips and news about codeguppy platform. For more information, please feel free to contact us.