AS3 drawing line with brush PNG images pattern - actionscript-3

This functionality exists in desktop programs such as Adobe Illustrator or Painter.
You can select a brush that is a pattern of images. Starting to paint on canvas displays a line (or any pattern) created from a set of images of different sizes and rotations. Approximately how I portrayed in the picture (the red line is a path of the brush motion).
Is there already a library for this effect, or how it can best be implemented?

Listen for MouseEvent.MOUSE_DOWN on your drawing canvas and once it fires, add a Event.ENTER_FRAME to begin drawing. The drawing itself is pretty straightforward - on every frame you take the mouseX and mouseY values and add the PNG image on the canvas in the exact place with any transformations (scaling, rotation, alpha) for that particular image. Here's a simple example:
private var PatternPNG:Class;
private var canvas:Sprite;
private function init() {
canvas = new Sprite();
addChild(canvas);
canvas.graphics.beginFill(0xFFFFFF);
canvas.graphics.drawRect(0,0,CANVAS_WIDTH,CANVAS_HEIGHT);
canvas.graphics.endFill();
canvas.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(e:Event):void
{
canvas.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
canvas.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
canvas.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onMouseUp(e:Event):void
{
canvas.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
canvas.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
canvas.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
var patternPiece:DisplayObject = new PatternPNG();
patternPiece.rotation = Math.random() * 360;
patternPiece.alpha = Math.random();
patternPiece.scaleX = patternPiece.scaleY = 0.2 + Math.random() * 0.8;
patternPiece.x = mouseX;
patternPiece.y = mouseY;
canvas.addChild(patternPiece);
}

Related

Stretch and rotate a Movieclip without distortion

i'm building a flash desktop app, where the user needs to link two Movieclips on stage (a computer and a router) using a line (or whatever can do the job), i want to achieve this same exact effect: image1. I searched and found this solution, i tried the code and did some modifications:
link.addEventListener(MouseEvent.CLICK, linkOnClick);
function linkOnClick(e:MouseEvent){
this.addEventListener(Event.ENTER_FRAME, enterFrame);
var linkPoint:Point = new Point(link.x, link.y);
var mousePoint:Point = new Point();
var distance:Number;
var radians:Number;
function enterFrame(e:Event):void {
//Distance
mousePoint.x = stage.mouseX;
mousePoint.y = stage.mouseY;
distance = Point.distance(linkPoint, mousePoint);
link.width = distance;
//Rotation
radians = Math.atan2(stage.mouseY - link.y, stage.mouseX - link.x);
link.rotation = radians * (180/ Math.PI);
if(link.hitTestObject(router)){trace("Success");}
}
When i compiled the code i got this: image2, so as you may remark, the problems i found are:
1-the edge of the line follows the direction of the mouse, but sometimes it goes beyond the cursor, i want the cursor to drag the edge of the line.
2-the line changes it's width, if it's 90° degrees the line width is so remarkable, i want the line to have a constant width.
how can i acheive the same exact effect shown in image1 ?
// First, lets create mouse-transparent container for drawing.
var DrawingLayer:Shape = new Shape;
addChild(DrawingLayer);
// Hook the event for starting.
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
// Define a storage for keeping the initial coordinates.
var mouseOrigin:Point = new Point;
function onDown(e:MouseEvent):void
{
// Save the initial coordinates.
mouseOrigin.x = DrawingLayer.mouseX;
mouseOrigin.y = DrawingLayer.mouseY;
// Hook the events for drawing and finishing.
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onDraw);
}
function onDraw(e:MouseEvent):void
{
// Remove the previous line.
DrawingLayer.graphics.clear();
// Draw a new line.
DrawingLayer.graphics.lineStyle(5, 0xFF6600);
DrawingLayer.graphics.moveTo(mouseOrigin.x, mouseOrigin.y);
DrawingLayer.graphics.lineTo(DrawingLayer.mouseX, DrawingLayer.mouseY);
}
function onUp(e:MouseEvent):void
{
// Unhook the events for drawing and finishing.
stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDraw);
}
It's because of that the actionscript is trying to stretch the line thickness by changing its container MovieClip's scale. But you can prevent this by setting the line Scale option to None.
To do that, select your line and open the properties menu and then select None from the drop down menu of the Scale option.
But,
I recommend you to draw a line by a code: Draw line from object to Mouse (AS3)
Write below code:
this.graphic.clear ();
this.graphic.lineStyle(0x000000);
this.moveTo(startPoint.x,startPoint.y);
this.lineTo(endpoint.X,endpoint.y);

Actionscript 3.0 - tracing the path of a moving body ;

I'm learning AS3.0 currently. I am trying to design a simple two body planet simulation. I need to show the paths of the planets on the screen. So my question is, once I have the updated x and y coordinates for the planets at each Timer interval, how do I change the color of the pixel (x,y) of the stage so that it shows the path of the planets? Is there some command of the form stage.x = color?
Thanks!
I recommend using BitmapData's draw() method to render your planets as pixels each time you update them. It basically works like a 'screenshot' of the display object you pass it as n argument. If you pass the objects transformation, the position/rotation/scale will be visible (as opposed to drawing from 0,0). This way, you will only be updating pixels instead of continuously creating new display objects.
Here's a basic commented example:
import flash.display.Sprite;
import flash.events.Event;
var trails:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.025,0,0,0,1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list
var dot:Sprite = addChild(new Sprite()) as Sprite;
dot.graphics.lineStyle(3);
dot.graphics.drawCircle(-4, -4, 8);
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
dot.x = mouseX;
dot.y = mouseY;
//draw trails of the dot
trails.draw(dot,dot.transform.concatenatedMatrix,trailsFade);//draw the dot into the bitmap data using the dot's transformation (x,y, rotation, scale)
}
Notice the trails when you move the mouse and how they are affected by the (update) speed.
Here's a longer example using multiple objects:
import flash.display.*;
import flash.events.Event;
import flash.geom.ColorTransform;
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var trails:BitmapData = new BitmapData(w,h,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.025,0,0,0,0.1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list
var spheres:Sprite = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)
var mercuryPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var venusPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var sun:Sprite = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var mercury:Sprite = mercuryPivot.addChild(getCircleSprite(24.40 / 4,0xCECECE)) as Sprite;
var venus:Sprite = venusPivot.addChild(getCircleSprite(60.52 / 4,0xFF2200)) as Sprite;
var earth:Sprite = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;
mercury.x = 5791 / 40;
venus.x = 10820 / 40;
earth.x = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
mercuryPivot.rotation += 0.5;
venusPivot.rotation += 0.25;
earthPivot.rotation += 0.12;
//draw trails
trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade);
}
function getCircleSprite(radius:Number,color:int):Sprite{
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
circle.graphics.endFill();
return circle;
}
Notice we call trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade);
but it could be trails.draw(earth,earth.transform.concatenatedMatrix,trailsFade); if you only want to draw the trails of earth.
In the example above I'm just nesting sprites and using the rotation property to keep things simple. You might want to use a bit of trigonometry to update positions because planets will probably not have perfectly circular orbits and pass through the exact location every single time.
Update
Thinking about this more, using the old school Graphics API might be handy for you if you get started and haven't got used to playing with pixels yet.
It's easy to get started with: objects that can be displayed in flash player can have a graphics property (see the Shape/Sprite/MovieClip classes). (You can have display object that you can't draw into whether you can nest elements into (DisplayObjectContainer) or not(DisplayObject), but that's a whole other thing for you too look into).
This graphics property Sprites and MovieClip has allows you to draw programmatically using simply commands such as: setting a stroke(lineStyle()), a fill (beginFill()/endFill()), moving an imaginary 'pen' without drawing (moveTo), drawing a line (lineTo), a circle, a rectangle, a rounded rectangle, etc. It's all there.
So, a minimal drawing program would look a bit like this:
import flash.events.MouseEvent;
import flash.events.Event;
var mousePressed:Boolean = false;//keep track if the mouse is pressed or not
graphics.lineStyle(1);//set the stroke to have a thickness of 1 (and the other parameters are defaults(color: black, transparency: 100% / 1.0, etc.))
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);//listend for mouse down
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);//...and mouse up changes
stage.addEventListener(Event.ENTER_FRAME,update);//update continuously
function mouseEventHandler(e:MouseEvent):void{
mousePressed = (e.type == MouseEvent.MOUSE_DOWN);
graphics.moveTo(mouseX,mouseY);//place the graphics 'pen' at this new location
}
function update(e:Event):void{
if(mousePressed) graphics.lineTo(mouseX,mouseY);//if the mouse is pressed, keep drawing a line to the current mouse location
}
or a more complex version where you use the speed of the mouse movement to influence the stroke thickness and transparency:
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Point;
var prevPos:Point = new Point();//previous mouse position
var currPos:Point = new Point();//current mouse position
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var mousePressed:Boolean = false;//keep track if the mouse is pressed or not
graphics.lineStyle(1);//set the stroke to have a thickness of 1 (and the other parameters are defaults(color: black, transparency: 100% / 1.0, etc.))
stage.doubleClickEnabled = true;
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);//listend for mouse down
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);//...and mouse up changes
stage.addEventListener(MouseEvent.DOUBLE_CLICK,function(e:MouseEvent):void{graphics.clear()});//double click to clear
stage.addEventListener(Event.ENTER_FRAME,update);//update continuously
function mouseEventHandler(e:MouseEvent):void{
mousePressed = (e.type == MouseEvent.MOUSE_DOWN);
graphics.moveTo(mouseX,mouseY);
}
function update(e:Event):void{
//currPos.setTo(mouseX,mouseY);//this works for flash player 11 and above instead of setting x,y separately
currPos.x = mouseX;
currPos.y = mouseY;
var mappedValue: Number = Point.distance(currPos,prevPos) / (w+h);//map the distance between points
//prevPos.copyFrom(currPos);//this works for flash player 11 and above instead of setting x,y separately
prevPos.x = mouseX;
prevPos.y = mouseY;
graphics.lineStyle(mappedValue * 100,0,1.0-(0.25+mappedValue));
if(mousePressed) graphics.lineTo(mouseX,mouseY);//if the mouse is pressed, keep drawing a line to the current mouse location
}
So going back to the tracing of a planet path, using the graphics api, my previous example would look like so:
import flash.display.*;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Point;
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var hasMoved:Boolean = false;//has the graphics 'pen' been moved ?
var spheres:Sprite = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)
var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var sun:Sprite = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var earth:Sprite = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;
earth.x = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
earthPivot.rotation += 0.12;
//draw trails
drawTrail(earth,0x0000FF);
}
function drawTrail(s:Sprite,color:int) {
var globalPos:Point = s.localToGlobal(new Point());//convert the local position of the sprite (it might have been nested several times) to the global/stage coordinate system
if(!hasMoved){//if the graphics 'pen' wasn't moved (is still at 0,0), this will happen only once: the 1st time you draw the mouse position
graphics.moveTo(globalPos.x,globalPos.y);//move it to where we're about to draw first
hasMoved = true;//and make sure we've marked that the above was done
}
graphics.lineStyle(1,color);
graphics.lineTo(globalPos.x,globalPos.y);
}
function getCircleSprite(radius:Number,color:int):Sprite{
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
circle.graphics.endFill();
return circle;
}
From my experience, using this older drawing API can get slow if you have a lot of lines on stage. I say older because it might actually be 15 years old now. Flash Player 10 introduced a newer drawing API. You can read on it on the Adobe Devnet but I warmly recommend Senocular's Flash Player 10 Drawing API Tutorial and his slides and example code from Flash Camp
Back to pixels: it's not that hard. You use the BitmapData class to manipulate pixels and use a Bitmap instance so you can add those pixels on stage. Here's a minimal drawing program:
var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);//setup pixels
addChild(new Bitmap(canvas));//add them to the stage
addEventListener(Event.ENTER_FRAME,update);//setup continuous updates
function update(e:Event):void{
canvas.setPixel(int(mouseX),int(mouseY),0x990000);//pretty easy, right ?
}
want to make trippy patterns, sure thing, have a play:
var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);//setup pixels
addChild(new Bitmap(canvas));//add them to the stage
addEventListener(Event.ENTER_FRAME,update);//setup continuous updates
function update(e:Event):void{
canvas.lock();//when updating multiple pixels or making multiple pixel operations
canvas.perlinNoise(mouseX,mouseY,mouseX/stage.stageWidth * 8,getTimer(),false,true);
canvas.unlock();//when you're done changing pixels, commit the changes
}
So, back to the trails example:
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var canvas:BitmapData = new BitmapData(w,h,false,0xFFFFFF);
addChild(new Bitmap(canvas));
var spheres:Sprite = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)
var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var sun:Sprite = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var earth:Sprite = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;
earth.x = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
earthPivot.rotation += 0.12;
//draw trails
drawTrail(earth,0x0000FF,canvas);
}
function drawTrail(s:Sprite,color:int,image:BitmapData) {
var globalPos:Point = s.localToGlobal(new Point());//convert the local position of the sprite (it might have been nested several times) to the global/stage coordinate system
image.setPixel(int(globalPos.x),int(globalPos.y),color);//colour a pixel at a set position
}
function getCircleSprite(radius:Number,color:int):Sprite{
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
circle.graphics.endFill();
return circle;
}
Which looks like this:
Not sure if it's what you want though, but pixels are fun to use and pretty fast too.
With a bit of math you can do some minimal 3D as well.
Also, for your inspiration on drawing in actionscript, you can have a look at some of Keith Peters', Erik Natzke, Joshua Davis, etc.
No, there isn't such a command, but you can always create a very simple Sprite object and add it to the stage at the corresponding position. Something like:
var dot:Sprite = new Sprite();
dot.graphics.beginFill(0xCCCCCC);
dot.graphics.drawRect(-1, -1, 2, 2);
dot.graphics.endFill();
dot.x = x;
dot.y = y;
addChild(dot);

as3 movieclip rotation according to mouse

Hi i'm looking to make a movieclip rotates depending on the angle from mouse. I have this code that seems fine according to what i search on net, but it's not working for me.
Btw, this movieclip has it's own class (Player.as) which is a child of the doc class.
I already put the movieclip on the stage.
public class Player extends MovieClip
{
private var player:MovieClip;
public function Player()
{
this.addEventListener(Event.ADDED_TO_STAGE,onStage);
}
private function onStage(e:Event)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_key_down);
stage.addEventListener(KeyboardEvent.KEY_UP, on_key_up);
this.addEventListener(Event.ENTER_FRAME,on_enter_frame);
removeEventListener(Event.ADDED_TO_STAGE,onStage);
}
private function on_enter_frame(e:Event)
{
var dist_Y:Number =mouseY -this.y ;
var dist_X:Number =mouseX -this.x ;
var angle:Number = Math.atan2(dist_Y,dist_X);
var degrees:Number = angle * 180/ Math.PI;
this.rotation = degrees;
}
}
The movieclip rotates when i move the mouse, but not accordingly. I can't find the problem with this, hope anyone could help. Thanks.
mouseX and mouseY should be stage.mouseX and stage.mouseY because you want to calculate positions in global space not in player`s local space.

Endless repeating scrolling background

I got a problem with AS3 and AIR. I'm working on a side-scrolling game for smartphones with a plane and I use different backgrounds as layers.
Before all other: I use GPU and only bitmaps, quality is set to low. So Performance settings are all set for smartphone use.
I putted them into a rectangle using the drawing API and move the background with a matrix:
protected var scrollingBitmap:BitmapData;
protected var canvas:Graphics;
protected var matrix:Matrix;
public function move(dx:Number, dy:Number):void {
matrix.translate(dx, dy);
if(dx != 0) matrix.tx %= scrollingBitmap.width;
if(dy != 0) matrix.ty %= scrollingBitmap.height;
drawCanvas();
}
protected function drawCanvas():void {
canvas.clear();
canvas.beginBitmapFill(scrollingBitmap, matrix, true, true);
canvas.drawRect(0, -scrollingBitmap.height, 1404, scrollingBitmap.height);
}
UPDATE2 (
Take a look at this: http://plasticsturgeon.com/2010/06/infinite-scrolling-bitmap-backgrounds-in-as3/
I used this to create my backgrounds.
With this I can simulate that my plane is flying to the right without moving the whole background and I can use a small single graphic which repeats every time (for the foreground layer).
For the background layer I use this method, too, but with a much larger graphic and I move it only with less the speed of my plane to simulate a far background.
My move-method is on an enterframe event. So I can update the background every frame with the "movement" of my plane.
)
The plane can exceed the height of the bitmaps. Everytime the bitmap comes back into the window/screen a real long lag occurs. And when the plane flies very fast, the game start to lag, too.
My first approach was to use .PNG files (but they are very big: 1-3MB size).
My next approach was to use .GIF files (much less size).
With both it's the same. So it can't be that.
I read about draw() and copyPixels() but I don't know, how I can use those to repeat the image.
UPDATE1:
protected var scrollingBitmap:BitmapData;
protected var canvas:Bitmap;
protected function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
canvas = new Bitmap(new BitmapData(1404, scrollingBitmap.height, true), "auto", true);
this.addChild(canvas);
drawCanvas();
}
public function move(dx:Number, dy:Number):void {
if(dx != 0) dx %= scrollingBitmap.width;
if(dy != 0) dy %= scrollingBitmap.height;
drawCanvas(dx, dy);
}
protected function drawCanvas(xPos:Number = 0, yPos:Number = 0):void {
canvas.bitmapData.copyPixels(scrollingBitmap, new Rectangle(0, 0, 1404, scrollingBitmap.height), new Point(xPos, yPos), scrollingBitmap);
}
I think you'd be better off with a Bitmap instead of using the graphics object with fill. copyPixels is very fast. So what you'd do is simply copyPixels over the top of whatever was there before, presuming everything is opaque. If everything is not opaque, you'll need to use your source bitmap as its own alpha data so previously drawn pixels don't show through.
Let's reframe your canvas so it is a Bitmap and not a MC. your new code will look like:
protected function drawCanvas():void {
canvas.bitmapData.copyPixels(scrollingBitmap, new Rectangle(0, 0, scrollingBitmap.width, scrollingBitmap.height), new Point(0,0), scrollingBitmap);
}
Oh, and look at that! Not only is this code faster, it's only one line of code!
EDIT: Added working code
package {
import flash.display.MovieClip;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.geom.Rectangle;
import flash.geom.Point;
public class EndlessBG extends MovieClip{
//this one stays stationary, we're getting the pixels for the right side of the pic from here
private var _source:BitmapData;
//this is the one moving to the left (the pixels for the right side are not visible except for once a cycle);
private var _movingPixels:BitmapData;
private var _canvas:Bitmap;
private var _xOffset:int = 0;
private var _rect:Rectangle = new Rectangle();;
private var _point:Point = new Point();
public function EndlessBG() {
super();
_source = new BathroomStillLife();
_canvas = new Bitmap(new BitmapData(_source.width, _source.height));
_canvas.bitmapData.draw(_source);
_canvas.x = stage.stageWidth/2 - _canvas.width/2;
_canvas.y = 5;
addChild(_canvas);
addEventListener(Event.ENTER_FRAME, gameLoop);
setGeometryDefaults();
_movingPixels = new BitmapData(_source.width, _source.height);
_movingPixels.copyPixels(_source, _rect, _point);
//turn this on to watch red pixels be drawn where the source pixels are coming in
//_source = new BitmapData(_source.width, _source.height, false, 0xFF0000);
}
private function gameLoop(e:Event):void {
_xOffset--;//where the background is moving to
if (_xOffset < -_source.width) {
_xOffset = 0;
//this doesn't seem to work correctly:
//_movingPixels.scroll(_source.width, 0);
_movingPixels = new BitmapData(_source.width, _source.height);
_movingPixels.copyPixels(_source, _rect, _point);
}
trace(_xOffset);
setGeometryDefaults();
_movingPixels.scroll(-1, 0);
//draw the moved part of the canvas
_canvas.bitmapData.copyPixels(_movingPixels, _rect, _point);
//If we stop here, we get a smear to the right
//so, get the remaining pixels directly from the source
//1) reset our rect and point to be to the right side
_rect.x = 0;
_rect.width = -_xOffset;
_point.x = _source.width + _xOffset;
//2) copy from the source
_canvas.bitmapData.copyPixels(_source, _rect, _point);
}
private function setGeometryDefaults():void {
_rect.x=0;
_rect.y=0;
_rect.width = _source.width;
_rect.height = _source.height;
_point.x = 0;
_point.y = 0;
}
}
}
Not ideal, and not polished enough yet for a blog post, but should get you started.
Edit:
Eventually I did write that blog post.
http://www.greensock.com/blitmask
This might help although not free

Flash CS4 AS3 horizontal movieclip scrolling with mouse move

I'm new to AS3 and have been working on an XML driven navigation system written in AS3.
At present, I've imported the contents of an XML file and plotted it inside a containing MovieClip created at root level dynamically on the stage. This MovieClip is called 'container'.
What I want to accomplish is a smooth, accelerating / decelerating effect which animates the container movieclip along the X axis depending on where the mouse cursor is in relation to the middle of the stage.
My code can be found here: http://pastie.org/521432
Line 87 onwards is the code I'm using right now to make the movieclip scroll left & right.
What I have does work but is clunky but does work - I just want it to be a little more polished and have drawn a blank with Google. Because I want the MovieClip to continue to scroll at the current relative speed even when the mouse stops moving, I used an instance of the Timer class.
Can anyone suggest improvements? Thanks in advance.
You should separate out you calculations and your drawing methods. So have it do all the calculations in an onMouseMove handler, but actually draw the changes in an onEnterFrame handler.
Also I think your algorithm could be much simpler and nobody would notice. I made a quick example of how you might do it. paste this code into an AS3 file called Main.as and make it the document class of a new FLA.
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private const boxCount:int = 10;
private const boxWidth:int = 45;
private const boxMargin:int = 5;
private const startPoint:int = 150;
private const boxesWidth:int = boxCount * (boxWidth + boxMargin);
private const endPoint:int = boxesWidth + startPoint;
private const zeroPoint:int = boxesWidth / 2 + startPoint;
private var container:MovieClip;
private var targetX:Number;
private var speed:Number = 0;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
container = new MovieClip();
addChild(container);
container.x = 150;
container.y = 300;
for (var i:int = 0; i < boxCount; i++)
{
container.graphics.beginFill(Math.random() * 0xFFFFFF);
container.graphics.drawRect(i*(boxWidth+boxMargin), 0, boxWidth, boxWidth);
}
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}
private function mouseMoveHandler(e:MouseEvent):void
{
var distanceFromCenter:int = stage.mouseX - zeroPoint;
speed = distanceFromCenter * -0.01; // Bring number into a good range, and invert it.
}
private function enterFrameHandler(e:Event):void
{
container.x += speed;
}
}
}