Dragged object tweened back into original position in actionscript 3 - actionscript-3

I have an object on my stage that can be dragged. On release, it snaps back into its orginal position. I want to be able to tween it back into its original position so that it will look smooth and not choppy. Here is the code that I have so far:
var startPosition:Point;
blockSmallz.addEventListener(MouseEvent.MOUSE_DOWN, dragz);
stage.addEventListener(MouseEvent.MOUSE_UP, dragStopz);
function dragz(e:Event):void {
blockSmallz.startDrag();
startPosition = new Point( blockSmallz.x, blockSmallz.y);
}
function dragStopz(e:Event):void {
blockSmallz.stopDrag();
//set back or tween position
blockSmallz.x = startPosition.x;
blockSmallz.y = startPosition.y;
startPosition = null;
}

You need a code based tweening library. I would recommend learning GTween: http://www.gskinner.com/libraries/gtween/
After importing the libary, at the point where you go:
blockSmallz.x = startPosition.x;
blockSmallz.y = startPosition.y;
You would simply instead insert a line of code to tween it back. Something as simple as:
GTweener.addTween (blockSmallz, 1, { x:startPosition.x, y:startPosition.y } );

Related

Flash/AS3 - MovieClip into Bitmap

I need to turn a MovieClip that I have on the stage into a Bitmap. The function I have made for this halfway works; it does make a Bitmap from the MovieClip with the correct image, but it does not rotate it.
Here is the function
function makeBitmapData(mov):BitmapData
{
var bmpData:BitmapData = new BitmapData(mov.width, mov.height, true, 0);
bmpData.draw(mov);
this.addChild(new Bitmap(bmpData)); //Shows the bitmap on screen purely for example
return bmpData;
}
Here is the output
How should I rotate the bitmap or just purely copy all the pixels in that bitmap, rotated and all?
Have you checked rotate() function and fl.motion.MatrixTransformer class? Also this question looks helpful.
In the function that implements your code.
var b:Bitmap = new Bitmap ( makeBitmapData(mov) );
addChild(b);
b.rotation = mov.rotation;
One way to accomplish this, is to draw from the items parent instead, that way any transformation/filters will be reflected in the bitmap data captured. So something like this:
function makeBitmapData(mov:DisplayObject):BitmapData
{
var rect:Rectangle = mov.getBounds(mov.parent); //get the bounds of the item relative to it's parent
var bmpData:BitmapData = new BitmapData(rect.width, rect.height, false, 0xFF0000);
//you have to pass a matrix so you only draw the part of the parent that contains the child.
bmpData.draw(mov.parent, new Matrix(1,0,0,1,-rect.x,-rect.y));
addChild(new Bitmap(bmpData)); //Shows the bitmap on screen purely for example
return bmpData;
}

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 :)

Comparing bitmap is not working

I am trying to compare the bitmap 1 to bitmap 2 and if they equal to 0 I want them to do something. so for sake of seeing what it's returning I added a trace. but it seems like it's tracing out something totally different from what I expected. This is the code:
var scratch_c : Scratch_card = new Scratch_card ();
var backgr: Background = new Background ();
var mouseclick:Number;
var masking:Sprite = new Sprite()
var bmd1:BitmapData = new BitmapData(742, 165);
var bm:Bitmap = new Bitmap(bmd1);
addChild (bm);
bm.x=20;
bm.y=40;
bmd1.draw(scratch_c);
var bmd2:BitmapData = new BitmapData(742, 165);
var bm2:Bitmap = new Bitmap(bmd2);
addChild (bm2);
bm2.x=20;
bm2.y=40;
bmd2.draw(backgr);
bm2.mask = masking;
addChild(masking);
stage.addEventListener(MouseEvent.MOUSE_DOWN, Pressing);
stage.addEventListener(MouseEvent.MOUSE_MOVE, Moving);
stage.addEventListener(MouseEvent.MOUSE_UP, Lifting);
function Pressing(event:MouseEvent):void {
mouseclick = 1;
}
function Moving(event:MouseEvent):void {
if (mouseclick == 1) {
masking.graphics.beginFill(0x000000);
masking.graphics.drawEllipse(mouseX, mouseY, 70, 60);
masking.graphics.endFill();
}
}
function Lifting(event:MouseEvent):void {
trace(bmd1.compare(bmd2));
mouseclick = 0;
}
This is what it is tracing out
How can I make it compare the pixels of bmd1 and bmd2?
Why is it not returning a number?
Not a percentage but it should return a new BitMapData object that you could assign as an image.
BitMapData.compare( )
Returns Object — If the two BitmapData objects have the same dimensions (width and height), the method returns a new BitmapData object that has the difference between the two objects (see the main discussion). If the BitmapData objects are equivalent, the method returns the number 0. If the widths of the BitmapData objects are not equal, the method returns the number -3. If the heights of the BitmapData objects are not equal, the method returns the number -4.
Taken from here
Result:
Your bitmaps are not equivalent, thats why you get an object made of 2 different bitmaps.
Have you tried
if(bmd1.compare(bmd2) == bmd2){
// complete
}
However after looking at your code a little more. i think you need to test on the masking not bmd1
So something like this.
var mymask:BitmapData = new BitmapData(742, 165, true,0x000000000);
mymask.draw(masking);
if(mymask.compare(bmd2) == bmd2){
// complete
}
untested code but should put you on the right path

how to move a movie clip from a ref movie clip

I want to make a movieClip which has a reference of another movie clip move.
But when i do it it stays still.
Here is an example code i am trying to do
var movieClip1 = new movieClip();
var movieClip2 = new movieClip();
movieClip1.ref = movieClip2;
movieClip1.x = 0;
movieClip2.x = 0;
addChild(movieClip1);
addChild(movieClip2);
while(movieClip1.x !=300){
movieClip1.x +=1;
// i want to make the reference of the clip move as well
movieClip1.ref.x = movieClip1.x;
}
How are you wanting it to move? Progressively, 1 unit at a time? If so Don't use a while loop or it will simply jump straight to 300 (x position).
Instead use some sort of update loop like an enter frame listener:
addEventListener(Event.ENTER_FRAME, Update);
function Update(e:Event):void
{
mc1.x++;
mc1.ref.x = mc1.x;
}

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.