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!
Related
I have the following hexagonal grid and trying to calculate the degrees to each edge hexagon from the center (light blue):
The blue highlighted hex is correct at 0 degrees and that quadrant (lower right) is correct. Here is my angle calculation method:
private static function calculateAngle(hex1:Hexagon, hex2:Hexagon):Number {
// hex1 is always passed in as the grid center or start
var diffY:Number = Math.abs(hex2.center.y) - Math.abs(hex1.center.y);
var diffX:Number = Math.abs(hex2.center.x) - Math.abs(hex1.center.x);
var radians:Number = Math.atan(diffY / diffX);
return radians * 180 / Math.PI;
}
Why are the remaining angles (text in each hexagon) incorrect?
You're really close to correct; you just need to compensate for the periodicity of atan. The standard way to do this is to use atan2, which returns a signed angle in (-pi, pi] instead of an unsigned angle in [0, pi). You can do so like this:
var radians:Number = Math.atan2(
hex2.center.y - hex1.center.y, hex2.center.x - hex1.center.x);
Note that I didn't include the call to abs in there: the signedness of those values is needed for atan2 to know which quadrant its in!
Edit: if you're looking for an angle in [0, pi], which represents the minimum angle between the center hex and the blue-highlighted hex, you can just take the absolute value of the result of atan2: return Math.abs(radians) * 180 / Math.PI; the question leaves it a little unclear as to which one you're asking for.
Hello all,
I'm creating a game where some particles are created after a collision between two objects. The particles are then given a random x and y velocity and they shoot out in every direction. I've been trying to alter the way the particles shoot out to resemble Figure 1, where the particles shoot out at a randoom angle between 330 to 30 and 150 to 210 (I wrote the angles in degrees rather than radians for an ease in understanding). The red areas in Figure 1 are where the particles shouldn't shoot out and the blue is where they should. I have not been able to achieve the desired effect however. I was wondering if anyone could assist with a link to helpful reading or an example in code. I have been searching google but cannot find a decent example.
Figure 1
Notes:
- The angles are written in degrees but will need to be changed to radians because Flash uses radians, a simple conversion (Math.pi/180) added to the code should suffice.
- Figure 1 resembles the Cartesian Coordinate system but the y axis is inverted in Flash's coordinate system.
- I would post the code that I have tried but it is so far from what is desired that it would not help.
var speed:Number = minSpeed + Math.random() * (maxSpeed - minSpeed);
var angle:Number = Math.random() * 120 - 30;
if (angle > 30) angle += 120;
angle *= Math.PI/180;
var speedX = Math.cos(angle) * speed;
var speedY = Math.sin(angle) * speed;
Oh god this must be so simple. I have a heading in range (0, 2π) and two points from which I get the heading in between. I must compare them to see if one is within a range of the other. What I've got so far is.
//get the angle
float angle = atan(here.x - there.x, here.y - there.y);
//atan2 uses (-pi, pi) range, convert to (0, 2pi)
if(angle < 0) angle += 2*pi;
//subtract them pesky headings
float diff = angle - givenAngle;
//a difference of 350 degrees really is a difference of 10 degrees
if(diff > pi) diff = 2*pi - diff;
//a difference of -10 degrees really is a difference of 10 degrees
if(diff < 0) diff *= -1;
//check if the point is in range of givenAngle
if(diff > fov) do_magic(diff - fov);
However, I get all sorts of issues when both angles wrap around to zero and I've been wasting way too much brainpower in solving this solved problem.
Where am I doing it wrong? How can I find the difference between two headings correctly?
I suspect the order of your operations may be slightly wrong:
//a difference of 350 degrees really is a difference of 10 degrees
if(diff > pi) diff = 2*pi - diff;
//a difference of -10 degrees really is a difference of 10 degrees
if(diff < 0) diff *= -1;
This doesn't account for an diff of -350, but if you switch the statements it does:
//a difference of -10 degrees really is a difference of 10 degrees
if(diff < 0) diff *= -1;
//a difference of ±350 degrees really is a difference of 10 degrees
if(diff > pi) diff = 2*pi - diff;
One of the main problems was in this line:
float angle = atan(here.x - there.x, here.y - there.y);
It was kind of tricky to notice, but that's not the right argument order for atan - even the mathematical definition on wikipedia takes the y component (sine) before the x component (cosine).
float angle = atan(here.y - there.y, here.x - there.x);
A second problem is that, as it turns out, angle was off by 180 degrees. In other words, instead of calculating here - there, I should be calculating there - here.
float angle = atan(there.y - here.y, there.x - here.x);
Add in sverre's observation about the incorrect order of operations, and we have something that works much better:
float angle = atan(there.y - here.y, there.x - here.x);
if(angle < 0) angle += pi * 2; //use (0, 2pi) range, the same as angle
float diff = abs(angle - givenAngle);
if(diff > pi) diff = 2*pi - diff;
if(diff > fov) do_magic(diff - fov);
I'm programming a flash game, I made an array of points (x and y positions) that some movieclips must follow. Those movieclips have a certain speed (they make steps of 5 pixels for now). When I want to move them horizontally or vertically, everything's fine, I have to add or remove 5 pixels of those clips' x or y. But sometimes they have to move diagonally and now that's complicated.
What I'm doing:
var angle:Number = Math.atan2(nextPoint.y - this.y, nextPoint.x - this.x) * 180 / Math.PI;
var xstep:Number = Math.cos(angle) * this.speed;
var ystep:Number = Math.sqrt(Math.pow(this.speed, 2) - Math.pow(xstep, 2));
this.x += xstep;
this.y += ystep;
It's only a fraction of the code, but I think it's all you need.
Basically, this makes my movieclip do a little step (of this.speed (currently set to 5) pixels).
If the current point and the next point have the same y position, it works fine. When they don't, it doesn't work. The angle is right at first but it slowly decreases (while it should stay the same). I don't know if it's the angle that isn't computed the right way or if it's the x and y steps, but it's one of those, I'm sure.
Try this instead:
var angle:Number = Math.atan2(nextPoint.y - this.y, nextPoint.x - this.x);
var xstep:Number = Math.cos(angle) * this.speed;
var ystep:Number = Math.sin(angle) * this.speed;
Because cos operates on angles in radians, you don't need to convert to degrees. Computing the y component of an angle uses sin, so it should be similar to x. I'm not able to test this, but it's possible that ystep will be backwards and may need to be multiplied by -1.
I am developing a white board application which allows the user to draw line with arrow head (some like Microsoft Word line with arrow feature). I am using graphics property along with lineTo() method to draw a line. Now i have to draw a angular arrow on the last point of line. I am drawing the arrow by connecting the points around last points. As 360 line can pass through this point and each line can have a different angle of arrow. Please suggest me the way to calculating these point around the last point.
I've been doing something myself, and I needed it to look a bit nicer than just a triangle, and use relatively inexpensive calculations (as few calls to other functions as possible, like Math trigonometry). Here it is:
public static function DrawArrow(ax:int, ay:int, bx:int, by:int):void
{
// a is beginning, b is the arrow tip.
var abx:int, aby:int, ab:int, cx:Number, cy:Number, dx:Number, dy:Number, ex:Number, ey:Number, fx:Number, fy:Number;
var size:Number = 8, ratio:Number = 2, fullness1:Number = 2, fullness2:Number = 3; // these can be adjusted as needed
abx = bx - ax;
aby = by - ay;
ab = Math.sqrt(abx * abx + aby * aby);
cx = bx - size * abx / ab;
cy = by - size * aby / ab;
dx = cx + (by - cy) / ratio;
dy = cy + (cx - bx) / ratio;
ex = cx - (by - cy) / ratio;
ey = cy - (cx - bx) / ratio;
fx = (fullness1 * cx + bx) / fullness2;
fy = (fullness1 * cy + by) / fullness2;
// draw lines and apply fill: a -> b -> d -> f -> e -> b
// replace "sprite" with the name of your sprite
sprite.graphics.clear();
sprite.graphics.beginFill(0xffffff);
sprite.graphics.lineStyle(1, 0xffffff);
sprite.graphics.moveTo(ax, ay);
sprite.graphics.lineTo(bx, by);
sprite.graphics.lineTo(dx, dy);
sprite.graphics.lineTo(fx, fy);
sprite.graphics.lineTo(ex, ey);
sprite.graphics.lineTo(bx, by);
sprite.graphics.endFill();
}
You can also add the line color and thickness to the argument list, and maybe make it a member function of an extended Sprite, and you have a pretty nice, versatile function :) You can also play a bit with the numbers to get different shapes and sizes (small changes of fullness cause crazy changes in look, so careful :)). Just be careful not to set ratio or fullness2 to zero!
If you store the start and end point of the line, adding the arrow head should be relatively simple. If you subtract the end point coordinates from the start point coordinates, you will get the arrow direction vector (let's call it D). With this vector, you can determine any point on the line between the two points.
So, to draw the arrow head, you would need to determine a point (P1) on the segment that has a specific distance (d1) from the end point, determine a line that passes through it, and is perpendicular to D. And finally get a point (P2) that has a distance (d2) from the previously determined point. You can then determine the point that is symmetrical to P2, relative to D.
You will thus have an arrow head the length of d1 and a base with of 2 * d2.
Some additional information and a few code examples here: http://forums.devx.com/archive/index.php/t-74981.html