Actionscript hitTest drawing - actionscript-3

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
}
}

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 - How do I make new instances draggable?

I am attempting to build a drag and drop game where a user can build something using the images I provide. I will have images in a menu that the user can click and drag to the building area. The user will be able to add however many instances of that image as they want.
I was able to get part of it working. So far, I can click the image and drag it around, and create as many instances as I want. However, I cannot click and drag the image once I have placed it.
When I do a trace to see what the name is, it says that all the new instances are named hillChild1. I tried to make them named hillChild1, hillChild2, etc., but that doesn't seem to work either... not sure that is an issue, though.
Here's my code:
thesubmenu1.hill.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
var myImage:Sprite = Sprite(new Hill_mc());
var i:Number=0; i++;
function onDown(e:MouseEvent):void {
var myImage:Sprite = Sprite(new Hill_mc());
myImage.name = "hillChild"+i;
addChild(myImage);
myImage.x = mouseX;
myImage.y = mouseY;
myImage.startDrag();
myImage.buttonMode = true;
}
function onUp(e:MouseEvent):void {
var myImage:Sprite = Sprite(new Hill_mc());
myImage.stopDrag();
myImage.name = "hillChild";
}
stage.addEventListener(MouseEvent.CLICK, traceName);
function traceName(event:MouseEvent):void { trace(event.target.name); }
myImage.getChild(myImage).addEventListener("mouseDown", mouseDownHandler);
stage.addEventListener("mouseUp", mouseUpHandler);
function mouseDownHandler (e:MouseEvent):void{
myImage.startDrag();
}
function mouseUpHandler (e:MouseEvent):void{
myImage.stopDrag();
}
I am new to StackOverflow and also Actionscript 3, if it isn't apparent.
Your issue is likely that you are creating a new instance on mouse up (when what you want is a reference to instance that was already created on mouse down). Also, you never add a click listener to you new objects. Add the mouse up listener to stage only after the mouse down (then remove the listener in the mouse up).
thesubmenu1.hill.addEventListener(MouseEvent.MOUSE_DOWN, createCopy);
var i:int=0;
var tmpImage:Sprite; //to store which image is being dragged currently
function createCopy(e:MouseEvent):void {
tmpImage = new Hill_mc();
tmpImage.name = "hillChild"+(i++); //increment every copy
addChild(tmpImage);
tmpImage.x = mouseX;
tmpImage.y = mouseY;
tmpImage.startDrag();
tmpImage.buttonMode = true;
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); //add the mouse down to this new object
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //since the mouse is currently down, we need to listen for mouse up to tell the current copy to stop dragging
}
//this will be called when click a copy
function onDown(e:MouseEvent):void {
tmpImage = Sprite(e.currentTarget); //get a reference to the one that was clicked, so we know which object to stop dragging on the global mouse up.
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //listen for the mouse up
tmpImage.startDrag();
}
function onUp(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP,onUp); //now that the mouse is released, stop listening for mouse up
tmpImage.stopDrag(); //stop dragging the one that was clicked
}

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

as3 draw with mouse and erase lines when hitTestObject is reached

I am trying to create a simple hitTestObject and see the lines that are being drawing on screen hit with a Ball. If it does it will erase all lines and start fresh. I am very close. The checkIt() function is where the code needs to happen and its clearing the lines but not making a new shape.
How can I erase the lines the mouse drew and start fresh when a hit test is reached?
var myshape:Shape;
myshape = new Shape();
myshape.graphics.lineStyle(12, 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);
function lineDraw(myevent:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, stopDraw);
function stopDraw(endevent:MouseEvent):void
{
alreadyDrawn = myshape;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, lineDraw);
}
myshape.graphics.lineTo(mouseX,mouseY);
myevent.updateAfterEvent();
checkIt();
}
}
function checkIt()
{
if (alreadyDrawn.hitTestObject(Ball) == true)
{
trace("Hit The Balls");
myshape.graphics.clear();
myshape.graphics.lineStyle(12, 0xC807DE);
}
}
You actually have ONE shape instead of two, because once you do alreadyDrawn=myshape you lose whatever object you attached there. You should instead do alreadyDrawn.graphics.copyFrom(myshape.graphics); this will copy all the strokes from argument to object without losing the other instance.
Next, you seemingly need to also stop drawing if you've detected a hit vs alreadyDrawn, for this, call stopDraw(null); from checkIt().
And next, you are not clearing all the listeners off stage while adding more and more. See, if you draw several lines in quick succession (press-drag-release), the stopDraw listener is added multiple times and not removed even once. To do this, use removeEventListener(MouseEvent.MOUSE_UP, stopDraw); inside stopDraw function and move the adding line into activateDraw, because there are multiple "mouse move" events while you drag the mouse, and another listener is added each time you process the event.
And finally, PLEASE don't nest functions without actual need!
The fixed code should be this:
var myshape:Shape;
myshape = new Shape();
myshape.graphics.lineStyle(12, 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);
event.updateAfterEvent();
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(Ball) == true)
{
trace("Hit The Balls");
myshape.graphics.clear();
myshape.graphics.lineStyle(12, 0xC807DE);
alreadyDrawn.graphics.clear(); // clear this too
stopDraw(null); // stop active draw, if any
}
}
copyFrom() manual reference
Interesting question~
I think the problem may be you forgot to moveTo after clear.
Here is my fix:
Pass mouseX, mouseY to checkIt.
checkIt( mouseX, mouseY );
function checkIt( mouseX:Number, mouseY:Number ):void
{
if (alreadyDrawn.hitTestObject(Ball))//you don't need == true here
{
trace("Hit The Balls");
myshape.graphics.clear();
myshape.graphics.lineStyle(12, 0xC807DE);
myshape.graphics.moveTo(mouseX,mouseY);
}
}

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.