A Flash Developer Resource Site

Results 1 to 19 of 19

Thread: Moving ball between two points... atan2?

  1. #1
    Senior Member
    Join Date
    Aug 2007
    Posts
    291

    Moving ball between two points... atan2?

    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:

    PHP Code:
    atanX = (targetX startX);
    atanY = (targetY startY);

    angle Math.atan2(atanYatanX)
    angle Math.round(angle/Math.PI 180);

    var 
    speed:Number 4;

    xSpeed Math.cos(angle)*speed//these are the two lines 
    ySpeed Math.sin(angle)*speed//that must be wrong
            
    guy_mc.rotation angle;

    this.addEventListener(Event.ENTER_FRAMEmoveGuy);

    function 
    moveGuy(e:Event):void
    {
         
    guy_mc.+= xSpeed;
         
    guy_mc.+= ySpeed;

    Someone please look at this and tell me what I'm doing wrong.
    Last edited by Taidaishar; 03-25-2008 at 04:13 PM.

  2. #2
    Senior Member
    Join Date
    Mar 2001
    Location
    Location : Location
    Posts
    131
    Is it moving along the lines really slowly?

    If so, maybe you should work out the length of the line and make the speed proportional to it.
    this[MCr.i + 'm_not_ok']._lyric = "you sing the words but you don't know what they mean";

  3. #3
    Senior Member
    Join Date
    Aug 2007
    Posts
    291
    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.

  4. #4
    Senior Member
    Join Date
    Mar 2001
    Location
    Location : Location
    Posts
    131
    Take out the line ...

    angle = Math.round(angle/Math.PI * 180);

    I don't think its required with atan2 ...
    this[MCr.i + 'm_not_ok']._lyric = "you sing the words but you don't know what they mean";

  5. #5
    Senior Member
    Join Date
    Aug 2007
    Posts
    291
    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?
    Attached Files Attached Files

  6. #6
    Senior Member
    Join Date
    Mar 2001
    Location
    Location : Location
    Posts
    131
    Quote Originally Posted by Taidaishar
    Actually, it converts radians to degrees. I know all that part works, because the angle turns out correct.
    I know that ... ;-) its just that initially you said ...

    Quote Originally Posted by Taidaishar
    No, it's just moving in completely wrong directions
    Best of luck to you ..
    this[MCr.i + 'm_not_ok']._lyric = "you sing the words but you don't know what they mean";

  7. #7
    Senior Member
    Join Date
    Aug 2007
    Posts
    291
    Quote Originally Posted by TechNoiZ
    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?

  8. #8
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770
    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;
        }
    }; 

  9. #9
    Senior Member
    Join Date
    Aug 2007
    Posts
    291
    Quote Originally Posted by JerryScript
    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:

    PHP Code:
    if(ball.>= targetX && ball.>= targetY)
    {
        
    ball.targetX
        ball
    .targetY
        removeEventListen
    ....(Enterframe...blahblah)

    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?

  10. #10
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770
    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.

  11. #11
    Senior Member
    Join Date
    Aug 2007
    Posts
    291
    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:73y:313},{x:503y:333},{x:300y:173},{x:490y: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;

    var 
    xSpeed:Number;
    var 
    ySpeed:Number;

    var 
    speed:Number 6;

    var 
    angle:Number;

    var 
    angleNum:Number;

    var 
    increaseX:Boolean;
    var 
    increaseY:Boolean;

    move_btn.addEventListener(MouseEvent.CLICKstartMove);
    reset_btn.addEventListener(MouseEvent.CLICKreset);

    function 
    startMove(e:MouseEvent):void
    {
        
    angleNum = (Number(this.input_txt.text))-1;
        
    targetX a[angleNum].x;
        
    targetY a[angleNum].y;
        
    startX guy_mc.x;
        
    startY guy_mc.y;

        if ((
    startX != targetX) && (startY != targetY))
        {
            
    atanX = (targetX startX);
            
    atanY = (targetY startY);
            
            
    dist Math.sqrt(atanX atanX atanY atanY);
            
            
    angle Math.atan2(atanYatanX);
            
    angle angle/Math.PI 180;
            
            
    nX atanX/dist;
            
    nY atanY/dist;
            
    xSpeed nX*speed;
            
    ySpeed nY*speed;
            
            
    guy_mc.rotation angle;
            
    this.addEventListener(Event.ENTER_FRAMEmoveGuy);
        }
    }

    function 
    reset(e:MouseEvent):void
    {

        
    this.removeEventListener(Event.ENTER_FRAMEmoveGuy);
        
    guy_mc.100;
        
    guy_mc.100;


    }

    function 
    moveGuy(e:Event):void
    {
        if (
    startX targetX)
        {
            
    increaseX true;
        }
        else
        {
            
    increaseX false;
        }
        if (
    startY targetY)
        {
            
    increaseY true;
        }
        else
        {
            
    increaseY false;
        }
        
    guy_mc.+= xSpeed;
        
    guy_mc.+= ySpeed;


        if (
    increaseX)
        {
            if (
    increaseY)
            {
                if (
    guy_mc.>= targetX || guy_mc.>= targetY)
                {
                    
    this.removeEventListener(Event.ENTER_FRAMEmoveGuy);
                    
    guy_mc.targetX;
                    
    guy_mc.targetY;
                }
            }
            else
            {
                if (
    guy_mc.>= targetX || guy_mc.<= targetY)
                {
                    
    this.removeEventListener(Event.ENTER_FRAMEmoveGuy);
                    
    guy_mc.targetX;
                    
    guy_mc.targetY;
                }
            }
        }
        else
        {
            if (
    increaseY)
            {
                if (
    guy_mc.<= targetX || guy_mc.>= targetY)
                {
                    
    this.removeEventListener(Event.ENTER_FRAMEmoveGuy);
                    
    guy_mc.targetX;
                    
    guy_mc.targetY;
                }
            }
            else
            {
                if (
    guy_mc.<= targetX || guy_mc.<= targetY)
                {
                    
    this.removeEventListener(Event.ENTER_FRAMEmoveGuy);
                    
    guy_mc.targetX;
                    
    guy_mc.targetY;
                }
            }
        }



  12. #12
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770
    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.targetX guy_mc.targetY guy_mc.targetY guy_mc.y);

        if(
    currentDist stepDist){
             
    guy_mc.targetX;
             
    guy_mc.targetY;
             
    this.removeEventListener(Event.ENTER_FRAMEmoveGuy);
        }else{
            
    guy_mc.+= xSpeed;
            
    guy_mc.+= ySpeed;
        }

    To optimize for speed, calculate both stepDist and currentDist without the Math.sqrt (the check is valid squared or not, but Math.sqrt is slow):
    PHP Code:
    stepDist = (xSpeed xSpeed ySpeed ySpeed);

    var 
    currentDist:Number = (targetX guy_mc.targetX guy_mc.targetY guy_mc.targetY guy_mc.y); 

  13. #13
    Knows where you live
    Join Date
    Oct 2004
    Posts
    944
    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

  14. #14
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770
    Quote Originally Posted by 691175002
    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?

  15. #15
    Knows where you live
    Join Date
    Oct 2004
    Posts
    944
    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

  16. #16
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770
    Quote Originally Posted by 691175002
    Come on people... It's take how many posts and only one person has spotted the problem?
    Quote Originally Posted by 691175002
    I didn't bother reading the entire thread since the initial problem was clear.
    Thanks for the variation on code, but the problem has already been fixed.

  17. #17
    Knows where you live
    Join Date
    Oct 2004
    Posts
    944
    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

  18. #18
    Senior Member
    Join Date
    Nov 2003
    Location
    Las Vegas
    Posts
    770
    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.

  19. #19
    When in doubt ask Eager Beaver's Avatar
    Join Date
    Feb 2007
    Location
    Planet Earth
    Posts
    911
    @Taidaishar
    Hey! Your original code works [F8]. Only thing is that you have to use radians
    instead of degrees for sin, and cos functions.
    Code:
    attachMovie("guy_mc","guy_mc",100,{_x:500,_y:300});
    attachMovie("target_mc","target_mc",200,{_x:100,_y:100});
    var speed=10;
    targetX=target_mc._x;
    targetY=target_mc._y;
    startX=guy_mc._x;
    startY=guy_mc._y;
    atanX = (targetX - startX);
    atanY = (targetY - startY);
    ang = Math.atan2(atanY, atanX);
    angle = Math.round(ang/Math.PI * 180);
    xSpeed = Math.cos(ang)*speed; 
    ySpeed = Math.sin(ang)*speed;
    guy_mc.onEnterFrame=function(){
    guy_mc._x+=xSpeed;
    guy_mc._y+=ySpeed;
    guy_mc._rotation=angle;
    }
    stop();
    <signature removed by admin>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center