As3 How to remove or update bitmapdata for a new level? - actionscript-3

I'm making a maze game. The character can't walk through the walls of the maze (because of a collition detection between the bitmapdata from the character and the bmd from the walls). When the character arrives at a door, the next level/frame should appear with a new maze (new bounds)
For the next level (next frame), I made a new maze with different walls. But the bitmapdata from the first maze is still 'active'. So even though there's a new maze, the bitmapdata from the previous walls is invisible but still drawn on the stage.
My question to you is:
I want to change the bounds/maze every frame, how can I remove the previous bitmapdata so the character won't walk through the bounds of the next maze? Or is it possible to make an array from the different 'bounds'?
stop();
var isRight:Boolean=false;
var isLeft:Boolean=false;
var isUp:Boolean=false;
var isDown:Boolean=false;
var speed:int = 10;
var mazeRect:Rectangle = bounds.getBounds(this);
var charRect:Rectangle = char.getBounds(this);
var boundsBmpData = new BitmapData(mazeRect.width, mazeRect.height, true, 0);
var charBmpData = new BitmapData(charRect.width, charRect.height, true, 0);
boundsBmpData.draw(bounds);
charBmpData.draw(char);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.ENTER_FRAME, moving);
function keyPressed(event:KeyboardEvent):void
{
if(event.keyCode==39){
isRight=true}
if(event.keyCode==37){
isLeft=true}
if(event.keyCode==38){
isUp=true}
if(event.keyCode==40){
isDown=true}
}
function keyReleased(event:KeyboardEvent)
{
if(event.keyCode==39){
isRight=false}
if(event.keyCode==37){
isLeft=false}
if(event.keyCode==38){
isUp=false}
if(event.keyCode==40){
isDown=false}
}
function moving(e: Event): void
{
var newx: Number = char.x - (isLeft ? speed : 0) + (isRight ? speed : 0);
var newy: Number = char.y - (isUp ? speed : 0) + (isDown ? speed : 0);
if(!boundsBmpData.hitTest(new Point(bounds.x, bounds.y),
255,
charBmpData,
new Point(newx, newy),
255))
{
char.x = newx;
char.y = newy;
}
if(char.hitTestObject(door))
{
onHitTest();
}
}
function onHitTest() : void
{
nextFrame();
}

Maybe try calling dispose() on old BitmapData first and then create new one?

After looking at the FLA, there were a few issues.
the main one is that though you switched frames, you did not reset your pointers to the bounds object, the door object, and the char object. So you were still tied to the old ones programmatically, though not visually.
I put the declarations into a method called setupFrame(), and call it from your onHitTest() method.
I added a check in onHitTest() to make sure that the bounds object exists in the current frame before setting up the frame. If not, the game stops.
The actions and char layers now extend across the entire game timeline, since they are reused.
char object is now repositioned each frame using points found in the startPts array, instead of having to recreate it each time.
removed the event listeners during the frame setup, and add them at the end of the frame setup. This prevents possible errors from listening to the events.
This is a pretty good effort at creating a simple game engine. Just fyi, gamedev.stackexchange.com is a place devoted to all levels of game development, and you can ask more theoretical questions there.
HTH!

Related

Playing a sequence of given frames using ActionScript3 Flash

I Am beginner with Flash and ActionScript 3
I have 8 lip code for a character that i did create in different frames, so i want to play my animation frame by frame but with a different order to form a phrase that my character will say
I did try it on my own but i did not successed:
stop();
var tableau = new Array();
tableau[0]=2;
tableau[1]=4;
tableau[2]=1;
tableau[3]=7;
tableau[4]=8;
tableau[5]=1;
tableau[6]=7;
for(var i =0;i<tableau.length;i++){
trace(tableau[i]==this.currentFrame);
if(tableau[i]==this.currentFrame){
gotoAndPlay(tableau[i]);
trace(this.currentFrame);
}
}
It's pretty much simple. What you need is to subscribe to the special event that fires once per frame and move the playhead once per frame according to the plan.
stop();
var Frames:Array;
// This will prevent things from overlapping
// if one of the frames on the list is the
// current one and playhead will hit here
// once again (and try to execute code).
if (Frames == null)
{
Frames = [2,4,1,7,8,1,7];
addEventListener(Event.ENTER_FRAME, onFrame);
}
function onFrame(e:Event):void
{
// Get the next frame index and remove it from the list.
var aFrame:int = Frames.shift();
// If there are no more frames to show,
// unsubscribe from the event.
if (Frames.length < 1)
{
removeEventListener(Event.ENTER_FRAME, onFrame);
}
gotoAndStop(aFrame);
}

AS3 shuffling movieclips

I've added the basic targets and applying drag and drop for my puzzle pieces, now Im having trouble making the shuffling aspect. As in, after the player completes or opens up the fla, each time will start the puzzle pieces in random places of the stage. I understand using arrays for shuffling somehow but Im not sure exactly how to achieve this. I've stored the instance of my 19 puzzle pieces inside the array but now I have no idea what to do with this array. Other tutorials were abit out of my league and leaves my head scratching.
Just started doing coding for flash professional so yeah, any help with the shuffling movie clips ie the puzzles pieces would be greatly appreciated.
Heres's my code, Im not posting the whole thing since from P1 to P19 is basically copy pasting:
import flash.events.Event;
stage.addEventListener(Event.ENTER_FRAME, EntFrame)
function EntFrame(e: Event) : void
{
P1.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
function fl_ClickToDrag(event:MouseEvent):void
{
P1.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
function fl_ReleaseToDrop(event:MouseEvent):void
{
P1.stopDrag();
}
if (T1.hitTestObject(P1.Tar1))
{
P1.x = 313.15;
P1.y = 242.75;
}
P19.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag_19);
function fl_ClickToDrag_19(event:MouseEvent):void
{
P19.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop_19);
function fl_ReleaseToDrop_19(event:MouseEvent):void
{
P19.stopDrag();
}
if (T19.hitTestObject(P19.Tar19))
{
P19.x = 624.35;
P19.y = 455.60;
}
}
Here is what I hope is more holistic answer.
First, ditch those inline functions. Right now you make an ENTER_FRAME listener and inside that function you have inline function defined. This means every frame tick (which is tied to your frame rate, not the main timeline), those functions are going to get created again, and since you are adding them as handlers for listeners, they will stay in memory forever.
Here is a way you code this, showing ways to reduce redundancy and get rid of those memory leaks. This assumes the following:
You have 19 objects on the stage called T1 - T19, that represent the possible locations the pieces can go.
You have 19 pieces on the stage called P1 - P19, that, and the numbers correlate to the T locations as per the correct location of the piece.
//let's create a function to randomize the piece location
function seedPieces() {
//create an array consisting of the integers 1 - 19
var unusedSpaces:Vector.<int> = new Vector.<int>;
var i:int;
for (i = 1; i <= 19; i++) {
//populate that array
unusedSpaces.push(i);
}
var curLocation:DisplayObject; //helper var for the loop below
var curPiece:Sprite; //helper var for the loop below
//loop 19 times (from 1 - 19) - one iteration for each piece
for (i = 1; i <= 19; i++) {
curPiece = this["P" + i] as Sprite; //you can get the piece this way, or use an array if you've made one, like `pieces[i];`
trace(curPiece.name);
//splice removes and returns the item at the specified index (in this case a random number between 0 and arrays length less 1) - the second parameter is amount of items to remove (just 1 for this case)
curLocation = this["T" + unusedSpaces.splice(int(Math.random() * unusedSpaces.length), 1)] as DisplayObject;
trace(" ",curLocation.name);
//move the piece to the random location:
curPiece.x = curLocation.x;
curPiece.y = curLocation.y;
}
}
//NOW, as an aside, you should use a loop to add all your listeners for the sake of sanity - if you have them in an array, loop through that, or use the sloppy way like this:
for (var i:int = 1; i <= 19; i++) {
Sprite(this["P" + i]).addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
}
//create a var to hold any piece that is currently being dragged, so you know which piece to stop drag on later
var currentDraggingItem:Sprite;
seedPieces();
function fl_ClickToDrag(event:MouseEvent):void
{
//assign this clicked item to the currentDraggingItem var
currentDraggingItem = event.currentTarget as Sprite;
//bring this one to the front
currentDraggingItem.parent.addChild(currentDraggingItem);
//you can use this one click handler for all pieces
//the piece that was actually clicked, is referenced by event.currentTarget
currentDraggingItem.startDrag();
//add the mouse up listener now that the mouse is currently DOWN
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
//listen every frame while dragging
stage.addEventListener(Event.ENTER_FRAME, EntFrame);
}
function fl_ReleaseToDrop(event:MouseEvent):void
{
//if currentDraggingItem has a value, stop drag it
if (currentDraggingItem) {
currentDraggingItem.stopDrag();
//send to the back
currentDraggingItem.parent.addChildAt(currentDraggingItem,0);
}
//remove the mouse up and enter frame listener now that the mouse is UP
stage.removeEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
stage.removeEventListener(Event.ENTER_FRAME, EntFrame);
if(checkComplete()){
//game over, do something
}
}
function EntFrame(e: Event) : void
{
//this will snap the peice to the correct spot when the mouse is touching the correct spot
if(currentDraggingItem){
if (this[currentDraggingItem.name.replace("P","T")].hitTestPoint(mouseX,mouseY))
{
currentDraggingItem.x = this[currentDraggingItem.name.replace("P","T")].x;
currentDraggingItem.y = this[currentDraggingItem.name.replace("P","T")].y;
}
}
}
function checkComplete():Boolean {
//use a loop to go through all your pieces and check if they are in the right spot. Again, you could have them in an array, or do it the lazy way
for (var i:int = 1; i <= 19; i++) {
if (!this["T"+i].hitTestObject(this["P"+i]))
{
return false;
}
}
return true;
}
Well, in general you can shuffle with the following code:
var shuffledVector:Vector.<someClass> = new Vector.<someClass>;
while (originalVector.length > 0) {
shuffledVector.push(originalVector.splice(Math.random() * originalVector.length, 1)[0]);
}
Longer, explained version:
var shuffledVector:Vector.<someClass> = new Vector.<someClass>; //We will store our shuffled vector in here
var randomIndex:int; //Random index from the originalVector
var resultVector:Vector.<someClass>; //result from the originalVector.splice(...) function
var randomElement:someClass; //Random element from the originalVector
while (originalVector.length > 0) { //We will reduce the size of the originalVector until the originalVector is empty.
randomIndex = Math.random() * originalVector.length; //Calculate a random index within the range of the originalVector from 0 to originalVector.lenght-1 (note that the range decreases by one on every loop)
randomVector = originalVector.splice(randomIndex, 1); //Use splice to remove one element at the randomly choosen index, we will receive a vector with the removed element...
randomElement = randomVector[0]; //...so we need to access the element
shuffledVector.push(randomElement); //Add the randomly choosen element to our shuffled vector
}
I've written the code for a vector as i suggest to use a vector instead of an array, but the principle behind it is the same for an array.
In your case the originalVector is a vector filled with your P1-P19 Movieclips and someClass would be MovieClip. The originalVector is empty at the end and could be replaced with the shuffled one and of course it would make a lot more sense if you put the code in a seperate function like this:
function Shuffle(originalVector:Vector.<someClass>) : void {
var shuffledVector:Vector.<someClass> = new Vector.<someClass>;
while (originalVector.length > 0) {
shuffledVector.push(originalVector.splice(Math.random() * originalVector.length, 1)[0]);
}
originalVector = shuffledVector;
}
Offtopic, but important for further coding: Someone else already mentioned, that it is not good to add EventListeners on every frame, because it is absolutely unnecessary. You only need to add the Listeners once. Your code is very repetitive, you should use a function which accepts a MovieClip, x and y then call that function 19 times.
e.g.:
function setUpMovieClip(MC:MovieClip, x:int, y:int) : {
MC.addEventListener(MouseEvent.MOUSE_DOWN, clickToDrag);
//more code...
}
within the clickToDrag function you can access the MovieClip which was clicked via the event.target property:
function clickToDrag(e:MouseEvent) : {
e.target.startDrag();
//more code...
}
I hope you get the idea.

AS3 tracking and using coordinates of a rotated object

How does one track and use the coordinates of an object that is rotated on initialization?
Let's say I have a sword that is put on the stage in Main init(); and rotated (adjusted) so that it would look ok together with the character perspective. In another class however, I am making the sword rotate some more on a keypress timer event so to create a 'swing' animation.
All this is done through flashdevelop. I only used CS6 to create the symbols. And as this 'swing' is happening, I want to add another symbol onto the tip of the sword which is a collision point object. It's being added to the stage when the swing starts and removed after every swing. I want this object to follow the very tip of the sword, yet it seems like I can only achieve that it follows the coordinates of the original sword object, as if I hadn't initially modified the rotation of the said sword. I tried to implement GlobalToLocal() and LocalToGlobal() methods, but I don't think I fully understand what is happening with that.
I hope I'm being clear enough of what I'm trying to do. Thank you. This is the relevant code in question. The code is as was before I tried the two mentioned methods and the issue currently is exactly as described before that. Do I want any of those methods or am I just doing something else wrong?
Main initialization:
sword = new Sword();
sword.x = 53;
sword.y = 90;
addChild(sword);
sword.rotationZ = -150;
sword.rotationY = 25;
sword.rotationX = -15;
Coll_Point = new coll_point();
The class that deals with the swing has a method like this:
private function SwingTime(event:Event):void
{
Main.Coll_Point.x = Main.sword.x + Main.sword.width;
Main.Coll_Point.y = Main.sword.y + Main.sword.height;
Main.MazeNr1.addChild(Main.Coll_Point);
if (Main.sword.rotationZ > -330)
Main.sword.rotationZ -= 20;
if (Main.sword.rotationX < 15)
Main.sword.rotationX += 10;
if ((Main.sword.rotationZ == -330) && (Main.sword.rotationX == 15))
{
SwingTimer.stop();
SwingBckTimer.start();
}
}
Edit:
A more holistic version of the code:
public class Main extends MovieClip
{
public static var from_point:Point = null;
public static var to_point:Point = new Point();
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
// Puts everything on the stage here.
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
PlayerInst = new Dorf();
PlayerInst.x = 45;
PlayerInst.y = 51;
addChild(PlayerInst);
sword = new Sword();
sword.x = 53;
sword.y = 90;
sword.rotationZ = -150;
sword.rotationY = 25;
sword.rotationX = -15;
from_point = new Point (Main.sword.width, Main.sword.height);
to_point = sword.localToGlobal(from_point);
addChild(sword);
swordBD = new BitmapData(32, 32, true, 0x0000000000);
swordBD.draw(sword);
Coll_Point = new coll_point();
Coll_PointBD = new BitmapData(2, 2, true, 0x0000000000);
Coll_PointBD.draw(Coll_Point);
}
}
This is how the Main looks like and literally every single object instantiation is added onto the stage this way. Including collision points, background, characters, gradient fills of line of sight radius, etc. And the relevant symbol class goes somewhat like this:
public class Creature extends MovieClip
{
protected var Swing:Boolean;
private var SwingTimer:Timer = new Timer (5, 0);
private var SwingBckTimer:Timer = new Timer (150, 1);
// Constructor.
public function Creature()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
// Initializer.
private function init(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
SwingTimer.addEventListener(TimerEvent.TIMER, SwingTime);
SwingBckTimer.addEventListener(TimerEvent.TIMER, SwingBack);
}
private function SwingAction():void
{
if (Swing == true)
{
SwingTimer.start();
}
}
private function SwingTime(event:Event):void
{
Main.Coll_Point.x = Main.sword.localToGlobal(Main.from_point).x;
Main.Coll_Point.y = Main.sword.localToGlobal(Main.from_point).y;
Main.sword.addChild(Main.Coll_Point);
trace(Main.Coll_Point.x);
trace(Main.Coll_Point.y);
if (Main.sword.rotationZ > -330)
Main.sword.rotationZ -= 20;
if (Main.sword.rotationX < 15)
Main.sword.rotationX += 10;
if ((Main.sword.rotationZ == -330) && (Main.sword.rotationX == 15))
{
SwingTimer.stop();
SwingBckTimer.start();
}
}
private function SwingBack(event:Event):void
{
Main.sword.rotationZ = -150;
Main.sword.rotationX = -15;
//Main.MazeNr1.removeChild(Main.Coll_Point);
}
There is also a rather long update(); function that animates and moves every single object that needs moving.
I think your problem might be in
Main.Coll_Point.x = Main.sword.x + Main.sword.width;
Main.Coll_Point.y = Main.sword.y + Main.sword.height;
Coll_Point expects global coordinates.
The parts + Main.sword.width and + Main.sword.height only work as expected if the sword is not rotated so that height is aligned with the y-axis and width with the x-axis.
You should use localToGlobal() on the position that is local to Main.sword (
Main.sword.width, Main.sword.height) to get the global position that represents the swords rotated tip before you add it as a child.
There are two ways you can approach this (you seem to have somewhat combined both). You can either
Add the Coll_Point as a child to something above the sword in hierarchy (Stage, MazeNr1, ...) and update the position manually every timer callback. You would have to recalculate the position everytime, so take the localToGlobal() from init to your timer function. It won't update if it doesn't get called.
For that you should have this kind of code in the timer callback:
var local:Point = new Point(Main.sword.width, Main.sword.height);
var global:Point = Main.sword.localToGlobal(local);
Main.Coll_Point.x = global.x;
Main.Coll_Point.y = global.y;
Add the point as a child to the sword. This might be a better approach as then the position will be updated automatically. What I did not remember before was that you then give the coordinates in "local" form, so do not use localToGlobal()
Run this once where you create the Collision_Point:
Coll_Point.x = <your x offset>;
Coll_Point.y = <your y offset>;
Main.sword.attachChild(Coll_Point);
Instead of sword height and width you might want to try something like -height and width/2.
Here is a quick (and not the prettiest) picture to demonstrate the problem. Local space is rotated with the object:
The only thing I can imagine to help you with this problem is to have your collision object have the same registration point as the sword. What I mean is that the orientation points should match, and the collision graphic should be moved inside of the sprite so that it matches the position of the top of the sword.
This way you can put the collision object at the very same location of the sword and apply the very same rotation. This way it will move along with the top of the sword and still have hitTest working properly.
I cannot imagine any other way to figure this out as any code will get bounds and positions. But the real thing that matters is the registration point and the top of the sword, which is a graphic thing and cannot be dealt with coding.
I hope you can imagine what I mean - if now, just say and I will provide an image for you :)

Enemy move randomly

To make things quick, I have an arrangement of tiles that a player and an enemy are on.
public static var floor1:Array = new Array(7);
floor1[0] = [0,1,1,1,1,1,0];
floor1[1] = [1,1,1,1,1,1,1];
floor1[2] = [1,1,1,0,1,1,1];
floor1[3] = [1,1,0,0,0,1,1];
floor1[4] = [1,1,1,0,1,1,1];
floor1[5] = [1,1,1,1,1,1,1];
floor1[6] = [0,1,1,1,1,1,0];
public function Main()
{
var tilew:int = 60;
var tileh:int = 60;
for (var i:int=0; i<floor1.length; i++)
{
for (var u:int=0; u<floor1[i].length; u++)
{
var cell:MovieClip = new Tile();
cell.gotoAndStop(floor1[i][u]);
cell.x = ((u-i)*tileh);
cell.y = ((u+i)*tilew/2);
addChild(cell);
cell.addEventListener(MouseEvent.ROLL_OVER, mouseover);
cell.addEventListener(MouseEvent.ROLL_OUT, mouseout);
cell.addEventListener(MouseEvent.CLICK, mouseclick);
cell.addEventListener(Event.ENTER_FRAME, beginfloor1);
}
}
var player:Player = new Player();
addChild(player);
player.mouseEnabled = false;
player.x = 5 * (tileh);
player.y = 5 * (tilew/2);
var enemy:Enemy = new Enemy();
addChild(enemy);
enemy.mouseEnabled = false;
enemy.x = 9 * (tileh);
enemy.y = 9 * (tileh/2);
My goal is to have the enemy move randomly on tiles in his range. What I did was create a square graphic called enemyVisionArea that checks which tile is hitting the enemy, which is basically surrounding tiles.
I have a timer function that tells the enemy to move every 5 seconds if the player isn't near him and if he's next to an available tile.
function timerenemy (event:TimerEvent){
if (enemy.enemyVisionArea.hitTestObject(enemyMover) && !player.visionPoint.hitTestObject(enemyMover.tileMiddle))
{
enemy.x = (enemyMover.x)+55;
enemy.y = (enemyMover.y)+20;
trace("moved");
}
}
enemyMover is a variable that I made equal to the tile objects.
function beginfloor1(event:Event)
{
enemyMover = event.currentTarget as Tile;
}
It just stays where it is. I'm just want to have the enemy move on its own on any tile that its enemyVisionArea is hitTesting a nearby tile. The beginfloor1 function doesn't seem to be working. Is there any way I can declare enemyMover = event.currentTarget as Tile and have the enemy move on a random tile that its enemyVisionArea is hitTesting?
If this is confusing, I can post the full code.
You are assigning 49 enterframe listeners which are called in sequence, and they ALL change one single variable to the cell they are attached to. Of course, the last tile is what's always assigned.
I expect that you want an enemy to check if there's a tile available for it to move to. You are essentially checking for one tile which is enemyMover - how do you determine what's that tile? You have to check all available tiles that are around the enemy, make a list of them and select one out of that list that's not the current tile, then move the enemy there.
So, first you need a complete tileset to be addressable from somewhere. The best way will be to declare a class-wide var tileset:Array and fill it where you make new tiles. Drop the Event.ENTER_FRAME listener from the code there, as it's useless. Then, in your timerevent that's for the enemy you do check all of the tileset if they are within your enemy's vision area (you use hitTestObject, I'd use clear distance grid-wise or coordinate-wise - it's a whole lot faster), if so, you add them to the TEMPORARY array you create within that function. Of course, if your enemy is at the currently processed cell, you ignore it - you have to move your enemy, not make him stand in place. Then, select (somehow, it's up to you) what cell your enemy should move to, and execute a move. Yes, if you want your enemy to move randomly, select a cell at random by its index via Math.floor(Math.random()*selectedcells.length).

Make an object snap to another ojbect, then follow its path with pure ActionScript?

I am still trying to come to grips with how make an object snap to another ojbect, then follow its path with pure ActionScript (snap an arrow oject to a circle, then the circle follows the direct of the arrow when play button in hit).
Can somebody please help me with an small example so I can get my head round it, any help will be much appreciated. I am trying to create an application aimed towards something like this
http://itunes.apple.com/us/app/basketball-coachs-clipboard/id317785081?mt=8
I have got my drawing line working but do now know how to make the object follow the line, here is how I have drawn my line on the stage. Please could you give me a clue of how to do this.
function startPencilTool(e:MouseEvent):void
{
pencilDraw = new Shape();
board.addChild(pencilDraw);
pencilDraw.graphics.moveTo(mouseX, mouseY);
pencilDraw.graphics.lineStyle(shapeSize.width);
board.addEventListener(MouseEvent.MOUSE_MOVE, drawPencilTool);
}
function drawPencilTool(e:MouseEvent):void
{
pencilDraw.graphics.lineTo(mouseX, mouseY); /
}
function stopPencilTool(e:MouseEvent):void
{
board.removeEventListener(MouseEvent.MOUSE_MOVE, drawPencilTool);
}
1st
If you mean by "following its path", that the object follows another object, then simply do
obj2.x = obj1.x;
obj2.y = obj1.y;
to follow the exact coordinates. If you want to make some distance between them, then
obj2.x = obj1.x + dx;
obj2.y = obj1.y + dy;
choose dx and dy according to your wish.
2nd
If you want to make an app, where you can "draw an arrow" or "draw a path" and then an object should follow it, then you can try to store the coordinates of the mouse, while "drawing the arrow", then snap the object you want to these coordinates.
var coordinates:Array = [];
stage.addEventListener("mouseDown", md);
function md(evt:*):void
{
//empty the coordinates
coordinates = [];
//add listener when mouse is released
stage.addEventListener("mouseUp", mu);
//add a listener for enterframe to record the mouse's motion
addEventListener("enterFrame", recordMouse);
}
function mu(evt:*):void
{
stage.removeEventListener("mouseUp", mu);
removeEventListener("enterFrame", recordMouse);
//snap the object to the drawn line and play it
addEventListener("enterFrame", playRecording);
}
function recordMouse(evt:*):void
{
coordinates.push(new Point(stage.mouseX, stage.mouseY));
}
function playRecording(evt:*):void
{
//snap object to the recorded coordinates
myObject.x = coordinates[0].x;
myObject.y = coordinates[0].y;
//delete first element of array
coordinates.splice(0, 1);
//stop playing if there are no more points
if(coordinates.length == 0) removeEventListener("enterFrame", playRecording);
}
Place a movieclip on the stage and name it myObject. Then add the code and compile the swf.
Also, while "recoring" the coordinates, you can also draw some lines.
Change md function to this:
function md(evt:*):void
{
//empty the coordinates
coordinates = [];
//add listener when mouse is released
stage.addEventListener("mouseUp", mu);
//add a listener for enterframe to record the mouse's motion
addEventListener("enterFrame", recordMouse);
//clear graphics, and initialize line
with(graphics) clear(), lineStyle(1, 0xff0000), moveTo(stage.mouseX, stage.mouseY);
}
and recordmouse to this.
function recordMouse(evt:*):void
{
coordinates.push(new Point(stage.mouseX, stage.mouseY));
//draw the line
with(graphics) lineTo(stage.mouseX, stage.mouseY);
}
3rd
If you want to follow a pre-drawn line, then you have several options depending on your task. But everything depends on, how you exactly want to "snap" your object.