Last active
August 25, 2019 17:55
-
-
Save maxmonax/7c77968157c2167e7772a2aded94315b to your computer and use it in GitHub Desktop.
Canvas Mng for the coloring game
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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