How to stop this triangle from moving, move it back few steps, and turn a few times.

Hi.

I'm working on a project of robots on a robot testing environment. We have to create three robots performing different movements on the screen. Everything is working fine, except that during randomWalk() method, as soon as it reaches a wall, it was supposed to take a few steps back, rotate a random number of times (to a random direction) and move forward again.

Due to the constant loop created by draw(), I'm struggling to make it go back. Another issue is that everything happens fast, so even if it's moving back a little bit, it's not visible.

Code:

public void randomWalk(){
        if((direction==1&&((x1+speed)>=parent.width-1))||(direction==2&&((y1+speed)>= parent.height-1))||(direction==3&&(x1-speed)<=1)||(direction==4&&((y1-speed)<= 1))){
                switch (direction){
                    case 1:
                        x1 -= speed;
                        x2 -= speed;
                        x3 -= speed;
                        break;
                    case 2:
                        y1 -= speed;
                        y2 -= speed;
                        y3 -= speed;
                        break;
                    case 3:
                        x1 += speed;
                        x2 += speed;
                        x3 += speed;
                        break;
                    case 4:
                        y1 += speed;
                        y2 += speed;
                        y3 += speed;
                        break;
                }

            int turns = parent.round(parent.random(10));
            for(int i = 0; i==turns; i++){
                int side = parent.round(parent.random(1));
                if (side == 0){
                    turnLeft();
                } else {
                    turnRight();
                }
            }
        }
        moveForward();
    }

And the other one:

    public void moveForward(){
        if((direction==1&&((x1+speed)<=parent.width))||(direction==2&&((y1+speed)<= parent.height))||(direction==3&&(x1-speed)>=0)||(direction==4&&((y1-speed)>=0))){
            switch (direction){
                case 1:
                    x1 += speed;
                    x2 += speed;
                    x3 += speed;
                    break;
                case 2:
                    y1 += speed;
                    y2 += speed;
                    y3 += speed;
                    break;
                case 3:
                    x1 -= speed;
                    x2 -= speed;
                    x3 -= speed;
                    break;
                case 4:
                    y1 -= speed;
                    y2 -= speed;
                    y3 -= speed;
                    break;
            }
        }
    }

The switch on randomWalk() is not visibly working. I think it's because as soon as it goes back, it's moving forward again, because the boundaries are not being reached.

Any thoughts? I'm really searching and trying!

Thank you very much! Gustavo Lessa

Tagged:

Answers

  • Yeah just set a flag like isGoingBackward

    Also store frameCount

    As long as it is true, go back

    Set a timer or check frameCount when to set it false again

  • @Chrisir Thanks for your quick answer! I'm trying to implement the isGoingBack. But I'm not sure about the frameCount. Should it be inserted into the randomWalk method?

    Thanks again

  • @Chrisir

    My randomWalk is now:

            public void randomWalk(){
                boolean isGoingBack;
                if((direction==1&&((x1+speed)>=parent.width-1))||(direction==2&&((y1+speed)>= parent.height-1))||(direction==3&&(x1-speed)<=1)||(direction==4&&((y1-speed)<= 1))){          
                    isGoingBack = true;
                } else {
                    isGoingBack = false;
                }
    
                if (isGoingBack){
                    for(int x = 0; x == 15; x++){
                        moveBackwards();
                    }
                    isGoingBack = false;
                    int turns = parent.round(parent.random(10));
                    for(int i = 0; i==turns; i++){
                        int side = parent.round(parent.random(1));
                        if (side == 0){
                            turnLeft();
                        } else {
                            turnRight();
                        }
                    }
                }           
                moveForward();
            }
    

    It still apparently doesn't move backwards. I think it's because I don't have this frameCount implemented.

    Thanks!

  • This should be global variable I guess:

    boolean isGoingBack;
    
  • Thanks again, @Chrisir I changed it, but still the same behavior. About the frameCount, where should I put it? And should I increment it every time or just when isGoingBack is true?

    Sorry to bother you! Thanks!

  • frameCount is build-in

    See reference

    The idea is when hitting a wall, store the frameCount in wallFrameCount

    Then use if

    if(frameCount- wallFrameCount > 67)

    isGoingBack=false;

  • edited February 2017

    @Chrisir @jeremydouglass Thank you for answering. I'm working on it now. I will post what I could do.

    I have a secondary question about the same movement.

    There are three "robots" (triangles) on the screen. I'd like them NOT TO touch each other. In other words, like it's hitting a wall. It can stop or go back, no preference.

    Considering they are triangles instead of rectangles, for example, it's harder for me to figure out some condition to determine if they are hitting each other.

    Thank you again!

    Gustavo

  • @gustavolessa -- re:

    There are three "robots" (triangles) on the screen. I'd like them NOT TO touch each other. In other words, like it's hitting a wall.

    Check out these collision detection tutorials on Triangles (and then polygons) for simple examples of how to implement this:

  • Thanks @jeremydouglass. I'm currently stuck on trying to make my robots go back a few steps. After finishing this part I will add this collision avoidance function. Really helpful even using just line/line collision!.

    Sorry to bother you, but I really don't understand why the robots aren't going back after hitting a wall.

    The code below is my current randomWalk. After a few trials I couldn't figure out why the moveBackwards() isn't being executed correctly. My guess is that moveForward() is still being called, nulling the difference on the coordinates (both use variable speed to change the x's and y's).

    Can you try to help me?

    Other question: how can I make it rotate visibly? For example, if I put a robot to rotate 4 times do the left, it's too fast, it seems it just changed the orientation to the final one directly. I've read something about using frameCount % 5 == 0, but it didn't seem to work.

    Thanks again!

        public void randomWalk(){
            if((direction==1&&((x1+speed)>=parent.width-1))||(direction==2&&((y1+speed)>= parent.height-1))||(direction==3&&(x1-speed)<=1)||(direction==4&&((y1-speed)<= 1))){          
                pode = false;
                if(hitFrameCount == 0){
                    hitFrameCount = parent.frameCount;
                }
    
            //  while(parent.frameCount - hitFrameCount < 100){
            //      moveBackwards();
            //  }
                //  isGoingBack = false;
    
                int k;
                for (k = 0; k == 200; k++){
                    moveBackwards();
                }
    
                int turns = parent.round(parent.random(10));
                for(int i = 0; i==turns; i++){
                    int side = parent.round(parent.random(1));
                    if (side == 0){
                        turnLeft();
                    } else {
                        turnRight();
                    }
                }
                if (k >= 200){
                    pode = true;
                }
            }           
            moveForward();
            hitFrameCount = 0;
    
        }
    
  • is this homework?

    When you post your entire code, we could help.

  • Hi @Chrisir. Thanks for you answer again.

    It's a project (big homework). I managed to make it correctly go back a little bit and then perform the random turn. =)

    I had a few problems about the draw() loop, that made some loops not get finished before the following lines of code were executed.

    Now my biggest concern is about making a movement slower. Specifically I want to be able to see a robot rotating 360°. Any ideas how to do this?

    I can post the whole code, but there are three classes with many lines each. =D

    Thanks again! Really helpful!

  • To slow things down

    frameRate(3);

    I think

  • More complex approach:

    Turn not hard by 90 degree

    but soft with 1 degree

    This might only be possible with an extra state in which you do the rotation. When its done set state back to normal

  • @gustavolessa --

    If I am understanding correctly you want your robot to go through a sequence of states -- forward, backward, turn, forward, backward, turn, etc. etc. Each state should either last a certain amount of time or else encounter a certain condition before switching to the next. You want forward to end based on collision detection, while backward and turn should end based on a timer. In essence, this describes a Roomba vaccuum.

    Below is a simple example of one approach. It uses an enum Motion for tracking the current state and a timer value based on millis() which is either set to 0 (not running) or sometime in the future. It separates the collision and timer checking (to change states) and a switch statement for location updating (based on the current state). The code is not in an object, and it doesn't include code in the functions that actually update the location.

    Motion mtn = Motion.FORWARD;
    int doneTime = 0;
    boolean done;
    
    enum Motion {
      FORWARD, BACKWARD, TURN
    }
    
    void randomWalk() {
    
      // on collision, change direction
      if (isColliding() && (mtn == Motion.FORWARD)) {
        mtn = Motion.BACKWARD;
        doneTime = millis()+2000; // back up for 2 secs
      }
      if (isColliding() && (mtn == Motion.BACKWARD)) {
        mtn = Motion.FORWARD;
      }
    
      // on timeout, change direction
      if ((doneTime>0)&&(doneTime<millis())) {
        if (mtn == Motion.BACKWARD) {
          mtn = Motion.TURN;
          doneTime = millis()+(int)random(3000); // turn for up to 3 secs
        }
        if (mtn == Motion.TURN) {
          mtn = Motion.FORWARD;
          doneTime = 0; // no timer, go forward until collision
        }
      }
    
      // move based on current direction
      switch (mtn) {
      case FORWARD:
        moveForward();
        break;
      case BACKWARD:
        moveBackward();
        break;
      case TURN:
        moveTurn();
        break;
      default: // direction not initialized, move forward
        mtn = Motion.FORWARD;
        moveForward();
        break;
      }
    }
    
    // unimplemented
    boolean isColliding() { return false; }
    void moveForward() { }
    void moveBackward() { }
    void moveTurn() { }
    
  • edited February 2017

    Nice.

    I would suggest (too strong a word, maybe mention is more appropriate) we could in randomWalk() have all ifs inside switch

    so nothing outside of switch is allowed in randomWalk()

    ( since most ifs are referring to mtn as well )

  • @Chrisir -- very true! I originally sketched it as one big switch statement, but then I refactored the code into separate "checking" and "moving" code blocks in an attempt to make it easier to understand. This may not have worked....

  • Interesting.

    Or implement 2 functions checkTimer and checkCollision and have therein a switch () each

Sign In or Register to comment.