Skip to content

Creating a Game

In the Quick Start guide, we learned how to set up a very simple project using dill pixel. Now let’s go through the process of creating a basic game.

Custom Splash Screen

  1. Create an Splash.ts file in the src folder. This will be displayed when the game starts. Similar to a Scene, there are added(), enter() and exit() methods to control how the screen is revealed and hidden. It also contains a update() method that can be used to update the progress of the loading screen, and a handleLoadProgress() method that can be used to update the progress of the loading screen. For simplicity’s sake we’re just creating a green background and adding a title that can be clicked to take us to the next screen:

    src/Splash.ts
    import { FlexContainer, SceneTransition } from 'dill-pixel';
    import { gsap } from 'gsap';
    import { Sprite, Text, Texture } from 'pixi.js';
    export default class Splash extends SceneTransition {
    private _labelPercent: Text;
    private _textContainer: FlexContainer;
    private _bg: Sprite;
    private _percent: number = 0;
    constructor() {
    super(true);
    }
    added() {
    this._bg = this.add.sprite({
    asset: Texture.WHITE,
    tint: 0x1f2937,
    width: this.app.size.width,
    height: this.app.size.height,
    anchor: 0.5,
    });
    this._textContainer = this.add.flexContainer({
    gap: 10,
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    });
    this._textContainer.add.text({
    text: 'Loading...',
    style: {
    fontWeight: 'bold',
    fontSize: 36,
    fill: 'white',
    dropShadow: true,
    },
    });
    this._labelPercent = this._textContainer.add.text({
    style: {
    fontWeight: 'bold',
    fontSize: 72,
    fill: 'white',
    dropShadow: true,
    },
    });
    }
    async exit() {
    // ensure percentage completes
    await gsap.to(this, { _percent: 100, duration: 1, ease: 'sine.out' });
    return gsap.to(this, { alpha: 0, duration: 1, ease: 'sine.in' });
    }
    update() {
    this._labelPercent.text = `${Math.round(this._percent)}%`;
    this._labelPercent.resolution = 2;
    this._textContainer.layout();
    }
    resize() {
    this._bg.setSize(this.app.size.width, this.app.size.height);
    }
    protected override handleLoadProgress(progress: number) {
    super.handleLoadProgress(progress);
    gsap.to(this, { _percent: Math.ceil(this.progress * 100), duration: 1, ease: 'sine.out' });
    }
    }
  2. In ./dill-pixel-config.ts, import your Splash class:

    import Splash from '@/Splash';

    and set the set the splash property to

    { ... // other config
    splash: {
    view: Splash
    }
    ...
    }

    your dill-pixel.config.ts should now look like this:

    dill-pixel.config.ts
    import Splash from '@/Splash';
    import { defineActions, defineButtons, defineConfig, defineContexts, defineControls } from 'dill-pixel';
    /** Default template */
    // TODO: Add custom contexts here if desired
    // by default, we use the default contexts
    export const contexts = defineContexts(); // e.g.
    // TODO: Add actions here
    // examples below
    export const actions = defineActions(contexts, {
    //pause: { context: '*' },
    //close: { context: ['menu', 'popup'] },
    //back: { context: ['menu'] },
    //next: { context: ['menu'] },
    //select: { context: ['menu', 'default'] },
    //show_popup: { context: '*' },
    });
    /** Don't touch */
    export type Contexts = (typeof contexts)[number];
    export type ActionTypes = keyof typeof actions;
    /** Don't touch */
    // TODO: Add buttons here
    const buttons = defineButtons();
    // TODO: Add controls here
    export const controls = defineControls(actions, buttons);
    /** End of Default Template */
    /** User config */
    export type Data = {
    dill: string;
    pixel: number;
    };
    export const config = defineConfig<Data>({
    id: 'Test',
    defaultSceneLoadMethod: 'immediate',
    defaultScene: 'start',
    splash: {
    view: Splash,
    },
    useSpine: true,
    showStats: true,
    useVoiceover: false,
    data: {
    initial: {
    dill: 'pixel',
    pixel: 0,
    },
    backupKeys: [],
    backupAll: false,
    },
    actions,
    input: {
    controls,
    },
    assets: {
    manifest: './assets.json',
    preload: {
    bundles: ['required'],
    },
    background: {
    bundles: ['audio'],
    },
    },
    plugins: [],
    storageAdapters: [],
    });
    /** End of User config */
  3. in index.html, you can remove the loader.css import, as we’re no longer using it.

Create Scenes

Game Scene

Create a Game.ts file in the scenes folder. This will be the main game scene with a few elements: an image, a title, a message, and a button.

Add the id and debug label to the scene

export const id = 'game';
export const debug = {
label: 'Game',
};

Clicking on the image will trigger a short animation and increment a counter. Clicking the button will take us back to StartScene.

Note that in the destroy() method we’re cleaning up the gsap animations.

src/scenes/Game.ts
import BaseScene from '@/scenes/BaseScene';
import { FONT_KUMBH_SANS } from '@/utils/Constants';
import { FlexContainer } from 'dill-pixel';
export const id = 'game';
export const debug = {
label: 'Game',
};
/**
* Game scene
* so you can access the application's properties and methods in all scenes extending this one
* it also allows you to add custom logic to the scene that can be shared across scenes
*/
export default class Game extends BaseScene {
private _layout: FlexContainer;
initialize() {
super.initialize();
// a temporary layout container
this._layout = this.add.flexContainer({
flexDirection: 'column',
gap: 10,
alignItems: 'center',
justifyContent: 'center',
});
// some title text
this._layout.add.text({
text: 'My',
style: { fontSize: 18, fontFamily: FONT_KUMBH_SANS, fill: 0xffffff },
});
// from src/assets.json
this._layout.add.sprite({ asset: 'wordmark.svg', scale: 1 });
this._layout.add.text({
text: 'GAME',
style: { fontFamily: FONT_KUMBH_SANS, fontWeight: 'bold', fill: 0xffffff },
});
}
async enter() {
return this.animate({ alpha: 1, duration: 1, ease: 'sine.out' });
}
async exit() {
return this.animate({ alpha: 0, duration: 0.5, ease: 'sine.in' });
}
}