Log in

View Full Version : Charcoal and crayon drawing effect.



evan
05-28-2008, 11:49 AM
I am currently exploring how to apply a charcoal or crayon effect to a pen tool.


To revisit the code for a generic draw tool in AS 3.0:


var drawing:Boolean=false;
this.graphics.lineStyle(1,0x000000);
this.graphics.moveTo(mouseX, mouseY);

this.addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp, false, 0, true);

function onDown(evt:MouseEvent):void {
drawing=true;
}
function onUp(evt:MouseEvent):void {
drawing=false;
}
function onLoop(evt:Event):void{
if(drawing){
this.graphics.lineTo(mouseX, mouseY);
}else{
this.graphics.moveTo(mouseX, mouseY);
}
}

I still haven't found code that allows a sort of "rubber stamp" that I think would give that result. -meaning -I create a vector symbol in flash that resembles the shape of the "brush" and as it gets dragged -it actually would repeat itself . So.... what I think should happen is a graphic from the library would repeat itself with MOUSE_DOWN and x/y being traced - I THINK that is the right approach to make it work, albeit I would have to set the movie for a high frame rate.

any links to as 3.0 examples of that being done?

Medyman
05-28-2008, 10:16 PM
any links to as 3.0 examples of that being done?

Nope...it can't be done. At least not in the way you describe. The logic will work with other methods though.

The Drawing API is for shapes only. You can't use library items as the "brush". In AS2 you would use the attachMovieClip() method to place multiple instances of a movieclip on the stage following the mouse.

Of course, attachMovieClip() and it's cousin duplicateMovieClip() have been deprecated in AS3. The AS3 syntax is much simpler. Here (http://www.flepstudio.org/forum/tutorials/492-duplicatemovieclip-removed.html) is a walkthrough of duplicateMovieClip() in AS3. The same logic (and most of the code) hold true for attachMovieClip() as well.

This (http://www.gotoandlearn.com/player.php?id=16) is a video tutorial by Lee Brimelow of gotoAndLearn() that shows the technique I'm talking about with AS 2.0. It's fairly simple. You should be able to easily port it to AS 3. Let me know if you have any troubles.

evan
05-29-2008, 02:18 PM
Good, one step closer.
I have been piling through Actionscript, The Definitive Guide CH13 -Oreilly.com had a free link with the whole chapter on the subject.

NOW I am closer to getting it done,

I didn't think the graphics class would make it work. But I'll need to produce the effect by repeating a movieclip on mousedown and tracking the mouse.

evan
05-30-2008, 04:30 PM
I looked at the dicussion about duplicatemovieclip being depreciated,

My first impression is this is a pretty ardous process if all I want to do is attach or display a movie clip from the library, unless he's really talking about importing whole fla files intact -then I understand why.

evan
05-30-2008, 09:39 PM
I have been messing around with an as 3 version that works with the xample you showed me.

I'm still playing around any ideas?



/*
var drawing :Boolean = false;
var inc:uint = 0;
this.graphics.moveTo(mouseX,mouseY);

stage.addEventListener(MouseEvent.MOUSE_DOWN, paintMe, false, 0, true);
this.addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true);
function paintMe(evt:MouseEvent):void{
drawing=true;
var ball:MovieClip = new Ball();
addChild(ball);
inc++;
}
function onLoop(evt:EVENT):void{
if (drawing)
{this.graphics.moveTo(mouseX,mouseY);}

}

Medyman
05-31-2008, 10:15 PM
I looked at the dicussion about duplicatemovieclip being depreciated,

My first impression is this is a pretty ardous process if all I want to do is attach or display a movie clip from the library, unless he's really talking about importing whole fla files intact -then I understand why.

arduous? how so? I think it's quite simpler than AS2. For example, here is how you would attach a clip from the library (linkage id = clip)to the Stage in both AS2 and AS3:

AS2:

this.attachMovie("clip", "newClip", this.getNextHighestDepth());

AS3:

this.addChild(new clip());

Medyman
05-31-2008, 11:21 PM
I have been messing around with an as 3 version that works with the xample you showed me.

I'm still playing around any ideas?

What are you doing with all those variables? Seems like you might be over complicating things. Something like this should work for what you're trying to do:


stage.addEventListener(MouseEvent.MOUSE_DOWN, paintMe);

function paintMe(e:MouseEvent):void {
var ball:MovieClip = new Ball();
addChild(ball);
ball.x = mouseX;
ball.y = mouseY;
}

That will place an instance of the Ball class (a movieclip probably in your library) at the exact spot you click on the stage.

Now, if you want that ball MC to attach to the stage as you move the mouse, change the event listener from a MOUSE_DOWN to MOUSE_MOVE.

evan
06-01-2008, 03:35 AM
I only meant arduous by looking at all the material. but when I read it over again I was like
-OH, OK -slap- got it.

I did initially manage to get AS2 to migrate with just placing the ball out there, but I got crazy with trying how to get

ball.x = mouseX;
ball.y = mouseY; in the right order -and then started guessing at all the wrong things,
It's kind of like driving and missing a turn not wanting to get directions and getting even more lost

OK ..I'll try the code now.

evan
06-03-2008, 10:08 PM
I have moddified the code to confine the the drawing to a drawing pad and activate with a button, this works.

var val:Number=5
var drawing : Boolean = false;

pad.addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true);
do_btn.addEventListener(MouseEvent.CLICK, allowDrawing, false, 0, true);

pad.addEventListener(MouseEvent.MOUSE_DOWN, drawOnpad, false, 0, true);
pad.addEventListener(MouseEvent.MOUSE_MOVE, onLoop, false, 0, true);
pad.addEventListener(MouseEvent.MOUSE_UP, stopMe, false, 0, true);
pad.addEventListener(MouseEvent.ROLL_OUT, stopMe, false, 0, true);




function allowDrawing(e:MouseEvent):void {(val=15);}

function drawOnpad(e:MouseEvent):void {if(val==15)drawing=true;}

function onLoop(e:Event):void {

if (drawing)
{
var grain:MovieClip = new Grain();
addChild(grain);
grain.x = mouseX;
grain.y = mouseY;
}
}
function stopMe(e:MouseEvent):void {
(drawing=false);
}

However the problem is it does not continue to follow the mouse it only works in spurts.

I think the MOUSE_DOWN is "fighting" with the MOUSE_MOVE any way to deal with it?

If you need me to post the swf to see let me know

-PLEASE

Medyman
06-03-2008, 11:35 PM
Again, I'm not sure what those variables are for. I can guess what the drawing variable is doing, but don't know what val is for.

You're right about the MOUSE_MOVE and MOUSE_DOWN being in conflict, but maybe not for the reasons you would have thought. So this should be the timeline of what happens with this code:

1) You click on the button (or as I have in the code below, the "pad") and the drawing begins.
2) You release the button and the drawing should stop.

Pay close attention to what your mouse is on when you release. It's not the pad or the stage, it's the "grain" MC that you're dragging around. So the MOUSE_UP event should be on the grain.

See if the below works. I took out the button, but you can add it back in. You'll probably need to add the drawing variable back in if you want the button.


pad.addEventListener(MouseEvent.MOUSE_DOWN, startDrawing);

function startDrawing(e:MouseEvent):void {
trace("START DRAWING");
pad.addEventListener(MouseEvent.MOUSE_MOVE,Draw);
}

function Draw(e:MouseEvent):void {
trace("DRAWING");
var grain:MovieClip = new Grain();
addChild(grain);
grain.x = mouseX;
grain.y = mouseY;
grain.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
}

function stopDrawing(e:MouseEvent):void {
trace("END DRAWING");
pad.removeEventListener(MouseEvent.MOUSE_MOVE, Draw);
}

evan
06-04-2008, 04:20 PM
check this link:
http://www.asmakta.com/eraseme2/charc/charcproto3.html

The reason for "var val" is in order to implement this tool into the greater project.

"Val" is set to 5 -hiiting a button sets the val to 15 -conditions for the tool to work are: the button needs to be pushed to activate it and the cursor needs to be over "pad".

That being said, I also need to dissable the tool when I click another -such as an eraser, clicking and eraser button sets "val" to 5 again -it dissables this drawing tool, and sets a new value for "val" which is a new condition for the eraser to work -ie: if(val==5)eraser=true ---then eraser is active and at the same time dissabling the other too.


Regarding your suggestion:
I read up on turning off event listeners but I ran into the same problem last time I experemented that is:


function stopDrawing(e:MouseEvent):void {
trace("END DRAWING");
pad.removeEventListener(MouseEvent.MOUSE_MOVE, Draw);
}

it didn't really stop drawing on on MOUSE_UP and although your code is set up more efficiently, I don't know why it didn't actually turn off the event listener, which is why it just keeps drawing with MOUSE_MOVE

It does it's job of activating with the button, and working with mouse move, but it does not stop on mouse up and enabe the user to start and stop drawing on MOUSE_DOWN.

Mine does that -but as you look at it -the bug is it in that it stops after a short interval in the MOUSE_DOWN position -But it does
1)limit use until activated 2) start only on MOUSE_DOWN 3) stop when the mouse is of the pad 4) resume again on the pad on mouse down 5) allow the whole process to be dissabled when I add another button later.

I'm trying to see the limitations in creating a draw tool like this -if in fact I have exceeded the limitations in what I can do with Flash in this area -unless there is another way to attack this problem.

separate bug:
I tried different frame-rate settings to ensure that rather than a "staggered" pattern I get a steady "stream" -as it does when you move the mouse slowly.

I saw some examples in using math functions to control the interval something happens, like maybe the rate new instances of "grain" are redrawn in order to make work faster when the user moves the mouse faster.

Medyman
06-04-2008, 06:37 PM
I saw some examples in using math functions to control the interval something happens, like maybe the rate new instances of "grain" are redrawn in order to make work faster when the user moves the mouse faster.

Take a look at the AS3 Timer class. It's much more robust that using some Math hacks.

Have a look at blog posts from Lee Brimelow (http://theflashblog.com/?p=231) and Peter deHann (http://blogs.adobe.com/pdehaan/2006/07/using_the_timer_class_in_actio.html) for some more insight.

evan
06-04-2008, 07:02 PM
check this link: BEFORE
http://www.asmakta.com/eraseme2/charc/charcproto3.html
my code


AFTER -see this
http://www.asmakta.com/eraseme2/charc/charcproto5.html
your code with some ajdustments -start and stop buttons and I had to add an event listener


var val:Number=5
end_btn.addEventListener(MouseEvent.CLICK, end);//added
do_btn.addEventListener(MouseEvent.CLICK, begin);//added
pad.addEventListener(MouseEvent.MOUSE_DOWN, startDrawing);/*added before it was continuing MOSE_MOVE when the mouse re-enterred the pad.*/

function begin(e:MouseEvent):void { (val=15);}

function end(e:MouseEvent):void { (val=5);}

function startDrawing(e:MouseEvent):void {
if (val>10){//added

trace("START DRAWING");
pad.addEventListener(MouseEvent.MOUSE_MOVE,Draw);
pad.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);//added
}
}

function Draw(e:MouseEvent):void {
trace("DRAWING");
var grain:MovieClip = new Grain();
addChild(grain);
grain.x = mouseX;
grain.y = mouseY;
grain.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
pad.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
}

function stopDrawing(e:MouseEvent):void {
trace("END DRAWING");
pad.removeEventListener(MouseEvent.MOUSE_MOVE, Draw);

}


working on math now thanks

Medyman
06-05-2008, 12:53 AM
Hmm...I see what you mean. I don't really see a way around that happening. The most you'll be able to do is to attach one MC to the stage per millisecond.

With a brush that's so small, it's going to be hard to get a steady stream. And really, it's intuitive, I think. Even if you look at something like MS Paint's spray paint tool, it does the same thing. If you move the mouse really fast, you get the same effect.

The only thing that you could do would be to increase the size of the brush.

evan
06-05-2008, 06:52 PM
If I make the grain mc larger and apply a blur filter it helps,
how about changing the color? I tried to apply a color property to it
-no errors but no activity


function Draw(e:MouseEvent):void {
trace("DRAWING");
var grain:MovieClip = new Grain();
addChild(grain);
//grain.filters = [ new BlurFilter() ];//good for brush

//grain.alpha=.5

grain.color=0xFF00FF;
grain.x = mouseX;
grain.y = mouseY;
grain.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
pad.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
}

Medyman
06-06-2008, 01:01 PM
You can't just declare the color like that. MovieClips don't have a color property. Instead, you can use a tweening engine like Tweener (http://code.google.com/p/tweener/) or Flash's native ColorTransform Class (http://livedocs.adobe.com/flex/2/langref/flash/geom/ColorTransform.html).