snuggy
v2.0.3
Published
A snuggy little HTML canvas game engine.
Readme
Snuggy
A snuggy simple game engine to make games with HTML canvas. Perfect for small games!
Features
- Game loop
- Resources (textures, fonts and sounds)
- Auto sizing canvas (based on screen and aspect ratio)
- Drawing (textures, sprites, text and shapes)
- Render textures (draw your own textures in code!)
- Camera (with smoothing and boundary)
- A few handy util functions
Installation
With a starter template
npx degit patrickswijgman/snuggy-template#main <project-name>
cd <project-name>
npm ci
npm startManually
npm i snuggyUsage
There is no extensive documentation, the example below should be enough to get you started! Also the source code of snuggy is not a lot :wink:
import {
addCameraTransform,
delta,
drawSprite,
drawText,
isInputDown,
loadFont,
loadSound,
loadTexture,
playSound,
resetTransform,
run,
scaleTransform,
setCameraBoundary,
setCameraSmoothing,
setCameraTarget,
translateTransform,
updateCamera,
} from "snuggy";
const enum Type {
NONE = 0,
PLAYER = 1,
ENEMY = 2,
}
// Arbitrary amount, can be less or more depending on your needs.
const MAX_ENTITIES = 2048;
// Entity data (Structure of Arrays).
const type = new Uint8Array(MAX_ENTITIES);
const positionX = new Float32Array(MAX_ENTITIES);
const positionY = new Float32Array(MAX_ENTITIES);
const isActive = new Uint8Array(MAX_ENTITIES);
const isFlipped = new Uint8Array(MAX_ENTITIES);
// Let's reserve the first index for the player.
const PLAYER_IDX = 0;
async function setup() {
const texture = await loadTexture("textures/atlas.png");
const font = await loadFont("fonts/font.ttf", "NameOfFont", 8);
const music = await loadSound("sounds/music.mp3");
playSound(music);
setCameraSmoothing(0.1);
setCameraBoundary(0, 0, 1000, 1000); // Restrict camera to the level size.
// Setup the player.
type[PLAYER_IDX] = Type.PLAYER;
positionX[PLAYER_IDX] = 50;
positionY[PLAYER_IDX] = 50;
isActive[PLAYER_IDX] = 1;
}
// Update and draw each frame.
function update() {
for (let i = 0; i < MAX_ENTITIES; i++) {
if (!isActive[i]) {
continue;
}
// Update entity logic.
switch (type[i]) {
case Type.PLAYER:
{
if (isInputDown("ArrowLeft")) {
positionX[i] -= 1.5 * delta;
isFlipped[i] = 1;
}
if (isInputDown("ArrowRight")) {
positionX[i] += 1.5 * delta;
isFlipped[i] = 0;
}
setCameraTarget(positionX[i], positionY[i]);
}
break;
}
// Transformation matrix operations (AKA the drawing pencil):
// 1. Reset transformations back to x=0, y=0
resetTransform();
// 2. Add camera transform (not needed for e.g. UI elements)
addCameraTransform();
// 3. Translate to entity's position
translateTransform(positionX[i], positionY[i]);
// 4. Flip sprite horizontally if flipped
if (isFlipped[i]) {
scaleTransform(-1, 1);
}
// Render entity.
switch (type[i]) {
case Type.PLAYER:
drawSprite(
texture,
-8, // Pivot point x
-16, // Pivot point y
0, // Frame x
0, // Frame y
16, // Frame width
16, // Frame height
);
break;
}
}
// Call this once every frame, the camera will then pan automatically to the camera's target.
updateCamera();
// Draw UI stuff here for example.
resetTransform();
drawText(font, "Hello World!", 0, 0, "white", "left", "top");
}
run(
// Logical canvas size, will be auto sized and scaled based on screen and aspect ratio.
640,
360,
setup,
update,
);