Is There an Offset Equation for Z Position Change in Actionscript? - actionscript-3

Say I have a movie clip that when loaded I set it's .z position to 2000 to make it look far off in the background... How in the world can I set it's x and y points with any certainty as to where it will appear on the stage? Is there an equation?
E.g.;
original.x = 200;
original.y = 200;
original.z = 0;
new.z = 2000;
new.x = original.x*10;
new.y = original.y*10;

you have to seperate out the actual x and y points with the 3D space points (i use _x, _y and _z). using a basic idea that anything further away from you is going to be you will need to define an origin for the vanishing point and a "focal length" (think of a camera lens) that will define how quickly things dissappear into the background. try playing with values, but something around 200 usually works fairly well.
this should give you something simple like this where my_mc is the object you want to have the effect on:
my_mc._x = 0;
my_mc._y = 0;
my_mc._z = 200;
var scaleRatio = focalLength/(focalLength + my_mc._z);
my_mc.x = origin.x + my_mc._x * scaleRatio;
my_mc.y = origin.y + my_mc._y * scaleRatio;
my_mc.scaleX = my_mc.scaleY = scaleRatio;
there are some really good tutorials at kirupa on this subject, try this one (though it is in as2 the theory is the same)
http://www.kirupa.com/developer/actionscript/3dexplore.htm

Related

How to detect that the AlphaMaskFilter is completely gone in easeljs/createjs

I am doing a little scratch/reveal game based on the AlphaMaskFilter example:
http://createjs.com/demos/easeljs/AlphaMaskReveal.html
I want to detect that the the mask is completely gone, or use a threshold (90% scratched for example).
I read the doc on AlphaMaskFilter, shape and graphics objects and im not really sure how to achieve this.
Im not even sure i Have acess to the pixel information and check the alpha channel to detect it, but even so, I wonder if I will performance issue.
any help is welcome, thanks.
**** EDIT **** ADD TO THE ACCEPTED ANSWER ****
So, I was able to have the pct of transparency using the AlphaMapFilter (thanks Lanny).
The AlphaMapFilter offer you a mapping to the alpha channel of all the pixels.
Here is a little sample code that worked for me:
// mShapeToScratch is a createjs Shape. like in the http://createjs.com/demos/easeljs/AlphaMaskReveal.html example
var alphaMaskFilter = new createjs.AlphaMapFilter(mShapeToScratch.cacheCanvas);
var canvas = alphaMaskFilter.alphaMap;
var ctx = canvas.getContext("2d");
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var alphaData = imgData.data;
var pixelTotal = rect.h*rect.w;
var transparentPixel = 0;
// rect.h is the height of the image and rect.w is the width not shown in the example
for (var y = 0; y < rect.h; ++y)
{
for (var x=0; x < rect.w; ++x)
{
var pixelIdx = (y*rect.w + x);
if(alphaData[pixelIdx] > 128) // transparent will be 255.
{
transparentPixel++;
}
}
console.log("transparent % = " + transparentPixel/pixelTotal);
This example checks all the pixels, but it's pretty easy to check one every X pixels to speeds up checks as Lanny suggested.
The alpha mask uses canvas composite operation, and not pixel access, so without some completely custom approach, there isn't a great way to do this.
Iterating pixels (check out AlphaMapFilter as an example) would work - but could be fairly slow. Maybe checking every 4th, 10th, or 25th pixel would speed it up.
Cheers.

Rotating a canvas object around the mouse cursor

I am trying to replicate this effect: http://hakim.se/experiments/html5/trail/03/
I have this as a Particle constructor:
function Particle(x, y) {
this.x = x;
this.y = y;
this.radius = 4;
this.color = '#f0f';
this.speed = 15;
this.angle = 0;
}
And I'm using this loop to animate all particle instances:
for (var i = 0, len = particles.length; i < len; i++) {
var dx = mouse.x - particles[i].x,
dy = mouse.y - particles[i].y,
angle = Math.atan2(dy, dx);
particles[i].vx = Math.cos(angle) * particles[i].speed;
particles[i].vy = Math.sin(angle) * particles[i].speed;
particles[i].x += particles[i].vx;
particles[i].y += particles[i].vy;
particles[i].draw(ctx);
}
The particles follow the mouse, but reach the cursor and start flickering around it, which is not a desired behaviour. I'd like to circle around the cursor, as in the example.. The interesting part is that if I set the particle.speed to something like 30 and add 1000 to the angle, the particles rotate around the cursor, but really fast and ruin the effect...
You can see a live example here: http://codepen.io/gbnikolov/pen/EwafI
All suggestions are more then welcome, thanks in advance!
P.S. I know that the code for the pointed example is easily findable, but I'm relatively new to javascript and I'm not that good at reading other people code and can't quite understand the logic behind it..
Currently the target of your particles is the mouse cursor. But that's not the target you want. You want a target that's moving around your cursor. And you want for every particle a different target, so they don't hover all at the same place.
There are also some other things that the original does and you don't:
in the original, the particle speed depends on the distance to the target
it seems they can't change the direction instantly, but change the direction of their movement relatively slowly.

Scaling points to match background. Actionscript 3

Using some code I found online has helped me create a zoom function for a program I am attempting to make. It is to make a map that allows a user to mark points. Currently the code scales in on the map image alone but I cant get the point icons to realign to where they originally where. I cant workout the maths of it.
Code to zoom in and out
if (mev.shiftKey) {
image.scaleX = Math.max(scaleFactor*image.scaleX, minScale);
image.scaleY = Math.max(scaleFactor*image.scaleY, minScale);
}
if (mev.ctrlKey) {
image.scaleX = Math.min(1/scaleFactor*image.scaleX, maxScale);
image.scaleY = Math.min(1/scaleFactor*image.scaleY, maxScale);
mat = image.transform.matrix.clone();
MatrixTransformer.matchInternalPointWithExternal(mat,internalCenter,externalCenter);
image.transform.matrix=mat;
This allows the image to scale up with the following factors
public var scaleFactor:Number = 0.8;
public var minScale:Number = 0.25;
public var maxScale:Number = 2.0;
The problem occurs when I try to move the pointer icons that are overlaid on this image. They are not to grow or shrink at the moment but they I cant get the maths to get them to move the correct number of pixels away from the mouse location so that they are still in line. Currently I am using the following formulas
//decrease zoom
stage.getChildAt(i).x = stage.getChildAt(i).x * scaleFactor;
//increase zoom
stage.getChildAt(i2).x = stage.getChildAt(i2).x / scaleFactor;
Any thoughts ? Code I am using came from
http://www.flashandmath.com/howtos/zoom/
Quite a few elements missing from the question like the moving map underneath. Anyway now that it's sorted out ...
If you are not a math genius and can't tackle 2 math formulas at the same time then don't and tackle them one by one then combine them. Once again don't use the x,y property of point for calculation but create specific property (like in a custom class for example). I will name them here origin for convenience.
Given a point with origin property of x:100, y:200, its position on the map is (assuming map is top left coordinate, if not adapt accordingly):
point.x = map.x + point.origin.x;
point.y = map.y + point.origin.y;
the positioning is solved now you need to solve for scale which is easy:
point.x = point.origin.x * scaleFactor;
point.y = point.origin.y * scaleFactor;
Both systems are solved now you can combine the two:
point.x = map.x + (point.origin.x * scaleFactor);
point.y = map.y + (point.origin.y * scaleFactor);

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

How do i calculate an objects scale using a perspective projection matrix?

Im currently building a little 3D particle engine in flash the uses sprites.
to set the position of each sprite I am using the projectVector function below. (the viewTransform matrix is the particles world matrix concatenated with a perspective projection matrix)
var projectedPoint:Vector3D = Utils3D.projectVector(viewTransform, point);
sprite.x = projectedPoint.x;
sprite.y = projectedPoint.y;
this works really well an places the sprites exactly where they should be :D
The problem I am having is trying to figure out how to calculate the scale of the each particle based on is distance from the camera..
sprite.scaleX = sprite.scaleY = ??
If I wasn't using a perspective projection matrix I would usually do something like this..
var scaleRatio:Number = (focus * zoom)/(focus + particle.globalz);
particle.depth = scaleRatio;
sprite.x = particle.globalx * scaleRatio;
sprite.y = particle.globaly * scaleRatio;
// set scale..
sprite.scaleX = sprite.scaleY = scaleRatio;
If there is anyone out there able to show me how to calculate the "scaleRatio" using a perspective projection matrix that would be ace
thanks!
I'm sure there's a more succinct way to do this, but since you already know how to project a point, you could do this:
var tl:Point = sprite.getRect(sprite.parent).topLeft;
var br:Point = sprite.getRect(sprite.parent).bottomRight;
var projectedTL:Point = Utils3D.projectVector(viewTransform, tl);
var projectedBR:Point = Utils3D.projectVector(viewTransform, br);
trace("projected width = "+(projectedBR.x - projectedTL.x));
trace("projected height = "+(projectedBR.y - projectedTL.y));