create/gen paint

 
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { create: create });

//  Dimensions
var previewSize = 6;
var spriteWidth = 8;
var spriteHeight = 8;

//  UI
var ui;
var paletteArrow;
var coords;
var widthText;
var widthUp;
var widthDown;
var heightText;
var heightUp;
var heightDown;
var previewSizeUp;
var previewSizeDown;
var previewSizeText;
var nextFrameButton;
var prevFrameButton;
var frameText;
var saveIcon;
var saveText;
var rightCol = 532;

//  Drawing Area
var canvas;
var canvasBG;
var canvasGrid;
var canvasSprite;
var canvasZoom = 32;

//  Sprite Preview
var preview;
var previewBG;

//  Keys + Mouse
var keys;
var isDown = false;
var isErase = false;

//  Palette
var ci = 0;
var color = 0;
var palette = 0;
var pmap = [0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'];

//  Data
var frame = 1;
var frames = [[]];

var data;

function resetData() {

    data = [];

    for (var y = 0; y < spriteHeight; y++)
    {
        var a = [];

        for (var x = 0; x < spriteWidth; x++)
        {
            a.push('.');
        }

        data.push(a);
    }

}

function copyToData(src) {

    data = [];

    for (var y = 0; y < src.length; y++)
    {
        var a = [];

        for (var x = 0; x < src[y].length; x++)
        {
            a.push(src[y][x]);
        }

        data.push(a);
    }

}

function cloneData() {

    var clone = [];

    for (var y = 0; y < data.length; y++)
    {
        var a = [];

        for (var x = 0; x < data[y].length; x++)
        {
            var v = data[y][x];
            a.push(v);
        }

        clone.push(a);
    }

    return clone;

}

function createUI() {

    game.create.grid('uiGrid', 32 * 16, 32, 32, 32, 'rgba(255,255,255,0.5)');

    //  Create some icons
    var arrow = [
        '  22  ',
        ' 2222 ',
        '222222',
        '  22  ',
        '  22  '
    ];

    var plus = [
        '2222222',
        '2.....2',
        '2..2..2',
        '2.222.2',
        '2..2..2',
        '2.....2',
        '2222222'
    ];

    var minus = [
        '2222222',
        '2.....2',
        '2.....2',
        '2.222.2',
        '2.....2',
        '2.....2',
        '2222222'
    ];

    var disk = [
        'DDDDDDDDDD',
        'DED1111DED',
        'DED1111DDD',
        'DEDDDDDDED',
        'DEEEEEEEED',
        'DEFFFFFFED',
        'DEFF222FED',
        'DEFF222FED',
        'DEFF222FED',
        'DDDDDDDDDD'
    ];

    game.create.texture('arrow', arrow, 2);
    game.create.texture('plus', plus, 3);
    game.create.texture('minus', minus, 3);
    game.create.texture('save', disk, 4);

    ui = game.make.bitmapData(800, 32);

    drawPalette();

    ui.addToWorld();

    var style = { font: "20px Courier", fill: "#fff", tabs: 80 };

    coords = game.add.text(rightCol, 8, "X: 0\tY: 0", style);

    game.add.text(12, 9, pmap.join("\t"), { font: "14px Courier", fill: "#000", tabs: 32 });
    game.add.text(11, 8, pmap.join("\t"), { font: "14px Courier", fill: "#ffff00", tabs: 32 });

    paletteArrow = game.add.sprite(8, 36, 'arrow');

    //  Change width

    widthText = game.add.text(rightCol, 60, "Width: " + spriteWidth, style);

    widthUp = game.add.sprite(rightCol + 180, 60, 'plus');
    widthUp.name = 'width';
    widthUp.inputEnabled = true;
    widthUp.input.useHandCursor = true;
    widthUp.events.onInputDown.add(increaseSize, this);

    widthDown = game.add.sprite(rightCol + 220, 60, 'minus');
    widthDown.name = 'width';
    widthDown.inputEnabled = true;
    widthDown.input.useHandCursor = true;
    widthDown.events.onInputDown.add(decreaseSize, this);

    //  Change height

    heightText = game.add.text(rightCol, 100, "Height: " + spriteHeight, style);

    heightUp = game.add.sprite(rightCol + 180, 100, 'plus');
    heightUp.name = 'height';
    heightUp.inputEnabled = true;
    heightUp.input.useHandCursor = true;
    heightUp.events.onInputDown.add(increaseSize, this);

    heightDown = game.add.sprite(rightCol + 220, 100, 'minus');
    heightDown.name = 'height';
    heightDown.inputEnabled = true;
    heightDown.input.useHandCursor = true;
    heightDown.events.onInputDown.add(decreaseSize, this);

    //  Change frame

    frameText = game.add.text(rightCol, 160, "Frame: " + frame + " / " + frames.length, style);

    nextFrameButton = game.add.sprite(rightCol + 180, 160, 'plus');
    nextFrameButton.inputEnabled = true;
    nextFrameButton.input.useHandCursor = true;
    nextFrameButton.events.onInputDown.add(nextFrame, this);

    prevFrameButton = game.add.sprite(rightCol + 220, 160, 'minus');
    prevFrameButton.inputEnabled = true;
    prevFrameButton.input.useHandCursor = true;
    prevFrameButton.events.onInputDown.add(prevFrame, this);

    //  Change preview

    previewSizeText = game.add.text(rightCol, 220, "Size: " + previewSize, style);

    previewSizeUp = game.add.sprite(rightCol + 180, 220, 'plus');
    previewSizeUp.inputEnabled = true;
    previewSizeUp.input.useHandCursor = true;
    previewSizeUp.events.onInputDown.add(increasePreviewSize, this);

    previewSizeDown = game.add.sprite(rightCol + 220, 220, 'minus');
    previewSizeDown.inputEnabled = true;
    previewSizeDown.input.useHandCursor = true;
    previewSizeDown.events.onInputDown.add(decreasePreviewSize, this);

    //  Save Icon

    saveText = game.add.text(rightCol, 520, "Saved to console.log", style);
    saveText.alpha = 0;

    saveIcon = game.add.sprite(750, 550, 'save');
    saveIcon.inputEnabled = true;
    saveIcon.input.useHandCursor = true;
    saveIcon.events.onInputDown.add(save, this);

}

function createDrawingArea() {

    game.create.grid('drawingGrid', 16 * canvasZoom, 16 * canvasZoom, canvasZoom, canvasZoom, 'rgba(0,191,243,0.8)');

    canvas = game.make.bitmapData(spriteWidth * canvasZoom, spriteHeight * canvasZoom);
    canvasBG = game.make.bitmapData(canvas.width + 2, canvas.height + 2);

    canvasBG.rect(0, 0, canvasBG.width, canvasBG.height, '#fff');
    canvasBG.rect(1, 1, canvasBG.width - 2, canvasBG.height - 2, '#3f5c67');

    var x = 10;
    var y = 64;

    canvasBG.addToWorld(x, y);
    canvasSprite = canvas.addToWorld(x + 1, y + 1);
    canvasGrid = game.add.sprite(x + 1, y + 1, 'drawingGrid');
    canvasGrid.crop(new Phaser.Rectangle(0, 0, spriteWidth * canvasZoom, spriteHeight * canvasZoom));

}

function resizeCanvas() {

    canvas.resize(spriteWidth * canvasZoom, spriteHeight * canvasZoom);
    canvasBG.resize(canvas.width + 2, canvas.height + 2);

    canvasBG.rect(0, 0, canvasBG.width, canvasBG.height, '#fff');
    canvasBG.rect(1, 1, canvasBG.width - 2, canvasBG.height - 2, '#3f5c67');

    canvasGrid.crop(new Phaser.Rectangle(0, 0, spriteWidth * canvasZoom, spriteHeight * canvasZoom));
    
}

function createPreview() {

    preview = game.make.bitmapData(spriteWidth * previewSize, spriteHeight * previewSize);
    previewBG = game.make.bitmapData(preview.width + 2, preview.height + 2);

    previewBG.rect(0, 0, previewBG.width, previewBG.height, '#fff');
    previewBG.rect(1, 1, previewBG.width - 2, previewBG.height - 2, '#3f5c67');

    var x = rightCol;
    var y = 250;

    previewBG.addToWorld(x, y);
    preview.addToWorld(x + 1, y + 1);

}

function resizePreview() {

    preview.resize(spriteWidth * previewSize, spriteHeight * previewSize);
    previewBG.resize(preview.width + 2, preview.height + 2);

    previewBG.rect(0, 0, previewBG.width, previewBG.height, '#fff');
    previewBG.rect(1, 1, previewBG.width - 2, previewBG.height - 2, '#3f5c67');
    
}

function refresh() {

    //  Update both the Canvas and Preview
    canvas.clear();
    preview.clear();

    for (var y = 0; y < spriteHeight; y++)
    {
        for (var x = 0; x < spriteWidth; x++)
        {
            var i = data[y][x];

            if (i !== '.' && i !== ' ')
            {
                color = game.create.palettes[palette][i];
                canvas.rect(x * canvasZoom, y * canvasZoom, canvasZoom, canvasZoom, color);
                preview.rect(x * previewSize, y * previewSize, previewSize, previewSize, color);
            }
        }
    }

}

function createEventListeners() {

    keys = game.input.keyboard.addKeys(
        {
            'erase': Phaser.Keyboard.X,
            'save': Phaser.Keyboard.S,
            'up': Phaser.Keyboard.UP,
            'down': Phaser.Keyboard.DOWN,
            'left': Phaser.Keyboard.LEFT,
            'right': Phaser.Keyboard.RIGHT,
            'changePalette': Phaser.Keyboard.P,
            'nextFrame': Phaser.Keyboard.PERIOD,
            'prevFrame': Phaser.Keyboard.COMMA,
            'color0': Phaser.Keyboard.ZERO,
            'color1': Phaser.Keyboard.ONE,
            'color2': Phaser.Keyboard.TWO,
            'color3': Phaser.Keyboard.THREE,
            'color4': Phaser.Keyboard.FOUR,
            'color5': Phaser.Keyboard.FIVE,
            'color6': Phaser.Keyboard.SIX,
            'color7': Phaser.Keyboard.SEVEN,
            'color8': Phaser.Keyboard.EIGHT,
            'color9': Phaser.Keyboard.NINE,
            'color10': Phaser.Keyboard.A,
            'color11': Phaser.Keyboard.B,
            'color12': Phaser.Keyboard.C,
            'color13': Phaser.Keyboard.D,
            'color14': Phaser.Keyboard.E,
            'color15': Phaser.Keyboard.F
        }
    );

    keys.erase.onDown.add(cls, this);
    keys.save.onDown.add(save, this);
    keys.up.onDown.add(shiftUp, this);
    keys.down.onDown.add(shiftDown, this);
    keys.left.onDown.add(shiftLeft, this);
    keys.right.onDown.add(shiftRight, this);
    keys.changePalette.onDown.add(changePalette, this);
    keys.nextFrame.onDown.add(nextFrame, this);
    keys.prevFrame.onDown.add(prevFrame, this);

    for (var i = 0; i < 16; i++)
    {
        keys['color' + i].onDown.add(setColor, this, 0, i);
    }

    game.input.mouse.capture = true;
    game.input.onDown.add(onDown, this);
    game.input.onUp.add(onUp, this);
    game.input.addMoveCallback(paint, this);

}

function cls() {

    resetData();
    refresh();

}

function nextFrame() {

    //  Save current frame
    frames[frame - 1] = cloneData();

    frame++;

    if (frames[frame - 1])
    {
        copyToData(frames[frame - 1]);
    }
    else
    {
        frames.push(null);
        resetData();
    }

    refresh();

    frameText.text = "Frame: " + frame + " / " + frames.length;

}

function prevFrame() {

    if (frame === 1)
    {
        return;
    }

    //  Save current frame
    frames[frame - 1] = cloneData();

    frame--;

    //  Load old frame
    copyToData(frames[frame - 1]);

    refresh();

    frameText.text = "Frame: " + frame + " / " + frames.length;
    
}

function drawPalette() {

    //  Draw the palette to the UI bmd
    ui.clear(0, 0, 32 * 16, 32);

    var x = 0;

    for (var clr in game.create.palettes[palette])
    {
        ui.rect(x, 0, 32, 32, game.create.palettes[palette][clr]);
        x += 32;
    }

    ui.copy('uiGrid');

}

function changePalette() {

    palette++;

    if (!game.create.palettes[palette])
    {
        palette = 0;
    }

    drawPalette();
    refresh();

}

function setColor(i, p) {

    if (typeof p !== 'undefined')
    {
        //  It came from a Keyboard Event, in which case the color index is in p, not i.
        i = p;
    }

    if (i < 0)
    {
        i = 15;
    }
    else if (i >= 16)
    {
        i = 0;
    }

    colorIndex = i;
    color = game.create.palettes[palette][pmap[colorIndex]];

    paletteArrow.x = (i * 32) + 8;

}

function nextColor() {

    var i = colorIndex + 1;
    setColor(i);

}

function prevColor() {

    var i = colorIndex - 1;
    setColor(i);

}

function increaseSize(sprite) {

    if (sprite.name === 'width')
    {
        if (spriteWidth === 16)
        {
            return;
        }

        spriteWidth++;
    }
    else if (sprite.name === 'height')
    {
        if (spriteHeight === 16)
        {
            return;
        }

        spriteHeight++;
    }

    resetData();
    resizeCanvas();
    resizePreview();

    widthText.text = "Width: " + spriteWidth;
    heightText.text = "Height: " + spriteHeight;

}

function decreaseSize(sprite) {

    if (sprite.name === 'width')
    {
        if (spriteWidth === 4)
        {
            return;
        }

        spriteWidth--;
    }
    else if (sprite.name === 'height')
    {
        if (spriteHeight === 4)
        {
            return;
        }

        spriteHeight--;
    }

    resetData();
    resizeCanvas();
    resizePreview();

    widthText.text = "Width: " + spriteWidth;
    heightText.text = "Height: " + spriteHeight;

}

function increasePreviewSize() {

    if (previewSize === 16)
    {
        return;
    }

    previewSize++;
    previewSizeText.text = "Size: " + previewSize;

    resizePreview();
    refresh();

}

function decreasePreviewSize() {

    if (previewSize === 1)
    {
        return;
    }

    previewSize--;
    previewSizeText.text = "Size: " + previewSize;

    resizePreview();
    refresh();

}

function create() {

    //   So we can right-click to erase
    document.body.oncontextmenu = function() { return false; };

    Phaser.Canvas.setUserSelect(game.canvas, 'none');
    Phaser.Canvas.setTouchAction(game.canvas, 'none');

    game.stage.backgroundColor = '#505050';

    createUI();
    createDrawingArea();
    createPreview();
    createEventListeners();

    resetData();
    setColor(2);

}

function save() {

    //  Save current frame
    frames[frame - 1] = cloneData();

    var output = "";

    for (var f = 0; f < frames.length; f++)
    {
        var src = frames[f];

        if (src === null)
        {
            continue;
        }

        output = output.concat("var frame" + f + " = [\n");

        for (var y = 0; y < src.length; y++)
        {
            output = output.concat("\t'");
            output = output.concat(src[y].join(''));

            if (y < src.length - 1)
            {
                output = output.concat("',\n");
            }
            else
            {
                output = output.concat("'\n");
            }
        }
        
        output = output.concat("];\n");
        output = output.concat("game.create.texture('yourKey', frame" + f + ", " + previewSize + ", " + previewSize + ", " + palette + ");\n");

    }

    console.log(output);

    saveText.alpha = 1;
    game.add.tween(saveText).to( { alpha: 0 }, 2000, "Linear", true);

}

function shiftLeft() {

    canvas.moveH(-canvasZoom);
    preview.moveH(-previewSize);

    for (var y = 0; y < spriteHeight; y++)
    {
        var r = data[y].shift();
        data[y].push(r);
    }

}

function shiftRight() {

    canvas.moveH(canvasZoom);
    preview.moveH(previewSize);

    for (var y = 0; y < spriteHeight; y++)
    {
        var r = data[y].pop();
        data[y].splice(0, 0, r);
    }

}

function shiftUp() {

    canvas.moveV(-canvasZoom);
    preview.moveV(-previewSize);

    var top = data.shift();
    data.push(top);

}

function shiftDown() {

    canvas.moveV(canvasZoom);
    preview.moveV(previewSize);

    var bottom = data.pop();
    data.splice(0, 0, bottom);

}

function onDown(pointer) {

    if (pointer.y <= 32)
    {
        setColor(game.math.snapToFloor(pointer.x, 32) / 32);
    }
    else
    {
        isDown = true;

        if (pointer.rightButton.isDown)
        {
            isErase = true;
        }
        else
        {
            isErase = false;
        }

        paint(pointer);
    }

}

function onUp() {
    isDown = false;
}

function paint(pointer) {

    //  Get the grid loc from the pointer
    var x = game.math.snapToFloor(pointer.x - canvasSprite.x, canvasZoom) / canvasZoom;
    var y = game.math.snapToFloor(pointer.y - canvasSprite.y, canvasZoom) / canvasZoom;

    if (x < 0 || x >= spriteWidth || y < 0 || y >= spriteHeight)
    {
        return;
    }

    coords.text = "X: " + x + "\tY: " + y;

    if (!isDown)
    {
        return;
    }

    if (isErase)
    {
        data[y][x] = '.';
        canvas.clear(x * canvasZoom, y * canvasZoom, canvasZoom, canvasZoom, color);
        preview.clear(x * previewSize, y * previewSize, previewSize, previewSize, color);
    }
    else
    {
        data[y][x] = pmap[colorIndex];
        canvas.rect(x * canvasZoom, y * canvasZoom, canvasZoom, canvasZoom, color);
        preview.rect(x * previewSize, y * previewSize, previewSize, previewSize, color);
    }

}