Position one object based on another that's rotated - actionscript-3

I have a set of blocks which could be rotated at any angle. My task is to create an extra block to one side of the set, adjacent to the last block. I'm using Flex/AS3 and openscales. An illustration will be good to explain what I want to achieve. I apologise in advance for the crudeness of my pictures, I only have MS Paint to hand!
My current formula for the picture 2 is simply:
block5XPos += block4XPos - block3XPos;
block5YPos += block4YPos - block3YPos;
** Edit **
I cannot work with Display Objects in the usual way i.e. rotate, addChild. I'm restricted to utilising x and y values and having to re-calculate these values.

If your solution allows, you could put all your blocks in a parent movieclip, rotate that movieclip. And then just modify the x parameter when you add new blocks to the parent movieclip. This would translate the block along the "local" x axis of the rotated parent.
Pseudocode:
var parent:MovieClip = new MovieClip()
parent.rotation = 45
addChild(parent)
var block1 = new BlockClip()
block1.x = 10
parent.addChild(block1)
var block2 = new BlockClip()
block2.x = 20
parent.addChild(block2)

I figured it out. I leveraged Math.cos and Math.sin to calculate the position of the new block based on the angle and distance from the last block.
private function calculateNewSlotPosition(slot:SlotDO):void {
var blockToRadians:Number = blockDegrees * Math.PI / 180;
var cos:Number = Math.cos(blockToRadians);
var sin:Number = Math.sin(blockToRadians);
for(var k:uint = 0; k < block.polygon.length; k++) {
block.polygon[k].x += ((block.width + workBlock.gap) * cos);
block.polygon[k].y -= ((block.width + workBlock.gap) * sin);
}
}

Related

how to move polygon points depending on movement of one point?

i have polygon say (Hexagonal with 6 lines) this Hexagonal connected from center with 6 point That make 6 triangles
I need when move any point(cause to move triangles) ,, other points move like this point i mean if the left point move to lift other points move to the left and so on
the code I want like this ptcP1.x and ptcP1.y the point that i moving it other point move depend on ptcP1 movement note that, this equations work fine in square shape ,, put in Penta and hexa ..etc this equations in valid so can any one help me
function button1_triggeredHandler( event:Event ):void
{
mode="mode2";
//trace(list.selectedIndex);
if(list.selectedIndex==1)
{
DrawSqure.ptcP1.x = Math.random() + 50;
DrawSqure.ptcP1.y = Math.random() + 50;
DrawSqure.ptcP2.y = 50-DrawSqure.ptcP1.x;
DrawSqure.ptcP2.x = DrawSqure.ptcP1.y;
DrawSqure.ptcP3.x = 50-DrawSqure.ptcP1.y;
DrawSqure.ptcP3.y = DrawSqure.ptcP1.x;
DrawSqure.ptcP4.x = 50-DrawSqure.ptcP1.x;
DrawSqure.ptcP4.y = 50-DrawSqure.ptcP1.y;
}
As stated in the comments, storing the vertices/points into a container (Array or Vector) and then adjusting those positions when you move is the best way to do it. Here is an example of how that might work:
//setup array or vector of vertices
var polygonVertices:Array = [DrawPolygon.ptcP1, DrawPolygon.ptcP2, DrawPolygon.ptcP3, DrawPolygon.ptcP4];
This method will take all the vertices and apply the translation:
//function for adjusting all the vertices based on the distance you pass
function moveShape( vertices:Array, dx:Number, dy:Number ) {
var i:int;
for ( ; i < vertices.length; i++ ) {
vertices[i].x += dx;
vertices[i].y += dy;
}
}
Then you would just need to know your distance X & Y your shape has moved and you can call moveShape( polygonVertices, 100, 100 );
I inserted 100,100 as the distance parameters as an example, but this should give you the results you are looking for.

AS3 drawing lines, making shorter after that

i have a little math/coding problem witch i don`t have any idea how could i do it work in a simple way, so the problem is is need to make a line shorter, with 15
in my program i have :
http://gyazo.com/aff5ff61fb9ad3ecedde3118d9c0895e
the line takes the center coordinates of both circles and draws from one to another, but i need it to be from the circumference of the circles, so it wont get inside
the code im using is :
var line:Shape = new Shape();
line.graphics.lineStyle(3,0xFF0000,2);
line.graphics.moveTo(sx,sy);
line.graphics.lineTo(fx,fy);
this.addChild(line);
arrow2(sx,sy,fx,fy);
var rline:Shape = new Shape();
rline.graphics.lineStyle(3,0xFF0000,2);
rline.graphics.moveTo(fx,fy);
rline.graphics.lineTo(xa,ya);
this.addChild(rline);
var rline2:Shape = new Shape();
rline2.graphics.lineStyle(3,0xFF0000,2);
rline2.graphics.moveTo(fx,fy);
rline2.graphics.lineTo(xb,yb);
this.addChild(rline2);
the rline and rline2 function is for the arrow lines, now my question is how do i make it shorter not depending on it direction so it will not overlap the circle
You can use vectors to solve your problem; they're pretty easy to get the hang of, and pretty much indispensable for things like game dev or what you're trying to do. You can get an overview here: http://www.mathsisfun.com/algebra/vectors.html or by searching "vector math" in google
So first step is to get a vector from one circle to another (pretty much what you've done):
var vector:Point = new Point( circle2.x - circle1.x, circle2.y - circle1.y );
var length:Number = vector.length; // store the length of the vector for later
This is the equivalent of saying "if you start at circle1 and move along vector, you'll arrive at circle2"
Next thing we're going to do is normalise it; all this does is set the length to 1 - the direction is unchanged - this makes it easier to work with for what you're looking to do. A vector with length 1.0 is called a unit vector:
vector.normalize( 1.0 ); // you can pass any length you like, but for this example, we'll stick with 1.0
Now, to draw a line from one circle to another, but starting from the outside, we simply find the start and the end points. The starting point is simple the position of circle1 plus vector (normalised to unit length) multiplied by the radius of circle1:
var sx:Number = circle1.x + vector.x * circle1.radius; // or circle1.width * 0.5 if you don't store the radius
var sy:Number = circle1.y + vector.y * circle1.radius;
The ending point can be found by starting at our start point, and continuing along our vector for a distance equal to the distance between the two circles (minus their radii). The length value that we created earlier is the distance between your two circles, from one center point to another, so we can use that to get the distance minus the radii:
var dist:Number = length - ( circle1.radius + circle2.radius ); // or circle1.width * 0.5 etc
And so the end point:
var ex:Number = sx + vector.x * dist;
var ey:Number = sy + vector.y * dist;
And to draw the line between them:
var line:Shape = new Shape;
line.graphics.lineStyle( 1.0, 0x000000 );
line.graphics.moveTo( sx, sy );
line.graphics.lineTo( ex, ey );
this.addChild( line )

RotateX a square around its center

I have 3 squares (50 px x 50 px) in a Sprite, one next to each other. Pivot of each is at 0, 0.
1st square X, Y: 0, 0
2nd square X, Y: 50, 0
3rd square X, Y: 100, 0
I would like to rotateX each square around its center-line. I cannot seem to figure out how to set the vanishing point so that all the squares rotate around their individual point and not all of them around the same point.
Any help greatly appreciated!
You can make the rotation of child movieclips by rotating and translating them to newer position. Required the pivot of the child movieclip coincides with it's registration point
in the following code, the holder is your sprite and content are the squares. ( Required that squares are having the pivot, coinciding with the registration point)
PS: Holder must have a width and height bigger than the content's. It's assumed that holder here is some kind of big container ( say stage).
var holder_Mc:MovieClip = holder_Mc
var content_Mc:MovieClip = holder_Mc.content_Mc ;
var rotation_val_num:Number = 50// in degrees
var bnd = holder_Mc.getBounds(MovieClip(holder_Mc.parent)) ;
var cw:Number = bnd.width ;
var ch:Number = bnd.height;
var cx:Number = bnd.x ;
var cy:Number = bnd.y ;
content_Mc.rotation = rotation_val_num ;
var bnd2 = holder_Mc.getBounds(MovieClip(holder_Mc.parent)) ;
var cw2 = bnd2.width ;
var ch2 = bnd2.height;
var cx2 = bnd2.x ;
var cy2 = bnd2.y ;
var dx = Math.abs( holder_Mc.x - cx2 ) ;
var dy = Math.abs( holder_Mc.y - cy2) ;
holder_Mc.x = cx + cw/2 + dx - cw2/2
holder_Mc.y = cy + ch/2 + dy - ch2/2
Basically, you need to move the box while it is rotating to get that effect. Since you also know the width/height of the box and the pivot points positions the calculations aren't that hard.
However, why calculate it yourself? With TweenLite, You could use the TransformAroundCenterPlugin, which handles the transformation for you. I would recommend to use it. If you don't want to tween it, then set the tween-duration (second parameter) to 0.
// Activate plugin (should be called once)
TweenPlugin.activate([TransformAroundPointPlugin]);
// Transform your boxes around it's center, does not use the pivot point.
TweenLite.to(this.mcBox1, 1, new TweenLiteVars().transformAroundCenter({rotationX: 50}));
TweenLite.to(this.mcBox2, 1, new TweenLiteVars().transformAroundCenter({rotationX: 190}));
TweenLite.to(this.mcBox3, 0, new TweenLiteVars().transformAroundCenter({rotationX: 5}));

AS3 - Finding the Y position of a rotated object if X is known

I am trying to find out the Y position of a rotated object on stage, when only the X position is known. I am not extremely formiliar with how I'd go about doing this, but I know it'll be related to the Rotation of the border object.
What I need to do is know that based on the below X position that is worked out, what the exact maximum Y position can be before it hits the black border that is onscreen. I know that the original position is 280, but I am not sure at all how I then work out what the Y position is further down the line.
I have attached the code to find the X (all be it, it doesn't take into account any rotation as on this level it isn't needed), as well as a screenshot so you can understand clearly.
Thank you for your time.
private function init(e:Event = null):void{
var maxX:int = stage.width
var freeSpace:int = 300
var startX:int = Math.ceil(Math.random() * (maxX - (freeSpace+this.width))) + freeSpace;
this.x = startX
}
I'm not entirely sure on your question but hopefully these suggestions will help:
You can use the localToGlobal() function on a display object to return a rotated, translated, and scaled point within that display container to the stage. Example, $p:Point = myMovieClip.localToGlobal(new Point(10, 10));
A Matrix is also a nice and easy way to rotate a point. Example, var $mtx:Matrix = new Matrix(); $mtx.tx = 10; $mtx.ty = 10; $mtx.rotate(); and now $mtx.tx and $mtx.ty have the rotated result
Those probably won't answer your question, but I figured I'd mention them just in case and before I get into something more complex. Like wvxvw said you can't really solve the equation you're trying to do without some other variables. I wrote some code that shows how to find Y when comparing X to a point in a line segment:
import flash.display.Shape;
import flash.geom.Point;
import flash.display.Graphics;
import flash.events.MouseEvent;
var $s:Shape = new Shape();
addChild($s);
var borderStart:Point = new Point(stage.stageWidth/2, stage.stageHeight/2);
var borderRotation:Number = 45;
var borderLength:Number = 800;
var borderRad:Number = borderRotation * (Math.PI/180);
var borderEnd:Point = new Point(borderStart.x + Math.cos(borderRad) * borderLength, borderStart.y + Math.sin(borderRad) * borderLength);
stage.addEventListener(MouseEvent.MOUSE_MOVE, update);
function update(e:MouseEvent):void{
var $g:Graphics = $s.graphics;
$g.clear();
//Drawing the rotated border
$g.lineStyle(3, 0xff0000, .5);
$g.moveTo(borderStart.x, borderStart.y);
$g.lineTo(borderEnd.x, borderEnd.y);
//Finding if and where mouseX collides with our border
if (stage.mouseX >= Math.min(borderStart.x, borderEnd.x) && stage.mouseX <= Math.max(borderStart.x, borderEnd.x)){
var $x:Number = stage.mouseX;
//SOLVING HERE : Solve collision with X
var $percent:Number = ($x - borderStart.x)/(borderLength * Math.cos(borderRad));
var $y:Number = borderStart.y + Math.sin(borderRad) * borderLength * $percent;
//Drawing to our collision
$g.lineStyle(1, 0xffff00, .6);
$g.moveTo($x, 0);
$g.lineTo($x, $y);
$g.lineStyle(2, 0xffff00, 1);
$g.drawCircle($x, $y, 3);
trace("----\nCollision #\t" + "x: " + $x + "\ty:" + Math.round($y));
}
}
Hopefully this will give some insight on how to solve your particular issue.
I'm not sure if I'm answering the right question, because as you worded it, it's impossible to solve, or rather you would have to accept that Y can be just anything... (In order to be able to find a point in a vector space over R^2 you need a basis of two vectors of a form (x,y), but you only have a vector in R^1).
But it looks like you want to find an intersection of the "black line on the screen" - i.e. an arbitrary line and a vertical line through the lowest point of the "shape" which you want to fit. It's hard to tell from the question, what shape are you trying to fit, but if it is a rectangle, which is not rotated, then it would be either its bottom right or bottom left corner. You can then find which point to choose by comparing the angle between a horizontal line and the "black line" and the horizontal line and the bottom of the rectangle.
Next, you would need to find an intersection between these two lines, the formula can be found here: http://en.wikipedia.org/wiki/Line_intersection

find closest point to mouse position

I've got a grid of sprites.
Now I would like to drag an image on a grid-element.
Therefore I need to know which x/y of the grid-element is the closest point to the mouse-position.
All the grid-elements are stored in an array.
How can I achieve that?
You must loop through all the elements and find the smallest distance to the mouse. Then store the array index of the element. Try something like this:
// Setup variables outside of loop.
var mousePoint:Point = new Point(mouseX, mouseY);
var elementPoint:Point = new Point();
var element:Sprite;
var closestIndex:uint = 0;
var closestDist:Number;
// Loop through elements
for (var i:int = 0; i < gridElements.length; i++)
{
element = gridElements[i] as Sprite;
// Set the elementPoint's x and y rather than creating a new Point object.
elementPoint.x = element.x;
elementPoint.y = element.y;
// Find distance from mouse to element.
var dist:Number = Point.distance(mousePoint, elementPoint);
// Update closestIndex and closestDist if it's the closest.
if (i == 0 || dist < closestDist)
{
closestDist = dist;
closestIndex = i;
}
}
// Can now use closestIndex to get the element from the array.
trace('The closest element is at index', closestIndex, ', with a distance of', closestDist);
Of course, this will only get you the first closest element, so you must decide what you want to happen if there are two elements an equal distance away.
You will also need to allow for the origins of your elements. The will probably have there origins set to there top left, so you need to allow for this in your distance calculation.
You could also check for a minimum distance. So if the user is dragging too far away from any of the elements then do nothing.
If all you need is the x,y of the closest grid then all you have to do is.
var gridX:int = Math.floor(mouseX / NumberOfColumns);
var gridY:int = Math.floor(mouseY / NumberOfRows);
This will convert your mouse coordinates to your grid coordinates.
Now comes the problem. If your storing them in a 2d array then you have your x/y if your storing them in a flat array (1d) you need to look it up just like you created it.
var myObject:Object = my2dArray[gridX, gridY];
var myObject:Object = myFlatArray[(gridX * NumberOfRows) + gridY];
If you have taken care of how you create your array and push the items in it, it should be no problem to retrieve stuff without searching it.