DEV Community

Adrian
Adrian

Posted on

Coding Hints. Part IV: Game Development

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

Music and Sound Effects

Other

Multi-scene games

Alt Text

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:

Drawing Layers

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');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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 by clear() 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');
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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

let img1 = img`
    . . . . . . . . . . . . . . . .
    . . . . . . . 7 7 7 . . . . . .
    . . . . . . . 7 7 7 . . . . . .
    . . . . . 7 7 7 7 7 7 7 . . . .
    . . . . 2 2 7 7 7 7 7 2 2 . . .
    . . . 2 5 2 2 7 7 7 2 2 5 2 . .
    . . 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    . . 2 5 2 2 5 2 2 2 5 2 2 5 2 .
    . . 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    . . . 2 2 5 2 2 5 2 2 5 2 2 . .
    . . . . 2 2 2 2 2 2 2 2 2 . . .
    . . . . . 2 2 5 2 2 5 2 . . . .
    . . . . . 2 2 2 2 2 2 2 . . . .
    . . . . . . 2 2 5 2 2 . . . . .
    . . . . . . . 2 2 2 . . . . . .
    . . . . . . . . . . . . . . . .
`;

noSmooth();
image(img1, 250, 300, img1.width * 3, img1.height * 3);
Enter fullscreen mode Exit fullscreen mode

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.

sprite(img`
    . . . . . . . . . . . . . . . .
    . . . . . . 4 4 5 . . . . . . .
    . 8 8 8 8 8 4 4 4 8 8 8 8 8 . .
    . . . . . . . f . . . . . . . .
    . . . . . 8 8 8 8 8 . . . . . .
    . . . . 8 1 1 8 1 1 8 . . . . .
    . . . . 8 1 f 8 f 1 8 . . . . .
    . . 8 . 8 8 8 2 8 8 8 . 8 . . .
    . . 8 8 8 2 8 8 8 2 8 8 8 . . .
    . . . . 8 8 2 2 2 8 8 . . . . .
    . . . . 8 8 8 8 8 8 8 . . . . .
    . . . . 8 8 8 8 8 8 8 . . . . .
    . . . . 8 . . . . . 8 . . . . .
    . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . .
`, 10);
Enter fullscreen mode Exit fullscreen mode

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.

// Note: Shark images are from Microsoft MakeCode Arcade
// https://arcade.makecode.com/

var shark1 = img`
    . . . . . . . . . . . . . c c f f f . . . . . . . . . . . . . .
    . . . . . . . . . . . c c d d b c f . . . . . . . . . . . . . .
    . . . . . . . . . . c c d d b b f . . . . . . . . . . . . . . .
    . . . . . . . . . . f c c b b c f . . . . . . . . . . . . . . .
    . . . . . f f f f f c c c c c c f f . . . . . . . . . c c c . .
    . . . f f b b b b b b b c b b b b c f f f . . . . c c b b c . .
    . . f b b b b b b b b c b c b b b b c c c f f . c d b b c . . .
    f f b b b b b b f f b b c b c b b b c c c c c f c d b b f . . .
    f b c b b b 1 1 f f 1 b c b b b b b c c c c c f f b b f . . . .
    f b b b 1 1 1 1 1 1 1 1 b b b b b c c c c c c c b b c f . . . .
    . f b 1 1 1 3 3 c c 1 1 b b b b c c c c c c c c c c c f . . . .
    . . f c c c 3 1 c 1 1 1 b b b c c c c c b d b f f b b c f . . .
    . . . f c 1 3 c 1 1 1 c b b b f c d d d d c c . . f b b f . . .
    . . . . f c c c 1 1 1 f b d b b c c d c c . . . . . f b b f . .
    . . . . . . . . c c c c f c d b b c c . . . . . . . . f f f . .
    . . . . . . . . . . . . . f f f f f . . . . . . . . . . . . . .
`;

var shark2 = img`
    . . . . . . . . . . . . . c c f f f . . . . . . . . . . . . . .
    . . . . . . . . . . . . c d d b b f . . . . . . . . . . . . . .
    . . . . . . . . . . . c d d b b f . . . . . . . . . . . . . . .
    . . . . . . . . . . f c c b b c f . . . . . . . . . . . . c c c
    . . . . f f f f f f c c c c c c f f . . . . . . . . . c c b b c
    . . f f b b b b b b b b b b b b b c f f f . . . . . c d b b c .
    f f b b b b b b b b b c b c b b b b c c c f f . . c d d b b f .
    f b c b b b b b f f b b c b c b b b c c c c c f f f d b b f . .
    f b b b 1 1 1 1 f f 1 b c b c b b b c c c c c c c b b b c f . .
    . f b 1 1 1 1 1 1 1 1 b b b b b b c c c c c c c c c b c c f . .
    . . f c c c 3 3 c c 1 1 b b b b c c c c c c c c f f f b b c f .
    . . . f c 1 3 1 c 1 1 1 b b b c c c c c b d b c . . . f b b f .
    . . . . f 3 3 c 1 1 1 c b b b f d d d d d c c . . . . . f b b f
    . . . . . f f 1 1 1 1 f b d b b f d d c c . . . . . . . . f f f
    . . . . . . . c c c c c f b d b b f c . . . . . . . . . . . . .
    . . . . . . . . . . . . . f f f f f . . . . . . . . . . . . . .
`;

var shark3 = img`
    . . . . . . . . . . . . . . c f f f . . . . . . . . . . . . . .
    . . . . . . . . . . . . c c d d b f . . . . . . . . . . . . . .
    . . . . . . . . . . . c b d d b f f . . . . . . . . . c c c . .
    . . . . . . . . . . f c c b b c f . . . . . . . . . c b b c . .
    . . . f f f f f f f c c c c c c f f . . . . . . . c d b c . . .
    . f f c b b b b b b b b b b b b b c f f f . . . . c d b f . . .
    f c b b b b b b b b b c b b b b b b c c c f f . c d b f . . . .
    f b c b b b b f f b b b c b c b b b c c c c c f f d c f . . . .
    f b b 1 1 1 1 f f b b b c b c b b b c c c c c c b b c f . . . .
    . f b 1 1 1 1 1 1 1 1 b b c b b b c c c c c c c c b b c f . . .
    . . f c c c 3 3 c b 1 1 b b b b c c c c c c c f f f b b f . . .
    . . . f c 1 3 1 c 1 1 1 b b b c c c c c b d b c . . f b b f . .
    . . . . f 3 3 c 1 1 1 c b b c c d d d d d b c . . . . f f f . .
    . . . . . f f 1 1 1 1 f d b b c c d d b c c . . . . . . . . . .
    . . . . . . . c c c c c f d b b b f c c . . . . . . . . . . . .
    . . . . . . . . . . . . . f f f f f . . . . . . . . . . . . . .
`;

var shark4 = img`
    . . . . . . . . . . . . . c c f f f . . . . . . . . . . . . . .
    . . . . . . . . . . . . c d d b b f . . . . . . . . . . . . . .
    . . . . . . . . . . . c d d b b f . . . . . . . . . . . . . . .
    . . . . . . . . . . f c c b b c f . . . . . . . . . . . . c c c
    . . . . f f f f f f c c c c c c f f . . . . . . . . . c c b b c
    . . f f b b b b b b b b b b b b b c f f f . . . . . c d b b c .
    f f b b b b b b b b b c b c b b b b c c c f f . . c d d b b f .
    f b c b b b b b f f b b c b c b b b c c c c c f f f d b b f . .
    f b b b 1 1 1 1 f f 1 b c b c b b b c c c c c c c b b b c f . .
    . f b 1 1 1 1 1 1 1 1 b b b b b b c c c c c c c c c b c c f . .
    . . f c c c 3 3 c c 1 1 b b b b c c c c c c c c f f f b b c f .
    . . . f c 1 3 1 c 1 1 1 b b b c c c c c b d b c . . . f b b f .
    . . . . f 3 3 c 1 1 1 c b b b f d d d d d c c . . . . . f b b f
    . . . . . f f 1 1 1 1 f b d b b f d d c c . . . . . . . . f f f
    . . . . . . . c c c c c f b d b b f c . . . . . . . . . . . . .
    . . . . . . . . . . . . . f f f f f . . . . . . . . . . . . . .
`;

sprite([shark1, shark2, shark3, shark4], 400, 300, 2);
Enter fullscreen mode Exit fullscreen mode

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.

let ship1 = img`
    . . . . . . . . . . . . . . . .
    8 8 1 . . . . . . . . . . . . .
    2 2 2 2 . . . . . . . . . . . .
    2 2 2 2 . . 9 9 9 9 . . . . . .
    8 8 8 8 8 9 9 9 9 9 9 . . . . .
    8 8 8 8 8 9 9 9 9 9 9 9 . . . .
    2 2 2 2 2 9 9 9 9 9 9 9 2 . . .
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    . 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    4 4 4 2 2 2 2 2 2 2 2 2 2 2 2 2
    4 4 4 4 2 2 8 8 8 8 8 8 8 2 2 .
    4 4 . . . 8 8 8 8 8 8 8 . . . .
    . . . . 8 8 8 8 8 8 8 . . . . .
    . . . 8 8 8 8 8 8 8 . . . . . .
    . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . .
`;

let ship2 = img`
    . . . . . . . . . . . . . . . .
    8 8 1 . . . . . . . . . . . . .
    2 2 2 2 . . . . . . . . . . . .
    2 2 2 2 . . 9 9 9 9 . . . . . .
    8 8 8 8 8 9 9 9 9 9 9 . . . . .
    8 8 8 8 8 9 9 9 9 9 9 9 . . . .
    2 2 2 2 2 9 9 9 9 9 9 9 2 . . .
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    4 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    . 4 4 2 2 2 2 2 2 2 2 2 2 2 2 2
    4 4 4 4 2 2 8 8 8 8 8 8 8 2 2 .
    . 4 4 . . 8 8 8 8 8 8 8 . . . .
    4 4 . . 8 8 8 8 8 8 8 . . . . .
    . . . 8 8 8 8 8 8 8 . . . . . .
    . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . .
`;

let shipLand1 = img`
    . . . . . . . 8 8 1 . . . . . .
    . . . . . . . 8 2 2 . . . . . .
    . . . . . . . 8 . . . . . . . .
    . . . . . 9 9 9 9 9 . . . . . .
    . . . . 9 9 9 9 9 9 9 . . . . .
    . . . 9 9 9 9 9 9 9 9 9 . . . .
    . . 2 9 9 9 9 9 9 9 9 9 2 . . .
    . 2 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    . 2 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    . . 8 8 . . . . . . . . 8 8 . .
    . . 8 8 . . . . . . . . 8 8 . .
    . . 8 8 . . . . . . . . 8 8 . .
    . 8 8 8 8 . . . . . . 8 8 8 8 .
    . 8 8 8 8 . . . . . . 8 8 8 8 .
`;

let shipLand2 = img`
    . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . .
    . . . . . 9 9 9 9 9 . . . . . .
    . . . . 9 9 9 9 9 9 9 . . . . .
    . . . 9 9 9 9 9 9 9 9 9 . . . .
    . . 2 9 9 9 9 9 9 9 9 9 2 . . .
    . 2 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    . 2 2 2 2 2 2 2 2 2 2 2 2 2 2 .
    . . 8 8 . 4 4 4 4 4 4 . 8 8 . .
    . . 8 8 . . 4 4 4 4 . . 8 8 . .
    . . 8 8 . . . 4 4 . . . 8 8 . .
    . 8 8 8 8 . . . . . . 8 8 8 8 .
    . 8 8 8 8 . . . . . . 8 8 8 8 .
`;

let oShip = { 
    Flying : [ship1, ship2],
    LandingDown : [shipLand1],
    LandingUp : [shipLand2] 
};

sprite(oShip, 40, 100, 3);
Enter fullscreen mode Exit fullscreen mode

Custom palette for custom sprites

If your program required different colors, you can define a custom palette using setPalette.

// Define a monochrome palette
setPalette(["", "Brown"]);

let pattern = `
1 1 1 1 1 1 1 1
. . . . . 1 . .
. . . . . 1 . .
. . . . . 1 . .
1 1 1 1 1 1 1 1
. . 1 . . . . .
. . 1 . . . . .
. . 1 . . . . .
`;

let imgBrick = img(pattern);

noSmooth();

for(var row = 0; row < 50; row++)
{
    for(var col = 0; col < 30; col++)
    {
        image(imgBrick, 300 + row * 8, 10 + col * 8);
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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.

background('Summer');

for(let i = 0; i < 10; i++)
{
    let flower = sprite(img`
    . . . . . . . . . . . . . . . .
        . . . . . . . 5 5 . . . . . . .
        . . . . 5 5 . 5 5 . 5 5 . . . .
        . . . . 5 5 5 5 5 5 5 5 . . . .
        . . 5 5 . 5 f e f e 5 . 5 5 . .
        . . 5 5 5 f e f e f e 5 5 5 . .
        . . . 5 f e f e f e f e 5 . . .
        . 5 5 5 e f e f e f e f 5 5 5 .
        . 5 5 5 f e f e f e f e 5 5 5 .
        . . . 5 e f e f e f e f 5 . . .
        . . 5 5 5 e f e f e f 5 5 5 . .
        . . 5 5 . 5 e f e f 5 . 5 5 . .
        . . . . 5 5 5 5 5 5 5 5 . . . .
        . . . . 5 5 . 5 5 . 5 5 . . . .
        . . . . . . . 5 5 . . . . . . .
        . . . . . . . . . . . . . . . .
    `, random(width), random(-height, 0), 3);

    flower.velocity.y = random(1, 3);

    flower.rotationSpeed = 2;
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

However, later one, you can change the animation of that sprite using the .show method:

player.show('run');
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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
let btnTrophy = sprite('CandyTrophy', 400, 300, 1);

btnTrophy.onMousePressed = btnTrophy_onMousePressed;
btnTrophy.onMouseOver = btn_onMouseOver;
btnTrophy.onMouseOut = btn_onMouseOut;

function btnTrophy_onMousePressed(sender)
{
    sound('female_congratulations');    
}

function btn_onMouseOver(sender)
{
    sender.scale = 1.1;
}

function btn_onMouseOut(sender)
{
    sender.scale = 1;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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).

let score = 0;

for(let i = 0; i < 10; i++)
{
    let coin = sprite('coin.bronze', random(100, 700), random(50, 550), 0.5);

    // Make the coin autoremove itself
    coin.life = randomInt(100, 300);

    coin.onMousePressed = coin_onMousePressed;
}

function coin_onMousePressed(sender)
{
    sender.remove();
    score++;
}
Enter fullscreen mode Exit fullscreen mode

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++;
}
Enter fullscreen mode Exit fullscreen mode

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
let player = sprite('game.happy', 400, 300, 0.5);
let coins = new Group();

for(let i = 0; i < 10; i++)
{
    let coin = sprite('coin', random(100, 700), random(50, 550), 0.5);

    // add coin to the group
    coins.add(coin);
}

function loop()
{
    player.x = mouseX;
    player.y = mouseY;

    // check collision against the group
    player.collide(coins, onCollision)
}

function onCollision(player, coin)
{
    // remove coin from the group
    coins.remove(coin);

    coin.velocity.y = -10;
    coin.life = 100;
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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');
Enter fullscreen mode Exit fullscreen mode

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)

let circleX = 400;
let circleY = 300;
let circleR = 200;

function loop()
{
    clear();

    let collide = collisionPointCircle(mouseX, mouseY, circleX, circleY, circleR);
    stroke(collide ? "red" : "black");

    circle(circleX, circleY, circleR);
}
Enter fullscreen mode Exit fullscreen mode

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)

let lineX1 = 300;
let lineY1 = 400;
let lineX2 = 500;
let lineY2 = 200;

function loop()
{
    clear();

    let collide = collisionPointLine(mouseX, mouseY, lineX1, lineY1, lineX2, lineY2);
    stroke(collide ? "red" : "black");

    line(lineX1, lineY1, lineX2, lineY2);
}
Enter fullscreen mode Exit fullscreen mode

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)

let rectX = 250;
let rectY = 200;
let rectWidth = 300;
let rectHeight = 200;

function loop()
{
    clear();

    let collide = collisionPointRect(mouseX, mouseY, rectX, rectY, rectWidth, rectHeight);
    stroke(collide ? "red" : "black");

    rect(rectX, rectY, rectWidth, rectHeight);
}
Enter fullscreen mode Exit fullscreen mode

Detect collision between two circles

Use the following instruction to detect collisions between two circles:

collisionCircleCircle(circle1X, circle1Y, circle1R, circle2X, circle2Y, circle2R)

let circle1R = 50;
let circle2X = 400;
let circle2Y = 300; 
let circle2R = 100;

function loop()
{
    clear();

    let circle1X = mouseX;
    let circle1Y = mouseY;

    let collide = collisionCircleCircle(circle1X, circle1Y, circle1R, circle2X, circle2Y, circle2R)
    stroke(collide ? "red" : "black");

    circle(circle1X, circle1Y, circle1R);
    circle(circle2X, circle2Y, circle2R);
}
Enter fullscreen mode Exit fullscreen mode

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)

let circleR = 50;
let rectX = 250;
let rectY = 200;
let rectWidth = 300;
let rectHeight = 200;

function loop()
{
    clear();

    let circleX = mouseX;
    let circleY = mouseY;

    let collide = collisionCircleRect(circleX, circleY, circleR, rectX, rectY, rectWidth, rectHeight);
    stroke(collide ? "red" : "black");

    circle(circleX, circleY, circleR);
    rect(rectX, rectY, rectWidth, rectHeight);
}
Enter fullscreen mode Exit fullscreen mode

Detect collision between two rectangles

Use the following instruction to detect collision between two rectangles:

collisionRectRect(rect1X, rect1Y, rect1Width, rect1Height, rect2X, rect2Y, rect2Width, rect2Height)

let rect1X = 0;
let rect1Y = 0;
let rect1Width = 100;
let rect1Height = 50;

let rect2X = 250;
let rect2Y = 200;
let rect2Width = 300;
let rect2Height = 200;

function loop()
{
    clear();

    rect1X = mouseX;
    rect1Y = mouseY;

    let collide = collisionRectRect(rect1X, rect1Y, rect1Width, rect1Height, rect2X, rect2Y, rect2Width, rect2Height);
    stroke(collide ? "red" : "black");

    rect(rect1X, rect1Y, rect1Width, rect1Height);
    rect(rect2X, rect2Y, rect2Width, rect2Height);
}
Enter fullscreen mode Exit fullscreen mode

Detect collision between two lines

Use this instruction to detect collisions between two lines:

collisionLineLine(x1, y1, x2, y2, x3, y3, x4, y4)

let x1 = 400;
let y1 = 300;
let x2 = 0;
let y2 = 0;

let x3 = 300;
let y3 = 400;
let x4 = 500;
let y4 = 200;

function loop()
{
    clear();

    x2 = mouseX;
    y2 = mouseY;

    let collide = collisionLineLine(x1, y1, x2, y2, x3, y3, x4, y4);
    stroke(collide ? "Red" : "Black");

    line(x1, y1, x2, y2);
    line(x3, y3, x4, y4);
}

function mouseClicked()
{
    x1 = mouseX;
    y1 = mouseY;
}
Enter fullscreen mode Exit fullscreen mode

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)

let x1 = 400;
let y1 = 300;

let x3 = 350;
let y3 = 250;
let w = 300;
let h = 100;

function loop()
{
    clear();

    let x2 = mouseX;
    let y2 = mouseY;

    let v = collisionLineRect(x1, y1, x2, y2, x3, y3, w, h);
    stroke(v ? "Red" : "Black");

    line(x1, y1, x2, y2);
    rect(x3, y3, w, h);
}

function mouseClicked()
{
    x1 = mouseX;
    y1 = mouseY;
}

Enter fullscreen mode Exit fullscreen mode

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()

background('Road');

let p = sprite('adventure_girl.idle', 400, 400, 0.5);

function loop()
{
    p.show("idle");

    if (keyIsDown(LEFT_ARROW)) 
    { 
        p.mirrorX(-1);
        p.x -= 10;
        p.show("run");
    }
    else if (keyIsDown(RIGHT_ARROW)) 
    { 
        p.mirrorX(1);
        p.x += 10;
        p.show("run");
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

background('Field');
textSize(40);

let plane = sprite('plane.fly', 50, 100, 0.3);
let textX = -280;

function loop()
{
    textX++;
    displayBanner();

    plane.x++;
}

function displayBanner()
{
    clear();
    fill("White");
    rect(textX - 10, 80, 250, 50);
    fill("Black");
    text("Hello, World!", textX, 120);
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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");
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Inside the "Congrats" scene, you can retrieve this passed data in the following way:

function enter()
{
    let score = sceneArgs;
    text(score, 400, 300);
}
Enter fullscreen mode Exit fullscreen mode

Passing a complex structure to "Congrats" scene

let data = {
    score : 1000,
    time : 10,
    bonusPoints : 100
}

showScene("Congrats", data);
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

Further reading

For a deeper understanding on how to work with sprites in codeguppy.com, please consult these tutorials:


codeguppy.com is using the p5.play library as the main game engine. Advanded users can consult directly this library for further details. Custom sprites are based on the Microsoft MakeCode Arcade format.


This article is part of a series of mini-articles containing JavaScript coding hints applicable to codeguppy.com environment.

Top comments (0)