Zooming and translate in as3 AIR Android - actionscript-3

I am developing an android app with Adobe Flash cs6 and actionscript3. I have multiple moviclips at various locations on stage. Now I need to add a zoom feature that will zoom all movieclips as one movieclip. I cannot combine all movieclips together into one movieclip. My zoom feature works but it does not translate the movieclips to a new position. (Meaning they zoom at their original positions only) How can I accomplish this? Following is my zooming code :
/* ZOOM FEATURE */
Multitouch.inputMode = MultitouchInputMode.GESTURE;
zoomer.addEventListener(TransformGestureEvent.GESTURE_ZOOM , onZoom);
function onZoom (e:TransformGestureEvent):void{
mc1.scaleX *= (e.scaleX+e.scaleY)/2;
mc1.scaleY *= (e.scaleX+e.scaleY)/2;
mc2.scaleX *= (e.scaleX+e.scaleY)/2;
mc2.scaleY *= (e.scaleX+e.scaleY)/2;
mc3.scaleX *= (e.scaleX+e.scaleY)/2;
mc3.scaleY *= (e.scaleX+e.scaleY)/2;
}

Not the cleanest code I've written, but it should do the trick. scaleInPlace() accepts 4 arguments, 2 required, two optional:
obj: the display object you want to scale
scaleFactor: just as it sounds, how big/small do you want it?
fromX: the X coordinate where you want to scale from. Left, middle, right? If omitted, it operates from the middle of the compiled stage size.
fromY: same as the previous, but for top, middle, bottom.
This will preserve your DisplayList hierarchy while allowing you to scale to your heart's desire. If you had a lot of objects to scale, I'd probably parent all of them to the container first, and then run the scale and reparenting operations. While it works, this is the reason I feel it's not the "cleanest" solution. In my own classes, I've written a purely mathematical solution that doesn't include adding/removing DisplayObjects, but it's fairly tied up in my own classes I couldn't pull it out here and have it work.
Cheers!
// Let's scale myObject to 50% of its original size.
scaleInPlace(myObject, 0.5);
function scaleInPlace(obj:DisplayObject, scaleFactor:Number, fromX:Number = NaN, fromY:Number = NaN):void {
// If no coordinates from where to scale the image are provided, start at the middle of the screen
if (isNaN(fromX)) { fromX = loaderInfo.width/2; }
if (isNaN(fromY)) { fromY = loaderInfo.height/2; }
var father:DisplayObjectContainer = obj.parent;
var rect:Rectangle; // Coordinates for tracking our object
var index:int = getChildIndex(obj) // Where this object should go when we put it back
// Create the container
var container:Sprite = new Sprite();
father.addChild(container);
// Place the origin of the scale operation
container.x = fromX;
container.y = fromY;
// Get the coordinates of our object relative to our container
rect = obj.getRect(container);
// Parent and move into place
container.addChild(obj);
obj.x = rect.x;
obj.y = rect.y;
// Scale
container.scaleX = container.scaleY = scaleFactor;
// Get the coordinates and size of our scaled object relative to our father
rect = obj.getRect(father);
// Cleanup the display list
father.addChildAt(obj, index);
father.removeChild(container)
// Apply the new coordinates and size
obj.x = rect.x;
obj.y = rect.y;
obj.width = rect.width;
obj.height = rect.height;
}

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

How to create smooth motion for a mouse follower along a predefined path?

I want to make a tracing game. I want my circle to follow the path as the user traces the letter (path of the letter). The user can not go back to the area which is already traced
import flash.events.Event;
import flash.geom.Point;
var i: Number;
var size: int = 80;
var down: Boolean = false;
var up: Boolean = true;
var inside: Boolean = true;
var outside: Boolean = true;
var circle: Shape = new Shape();
stage.addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseup);
char.addEventListener(MouseEvent.MOUSE_DOWN, mousedown);
function loop(e: Event) {
if (down == true) {
// Checks if mouse pointer is on path i.e 'S' alphabet
if (s.hitTestPoint(stage.mouseX, stage.mouseY, true)) {
inside = true;
outside = true;
var point: Point = maskobj.globalToLocal(new Point(stage.mouseX, stage.mouseY));
var point2: Point = new Point();
//Checks if mouse pointer is completely outside of drawn area
for (i = 0; i < 2 * Math.PI; i += (2 * Math.PI) / 10) {
point2.x = stage.mouseX + (size / 3) * Math.cos(i);
point2.y = stage.mouseY + (size / 3) * Math.sin(i);
if ((maskobj.hitTestPoint(point2.x, point2.y, true))) {
outside = false;
break;
}
}
//Checks if mouse pointer is completely inside drawn area
for (i = 0; i < 2 * Math.PI; i += (2 * Math.PI) / 10) {
point2.x = stage.mouseX + (size / 3) * Math.cos(i);
point2.y = stage.mouseY + (size / 3) * Math.sin(i);
if (!(maskobj.hitTestPoint(point2.x, point2.y, true))) {
inside = false;
break;
}
}
//Character will be moved only if mouse position not to far from current position
if (outside == false) {
if (inside == false) {
//Increases drawn area by drawing a circle shape in 'maskobj' MovieClip
circle.graphics.beginFill(0x0000ff);
circle.graphics.drawCircle(point.x, point.y, size);
circle.graphics.endFill();
maskobj.addChild(circle);
//Moves character to new position
char.x = stage.mouseX;
char.y = stage.mouseY;
}
}
}
}
}
function mouseup(e: MouseEvent): void {
up = true;
down = false;
}
function mousedown(e: MouseEvent): void {
down = true;
up = false;
}
When I trace the path,the motion is not smooth. Can someone please suggest a way to make the motion smooth OR suggest another way to achieve the same. Thank you in advance.
I've created a drawing game before that allowed the user to draw a path.
Not sure why Wicked's answer was down-voted, as the first thing you need to do is to use the highest frame rate that you can get away with. The higher the frame rate, the smoother your curve.
I see that your code draws a circle at the current position if the conditions are met. It might be better to draw a line from the last point.x/point.y to the current one instead of just a circle, so that you don't have any holes in your path.
I couldn't get around the fact that the line was jagged (a series of straight lines) as it was being drawn, but as soon as the user lifted their finger I was able to take the points along the line they had drawn and replace them with a smooth bezier Path (a series of simple bezier curves), which worked well. You could also do this on-the-fly once you have 3 points (you need 3 points to draw a curve).
Here is a good reference on how to achieve this, with theory and code samples. See further down the page for bezier paths. You'll need to convert to AS3, but it shouldn't be difficult.
Another tip is to do as little calculation as possible within the ENTER_FRAME. You could pre-calculate the two values used by your loops (2 * Math.PI) and ((2 * Math.PI) / 10) as these are constants. You could also calculate (size/3) once at the top of the function, and especially pre-calculate the 10 values for Math.sin(i) and Math.cos(i) and store them in an Array (basically a LUT - Look Up Table) as these are the heaviest math ops you're doing.
My final tip is that your code doesn't check if the point being drawn is very close to the last point that was drawn. I would recommend you do this, and only draw a point after the mouse has moved a minimum distance (e.g. 2 pixels). Otherwise you could get the mouse sitting still in one spot and your code is drawing circle upon circle on top of itself needlessly.
Try increasing the FPS in your document to atleast double what you currently have
Modify>Document...>Frame Rate

Collision with Bitmap AS3

So I created a nice collision system shown here. Now I have my own character sprite, which has messed up the collision on all sides.
edit: because people are misunderstand what I want, I WANT it to overlap on the bottom and top, it gives it a 3D effect. My problem is that it's colliding incorrectly with the bitmap
I've tried using the pixel perfect collision system but I have a problem with it:
It only detects collision right at the edge, as you can see in the video, the ball can go slightly in front and behind the wall like it wasn't just a flat plane.
code responsible for the current collision (it did have some other stuff but that's been removed):
for each (var wall in Walls)
{
if (wall.hitTestPoint(Character.x, Character.y, true)) //col right
{
Character.x+=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x, Character.y, true)) //col left
{
Character.x-=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x , Character.y, true)) //col bottom
{
Character.y+=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x, Character.y, true)) //col top
{
Character.y -= CharacterSpeed;
}
}
That is correct (and I mean that's what the code does) and that effect depends on framerate as well.
The principle is easy to understand. ex: You move an object by 5 pixels, the colliding object is 3 pixels away, when you test for collision you have an overlap of 2 pixels. To correct this you need what's called a TOI (time of impact) algorithm.
As of right now there's no fixing your code because you apply a motion is the inverse way it's supposed to work. You move first then you test while the correct way is you test then you move. For example:
you are about to move the object by x pixels.
test if the object + x pixels will collide.
if it will collide calculate by how much you should move it then move it by x pixels - corrected pixels.
if it will not collide then move it by x pixels.
As you see you do the opposite:
move by x pixels.
test for collision.
The result is overlapping objects.
What you can do as a hack without changing your code is calculate the overlapping and then correct the object position.
you can try draw your objects to a BitmapData using BitmapData.draw method, and than use BitmapData.hittest, here a sample:
import flash.display.BitmapData;
import flash.geom.Point;
var myBitmapData:BitmapData = new BitmapData(100, 80, false, 0x00CCCCCC);
var mc_1:MovieClip = this.createEmptyMovieClip("mc", this.getNextHighestDepth());
mc_1.attachBitmap(myBitmapData, this.getNextHighestDepth());
var mc_2:MovieClip = createRectangle(20, 20, 0xFF0000);
var destPoint:Point = new Point(myBitmapData.rectangle.x, myBitmapData.rectangle.y);
var currPoint:Point = new Point();
mc_1.onEnterFrame = function() {
currPoint.x = mc_2._x;
currPoint.y = mc_2._y;
if(myBitmapData.hitTest(destPoint, 255, currPoint)) {
trace(">> Collision at x:" + currPoint.x + " and y:" + currPoint.y);
}
}
mc_2.startDrag(true);
function createRectangle(width:Number, height:Number, color:Number):MovieClip {
var depth:Number = this.getNextHighestDepth();
var mc:MovieClip = this.createEmptyMovieClip("mc_" + depth, depth);
mc.beginFill(color);
mc.lineTo(0, height);
mc.lineTo(width, height);
mc.lineTo(width, 0);
mc.lineTo(0, 0);
return mc;
}

AS3 Determining what object overlaps it?

I'm current building a game in as3; the proplem I have right now is when I roll the virtual dice, the player(marker) moves accross the board but what I need to know is: is there a way to find the instance name of the object(box) that the player lands on?
And Sorry my english isn't good.
It depends a lot on how your board is laid out. One way is to put all of the objects your player can land on into an array, then check the player's x and y coordinates to see if they fall inside of each object's box.
For example:
var boardObjects:Array; // This would contain references to all the objects the
// player object might land on. Initialize it, then use boardObjects.add(object)
// on each one until they're all in the array.
// once the player has moved:
for(var i:int = 0; i < boardObjects.size; i++) {
var obj:* = boardObjects[i];
if (player.x >= obj.x && player.x <= obj.x + obj.width) {
if (player.y >= obj.y && player.y <= obj.y + obj.height) {
// If these if statements are all true, the Player's top-left corner
// is inside the object's bounding box. If this is a function,
// here is a good spot to put a return statement.
}
}
}
You may want to calculate it based on the middle of the player rather than their top-left corner, in which case just add half the player's width to their x position and half their height to their y position.
For performance (and avoiding unnecessary code), if it's tile based / dice why not do something like this
private function rollDice(){
var results:Array = [Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6)] //Accurately simulates two 6 sided dice
dice1.rollAnimation(results[0]);
dice2.rollAnimation(results[1]);
player.position += results[0] + results[1];
}
The board would be an array, and in Player you can use getters/setters to 'wrap' the board like this
private var _position:int = 0;
public function get position():int{
return _position;
}
public function set position(value:int){
_position = value;
while(_position > GameBoard.TILES){
_position -= GameBoard.TILES;
}
x = //Whatever you determine the positioning of the player..
}

AS3 : Scaling Sprite with Matrix on slider change?

I have a sprite that holds a bitmap data.
I want to give the user the ability to resize the image with a slider.
I am using the code beneath, as you can see the problem is that the scaling is additive so very quickly the image is gone totally.
I understand that i have to scale it in non additive way, just can not figure out how?
I tried to pass :
var m:Matrix = userImageCopy.transform.matrix;
when userImageCopy holds the original image. that helped for the scaling but then, each time the scaling started the userImage jumped to the position of the userImageCopy.
Any help?
function onSliderChange(evt:Event):void
{
trace( evt.target.value);
//this will create a point object at the center of the display object
var ptRotationPoint:Point = new Point(userImage.x + userImage.width / 2,userImage.y + userImage.height / 2);
//call the function and pass in the object to be rotated, the amount to scale X and Y (sx, sy), and the point object we created
scaleFromCenter(userImage, evt.target.value, evt.target.value, ptRotationPoint);
}
private function scaleFromCenter(ob:*, sx:Number, sy:Number, ptScalePoint:Point)
{
var m:Matrix = userImage.transform.matrix;
m.tx -= ptScalePoint.x;
m.ty -= ptScalePoint.y;
m.scale(sx, sy);
m.tx += ptScalePoint.x;
m.ty += ptScalePoint.y;
ob.transform.matrix = m;
}
Rather than combining your center values with the current tx and ty, just set them directly with the Matrix.translate method:
private function scaleFromCenter(ob:*, sx:Number, sy:Number, ptScalePoint:Point)
{
var m:Matrix = new Matrix();
m.translate(-ptScalePoint.x,-ptScalePoint.y);
m.scale(sx, sy);
m.translate(ptScalePoint.x,ptScalePoint.y);
ob.transform.matrix = m;
}