Handling Editable Objects - actionscript-3

Here's the scenario.
A user selects an image, video, or other type of display object. It gets loaded inside a custom class known as EditableObject. The goal of EditableObject is re-sizing and re-positioning. EditableObject has 4 movieclips.
center_mc : Handles drag and drop and contains the display object.
rightside_mc : Handles re-sizing of width on mousedown
bottomside_mc : Handles re-sizing of height on mousedown
bottomright_mc : Handles scaling of object on mousedown
So far I can scale all parts of these objects. The bugs are what's causing trouble.
When I click down on the bottom or right side of the display object, the display object increases size from whichever side it's handling before I move the mouse. I get the amount to move based on the difference of the stageX and stageY positions of the mouse passed on MOUSE_DOWN and at the end of every MOUSE_MOVE. This isn't a problem, it just looks bad and currently solves the second bug..
When I handle bottomright_mc, I can only scale the object down. When trying to scale out, I have to position the mouse outside of EditableObject to get a difference greater than bottomright_mc's current position. This doesn't work because any attempts to exit the bounds of EditableObject trigger MOUSE_UP, even if I add the event listener using this.parent..
I want to be able to re-position and scale anything inside EditableObject using two sides and one corner of EditableObject when a mouse is held down and moved. Currently I can only move the object, scale the object less than its current size, and use the two sides to adjust the objects width and height but without having the mouse match the position of the side it's currently handling on initialization.
Here's an excerpt for the MOUSE_MOVE handler.
private function handleMouseMove(e:MouseEvent):void
{
switch(dragType)
{
case "right":
trace("Right triggered.");
this.width = e.stageX - this.x;
break;
case "bottom":
trace("Bottom triggered");
this.height = e.stageY - this.y;
break;
case "bottomright":
resizeMe(this, e.stageX - this.x, this.height);
break;
}
prevMouseX = e.stageX;
prevMouseY = e.stageY;
}
The full code for the class can be found here on pastebin.
Here's Editable Object in Adobe Flash CC
Here's EditableObject currently containing and handling an image inside the editor.

Based on this answer on stackoverflow provided by TOMATO in the comments, I found a great API that easily lets you handle DisplayObjects with just a few lines of code.
The one I have chosen is senocular's transform tool. A demonstration of his work can be found here. Broken down, this is how to use it.
//Constructor
var editTool:TransformTool = new TransformTool();
//Add to stage (This will not be visible until you give your TransformTool a target)
addChild(editTool);
desiredDisplayObject.addEventListener(MouseEvent.CLICK, handleMouseClick)
function handleMouseClick(e:MouseEvent):void
{
//Set the object clicked as the target for the TransformTool
editTool.target = e.target as Sprite;
//Swap the positioning in the display list so the TransformTool appears in front
editTool.parent.setChildIndex(editTool, editTool.parent.numChildren - 1);
}
You can do this a number of ways, but the basics of it is to simply add the transform tool to the stage and assign whatever display object you would like to the TransformTool.

Related

How to hide mouse over multiple frames?

I'm an actionscript n00b, please excuse my ignorance.
currently trying to make my first person shooter game and have picked up great tips from Lynda(.com) but im having difficulty changing my mouse into a crosshair cursor and having that crosshair not show up permanently in subsequent frames as I create this game.
so i have this code on an action layer but on other layers when I create another key frame to change what I shoot at on other layers, my cursor stamps a permanent image of itself onto the screen. I definitely need to understand this language more if Im going to become good at it but for now i'f like to be able to make a few games to entertain myself, any suggestions? are appreciated
var cursor:MovieClip;
function initializeGame():void
{
cursor = new Cursor();
addChild(cursor);
cursor.enabled = false;
Mouse.hide();
stage.addEventListener(MouseEvent.MOUSE_MOVE, dragCursor);
}
function dragCursor(event:MouseEvent):void
{
cursor.x = this.mouseX;
cursor.y = this.mouseY;
}
initializeGame();
In AS3, items will remain on the display list (on screen) until explicitly removed (or their parent is removed).
So to keep your cursor from staying on screen, you need to remove it:
removeChild(cursor);
Doing Mouse.show() doesn't affect any display objects on the screen.
If you assign a new value to the var cursor, it doesn't automatically remove the previous object - as variables are just references to objects. So if in your subsequent frames you are making a new cursor, you want to remove the existing one prior to assigning a new one to the variable:
if(cursor.parent) removeChild(cursor); //if there is an object assigned to cursor, and it has a parent (which means it's on screen), then remove it before doing the below code
cursor = new Cursor();
addChild(cursor);

Bitmap inside a Sprite - But still not clickable? AS3

Basically I've got a bitmap which is an image that the user captures from a webcam which was previously stored as bitmapdata which I converted into a bitmap and added it onto the stage..
From here I want the bitmap to be selectable so I can do other things to it, so I realised I would need to add this into sprite in order to add event listeners onto it.
Having done so, for some reason my application ain't wanting to recognise the events added?
Here is the code I've got..
Bitmap..
//Create a new bitmap from the video capture
image = new Bitmap(bitmap,"auto",true);
//Set the width and height properties
image.width=150;
image.height=125;
//Set the stage position
image.x = 430;
image.y = 280;
stage.addChild(image);
Sprite..
var imageSprite:Sprite;
imageSprite = new Sprite();
imageSprite.x = 200;
imageSprite.y = 50;
imageSprite.addChild(image);
stage.addChild(imageSprite);
Event listener:
imageSprite.addEventListener(MouseEvent.MOUSE_DOWN, SelectWebImage1);
Function:
function SelectWebImage1(e:MouseEvent): void {
trace("Clicked");
}
I receive no errors from this but I noticed that when I have that code written in my application, all of the code underneath it doesn't seem to function?
I really don't know what i'm doing wrong, any help appreciated thanks!
When you set Sprite's dimensions, you implicitly set its scale, and also if you place some graphics by using width and height, the width and height includes any sprite's children, accounting for their position. You should place that bitmap into imageSprite and not set x,y proerties for the bitmap, this way you won't have to account for its position inside the sprite to position the bitmap.

Rotating a Model in Away3D

Here's what i want to do:
I want to load a model (most likely .3ds) into my .swf and be able to rotate it with the mouse.
This works fine at first glance, but there's problem, the rotations 'switch' over. Or to say it differently:
Imagine we have a model in the shape of a pipe.
If we drag the mouse to the right, the model rotates along its X-Axis to the left, mouse to the left, X-Axis rotation to the right, moving the mouse up, Y-Axis rotation downward, mouse down, Y-Axis rotation upward.
Now, lets say we turn the pipe to the right or left, until we face the (former) 'backside' of the pipe, and then we move the mouse down. The model will rotate downward instead of upward.
I hope you understand what i mean with this. I've been looking around for a good while now and never found a satisfying solution. There was talk about quaternions, but i can't grasp them.
Another suggestion i read somewhere is the following:
create a Matrix3D object, apply rotation on it, then multiply it with the desired Matrix3D of my 3d-Model.
I tried to do it, but the result stays the same, the directions of rotation switches depending on what side i'm facing.
private function update(e:Event):void
{
xCalc = (0.3*(stage.mouseX - lastMouseX));
yCalc = (0.3*(stage.mouseY - lastMouseY));
if(move)
{
var objTransform:Matrix3D = new Matrix3D();
objTransform.prependRotation(xCalc, Vector3D.Y_Axis, objC.pivotPoint);
objTransform.prependRotation(yCalc, Vector3D.X_Axis, objC.pivotPoint);
mesh.transform = multiply3DMatrices(mesh.transform, objTransform);
}
lastMouseX = stage.mouseX;
lastMouseY = stage.mouseY;
view.render();
}
multiply3DMatrices simply multiplies two 4x4 Matrices together.
objC is the ObjectContainer3D that holds my model. For some reason i cannot rotate it properly, unless i manipulate the rotationX/Y/Z properties.
mesh is the mesh inside of the Model (which is very simple, a single mesh).
Also, i'm aware that i could try another Framework for this (like papervision) but this project requires me to use Away3D.
Solved it by myself, the problem was that i created a new Matrix3D Object every time. The fixed code looks like this:
private function update(e:Event):void
{
...
if(move)
{
var objTransform:Matrix3D = mesh.transform;
objTransform.appendRotation(xCalc, Vector3D.Y_Axis, objC.pivotPoint);
objTransform.appendRotation(yCalc, Vector3D.X_Axis, objC.pivotPoint);
mesh.transform = objTransform;
}
...
}
And yes, the user bwroga was actually right, i should've used appendRotation instead of prependRotation, as well.

How to set mouse click to do not hit transparent pixels

Imagine a painting program. I have two imagens overlaping each other. I must be able to click on the image behind if I click on a transparent part of the above one.
I add an event listener on each image. So I must prevent the first one to dispatch click event in order to the behind one dispatch it.
(I mean, I already check for transparent pixels, but i can't cancel that event to the other imagem dispatch it.)
There is some dirty solution. Say your "images" are encapsulated in Sprites, otherwise you can't attach a listener to a Bitmap object or a Shape object. MovieClips - well, should still work, although checking alpha is a lot harder. You have your listeners attached to those sprites. First, that sprite in itself can check transparency, and if not transparent, proceed the event. To get what's behind, you can call stage.getObjectsUnderPoint(), this will return an Array of DisplayObjects, with foreground being on top. So you might have one single listener that would call this to enumerate what's under the point, then do as Roman Trofimov advises to determine that object's transparency. Once you'll find a non-transparent object, you do:
// "b" is a non-transparent DisplayObject found beforehand
while (b && (!(b is InteractiveObject))) b = b.parent;
if (b) {
var p:Point = new Point(e.stageX, e.stageY);
p = b.globalToLocal(p);
b.dispatchEvent(new MouseEvent('click', true, true, p.x, p.y));
}
This will dispatch a click event to the object that's able to receive events, and is opaque enough to obscure the background.
The MovieClip property 'mouseEnabled' can prevent click events from triggering on objects in front of other objects, for example, take two movie clips of the same size and same position:
mc1.addEventListener(MouseEvent.CLICK, click1);
function click1(e:MouseEvent) : void
{
trace("1");
}
mc2.addEventListener(MouseEvent.CLICK, click2);
function click2(e:MouseEvent) : void
{
trace("2");
}
mc1.mouseEnabled = false;
Output would be "2" as the click would essentially go 'through' mc1.
In flex you can add mouseEnabledWhereTransparent="false" to components. Not fully sure if that variable is available to you though
Generally, you will always get first event from first sprite (if it was not capture phase ot priority change). But as I understand, you need to check was it transparent and if not - stop bubbling this event.
To stop event - use event.stopImmediatePropagation() in event handler.
To determine transparency:
1) If it is just only the one bitmap, you can check its .bitmapData with method .getPixel32, it returns you alpha value.
2) If it is combined sprite (vector and bitmap), you need to manually render it to Bitmap using BitmapData.draw and then use solution from second case
3) To understand if it was absolutelly miss click, you can try this method: Check transparency

Deleting a shape via code

Pretty basic question here, but its still got me a little confused..
I have an object(navigation menu bar) that I want to change the colors on with code, so in an updateColor function, I get the bounds of the object (which is a drawing shape contained in a movieclip) and redraw a new shape on top of it with the new color, but I've noticed that the last shape still exists behind this redraw.
I tried using obj.graphics.clear(); before the redraw but that didn't get rid of the original shape. Is there another command that I'm overlooking?
Unless you drew the object you wish to remove within the same graphics object, clearing won't work. You need to remove the DisplayObject.
Depending on the number of children you can do:
obj.removeChildAt(0);
This also removes movieclips / buttons you placed on the stage manually.
If you have a reference to the DisplayObject you wish to remove you can simply do
obj.removeChild(backgroundClip);
Note that you can also change the color of a DisplayObject directly:
import flash.geom.ColorTransform;
...
public var test:MovieClip; //instance on stage
...
var cf:ColorTransform = test.transform.colorTransform;
cf.color = 0xff0000;
test.transform.colorTransform = cf;
while(this.numChildren)
{
this.removeChildAt(0);
}
Will clear child object on this MovieClip,
if it's clearing too much, then put the shape drawing in a subclip, and clear the subclip.