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

2011/8/2

Moving objects to objects/location

1
2
Robto Robto

2011/8/2

#
Hi, I'm new to programming and I stumbled on greenfoot by accident. I have watched the tutorials and I can fairly read the codes. I'm puzzling to solve an issue how to get an object to move from a random location to a clicked location (not appearing on the clicked location!). Basically I would like to activate an object (actor) by leftclick and moving it to a location/object specified by rightclick (prefferably in a straight line). Any thoughts? Cheers, R.
davmac davmac

2011/8/3

#
As far as I can see an actor has three states:
  • Neutral (waiting to be clicked)
  • Clicked; waiting for destination
  • Moving towards destination
You should have at least one variable to keep track of which state the actor is currently in. An "int" will do; you can define the state values as constants ("static final" variables):
private static final int STATE_NEUTRAL = 0;
private static final int STATE_WAITFORDEST = 1;
private static final int STATE_MOVING = 2;

private int state = STATE_NEUTRAL;
Then in your act() method:
public void act()
{
    if (state == STATE_NEUTRAL) {
        // fill this in
    }
    else if (state == STATE_WAITFORDEST) {
        // fill this in
    }
    else if (state == STATE_MOVING) {
        // fill this in
    }
}
Your code needs to set "state" appropriately when relevant events occur. You'll also need two instance variables to store the destination to move towards in state STATE_MOVING. If you need more help, try to be specific with your questions. What exactly are you having trouble with?
Robto Robto

2011/8/3

#
Hi davamac, Thank you for your reply. I have had a different approach without setting "state". Maybe I'm thinking to simple about this. Can I share my conceptual code design? Backgroundinfo: I have a subclass of world which populates the world with to subclasses of actor (a player and a resource). My goal is to create a game similar as age of empire where you select a unit (object) and assign it a task (tasks: walk to location, gather resources, build items, etc) Conceptual code design actor in subclass of actor (player): 1. public void act (this method can be created via the various tutorials and documentation) - when clicked go to method whatAction 2.public void whatAction (this method can be created via the various tutorials and documentation) - listen for keypressed - if b was pressed show popup with build menu (the next steps still has to be worked out. For now I focus on the movement and gathering) - if w was pressed go to method moveWhere 2. public void moveWhere (this method can be created via the various tutorials and documentation) - do nothing untill mouseclicked - when mouseclicked { - determine which button was clicked - if leftclick break - if rightclicked check if an object was clicked - if no object was rightclicked store x and y location of mousepointer (out of method for availability in other method) and go to method moveToLocation - if object was rightclicked store which object was rightclicked (out of method for availability in other method) and go to method doActionOnObject 3.public void moveToLocation (this method is for me the tricky part at the moment) - determine current position of "this" via getX() and getY() - calculate angle (direction) and distance to clicked location - move to clicked location - when in route to clicked location, check for collision with other objects - when in collision with other objects go around object - at arrival of location break 4.public void doActionOnObject - determine position of rightclicked object - execute moveToLocation method to go to rightclicked object - do gather action... etc etc etc... I would like to know if my conceptual approach is ok (a lot of code in the actor subclass), perhaps it is better to create supporting subclasses? And specific how to achieve (which formula to use) method 3. Thank you.
davmac davmac

2011/8/4

#
Actors always take turns acting - they don't act at the same time. So you need state to keep track of what the actor is currently doing. For instance, in:
2. public void moveWhere (this method can be created via the various tutorials and documentation) - do nothing untill mouseclicked - when mouseclicked {
... the problem is that "do nothing until mouseclicked" means your actor waits until the mouse is clicked; but if it waits using a conventional loop then it will stop every other actor from doing anything. The correct way to do it is to keep track of state, and in that state, the actor should check if the mouse is clicked; if it is, then it transitions to a new state, and so on. Most of the points you have above describe the different states your actor has.
I would like to know if my conceptual approach is ok (a lot of code in the actor subclass), perhaps it is better to create supporting subclasses? And specific how to achieve (which formula to use) method 3
At this stage, I think it's ok to put most of the code into your Actor subclass. You can move some of it out later if you need to. In terms of formulas for part 3:
int dx = targetX - getX();
int dy = targetY - getY();
double angle = Math.toDegrees(Math.atan2(dy, dx));
double distance = Math.sqrt(dx * dx + dy * dy);
Robto Robto

2011/8/4

#
Hi davmac, Thank you clearing that out for me and describing the formula! *off to work on code*
Robto Robto

2011/8/4

#
Hi davmac, How do I use the double angle? All the methods I looked at regarding rotation, turn, angle use int as a value. Your remarks about state works like a charm. I have a working code where I move the object based on clicks with the setLocation method. Now I need to move the object to the location. I expect to just rotate the object and move(distance)?
Robto Robto

2011/8/4

#
Solved the issue with double angel (just casted it to int), but somehow my move method doesn't "move". It just makes the object appear at the released click location. Any thoughts? Here's my code:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class myActor here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class myActor extends Mover
{
    //static integers for state of actor
    private static final int STATE_NEUTRAL = 0;  
    private static final int STATE_WAITFORDEST = 1;  
    private static final int STATE_MOVING = 2;  
    //specifying initial state at run
    private int state = STATE_NEUTRAL;  
    //integers for target destination
    private int targetX;
    private int targetY;

    /**
     * Act - do whatever the myActor wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
          
        if (state == STATE_NEUTRAL) {  

                if (Greenfoot.mousePressed(this))
                {
                    state = STATE_WAITFORDEST;
                }
        }  
        else if (state == STATE_WAITFORDEST) {
            
                if (Greenfoot.mouseClicked(null)) 
                    {
                  updateDest();
                  state = STATE_MOVING;
                }  
        }  
        else if (state == STATE_MOVING) {  
                moveDest();
                state = STATE_NEUTRAL;
            }  
    }  
    
    /**
     * This method updates the private integers targetX and targetY
     */
    
    public void updateDest()
    {
        MouseInfo mouse = Greenfoot.getMouseInfo();
                  targetX = mouse.getX();
                  targetY = mouse.getY();
    }
    
    /**
     * This method moves the actor to the location where the mousebutton was released
     */
    public void moveDest()
    {
        //fill in code
            int dx = targetX - getX();  
            int dy = targetY - getY();  
            double angle = Math.toDegrees(Math.atan2(dy, dx));  
            double distance = Math.sqrt(dx * dx + dy * dy);
            int x = (int) angle;
            setRotation (getRotation() + x);
            move(distance);
            setRotation(0);
    }

}
Robto Robto

2011/8/4

#
Thought I had it fixed by making a while loop
public void moveDest()
    {
        //fill in code
            int dx = targetX - getX();  
            int dy = targetY - getY();  
            double angle = Math.toDegrees(Math.atan2(dy, dx));  
            double distance = Math.sqrt(dx * dx + dy * dy);
            int x = (int) angle;
            setRotation (getRotation() + x);
            int i = 0; 
            while (i<distance){
                        move();
                        i++;
                    }
            setRotation(0);
    }
But no cigar. Any thoughts?
danpost danpost

2011/8/4

#
As davmac had said earlier, waiting for a mouseclick, or moving an object in a loop (while or for) prevent other actor from doing what they do. They have to wait for the current object to finish what it does before continuing on. An option is to move a small distance in the direction it needs to go, checking to see if it has reached its destination to change the state variable back to neutral. Take statement 45 above out of act() and put in in moveDest() or have moveDest() return the distance remaining back to act(). Test: if distance < 1 , state = state_neutral.
Robto Robto

2011/8/5

#
Hi danpost, Thank you for your reply. I actually tried moving the update state from 45 to moveDest, but that didn't worked for me. I managed to get it working with your tips, but now it only executes ones or twice before it hangs (move back and forth). Probably something wrong with my loop.
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class myActor here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class myActor extends Mover
{
    //static integers for state of actor
    private static final int STATE_NEUTRAL = 0;  
    private static final int STATE_WAITFORDEST = 1;  
    private static final int STATE_MOVING = 2;  
    //specifying initial state at run
    private int state = STATE_NEUTRAL;  
    //integers for target destination
    private int targetX;
    private int targetY;

    /**
     * Act - do whatever the myActor wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        if (state == STATE_NEUTRAL) {  

                if (Greenfoot.mousePressed(this))
                {
                    state = STATE_WAITFORDEST;
                }
        }  
        else if (state == STATE_WAITFORDEST) {
            
                if (Greenfoot.mouseClicked(null)) 
                    {
                  updateDest();
                  state = STATE_MOVING;
                }  
        }  
        else if (state == STATE_MOVING) {  
                moveDest();
                //state = STATE_NEUTRAL;
            }  
    }  
    
    /**
     * This method updates the private integers targetX and targetY
     */
    
    public void updateDest()
    {
        MouseInfo mouse = Greenfoot.getMouseInfo();
                  targetX = mouse.getX();
                  targetY = mouse.getY();
    }
    
    /**
     * This method moves the actor to the location where the mousebutton was released
     */
    public void moveDest()
    {
        //fill in code
            int dx = targetX - getX();  
            int dy = targetY - getY();  
            double angle = Math.toDegrees(Math.atan2(dy, dx));  
            double distance = Math.sqrt(dx * dx + dy * dy);
            int x = (int) angle;
            setRotation (getRotation() + x); 
            int i = 0;          
            if (state == STATE_MOVING){
                move();                
                if (distance < 1){
                    state = STATE_NEUTRAL;
                }
            }
            
            setRotation(0);
            //state = STATE_NEUTRAL;
    }

}
Also, the remarks about only having one actor move at the same time has got me thinking. I can have multiple actors moving like this right? As the game AoE?
danpost danpost

2011/8/5

#
Move lines 79 and 80 up to 75 inside the conditional 'if' that determines it has reached its destination. What is apparently happening is you are making the image revert back to the NEUTRAL_STATE image every time it takes a step toward its destination. But, from what see that you have here, it should not be hanging up. I am not sure if you want 'setRotation(getRotation() + x)'; You might want 'setRotation(x)', or just get rid of 'x', and use 'setRotation((int) angle)'. I am still looking at it to see if I can find anything. :+)
danpost danpost

2011/8/5

#
By the way, where is your move() method? I do not see the code for that. Is there a parameter that should be with it?
davmac davmac

2011/8/6

#
danpost wrote...
Move lines 79 and 80 up to 75 inside the conditional 'if' that determines it has reached its destination. What is apparently happening is you are making the image revert back to the NEUTRAL_STATE image every time it takes a step toward its destination.
That's not quite right... line 80 is commented out. The main problem is that when you click on the actor, both mousePressed() and mouseClicked() are triggered. So, the state immediately transitions from NEUTRAL to WAITFORDEST and immediately to MOVING. If you change line 30 to use "mouseClicked(this)" instead of "mousePressed(this)" the problem is mostly solved. The next problem is that move() on 73 (which I assume is from the Mover class) moves a fixed distance which is normally defined as 5.0. That's greater than the check for destination reached on line 74. It's possible for the actor to get close to its destination, then move() right over and past it, but still be too far away - so it then turns around and tries to move back, but it moves over it again, and so on. Either supply an argument to move (so "move(1.0)") or increase the allowed distance line 74.
Robto wrote...
Also, the remarks about only having one actor move at the same time has got me thinking. I can have multiple actors moving like this right? As the game AoE?
Yes, that's the whole point of not using for/while loops. If you didn't care about that, your while loop before would have worked fine, as long as you put a Greenfoot.delay(1) inside the loop. (The reason why it looked like the actor reached its destination instantly is because, well, computers are fast - it moved each step of the way before you could see it!).
danpost danpost

2011/8/6

#
@davmac -- My comment about NEUTRAL_STATE was specified about the image, not the actual state. I was only saying that the rotation of the image goes back to zero after each step toward its destination. Then the next time act() is called for that Actor, it changes it back to heading toward its destination, moves, and again goes back to zero. It was not line 80 that I was referring to, it was line 79.
davmac davmac

2011/8/6

#
danpost wrote...
It was not line 80 that I was referring to, it was line 79.
Actually, you did say lines 79 and 80. However, I see now what you meant; but I believe the setting of rotation back to 0 is deliberate in this case. That is, regardless of which direction the actor is moving, Robto wants the image to remain in its original orientation; so the setRotation() is used to control the direction of movement, but the rotation is afterwards restored to 0 so that the image is unaffected. (Robto - is that correct?)
There are more replies on the next page.
1
2