Skip to content

Instantly share code, notes, and snippets.

@maxmonax
Last active August 25, 2019 17:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxmonax/7c77968157c2167e7772a2aded94315b to your computer and use it in GitHub Desktop.
Save maxmonax/7c77968157c2167e7772a2aded94315b to your computer and use it in GitHub Desktop.
Canvas Mng for the coloring game
module PhaserGame.Client {
export const IMG_W_MIN = 760;
export const IMG_W_MAX = 760 * 1.4;
export const IMG_H = 760;
const IMG_DATA = [
{ img_bg: 'heart_bg', img: 'heart' },
{ img_bg: 'rocket_bg', img: 'rocket' },
{ img_bg: 'star_bg', img: 'star' },
{ img_bg: 'tree_bg', img: 'tree' },
{ img_bg: 'rabbit_bg', img: 'rabbit' },
{ img_bg: 'bag_bg', img: 'bag' },
{ img_bg: 'raspberry_bg', img: 'raspberry' },
{ img_bg: 'bear_bg', img: 'bear' },
{ img_bg: 'seastar_bg', img: 'seastar' },
{ img_bg: 'fish_bg', img: 'fish' },
];
const RAINBOW_COLORS = [
{ color: 'rgba(46, 16, 154, 1)' },
{ color: 'rgba(11, 12, 130, 1)' },
{ color: 'rgba(62, 158, 251, 1)' },
{ color: 'rgba(64, 187, 29, 1)' },
{ color: 'rgba(252, 245, 51, 1)' },
{ color: 'rgba(242, 99, 55, 1)' },
{ color: 'rgba(210, 14, 22, 1)' },
];
const DX = -6;
const DY = -6;
export class CanvasMng extends Phaser.Sprite {
private image_id = -1;
private prev_image_id = -1;
private image_key = '';
private image_mask: Phaser.Graphics;
private brush_id = -1;
private color_id = -1;
private bmdDraw: Phaser.BitmapData;
private bmdImage: Phaser.Image;
private overlay: Phaser.Sprite;
private image_frame: Phaser.Sprite;
private prev_draw_x = -1;
private prev_draw_y = -1;
private draw_x = 0;
private draw_y = 0;
private tolerance = 50;
private isDrawState = false;
constructor(game, x, y) {
super(game, x, y);
this.image_frame = new Phaser.Sprite(this.game, 0, 0, 'game', 'paintboard');
this.image_frame.anchor.set(0.5);
this.addChild(this.image_frame);
}
private saveCurrentImage() {
let dataUrl = this.bmdDraw.canvas.toDataURL();
Params.imageData[this.image_id] = dataUrl;
}
reloadImage(aIsBlank = false) {
if (this.bmdDraw) {
// save bmd
if (this.prev_image_id >= 0) {
let dataUrl = this.bmdDraw.canvas.toDataURL();
}
}
else {
// The BitmapData on which the fill takes place
this.bmdDraw = this.game.add.bitmapData();
// Load the black and white outline picture into it.
this.bmdImage = this.bmdDraw.addToWorld();
if (!this.image_mask) {
this.image_mask = new Phaser.Graphics(this.game, 0, 0);
this.image_mask.beginFill(0x0, 1);
this.image_mask.drawRoundedRect(0, 0, IMG_W_MAX, IMG_H, 10);
this.image_mask.endFill();
this.game.add.existing(this.image_mask);
}
this.bmdImage.mask = this.image_mask;
// Enable input for this sprite, so we can tell when it's clicked.
this.bmdImage.inputEnabled = true;
this.bmdImage.events.onInputDown.add(this.onBmdDown, this);
this.game.input.addMoveCallback(this.onGameMove, this);
this.bmdImage.events.onInputUp.add(this.onBmdUp, this);
}
this.bmdDraw.clear();
// try get data from storage
let localDataUrl = Params.imageData[this.image_id];
if (localDataUrl) {
let key_prev_img = this.image_key + '_prev';
if (this.game.cache.hasFrameData(key_prev_img)) {
this.game.cache.removeImage(key_prev_img);
}
let img: any = document.getElementById("temp_img");
img.onload = () => {
this.game.cache.addImage(key_prev_img, localDataUrl, img);
this.bmdDraw.load(key_prev_img);
};
img['src'] = localDataUrl;
}
else {
this.bmdDraw.load(this.image_key);
}
// This applies a small alpha to the image, allowing you to see
// the paper texture through it. You can remove this depending
// on what your requirements are.
this.bmdImage.alpha = 0.95;
// A copy of the image to be filled, placed over the top of the canvas
// This keeps the outline fresh, no matter how much filling takes place
// It could also contain a watermark or similar.
if (this.overlay) {
this.overlay.loadTexture(this.image_key);
}
else {
this.overlay = new Phaser.Sprite(this.game, 0 + DX, 0 + DY, this.image_key);
this.overlay.anchor.set(0.5);
this.overlay.alpha = this.bmdImage.alpha;
this.addChild(this.overlay);
}
// This just centers it in the bottom-middle of the screen.
this.game.time.events.add(10, () => {
this.image_mask.x = Config.GW / 2 - IMG_W_MAX / 2;
this.image_mask.y = Config.GH / 2 - IMG_H / 2 - 5;
this.bmdImage.centerX = Config.GW / 2;
this.bmdImage.centerY = Config.GH / 2 - 5;
}, this);
let parent = this.parent;
if (parent)
parent.setChildIndex(this, parent.children.length - 1);
}
private updateDrawPos(p: Phaser.Pointer) {
this.draw_x = p.x - this.bmdImage.x;
this.draw_y = p.y - this.bmdImage.y;
if (!this.isDrawState) {
this.rb_prev_x = this.prev_draw_x = this.draw_x;
this.rb_prev_y = this.prev_draw_y = this.draw_y;
}
}
private onBmdDown(sprite: Phaser.Sprite, pointer: Phaser.Pointer) {
let brush_size = BRUSHES[this.brush_id].size;
let color2 = Phaser.Color.unpackPixel(COLORS[this.color_id].code2);
let color3 = COLORS[this.color_id].code3;
switch (GameData.brush_id) {
case 0:
// magic wand
let localbmdDraw = this.game.add.bitmapData();
localbmdDraw.load(this.image_key);
let bmd: any = localbmdDraw;
bmd.floodFill(
pointer.x - this.bmdImage.x,
pointer.y - this.bmdImage.y,
color2.r, color2.g, color2.b, color2.a,
this.tolerance);
// After filling, we'll re-apply the outline, so it never gets 'destroyed' by the fill
localbmdDraw.copy(this.image_key);
this.bmdDraw.copy(localbmdDraw);
// And update the pixel data, ready for the next fill
this.bmdDraw.update();
break;
case 1: // erase
case 2: // big brush
case 3: // mid brush
case 4: // small brush
this.isDrawState = true;
break;
default:
break;
}
}
private onGameMove(pointer: Phaser.Pointer, x, y) {
this.updateDrawPos(pointer);
}
private onBmdUp(sprite, pointer: Phaser.Pointer) {
this.isDrawState = false;
this.isNewDraw = true;
this.saveCurrentImage();
}
private isNewDraw = true;
private rb_an = 0;
private rb_prev_x = 0;
private rb_prev_y = 0;
private rb_prev_pos = {};
private paint(dst: Phaser.BitmapData, current_x: number, current_y: number, previous_x: number, previous_y: number) {
if (!this.bmdDraw) return;
let brush_size = BRUSHES[this.brush_id].size;
let ctx = this.bmdDraw.context;
let color3 = COLORS[this.color_id].code3;
switch (GameData.brush_id) {
case 1: // erase
let oldGlobalCompositeOperation: string = ctx.globalCompositeOperation;
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
ctx.moveTo(previous_x, previous_y);
ctx.lineTo(current_x, current_y);
ctx.lineWidth = brush_size;
ctx.lineCap = "round";
ctx.strokeStyle = "rbga(0, 0, 0, 1)";
ctx.stroke();
dst.dirty = true;
ctx.globalCompositeOperation = oldGlobalCompositeOperation;
this.bmdDraw.copy(this.image_key);
break;
case 2: // big brush
case 3: // mid
case 4: // small
ctx.beginPath();
ctx.moveTo(previous_x, previous_y);
ctx.lineTo(current_x, current_y);
ctx.lineWidth = brush_size;
ctx.lineCap = "round";
ctx.strokeStyle = color3;
ctx.stroke();
dst.dirty = true;
break;
}
this.isNewDraw = false;
}
setBrush(id: number) {
this.brush_id = id;
}
setColor(id: number) {
this.color_id = id;
}
setImage(id: number) {
if (this.image_id == id) return;
this.prev_image_id = this.image_id;
this.image_id = id;
this.image_key = 'img' + this.image_id;
this.reloadImage();
}
update() {
super.update();
let dt = this.game.time.elapsed * 0.001;
let sc = ScaleManager.gameViewW / Config.GW;
let colScale = Math.min(1.4, sc / 0.58);
this.image_frame.scale.x = colScale;
let new_w = IMG_W_MIN * colScale;
this.image_mask.clear();
this.image_mask.beginFill(0x0, 1);
this.image_mask.drawRoundedRect(0, 0, new_w, IMG_H, 10);
this.image_mask.endFill();
this.image_mask.x = Config.GW / 2 - new_w / 2;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment