Flash AS3 square root? - actionscript-3

I can't do this: How can I get a number of displacement (movieclip)?
Example: MovieClip.x == 0 and MovieClip.y == 0
Then I move it.
MovieClip.x == 50 and MovieClip.y == -90
Now if I make a tween, what is the number of displacement (moving)?

I'm going to take a guess and interpret the question to be something like, "How far as the MovieClip moved (or been displaced)?".
The answer would then be: 102.956 -> 103 units (pixels). You can use the Pythagorean theorem to figure this out:
xDist = 50 - 0
yDist = -90 - 0
distanceTraveled = sqrt((xDist * xDist) + (yDist * yDist))
Which would link as to why the poster asked about sqaure root.
Use Math.sqrt() to take the sqaure root of a number.

Related

Convert from one range to another

I have two sets of ranges that I need to be translated from one to the other.
The first range is -100 ↔ 100 with 0 being default.
The second range is 0.0 ↔ 10.0 with 1 being default.
I am working in AS3 with the first range and the second range is a python class and I need these numbers to line up.
I am adjusting brightness of a video in realtime with a slider. The video filter accepts values between -100 ↔ 100. I need to then take that value and pass it to a python script but it only accepts values from 0.0 ↔ 10.0
I tried this function I found on the net, but it doesn't translate the values correctly in this particular case.
private function convertRange(originalStart:Number,originalEnd:Number,newStart:Number,newEnd:Number,value:Number):Number
{
var originalRange:Number = originalEnd - originalStart;
var newRange:Number = newEnd - newStart;
var ratio:Number = newRange / originalRange;
var newValue:Number = value * ratio;
var finalValue:Number = newValue + newStart;
return finalValue;
}
Is this even possible? Hopefully my question is clear, please let me know if it needs clarification.
This is the python class I am referring to: https://github.com/dubhater/vapoursynth-adjust It uses the second range whereas AS3 uses the first range.
Why not trying something like this :
function from_AS_to_PY(as_value:Number): Number // as_value : -100 ----- 0 ----- 100
{
var py_value:Number = (as_value / 100);
py_value = (py_value <= 0 ? py_value : py_value * 9) + 1;
return py_value;
}
function from_PY_to_AS(py_value:Number): Number // py_value : 0 - 1 --------- 10
{
var as_value:Number = (py_value <= 1 ? py_value - 1 : ((py_value - 1) / 9)) * 100;
return as_value;
}
trace(from_AS_to_PY(-100)); // gives : 0
trace(from_AS_to_PY(-99)); // gives : 0.01
trace(from_AS_to_PY(-1)); // gives : 0.99
trace(from_AS_to_PY(0)); // gives : 1
trace(from_AS_to_PY(1)); // gives : 1.09
trace(from_AS_to_PY(99)); // gives : 9.91
trace(from_AS_to_PY(100)); // gives : 10
//---------------------------------------------------
trace(from_PY_to_AS(0)); // gives : -100
trace(from_PY_to_AS(0.01)); // gives : -99
trace(from_PY_to_AS(0.99)); // gives : -1
trace(from_PY_to_AS(1)); // gives : 0
trace(from_PY_to_AS(1.09)); // gives : 1
trace(from_PY_to_AS(9.91)); // gives : 99
trace(from_PY_to_AS(10)); // gives : 100
Hope that can help.
There is a fundamental difficulty with the problem. You are trying to fit three point of one range onto another range. If you were just interested in matching the two end points that would be easy you can use a linear interpolation y = 10 * (x+100) /200 or simply y = (x+100)/20 or equivalently y=x/20+5. The problem is it this does not match the default value and x=0 -> 5.
This might be the solution you want. However if it is important that he default values match you need to use a non-linear solution. There are many possible solutions. You can use a piecewise-linear solution like akmozo solution, which needs an if statement. if x<0 then y = x/100+1 else y = 1 + 9 x /100. The problem with this one is that you do not get a smooth response. Consider adjusting the slider from min to max, you see a very slow increase in brightness to start with and then it starts to increase much faster once you pass zero.
The big difference between the first half of the range and the second half suggests an exponential type solution. y = A exp(b x). Taking y = exp(x * ln(10)/100) matches the center point and the top end, the bottom end is just a little bit high at 0.1, rather than zero. This might be fine, if not you could find an exponential solution y = A exp(b x)-c which matches all three points.
Another possibility is using a power. An equation like y = A pow(x,n). A bit of calculation shows y=10 pow(x/200+0.5),3.321928095) matches all three points. The constant 3.321928095 = ln(0.1)/ln(0.5).
In the diagram the black curve is a simple linear solution. The red curve is the piecewise linear one, the green is the exponential one then the blue is the power.

AS3: can't figure out Math.random

I'm very bad at math, so i can't figure out why this isn't working. It should calculate a random number between 0 and 360.
var minDegree:int = 0
var maxDegree:int = 360
function randomDegree (minDegree:Number, maxDegree:Number):Number
{
return (Math.random() * (maxDegree - minDegree + minDegree));
trace(randomDegree)
}
I assume you actually want integers, right? This is the actual code:
private function randRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
I'm posting it because #Xenophage's answer is not correct. And it's not correct because of the fact that Math.random Returns a pseudo-random number n, where 0 <= n < 1. (reference). What this means is that if you pass 0 as minimum and 360 as maximum, the biggest number you can get is 359 because:
(Math.random() * (maxDegree - minDegree) + minDegree);
(0.99999 * (360 - 0) + 0) = 359
So the upper solution would work better :) If you are not looking for an integer - let me know.
Edit: I've made the random to return more precise number, as if it was simply 0.99 it would calculate to 354 instead of 359. Either ways won't go up to 360.
And yes, I know you need degrees, so 0 is similar to 360 if you are not doing some precise calculations, but I had to mention it as it's a Math.random problem, not a degrees problem.
You were very close, move the closing parenthesis over a little. Multiplying the difference between max and min, then adding min back on to bring the value back into the proper range. I find it easy to try some examples using a simple calculator and seeing if the results make sense.
var minDegree:int = 0
var maxDegree:int = 360
function randomDegree (minDegree:Number, maxDegree:Number):Number
{
return Math.min(maxDegree, Math.random() * (maxDegree - minDegree) + minDegree + .01);
}
trace(randomDegree(minDegree, maxDegree));

Nape Moving Platform

Okay Im relatively new to nape and Im in the process of making a game, I've made a Body called platform of type KINEMATIC, and I simply want to move it back a forth in a certain range on the stage. Can somebody please see where im going wrong , thanks.
private function enterFrameHandler(ev:Event):void
{
if (movingPlatform.position.x <= 150 )
{
movingPlatform.position.x += 10;
}
if (movingPlatform.position.x >= 260)
{
movingPlatform.velocity.x -= 10;
}
}
First of in one of the if blocks you are incrementing position.x by 10 in the other one you are decrementing velocity.x by 10. I guess you meant position.x in both.
Secondly, imagine movingPlatform.position.x is 150 and your enterFrameHandler runs once. movingPlatform.position.x will become 160 and on the next time enterFrameHandler is called none of the if blocks will execute since 160 is neither less than or equal to 150 or greater than or equal to 260.
You can use the velocity to indicate the side its moving and invert it once you go beyond an edge, something like :
// assuming velocity is (1,0)
private function enterFrameHandler(ev:Event):void {
if (movingPlatform.position.x <= 150 || movingPlatform.position.x >= 260) {
movingPlatform.velocity.x = -movingPlatform.velocity.x;
}
movingPlatform.position.x += movingPlatform.velocity.x;
}
Obviously this might cause problems if the object is already at let's say x=100, it will just keep inverting it's velocity, so either make sure you place it between 150-260 or add additional checks to prevent it from inverting it's direction more than once.
This might be a better way of doing it :
// assuming velocity is (1,0)
private function enterFrameHandler(ev:Event):void {
if (movingPlatform.position.x <= 150) {
movingPlatform.velocity.x = 1;
} else if (movingPlatform.position.x >= 260) {
movingPlatform.velocity.x = -1;
}
movingPlatform.position.x += movingPlatform.velocity.x;
}
In general:
Kinematic bodies are supposed to be moved solely with velocity, if you change their position directly then they are not really moving as much as they are 'teleporting' and as far as the physics is concerned their velocity is still exactly 0 so things like collisions and friction will not work as you might expect.
If you want to still work with positions instead of velocities, then there's the method setVelocityFromTarget on the Body class which is designed for kinematics:
body.setVelocityFromTarget(targetPosition, targetRotation, deltaTime);
where deltaTime is the time step you're about to use in the following call to space.step();
All this is really doing is setting an appropriate velocity and angularVel based on the current position/rotation, the target position/rotation and the amount of time it should take to get there.

How to make my character move relative to the mouse position with actionscript 3?

ok so i have a character called character_mc and i want it to move towards the mouse when you press the forward arrow and strafe relative to right angles of that.
i am quite new to actionscript so could you please include and example of your code in my original code
Here is my current code:
import flash.events.MouseEvent;
//Event Listners
stage.addChild(crosshair_mc);
crosshair_mc.mouseEnabled = false;
crosshair_mc.addEventListener(Event.ENTER_FRAME, fl_CustomMouseCursor);
function fl_CustomMouseCursor(event:Event)
{
crosshair_mc.x = stage.mouseX;
crosshair_mc.y = stage.mouseY;
}
Mouse.hide();
stage.addEventListener(MouseEvent.MOUSE_MOVE,facecursor);
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_KeyboardDownHandler);
//Functions
function facecursor(event):void
{
character_mc.rotation = (180 * Math.atan2(mouseY - character_mc.y,mouseX - character_mc.x))/Math.PI + 90;
}
function fl_KeyboardDownHandler(event:KeyboardEvent):void
{
trace("Key Code Pressed: " + event.keyCode);
if (event.keyCode == 38)
{
character_mc.y = character_mc.y - 5;
}
if (event.keyCode == 40)
{
character_mc.y = character_mc.y + 5;
}
if (event.keyCode == 39)
{
character_mc.x = character_mc.x + 5;
}
if (event.keyCode == 37)
{
character_mc.x = character_mc.x - 5;
}
}
I can tell you the basic concept of how you could do this, but you'll have to apply it to your own code. To involves converting your movement code to use a vector, then modifying the vector to get a direction facing the mouse (or at right angles to that direction) and a little bit of math.
Right now you have the character moving straight along the x and y axis only in each key press case. Left/Right only move along the X and Up/Down only move along the Y.
To move towards the mouse will require the character to move both along the X and Y when the Up/Down/Left/Right keys are pressed. Clearly you can see if you move both the character's x/y positions by the same amount, say 5, then it'll move exactly at 45 degrees (though it'll actually move a step of 7.07 pixels, hopefully you can see why). You can represent this as a vector: (5,5). You can use a Point object to represent this vector:
var movementVector:Point = new Point(5, 5);
trace(movementVector.x); // gives 5
trace(movementVector.y); // also gives 5
With that in mind, you can also use a vector to represent movement straight up and down on the y axis:
// set the x to 0 and y to 5
movementVector.x = 0; // 0 would mean not to move the character along the x
movementVector.y = 5; // using -5 would move the character up
And to move along the x axis only:
movementVector.x = 5; // using -5 would move the character right
movementVector.y = 0; // 0 would mean not to move the character along the y
To do the actual movement of the character would be the same as you are doing now, except you use the vector's values:
character_mc.x = character_mc.x + movementVector.x;
character_mc.y = character_mc.y + movementVector.y;
Now to figure out the proper vector to move on a diagonal from the character's position to the mouse position is pretty simple. The x value of the vector is the x distance from the character to the mouse, and the y value of the vector is the y distance from the character to the mouse.
Let's say the character is ay 125, 100 and the mouse at 225, 150. This means the distance between the character and mouse is 100, 50 x and y. Thus you'd end up with a vector:
movementVector.x = 100;
movementVector.y = 50;
If you were to apply this vector as it is to the character's position as it is, it would arrive at the mouse instantly (and then go beyond it) as the character is moving 100 pixels along the x and 50 pixels along the y right away. The step size would be 111.8 pixels long -too big. You would need to scale it down to the character's speed. You can do this by calling the normalise() method on the Point class to scale down the vector:
trace(movementVector.x); // gives 100
trace(movementVector.y); // gives 50
// assuming '5' is the max speed of the character
movementVector.normalise(5);
trace(movementVector.x); // gives 4.47213595499958
trace(movementVector.y); // gives 2.23606797749979
This would result in a 'step' size of 5 now. Applying this would make your character move 5 pixels towards a point 100 pixels to the right and 50 pixels down from where it started.
To transform a vector exactly 90 degrees, a quick and simple way is to swap the x and y values around.
If you are curious on what normalise() method mathematically does, is that it takes the x and y values of the vector (or point) and divides it by the length to get a unit vector (or a vector with a step size of 1), then times the input you give it to scale it to the desired length.
To move your character_mc towards the mouse point you only need the direction vector between the two:
var dir:Point = new Point(mouseX - character_mc.x, mouseY - character_mc.y);
dir.Normalize();
// The following should be called when the 'up' or 'forward' arrow is pressed
// to move the character closer to mouse point
character_mc.x += dir.x; // dir can be multiplied by a 'speed' variable
character_mc.y += dir.y;
Strafing left and right around the point is a little more tricky:
// Where radius is the distance between the character and the mouse
character_mc.x = mouseX + radius * Math.cos(rad);
character_mc.y = mouseY + radius * Math.sin(rad);
You should find this tutorial useful as it does everything you describe and more:
http://active.tutsplus.com/tutorials/actionscript/circular-motion-in-as3-make-one-moving-object-orbit-another/

AS3 Continuous value from rotation slider

I have a dial which I drag around a circle to give me a reading between 0 and 1.
Something like this:
dx = mouseX-centerX;
dy = mouseY-centerY;
rad = Math.atan2(dy,dx);
rad += offset;
Tweener.addTween(knob,{y:centerY - Math.cos(rad)*radius, time:.1, transition:"easeOutSine"});
Tweener.addTween(knob,{x:centerX + Math.sin(rad)*radius, time:.1, transition:"easeOutSine"});
knob.rotation = rad * 180 / Math.PI;
This work's great, except when the slider goes from 359 degrees to 1 degree, my value between 0 and 1 returns to zero. (Which makes sense, as the value is based on the angle of my slider)
I'm trying to find a way for the dial to move from 359 degrees to 361 and onwards basically.
In my head: I need to check if the next value of my mouse drag goes past the 360 degree point and add 360 to the total, to stop it returning to zero and continue to 361 degrees.
I just cant work out how to put this into code...
On each frame when you are rotating the knob, check the change in angular distance instead of direct angle.
Save the previous frames angle and see if the difference is positive or negative.
var rad = Math.atan2(dy, dx);
var diff = rad - oldRad;
oldRad = rad;
if( diff > Math.PI )
diff -= Math.PI * 2;
if( shortestAngle < -Math.PI )
diff += Math.PI * 2;
diff should contain a value that if it's been rotated to the right, is positive (or negative if rotated left). Simply add that to the total angle.
There might be some errors in the code (took it from an old project), but that's the gist of it :)
Hope that helps!