This site requires JavaScript, please enable it in your browser!
Greenfoot back
iiRainzZ
iiRainzZ wrote ...

2011/12/12

move() is not accurate?

iiRainzZ iiRainzZ

2011/12/12

#
I am not sure what I am doing wrong, but I have a feeling the move() method not the best option for this. I am trying to get the actor to move to the location where I have right clicked. I used trigonometry to calculate the angle (tanX = Opposite/Adjacent) of "X". Then I rotated the actor by -X then used the move() method. For some locations the actor does not come close to the point in which it theoretically should. I'am not sure if its my code, or it's just that move() moves by whole pixels. Any suggestions? P.S. I looked at Bresenham's line algorithm, but was really confused by it.
    public void act() 
    {   
        setImage("testPlayer.PNG");
        playerMove();
        playerStats();
    }

    /** sets moving to True if the player is moving, else false */
    public void setMoving(boolean move){
        moving = move;
    }

    /** Returns True if the player is moving, else returns false */
    public boolean getMoving(){
        return moving;
    }

    /** move() the player by 1 towards the clicked location */
    public void playerMove(){
        mouse = Greenfoot.getMouseInfo();

        if (mouse!= null){
            if (mouse.getButton() == 3){
                double x2,x1,y1,y2;
                int degreesRotate = 0;
                int previousRotation = 0;
                double base;
                double height;

                nextX = mouse.getX(); //The last clicked X position of mouse
                nextY = mouse.getY(); //The last clicked Y position of mouse

                x2= nextX;
                x1= getX();
                y2 = nextY;
                y1= getY();

                base = Math.abs(x1-x2);
                height = Math.abs(y1-y2); 

                if (x1 != x2 && y1 != y2){
                    if (x1 < x2 && y1 > y2){
                        degreesRotate = (int)( Math.toDegrees(Math.atan(height/base)) * -1);

                    }else if( x1 > x2 && y1 > y2){
                        degreesRotate = (int)(180- Math.toDegrees(Math.atan(height/base)) * -1);

                    }else if( x1 > x2 && y1 < y2){
                        degreesRotate = (int)( Math.toDegrees(Math.atan(height/base)) * -1 - 180);

                    }else if( x1 < x2 && y1 < y2){
                        degreesRotate = (int)( 360 - Math.toDegrees(Math.atan(height/base)) * -1);

                    }
                }else if (y1!= y2){
                    if(y1 > y2){
                        degreesRotate= -90;
                    }else{
                        degreesRotate = 90;
                    }
                }else if(x1 != x2){
                    if(x1 > x2){
                        degreesRotate= 180;
                    }else{
                        degreesRotate = 0;
                    }
                }
                setMoving(true);
                setRotation(getRotation() * 0);
                setRotation(degreesRotate);
            }              
        }
        if(Math.abs(getX() - nextX) < 5 && Math.abs(getY()- nextY) < 5){
            setMoving(false);
        }
        if (getMoving() == true){
            move(1);
        }
    }

    public void playerStats(){
        System.out.println("\f");
        System.out.println("Player X: " + getX());
        System.out.println("Player Y: " + getY());
        System.out.println("Next X: " + nextX);        
        System.out.println("Next Y: " + nextY);  
        System.out.println("Rotation: " + (360-getRotation())); 
        System.out.println("Moving: " + getMoving());
    }

}
darkmist255 darkmist255

2011/12/12

#
You might want to try something like this: doubleX is the X, doubleY is the Y get your x and y distance that you need to move, as doubles or ints (whatever you want)
public void addedToWorld(World world)
{
    realXloc = getX();
    realYloc = getY();
}

public void move()
{
realXloc = (realXloc + xMove);
realYloc = (realYloc + yMove);
setLocation((int)realXloc, (int)realYloc);
}
This will give you decimal precise movement (so it's not twitchy), and should help. Though at this point the rotation would no longer have an effect, so you would have to rely on trig alone. Maybe not even trig, just literally the X and Y difference between the mouse and the actor. If you can get the X and Y difference, just move it based on that maybe?
iiRainzZ iiRainzZ

2011/12/12

#
Doesn't (int) drop the decimals of the double, so it be only a whole integer? I have thought of this before, but I'am not sure if it is what you mean. I thought about using the slope (rise/run), rise for the Y and run for the X. Then I would find the lowest ratio where X would = 1. (5/2) = 2.5/1, but this creates decimal values.
nccb nccb

2011/12/12

#
As a sidenote, that whole block of code with the four atan calls, while commendable for knowing the pitfalls of atan, can probably be replaced by using Math.atan2 (which has all this logic bundled in). As to your actual problem: Greenfoot stores the X/Y coordinates for actors in integer variables, and move thus takes place using integer amounts. When you call move(1), your actor can only move in eight different ways: (1,0), (1, 1), (0,1), (-1,1), (-1, 0), (-1, -1), (0, -1), (1, -1). This means that there isn't enough precision in the movement to go in a straight line to your destination, and probably won't get too close in the end. The main two solutions are: move faster (move(4) probably has enough precision in smallish worlds), or use a class like SmoothMover which keeps track of your movement in higher precision (and feeds Greenfoot the rounded version). You can find SmoothMover in several of the book projects (for which you don't need to own the book), or build your own similar mechanism.
iiRainzZ iiRainzZ

2011/12/12

#
Thanks for the help! After making move() larger it was more precise and was a good solution, but is still not as accurate as I liked it to be. I looked through the SmoothMover and Vector class, I didn't understand all the code, but I think I have the general idea of how it works. I don't feel right taking someone else's code, so I am going to attempt to create similar one.
darkmist255 darkmist255

2011/12/12

#
The code I showed you is my own simple version of SmoothMover. It uses "RealX" and "RealY" to keep track of the coordinates in double precision, then just outputs the coordinates to the world as rounded integers. I use it for all of my projects since I thought of it :D.
iiRainzZ iiRainzZ

2011/12/13

#
I noticed :P, didn't really see the big picture at first ,but after nccb said
nccb wrote...
SmoothMover which keeps track of your movement in higher precision (and feeds Greenfoot the rounded version)
it started to fit together. I was thinking too complex, thought there really was a way to make the grid run on doubles.
darkmist255 darkmist255

2011/12/13

#
Nope :D. It looks good when it's rounded to pixels though, don't worry, as long as the precise coordinates are kept.
You need to login to post a reply.