// forked from nengafl's nengafl // // 小さい頃に、遊びませんでしたか?クレヨンで塗りつぶした // 絵を、上から釘で削って絵を描く手法。あれを再現してみました。 // package { import flash.display.GradientType; import flash.display.SpreadMethod; import flash.display.Sprite; import flash.display.MovieClip; import flash.display.SimpleButton; import flash.display.StageScaleMode; import flash.display.StageAlign; import flash.display.BlendMode; import flash.display.Bitmap; import flash.display.BitmapData; import flash.events.MouseEvent; import flash.geom.Matrix; import flash.events.*; import flash.geom.Point; import flash.geom.ColorTransform; import flash.ui.Mouse; import flash.geom.Matrix; import flash.text.TextField; [SWF(width=465, height=465, frameRate=30, backgroundColor=0xffffff)] public class DocumentClass extends Sprite { private var backGround:ImageClip; private var board:MovieClip; private var blackMC:ImageClip; private var buttonsMC:MovieClip; private var material_eraser:ImageClip; private var material_nail:ImageClip; private var material_palm:ImageClip; private var material_thumb:ImageClip; private var cursorMC:MovieClip; private var eraser:ImageClip; private var nail:ImageClip; private var palm:ImageClip; private var thumb:ImageClip; private var hittestObject:Sprite; private var messages:MovieClip; private var m1:ImageClip; private var m2:ImageClip; private var drawSprite:Sprite; private var drawSpriteA:Sprite; private var drawSpriteB:Sprite; private var drawSpriteC:Sprite; private var buttons:Array = []; private var cursors:Array = []; private var drawingIsEnable:Boolean=false; private var drawingMaterial:String="nail"; private var bmd:BitmapData; private var bmdSmall:BitmapData; private var bm:Bitmap; private var palmAX:int=-13,palmBX:int=17,palmCX:int=33; private var palmAY:int=6,palmBY:int=-7,palmCY:int=-6; private var selectedCT:ColorTransform=new ColorTransform(1,1,1,1,0,-50,-205,0); private var attentionCT:ColorTransform=new ColorTransform(1,1,1,1,0,-255,-255,0); private var normalCT:ColorTransform=new ColorTransform(1,1,1,1,0,0,0,0); private var mSmall:Matrix = new Matrix(); private var scratchRatio:Number = 0; private var isErasedHalf:Boolean = false; public function DocumentClass() { stage.scaleMode = StageScaleMode.NO_SCALE; backGround = new ImageClip(); backGround.loaderVisible = false; backGround.visible = false; backGround.load("http://pokeal.com/happy-tiger-year/wonderfl/tiger.jpg"); addChild(backGround); board = new MovieClip(); board.blendMode = BlendMode.MULTIPLY; addChild(board); blackMC = new ImageClip(); blackMC.imageStyle = {width:465,height:465}; blackMC.load("http://pokeal.com/happy-tiger-year/wonderfl/black.jpg"); board.addChild(blackMC); blackMC.addEventListener(ImageClip.READY_TO_DISPLAY,function(e:Event):void{backGround.visible = true;}); buttonsMC = new MovieClip(); addChild(buttonsMC); buttonsMC.x = 270; buttonsMC.y = 410; material_eraser = new ImageClip(); material_eraser.visible = false; material_eraser.load("http://pokeal.com/happy-tiger-year/wonderfl/eraser_small.png"); buttonsMC.addChild(material_eraser); material_nail = new ImageClip(); material_nail.load("http://pokeal.com/happy-tiger-year/wonderfl/nail_small.png"); buttonsMC.addChild(material_nail); material_nail.x = 60; material_palm = new ImageClip(); material_palm.load("http://pokeal.com/happy-tiger-year/wonderfl/palm_small.png"); buttonsMC.addChild(material_palm); material_palm.x = 100; material_palm.y = -3; material_thumb = new ImageClip(); material_thumb.load("http://pokeal.com/happy-tiger-year/wonderfl/thumb_small.png"); buttonsMC.addChild(material_thumb); material_thumb.x = 150; material_thumb.y = -2; buttons = [material_nail, material_palm, material_thumb, material_eraser]; cursorMC = new MovieClip(); addChild(cursorMC); hittestObject = new Sprite(); hittestObject.graphics.beginFill(0,0); hittestObject.graphics.drawRect(0,0,1,1); hittestObject.graphics.endFill(); cursorMC.addChild(hittestObject); eraser = new ImageClip(); eraser.load("http://pokeal.com/happy-tiger-year/wonderfl/eraser.png"); cursorMC.addChild(eraser); eraser.x = -100; eraser.y = -100; nail = new ImageClip(); nail.load("http://pokeal.com/happy-tiger-year/wonderfl/nail.png"); cursorMC.addChild(nail); nail.x = -1; nail.y = -118; palm = new ImageClip(); palm.load("http://pokeal.com/happy-tiger-year/wonderfl/palm.png"); cursorMC.addChild(palm); palm.x = -17; palm.y = -10; thumb = new ImageClip(); thumb.load("http://pokeal.com/happy-tiger-year/wonderfl/thumb.png"); cursorMC.addChild(thumb); thumb.x = -30; thumb.y = -30; cursors = [nail, palm, thumb, eraser]; messages = new MovieClip(); addChild(messages); messages.x = 15; messages.y = 415; m1 = new ImageClip(); m1.visible = false; m1.load("http://pokeal.com/happy-tiger-year/wonderfl/message01.png"); messages.addChild(m1); m2 = new ImageClip(); m2.visible = false; m2.load("http://pokeal.com/happy-tiger-year/wonderfl/message02.png"); messages.addChild(m2); mSmall.scale(1/10,1/10); bmdSmall = new BitmapData(465/10,465/10,true,0xff000000); bmd=new BitmapData(465,465,true,0); bm=new Bitmap(bmd,"auto",true); board.addChild(bm); onClickNail(); addEventListener(MouseEvent.MOUSE_DOWN,enable); addEventListener(MouseEvent.MOUSE_MOVE,drawing); addEventListener(MouseEvent.MOUSE_UP,disable); //addEventListener(Event.ENTER_FRAME,onEnterFrames); material_nail.addEventListener(MouseEvent.CLICK,onClickNail); material_palm.addEventListener(MouseEvent.CLICK,onClickPalm); material_thumb.addEventListener(MouseEvent.CLICK,onClickThumb); material_eraser.addEventListener(MouseEvent.CLICK,onClickEraser); } private function enable(e:MouseEvent):void { drawingIsEnable=true; drawSprite = new Sprite(); drawSprite.graphics.moveTo(board.mouseX,board.mouseY); board.addChild(drawSprite); if (drawingMaterial=="palm") { drawSpriteA = new Sprite(); drawSpriteB = new Sprite(); drawSpriteC = new Sprite(); board.addChild(drawSpriteA); board.addChild(drawSpriteB); board.addChild(drawSpriteC); drawSpriteA.graphics.moveTo(board.mouseX+palmAX,board.mouseY+palmAY); drawSpriteB.graphics.moveTo(board.mouseX+palmBX,board.mouseY+palmBY); drawSpriteC.graphics.moveTo(board.mouseX+palmCX,board.mouseY+palmCY); } switch (drawingMaterial) { case "nail" : drawSprite.graphics.lineStyle(1,0xffffff,1); break; case "palm" : drawSprite.graphics.lineStyle(2,0xffffff); drawSpriteA.graphics.lineStyle(2,0xffffff); drawSpriteB.graphics.lineStyle(2,0xffffff); drawSpriteC.graphics.lineStyle(2,0xffffff); break; case "thumb" : drawSprite.graphics.lineStyle(40,0xffffff,0.1); break; case "eraser" : drawSprite.graphics.lineStyle(200,0xffffff,1); break; } } private function drawing(e:MouseEvent):void { if (drawingIsEnable) { switch (drawingMaterial) { case "nail" : drawSprite.graphics.lineTo(board.mouseX,board.mouseY); break; case "palm" : drawSprite.graphics.lineTo(board.mouseX,board.mouseY); drawSpriteA.graphics.lineTo(board.mouseX+palmAX,board.mouseY+palmAY); drawSpriteB.graphics.lineTo(board.mouseX+palmBX,board.mouseY+palmBY); drawSpriteC.graphics.lineTo(board.mouseX+palmCX,board.mouseY+palmCY); break; case "thumb" : drawSprite.graphics.lineStyle(40,0xffffff,0.1); //ここにこれを入れてやることで、「塗り続けるとどんどん濃くなる」が表現できる drawSprite.graphics.lineTo(board.mouseX,board.mouseY); break; case "eraser" : drawSprite.graphics.lineTo(board.mouseX,board.mouseY); break; } } cursorMC.x=mouseX; cursorMC.y=mouseY; //カーソルの基準点がbuttonsMC内なら、通常カーソルに。buttonsMC外なら特殊カーソルに。 if (hittestObject.hitTestObject(buttonsMC) && !drawingIsEnable) { Mouse.show(); cursorMC.visible=false; } else { Mouse.hide(); cursorMC.visible=true; } } private function disable(e:MouseEvent):void { drawingIsEnable=false; //動作を軽くするために、BitmapDataに変換して入れ替える bmd.draw(drawSprite,null,null,BlendMode.NORMAL,null,true); board.removeChild(drawSprite); if (drawingMaterial=="palm") { bmd.draw(drawSpriteA,null,null,BlendMode.NORMAL,null,true); bmd.draw(drawSpriteB,null,null,BlendMode.NORMAL,null,true); bmd.draw(drawSpriteC,null,null,BlendMode.NORMAL,null,true); board.removeChild(drawSpriteA); board.removeChild(drawSpriteB); board.removeChild(drawSpriteC); } ckeckScratch(); } private function onClickNail(e:MouseEvent = undefined):void { drawingMaterial="nail"; buttonIsSelected(material_nail); cursorIsChanged(nail); } private function onClickPalm(e:MouseEvent):void { drawingMaterial="palm"; buttonIsSelected(material_palm); cursorIsChanged(palm); } private function onClickThumb(e:MouseEvent):void { drawingMaterial="thumb"; buttonIsSelected(material_thumb); cursorIsChanged(thumb); } private function onClickEraser(e:MouseEvent):void { drawingMaterial="eraser"; buttonIsSelected(material_eraser); cursorIsChanged(eraser); } private function buttonIsSelected(mc:MovieClip):void{ //ボタンの色をかえる。選択されていないものは、もとに戻す for (var i:int = 0; i < buttons.length; i++){ if (mc == buttons[i]){ mc.transform.colorTransform=selectedCT; } else { buttons[i].transform.colorTransform=normalCT; } } } private function cursorIsChanged(mc:MovieClip):void{ //カーソルをかえる for (var i:int = 0; i < cursors.length; i++){ if (mc == cursors[i]){ mc.visible=true; } else { cursors[i].visible = false; } } } private function onEnterFrames(e:Event):void { } private function ckeckScratch():void { // 描画率を計算する。すべてのピクセルをfor文でまわすと時間がかかるので、一度画像を縮小してから計算する。 var numWhite:int = 0; bmdSmall.draw(bmd,mSmall); for (var y:int = 0; y < bmdSmall.height ; y ++){ for (var x:int = 0; x < bmdSmall.width ; x ++){ if(bmdSmall.getPixel(x,y) > 0){ //黒でないピクセルを合計 numWhite ++; } } } scratchRatio = numWhite/(bmdSmall.height*bmdSmall.width); //trace(scratchRatio); if(0.1 < scratchRatio && scratchRatio < 0.8){ //10%以上描いたら、何かが出る m1.visible = true; if(!material_eraser.visible) { //最初だけわかりやすく、色をつける material_eraser.transform.colorTransform=attentionCT; } material_eraser.visible = true; } else if (scratchRatio >= 0.8){ //80%以上描いたら、何かが出る m1.visible = false; m2.visible = true; } } } } //////////////////////////////////////////// // ここから下は ImageClip Class //////////////////////////////////////////// // ImageClipクラスだけで別に投稿してます // http://wonderfl.net/code/b5e4a53e5ea9cf4a188ef30313a7d6d327144c10 import flash.events.Event; import flash.events.EventDispatcher; import flash.events.ProgressEvent; import flash.events.IOErrorEvent; import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.LoaderInfo; import flash.display.Shape; import flash.text.TextField; import flash.net.URLRequest; import flash.system.LoaderContext; import caurina.transitions.Tweener; class ImageClip extends MovieClip { public static const READY_TO_DISPLAY:String = "ready_to_display"; private var _imageStyle:Object = new Object(); private var _loaderStyle:Object = new Object(); private var imgLoader:Loader; private var tmpLoader:Loader; private var imageMask:Shape; private var req:URLRequest; private var donut:Donut; private var bmp:Bitmap; private var imageType:String; private var areaWidth:Number; private var areaHeight:Number; private var bg:Shape; private var bgColor:int; private var bgAlpha:Number; private var bgVisible:Boolean; private var padding:Number; private var _loaderVisible:Boolean = true; //private var _imageVisible:Boolean = true; public function ImageClip() { super(); } private function init():void{ _imageStyle.type ? imageType = _imageStyle.type : imageType = "original"; _imageStyle.width ? areaWidth = _imageStyle.width : areaWidth = 100; _imageStyle.height ? areaHeight = _imageStyle.height : areaHeight = 100; _imageStyle.bgColor ? bgColor = _imageStyle.bgColor : bgColor = 0; _imageStyle.bgAlpha ? bgAlpha = _imageStyle.bgAlpha : bgAlpha = 1; _imageStyle.padding ? padding = _imageStyle.padding : padding = 0; _imageStyle.bgVisible ? bgVisible = _imageStyle.bgVisible : bgVisible = false; if(!_imageStyle.width && !_imageStyle.height){ _loaderVisible = false; } if(bgVisible){ bg = new Shape(); bg.graphics.beginFill(bgColor,bgAlpha); bg.graphics.drawRect(0,0,areaWidth,areaHeight); bg.graphics.endFill(); addChild(bg); } imageMask = new Shape(); imageMask.graphics.beginFill(0,1); imageMask.graphics.drawRect(0,0,areaWidth - (padding*2), areaHeight - (padding*2)); imageMask.x = padding; imageMask.y = padding; imgLoader = new Loader(); imgLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imageOnProgress); imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageOnLoaded); imgLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, imageIOError); if(_loaderVisible){ donut = new Donut(_loaderStyle, areaWidth, areaHeight); addChild(donut); } } private function imageOnProgress(event:ProgressEvent):void { if(_loaderVisible){ var ratio:Number = event.bytesLoaded/event.bytesTotal; donut.loadedRatio = ratio; } } private function imageIOError(event:Event):void { imgLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, imageOnProgress); imgLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE,imageOnLoaded); imgLoader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, imageIOError); if(_loaderVisible){ donut.removeEventListener(Donut.TWEEN_COMPLETE, displayImage); donut.kill(); removeChild(donut); } // エラー表示 var errorBGColor:int; var errorLineColor:int; _loaderStyle.bgColor ? errorBGColor = _loaderStyle.bgColor : errorBGColor = 0x333333; _loaderStyle.color ? errorLineColor = _loaderStyle.color : errorLineColor = 0xaaaaaa; var errorBox:Sprite = new Sprite(); errorBox.graphics.beginFill(errorBGColor,1); errorBox.graphics.drawRect(0,0,areaWidth,areaHeight); errorBox.graphics.endFill(); errorBox.graphics.lineStyle(1,errorLineColor,1); errorBox.graphics.lineTo(areaWidth,areaHeight); errorBox.graphics.moveTo(0,areaHeight); errorBox.graphics.lineTo(areaWidth,0); addChild(imageMask); errorBox.mask = imageMask; addChild(errorBox); this.alpha = .2; trace(event); // TODO // クロスドメイン無しのアラートは可能か? } private function imageOnLoaded(event:Event):void { imgLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE,imageOnLoaded); imgLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, imageOnProgress); imgLoader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, imageIOError); tmpLoader = new Loader(); tmpLoader.contentLoaderInfo.addEventListener(Event.INIT, tmpOnLoaded); tmpLoader.loadBytes(imgLoader.contentLoaderInfo.bytes); } private function tmpOnLoaded(event:Event):void { tmpLoader.contentLoaderInfo.removeEventListener(Event.INIT, tmpOnLoaded); var loader:Loader = event.currentTarget.loader; var bd:BitmapData = new BitmapData(loader.content.width, loader.content.height, true, 0x00ffffff); bd.draw(loader.content); bmp = new Bitmap(bd); bmp.smoothing = true; if(_loaderVisible){ donut.swapContent = bmp; donut.addEventListener(Donut.TWEEN_COMPLETE, function(e:Event):void{ dispatchEvent(new Event(READY_TO_DISPLAY)) }); } else { dispatchEvent(new Event(READY_TO_DISPLAY)); } displayImage(); } private function displayImage(event:Event = undefined):void { if(_loaderVisible){ donut.removeEventListener(Donut.TWEEN_COMPLETE, displayImage); } var areaAspectRatio:Number = areaWidth/areaHeight; var bmpAspectRatio:Number = bmp.width/bmp.height; var bmpRatioIsHigher:Boolean = ((bmpAspectRatio - areaAspectRatio) >= 0); switch (imageType){ case "original": break; case "fit": bmp.width = areaWidth - (padding*2); bmp.height = areaHeight - (padding*2); bmp.x = padding; bmp.y = padding; break; case "auto": bmpRatioIsHigher ? adjustHeightFirst() : adjustWidthFirst(); addChild(imageMask); bmp.mask = imageMask; break; case "show all": bmpRatioIsHigher ? adjustWidthFirst() : adjustHeightFirst(); break; case "trim center": bmp.y = (areaHeight - bmp.height)/2; bmp.x = (areaWidth - bmp.width)/2; addChild(imageMask); bmp.mask = imageMask; break; } addChild(bmp); function adjustWidthFirst():void{ bmp.width = areaWidth - (padding*2); bmp.height = bmp.width/bmpAspectRatio; bmp.x = padding; bmp.y = (areaHeight - bmp.height)/2; } function adjustHeightFirst():void{ bmp.height = areaHeight - (padding*2); bmp.width = bmp.height*bmpAspectRatio; bmp.x = (areaWidth - bmp.width)/2; bmp.y = padding; } } public function load(url:String):void { init(); req = new URLRequest(url); imgLoader.load(req,new LoaderContext(true)); } public function set imageStyle(o:Object):void { _imageStyle = o; } /*public function set imageVisible(b:Boolean):void { _imageVisible = b; }*/ public function set loaderStyle(o:Object):void { _loaderStyle = o; } public function set loaderVisible(b:Boolean):void { _loaderVisible = b; } } //////////////////////////////// // Donut Class //////////////////////////////// // ImageClipクラスとセットで使う。ドーナツを描くためのクラス。 import flash.display.Shape; import flash.display.Bitmap; import frocessing.display.*; import flash.events.EventDispatcher; class Donut extends F5MovieClip2DBmp { private var bg:Shape; private var _style:Object = new Object(); private var _loadedRatio:Number = 0; private var _radius:Number; private var _weight:Number; private var _color:int; private var _bgColor:int; private var lastRadian:Number = 0; private var acceleration:Number = 8; private var isLoadedEnough:Boolean = false; private var _swapContent:Bitmap; public static const TWEEN_COMPLETE:String = "load_complete"; public function Donut(style:Object, areaWidth:Number, areaHeight:Number):void { super(); if(style) { _style = style }; _style.radius ? _radius = _style.radius : _radius = 15; _style.weight ? _weight = _style.weight : _weight = 5; _style.color ? _color = _style.color : _color = 0xaaaaaa; _style.bgColor ? _bgColor = _style.bgColor : _bgColor = 0x666666; this.x = (areaWidth/2)-_radius-1; this.y = (areaHeight/2)-_radius-1; } public function setup():void { bg = new Shape(); bg.graphics.beginFill(_bgColor,1); bg.graphics.drawCircle(_radius+1,_radius+1,_radius); bg.graphics.drawCircle(_radius+1,_radius+1,_radius-_weight); bg.graphics.endFill(); addChild(bg); size(_radius*2+2,_radius*2+2); background(255,0); fill(_color); stroke(0,0); } public function draw():void { background(255,0); translate(_radius+1,_radius+1); var targetRadian:Number = Math.PI*2/(360/_loadedRatio); var amount:Number = lastRadian+(targetRadian - lastRadian)/acceleration; if(amount < 6.283185307179583){ beginShape(); moveTo(0,-_radius); arcTo(0, 0, _radius, _radius, 0, amount, -Math.PI/2); arcTo(0, 0, _radius-_weight, _radius-_weight, amount, 0, -Math.PI/2); endShape(); } lastRadian = amount; if(amount >= 3.14){ acceleration = 4 } if(amount >= 6.26){ this.alpha -= .1; if(!isLoadedEnough){ isLoadedEnough = true; } if(isLoadedEnough && _swapContent){ _swapContent.alpha = 1-this.alpha; } if(this.alpha <= 0){ dispatchEvent(new Event(TWEEN_COMPLETE)); noLoop(); } } } public function set loadedRatio(n:Number):void{ _loadedRatio = n*360; } public function set swapContent(bmp:Bitmap):void{ _swapContent = bmp; _swapContent.alpha = 0; } public function kill():void{ noLoop(); } } Happy Tiger Year 2010