Recently Deno has been taking the world by storm. Deno is a fast, secure, and open-source runtime environment created as a replacement for Node.js. In this tutorial we will create a basic pong game using the Caviar library which uses WebGPU bindings and resembles most javascript game engines. Feel free to check out caviar here.
you can find the final version in the examples repo right here aswell.
lets get started shall we?
Project Setup
for this project all we'll need is a file hierarchy as such
├── pong
│ ├── src
│ │ ├── scenes
│ │ │ ├── Game.ts
│ ├── main.ts
lets start by creating a basic setup in main.ts
import { World } from 'https://deno.land/x/caviar/mod.ts';
import { Game } from './src/scenes/Game.ts';
const pong = new World({
title: "test",
width: 1300,
height: 800,
resizable: true,
}, [Game]);
await pong.start();
after this we will no longer need to touch main.ts
and we'll direct our attention to the Game.ts
file
Setting up our Components
in the Game.ts
file we'll add the following code to create our first player
import { PICO8, Scene, TextureSprite } from 'https://deno.land/x/caviar/mod.ts';
export class Game extends Scene {
public p1: TextureSprite | undefined;
public setup() {
this.p1 = new TextureSprite(this, 0, 336, {
data: [
".9.",
".9.",
".9.",
],
pixelWidth: 32,
pixelHeight: 32,
palette: PICO8,
})
this.addChild(this.p1);
}
public update() {
}
}
we create a new texture sprite with 3 pixels down and we use the built-in PICO8 palette.
if we run our code using deno run -A --unstable main.ts
we should get a window looking something like
we now create a second player and a ball the same way
export class Game extends Scene {
public ball: TextureSprite | undefined;
public p1: TextureSprite | undefined;
public p2: TextureSprite | undefined;
public setup() {
this.p1 = new TextureSprite(this, 0, 336, {
data: [
".9.",
".9.",
".9.",
],
pixelWidth: 32,
pixelHeight: 32,
palette: PICO8,
});
this.p2 = new TextureSprite(this, 1168, 336, {
data: [
".A.",
".A.",
".A.",
],
pixelWidth: 32,
pixelHeight: 32,
palette: PICO8,
});
this.ball = new TextureSprite(this, 568, 336, {
data: [
"E",
],
pixelWidth: 32,
pixelHeight: 32,
palette: PICO8,
});
this.addChild(this.p1);
this.addChild(this.p2);
this.addChild(this.ball);
}
public update() {
}
}
Movement
to listen for keypresses in Caviar you need to define which keys you want to listen for, do this at the beginning of the setup
method. In this tutorial we'll listen for W
,S
,E
and D
.
...
public setup() {
this.setKeys(['W','S','E','D']);
...
next we'll create a keyDown
method and check for each key and change the player's positions based on the key pressed
...
public keyDown(key: any) {
const p1 = this.p1 as TextureSprite;
const p2 = this.p2 as TextureSprite;
switch (key) {
case "W":
if (p1.y > 25) p1.setY(p1.y - 4);
break;
case "S":
if (p1.y < 700) p1.setY(p1.y + 4);
break;
case "E":
if (p2.y > 25) p2.setY(p2.y - 4);
break;
case "D":
if (p2.y < 700) p2.setY(p2.y + 4);
break;
}
}
Ball Movement
first lets create 2 new properties vx
and vy
for the balls velocity and why not also make a score property aswell
...
public vx = 2;
public vy = 2;
public score: number[] = [0,0];
...
now we add the ball physics to the update function
...
public update() {
const ball = this.ball as TextureSprite;
const p1 = this.p1 as TextureSprite;
const p2 = this.p2 as TextureSprite;
if (ball.y > 25 || ball.y < 10) {
this.vy *= -1;
}
if (
ball.x < p1.x + 32 + 10 &&
ball.y > p1.y &&
ball.y < p1.y + 96
) {
this.vx *= -1.1;
this.vy = Math.floor(Math.random() * 8) - 4;
}
if (
ball.x > p2.x - 10 &&
ball.y > p2.y &&
ball.y < p2.y + p2.height
) {
this.vx *= -1.1;
this.vy = Math.floor(Math.random() * 8) - 4;
}
if (ball.y < 25 || ball.y > 800) {
this.vy *= -1;
}
if (ball.x < 25) {
//p1 side
ball.setX(568);
ball.setY(336);
this.score[1] += 1;
this.vx = 4;
this.vy = 4;
}
if (ball.x > 1168) {
//p2 side
ball.setX(568);
ball.setY(336);
this.score[0] += 1;
this.vx = -4;
this.vy = 4;
}
ball.setX(ball.x + this.vx);
ball.setY(ball.y + this.vy);
}
...
now the game should be working.
Conclusion
Caviar is currently only native (time of writing) but we plan to implement cross platform features in the future. feel free to contribute here
Top comments (0)