Hey guys. I'm getting really frustrated with this. I created a little flash document to help me understand how to use Math in Flash to move an object to a target X and Y at a constant speed, and I can't seem to get ANYTHING to work. This is what I have so far... first, I've attached an image of the app I'm creating:
picture
basically, I just put in the number of the point (1-4) and have the ball move to that point. Everything works except for the trajectory of the ball. I've got the angles right because when I set the rotation of the ball equal to the angle that I get, the black dot lines up with whichever blue line applies. The only problem is, the speed is messed up. Here's what I need help with:
No, it's just moving in completely wrong directions.
The following lines:
PHP Code:
var speed:Number = 4;
xSpeed = Math.cos(angle)*speed; //these are the two lines ySpeed = Math.sin(angle)*speed; //that must be wrong
are supposed to calculate the percentage of speed that should be applied to X movement and the percentage of speed that should be applied to Y movement. It seems that I'm just getting the wrong numbers in those areas.
Actually, it converts radians to degrees. I know all that part works, because the angle turns out correct.
In fact, I've got an update. Right now I'm using the same code except for the following changes:
PHP Code:
//xSpeed = Math.sin(angle)*speed; //I'm not using these //ySpeed = Math.cos(angle)*speed; //two lines anymore xSpeed = (atanX/(atanX + atanY))*speed; ySpeed = (atanY/(atanX + atanY))*speed;
The last two lines calculate the total of the two numbers that make up the slope (we'll call it X = atanX + atanY) and then find out what percentage of X is comprised of atanX and what percentage is comprised of atanY. Then, I use those percentages to calculate the percentage of X movement and Y movement. It's working, but it's not completely accurate. My guy is always off by a couple of pixels in each direction. I'm going to attach the file so anyone who wants to can see it. I don't know what 'save and compact' means, but that's what I had to do to get the file size low enough...
Anyway, it's sort of working, but it's not very precise and there MUST be another way that's easier to do. Anyone got any more ideas?
I know that ... ;-) its just that initially you said ...
Best of luck to you ..
Yeah, and it is moving in the wrong direction, but the angles that I'm getting from the Atan2 function are correct. When I plug those angles into the ball as the rotation, the ball rotates to face the correct direction, but the x and y speeds weren't working as they should and so it faced the correct direction and then just went the completely wrong direction. Anyway, thanks for your suggestions and help. Anyone else out there looking in this forum?
Using cos and sin gets buggy due to how the signs are twiddled. You will get better results, both in accuracy and performance by using vectors. Here's some quick psuedo-code as an example:
PHP Code:
endX = point.x;
endY = point.y;
vX = endX - ball._x; // x vector
vY = endY - ball._y; // y vector
dist = Math.sqrt(vX * vX + vY * vY); // distance from start to finish
nX = vX / dist; // normalized x vector
nY = vY / dist; // normalized y vector
vx = nX * speed; // x motion vector (adjust speed to suit your needs)
vy = nY * speed; // y motion vector (same as above)
ball.onEnterFrame = function(){
if(this._x != endX){
this._x += vx;
this._y += vy;
}
};
Using cos and sin gets buggy due to how the signs are twiddled. You will get better results, both in accuracy and performance by using vectors. Here's some quick psuedo-code as an example:
PHP Code:
endX = point.x;
endY = point.y;
vX = endX - ball._x; // x vector
vY = endY - ball._y; // y vector
dist = Math.sqrt(vX * vX + vY * vY); // distance from start to finish
nX = vX / dist; // normalized x vector
nY = vY / dist; // normalized y vector
vx = nX * speed; // x motion vector (adjust speed to suit your needs)
vy = nY * speed; // y motion vector (same as above)
ball.onEnterFrame = function(){
if(this._x != endX){
this._x += vx;
this._y += vy;
}
};
Beautiful. It works a lot better than mine did. Thank you SOOO much. I still have a question though if you're available:
I have it set up so the ball stops when it gets to the point... like this:
I have different code to account for whether or not the points are above below to the left and right of the ball, I just posted one example for brevity's sake. Anyway, the ball seems to be a very little bit off on some of the trips it makes. Like, say it's going from x:100, y:100 to x:500, y:120 (almost a perfectly horizontal line). Well, it will pass the targetX at about y:115 or something and then snap back when it gets to the correct numbers. I tried changing the '&&' symbols to '||' to just test for ONE of the factors (x or y) and then, sometimes it will get to the right Y or X early and jump ahead to the point. Is there any way for it to be more exact, or is this the best I'm going to get?
I'm not sure why it's doing that, could you post the code you are using?
Rather than a bunch of different checks for each orientation, you could use a variable to keep track of the distance traveled, and stop motion when that distance is equal to or greater than the originally determined distance.
That's a very good idea, and if something in my code doesn't stick out to you as wrong, I may end up doing just that. Here's what I have... be gentle... I only just started AS 3 a little while ago:
PHP Code:
var a:Array = [{x:73, y:313},{x:503, y:333},{x:300, y:173},{x:490, y:80}];
var targetX:Number;
var targetY:Number;
var startX:Number;
var startY:Number;
var atanX:Number;
var atanY:Number;
var dist:Number;
var nX:Number;
var nY:Number;
I don't see any problem with the vector code, though your variable names and leaving in the atan2 function threw me at first.
I'm pretty sure the issue is with your nested if/else checks. A better approach would be to check the current distance, and if it is less than the step distance, move to the target point.
PHP Code:
// in your vector code, add a variable to hold the step distance
stepDist = Math.sqrt(xSpeed * xSpeed + ySpeed * ySpeed);
// then use something like this
function moveGuy(e:Event):void
{
var currentDist:Number = Math.sqrt(targetX - guy_mc.x * targetX - guy_mc.x + targetY - guy_mc.y * targetY - guy_mc.y);
Come on people... It's take how many posts and only one person has spotted the problem?
Code:
atanX = (targetX - startX);
atanY = (targetY - startY);
angle = Math.atan2(atanY, atanX)
angle = Math.round(angle/Math.PI * 180); //BAD CONVERSION!!! BAD
var speed:Number = 4;
xSpeed = Math.cos(angle)*speed; //these are the two lines
ySpeed = Math.sin(angle)*speed; //that must be wrong - Because you are feeding them degrees when they want radians
All math operations take radians while the movieclip.rotation takes degrees.
If you want to use vectors the best method would be to normalize the displacement from the object to the target and perform scalar multiplication by the speed.
Last edited by 691175002; 03-27-2008 at 02:14 AM.
The greatest pleasure in life is doing what people say you cannot do.
- Walter Bagehot The height of cleverness is to be able to conceal it.
- Francois de La Rochefoucauld
If you want to use vectors the best method would be to normalize the displacement from the object to the target and perform scalar multiplication by the speed.
That's exactly what my sample code does, normalizes and multiplies by speed.
Perhaps you have the same problem seeing things as you say everyone else does?
I didn't bother reading the entire thread since the initial problem was clear.
IMO For something this simple trig is the best choice anyways since it is more clear what is going on, and you are going to do an atan2 anyways to rotate the object.
Having it stop once it reaches the destination is also quite straightforward.
Heres some sample code, copy paste it onto a movieclip in an as2.0 project:
Code:
/* AS2 Code because its quicker to type up,
* easilly copy-pastable and all in one place.
*/
onClipEvent (load) {
var nAngle:Number;
var nSpeed:Number = 3;
var nDistance:Number = 0;
var nTargetX:Number;
var nTargetY:Number;
}
onClipEvent (mouseDown) {
nTargetX = _root._xmouse;
nTargetY = _root._ymouse;
// Determine the angle (In radians) and the
// distance to the target.
nAngle = Math.atan2(nTargetY-_y, nTargetX-_x);
nDistance = Math.sqrt((_y-nTargetY)*(_y-nTargetY)+(_x-nTargetX)*(_x-nTargetX));
}
onClipEvent (enterFrame) {
//This line reduces the distance to the target by the speed
//Then checks to make sure that the disance is still greater than 0
//to avoid moving past the target.
if ((nDistance -= nSpeed) >= 0) {
// Keep the angle in radians for math
// Note that "Math.cos(nAngle) * nSpeed"
// could be precalculated in the mouseDown
// for speed.
_x += Math.cos(nAngle) * nSpeed;
_y += Math.sin(nAngle) * nSpeed;
// Convert to degrees for display
_rotation = nAngle * (180/Math.PI);
}
}
The greatest pleasure in life is doing what people say you cannot do.
- Walter Bagehot The height of cleverness is to be able to conceal it.
- Francois de La Rochefoucauld
I believe an explanation of why his original code didn't work is just as important as an alternate solution.
The greatest pleasure in life is doing what people say you cannot do.
- Walter Bagehot The height of cleverness is to be able to conceal it.
- Francois de La Rochefoucauld
I agree, I was just confused where your comments were coming from based on what you posted. First you say only one person found the problem after so many posts, indicating you had read the entire thread, then you stated you didn't read the entire thread. So I wasn't sure exactly what you had read, and therefor if you realized the problem was solved.