Stretch and rotate a Movieclip without distortion - actionscript-3

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

Related

Actionscript hitTest drawing

I've gotten actions on a frame, what I'm trying to do is have a hitTest that triggers gotoAndStop(<lose frame>) when the shape I am drawing collides with the touchTest. The only issue I'm having is I cannot get the hitTest to register directly when the line hits it, it only registers after the next click event. The other issue I'm encountering is a hit box on the touchTest is many times larger than the actual image of the symbol.
var myshape:Shape;
myshape = new Shape();
myshape.graphics.lineStyle(5, 0xC807DE);
var alreadyDrawn:Shape;
alreadyDrawn = new Shape();
stage.addEventListener(MouseEvent.MOUSE_DOWN, activateDraw);
function activateDraw(event:MouseEvent):void
{
myshape.graphics.moveTo(mouseX,mouseY);
addChild(myshape);
stage.addEventListener(MouseEvent.MOUSE_MOVE, lineDraw);
stage.addEventListener(MouseEvent.MOUSE_UP, stopDraw);
}
function lineDraw(event:MouseEvent):void
{
myshape.graphics.lineTo(mouseX,mouseY);
checkIt();
}
function stopDraw(event:MouseEvent):void
{
alreadyDrawn.graphics.copyFrom(myshape.graphics);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, lineDraw);
stage.removeEventListener(MouseEvent.MOUSE_UP, stopDraw);
}
function checkIt()
{
if (alreadyDrawn.hitTestObject(touchTest) == true)
{
trace("wall");
myshape.graphics.clear();
myshape.graphics.lineStyle(5, 0xC807DE);
alreadyDrawn.graphics.clear(); // clear this too
stopDraw(null); // stop active draw, if any
}
}
it only registers after the next click event
This is because the object you are testing the collision against alreadyDrawn doesn't have a collision area yet. You create the new shape, add your listeners, and test your collision in your lineDraw() using the method checkIt(), but the shape doesn't have a collision area until your mouse up function stopDraw() where it does alreadyDrawn.graphics.copyFrom(myshape.graphics);
So to fix this you would have to create the graphics object earlier. The change could look something like this (at the top):
var alreadyDrawn:Shape = new Shape();
alreadyDrawn.graphics.copyFrom(myshape.graphics);
That would give a collision area to test against in checkIt()
The other issue I'm encountering is a hit box on the touchTest is many
times larger than the actual image of the symbol.
For this issue, you can access the clip or a symbol inside it and grab its bounds relative to the parent of the alreadyDrawn shape. Then you can use the bounds of both shapes to test for a collision. This will give you a more accurate collision area for testing:
function checkIt()
{
var alreadyDrawnBounds:Rectangle = alreadyDrawn.getBounds( alreadyDrawn.parent );
var testBounds:Rectangle = touchTest.someSymbolName.getBounds( alreadyDrawn.parent );
//could also try this instead:
//var alreadyDrawnBounds:Rectangle = alreadyDrawn.getBounds( touchTest.parent );
//var testBounds:Rectangle = touchTest.getBounds( touchTest );
if ( alreadyDrawnBounds.intersects( testBounds ) ) {
trace("wall");
myshape.graphics.clear();
myshape.graphics.lineStyle(5, 0xC807DE);
alreadyDrawn.graphics.clear(); // clear this too
stopDraw(null); // stop active draw, if any
}
}

AS3 Creating a drawing app using bitmapdata

I'm trying to create a drawing application that renders vector lines into bitmap. I've read the documentation about bitmapdata and I have a basic understanding of how it should work. But I'm having some trouble. As of right now my goal is simple, allow the user to draw lines with their mouse, that's all I want. The problem is somewhere with the matrix i'm using, could someone help me out?
import flash.display.Sprite; //imports needed
import flash.events.Event;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.events.MouseEvent;
import flash.geom.Matrix;
var draw:Boolean = false; //Boolean to determine when the mouse is down since bitmapdata doesnt receieve mouse events.
var brush:Sprite =new Sprite(); // Creating the "brush", determining the stroke it will make.
brush.graphics.lineStyle(0x000000);
brush.graphics.lineTo(mouseX,mouseY);
var data:BitmapData = new BitmapData(600,400, false); // Creating bitmapdata to allow the work with pixels.
var canvas:Bitmap = new Bitmap(data);
addChild(canvas);
stage.addEventListener(MouseEvent.MOUSE_DOWN, drawStart); // Event listeners to determine when the mouse is up or down.
stage.addEventListener(MouseEvent.MOUSE_UP, drawStop);
stage.addEventListener(Event.ENTER_FRAME, render);
function drawStart(e:MouseEvent):void // When the mouse is down we are drawing
{
draw= true;
}
function drawStop(e:MouseEvent):void // When the mouse is up we are not drawing
{
draw= false;
}
function render(e:Event):void //Rendering the vector into bitmap
{
if(!draw) return;
var mat:Matrix=new Matrix(); // We need a matrix to get the correct mouse coordinates
mat.translate(mouseX,mouseY)
data.draw(brush,mat); // Then we draw the bitmap into vector.
}
I have listed comments to show what I understand is happening. If I have gotten something wrong i'd like it if someone could explain it better to me.
When tested, the program draws lines, but all it does is draw a line to the mouse position from some other seemingly random position. So I figure the problem has something to do with the matrix.
I appreciate any help I can get, i've been looking at this for a while and it's just not clicking. Thanks.
The main problem with your code is that you draw the line into your bush.graphics only once (when your app starts), before any user input and then draw that same line into your bitmap data every frame as long as the mouse is down.
One way to do things correctly would be to redraw that line every frame while the user keeps the mouse key down. The drawing should happen in your brush.graphics (which now serves more like a canvas) and finally, once the user releases the mouse the line he has drawn should be rendered into the bitmap data so you can reuse your brush.graphics for drawing new lines.
var draw:Boolean = false; //Boolean to determine when the mouse is down since bitmapdata doesnt receieve mouse events.
var brush:Sprite;
var canvas:Bitmap;
var data:BitmapData;
var start:Point = new Point();
brush = new Sprite(); // This will serve as a canvas
data = new BitmapData(600,400, false); // Creating bitmapdata to allow the work with pixels.
canvas = new Bitmap(data);
addChild(canvas);
addChild(brush); // Add to display list so we can see what we are drawing visually
stage.addEventListener(MouseEvent.MOUSE_DOWN, drawStart); // Event listeners to determine when the mouse is up or down.
stage.addEventListener(MouseEvent.MOUSE_UP, drawStop);
stage.addEventListener(Event.ENTER_FRAME, render);
private function drawStart(e:MouseEvent):void // When the mouse is down we are drawing
{
draw = true;
start.setTo(e.localX, e.localY); // Save mouse position at interaction start
}
private function drawStop(e:MouseEvent):void // When the mouse is up we are not drawing
{
draw = false;
data.draw(brush, null); // User released the mouse and we can draw the result into bitmap
}
private function render(e:Event):void //Rendering the vector into bitmap
{
if(!draw) return;
// Redraw the line each frame as long as the mouse is down
brush.graphics.clear();
brush.graphics.lineStyle(0x000000);
brush.graphics.moveTo(start.x, start.y);
brush.graphics.lineTo(mouseX, mouseY);
}

over drawn the circle when input angle in actionscript?

var theTextField:TextField = new TextField();
var theText:TextField = new TextField();
theTextField.type = TextFieldType.INPUT;
theTextField.border = true;
theTextField.x = 50;
theTextField.y = 10;
theTextField.height = 20;
theTextField.multiline = true;
theTextField.wordWrap = true;
theText.border = false;
theText.x = 10;
theText.y = 10;
theText.text = "Angle";
addChild(theText);
addChild(theTextField);
submit.addEventListener(MouseEvent.CLICK, click_handler);
function click_handler(event:MouseEvent):void
{
var txt:String = theTextField.text;
ang = Number(txt);
if (ang<0)
{
angle = - ang;
}
else
{
angle = 360 - ang;
}
var circleSlider:CircleSlider=new CircleSlider(120,angle); //draw Circle According to the angle i think here is problem becoz every time clicked it creates new circle and draw over the old circle.
circleSlider.x = stage.stageWidth / 2;
circleSlider.y = stage.stageHeight / 2;
circleSlider.addEventListener(CircleSliderEvent.CHANGE, circleSliderEventHandler);
addChild(circleSlider);
}
Can someone help me.
var circleSlider:CircleSlider=new CircleSlider(120,angle);//draw Circle According to the angle i think here is problem becoz every time clicked it creates new circle and draw over the old circle.
this code is the problem. CircleSlider is a separate class.I tried like this
circleSlider.CircleSlider(120,angle);
but it gives an error "" Call to a possibly undefined method CircleSlider through a reference with static type CircleSlider.""
when i run the program and input value as 90.
then i enter another value as 180 then it becomes
how can i overcome this error
Every time your click handler is executed you're creating a new instance of your circle class and adding it to the stage without removing the old instance. I think the best way to resolve it would be to move the logic you have in the constructor of your CircleSlider class into a separate public method, say draw and call that in the click handler.
Your code would look something like this:
// Set up the circle once
var circleSlider = new CircleSlider();
circleSlider.x = stage.stageWidth / 2;
circleSlider.y = stage.stageHeight / 2;
circleSlider.addEventListener(CircleSliderEvent.CHANGE, circleSliderEventHandler);
// and add it to the stage once
addChild(circleSlider);
function click_handler(event:MouseEvent):void
{
var txt:String = theTextField.text;
ang = Number(txt);
if (ang<0)
{
angle = - ang;
}
else
{
angle = 360 - ang;
}
// Now simply redraw in the same circle instance
circleSlider.draw(120,angle); //draw Circle According to the angle i think here is problem becoz every time clicked it creates new circle and draw over the old circle.
}
Assuming you're using the drawing API to draw the graphic, you could draw the circle (which seems to be constant) in the constructor (once) and the line illustrating the angle in the draw method (repeatedly). You'll need to clear the old line each time like this:
// Assumes you're drawing in the graphics property of the class
this.graphics.clear();

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.

AS3 laser weapon

I am pretty new to action script 3 (I did a little bit in as2) and i am trying to create a laser gun that rotates towards the mouse and shoots when the mouse is fired.
kind of like this but in as3
http://www.freeactionscript.com/2009/04/laser-hitting-solid-objects-walls/
Thanks,
Thor
You can start to play with something like this:
//adding listener to run all the time
m.addEventListener("enterFrame", runGame);
//listener for mouse is down
stage.addEventListener("mouseDown", md);
//listener for mouse is up
stage.addEventListener("mouseUp", mu);
//to know if mouse is down
var _fire:Boolean = false;
//function for all the time
function runGame(evt:*):void
{
//to know the angle where the mouse is from the "canon" in radians
var angle:Number = Math.atan2(stage.mouseY - m.y, stage.mouseX - m.x);
//set the canon's rotation
m.rotation = 180 * angle / Math.PI;
//if mouse us down -> fire
if(_fire)
{
//create a point far away, so it will always work if the screen is normal
var point:Point = Point.polar(10000, angle);
//shoot the laser
graphics.lineTo(point.x, point.y);
}
}
//when mouse is down
function md(evt:*):void
{
//prepare graphics
graphics.clear();
graphics.lineStyle(2, 0xff0000);
graphics.moveTo(m.x, m.y);
//set fire to true
_fire = true;
}
//when mouse is up
function mu(evt:*):void
{
//set fire to false
_fire = false;
//clear the laser
graphics.clear();
}
Create a new project, place a movieclip on the stage, name it "m" (without the quotes ;)). Paste the script where the actionscript goes on frame 1.
If you want the laser to follow the mouse when it's down, change
runGame function to this:
function runGame(evt:*):void
{
//to know the angle where the mouse is from the "canon" in radians
var angle:Number = Math.atan2(stage.mouseY - m.y, stage.mouseX - m.x);
//set the canon's rotation
m.rotation = 180 * angle / Math.PI;
//if mouse us down -> fire
if(_fire)
{
//create a point far away, so it will always work if the screen is normal
var point:Point = Point.polar(10000, angle);
//shoot the laser
graphics.clear();
graphics.lineStyle(2, 0xff0000);
graphics.moveTo(m.x, m.y);
graphics.lineTo(point.x, point.y);
}
}
and md function to this:
//when mouse is down
function md(evt:*):void
{
//set fire to true
_fire = true;
}
"Epic" laser, with source. Also great site btw.
Probably best to learn the basic concepts of programming before trying to tackle things like this. Cutting/Pasting code is not programming, and can have frankenstein-ish results.
There is no magical shortcut to programming, you need to learn the basic concepts and build on them. Wonderfl.net is a cool place to check out, but I'd suggest starting out far more basic concepts to start. Until you do that, it's all going to appear as voodoo to you.