Draw a square line by line

I am trying to draw a square one line at a time, with a keypress. In other words, press “1” to draw a line, turn 90 degrees, press “1” to draw a line, turn 90 degrees, etc. I know about the rectangle function. This is just a small part of a bigger project I am working on. Here is the code I have now:

int length=10; //length of line segment
int xPos=0;
int yPos=0;
void setup() {
size(500,500);
}

void draw () {
}

void keyPressed() {
  translate(xPos, yPos);
  
    if (key == '1') {
    line(0,0,1*length, 0);
    xPos += 10;
    rotate(PI/2);
    }
}

It draws the line on the keypress but it doesn’t rotate. When I have used the rotate function without the keypresses aspect it has worked fine. What makes this different?

At the moment you have to press wasd in my code in this order

To change , store the angle and say rotate directly after translate as I suggested

oh, it’s harder than I thought…

I am sorry

OLD version - new version below

Turtle program.

Use wasd keys.

  • The movement is always seen relative from the Turtle perspective.
  • w is forward, a is left, d is right, s is backward
  • c is reset.
  • p Pen up/down.
  • l (L) prints the commands (to save).

Chrisir




// A String exec gets recorded (in keyPressed()) and then evaluated (executed) in evaluateInputs().

// https://discourse.processing.org/t/drawing-connected-lines-with-keystroke-commands/17947/5
// with help from Jeremy et al., see https://forum.processing.org/two/discussion/20706/how-3d-turtle-like-in-logo-but-3d-math-problem

final String helpText = 
  "Turtle program. Use wasd keys. The movement is always seen relative from the Turtle perspective. w is forward, a is left, d is right, s is backward, c is reset. p Pen up/down. l (L) prints the commands (to save)."; 

final color BLACK = color(0);
final color RED = color(255, 0, 0);

// For the Turtle: 
int lineSegment=30; //length of line segment

String exec=""; // A String exec gets recorded (in keyPressed()) and then evaluated (executed) in evaluateInputs().
boolean penUp=false; // when the pen is up (true), it is not touching the ground, the Turtle is not drawing. penUp = false means the Turtle draws.   

// For the User Interface (UI):  
boolean showHelp = true; // show help text / UI 

//----------------------------------------------------------------------------

void setup() {
  size(1500, 500);
  background(111); 

  println(helpText);
}

void draw() {
  //
  background(111); 

  // Help text 
  if (showHelp) {
    fill(0); 
    text(helpText, 
      17, 17);
    text(penUpText(), 
      width-135, 17);
  }

  translate(width/2, height/2); 
  rotate(-HALF_PI);
  penUp=false;

  evaluateInputs();

  if (showHelp) {
    // show Turtle
    noFill(); 
    stroke(RED); 
    ellipse(0, 0, 6, 6);
  }
}

//----------------------------------------------------------------------------

void keyPressed() {
  // wasd 
  if (key == 'w' || 
    key == 'a'  ||
    key == 's'  ||
    key == 'd' ||
    key == 'p' ) {
    // record keys ---- 
    exec += key;
    //
  } else if (key=='c') {
    // clear
    println(exec); 
    exec="";
  } else if (key=='l') {
    // print 
    println(exec);
  } else if (key==' ') {
    // showHelp 
    showHelp = !showHelp;
  }
}

//----------------------------------------------------------------------------

void evaluateInputs() {

  // eval the recorded String
  for (int i=0; i < exec.length(); i++) {
    // println (exec.charAt(i));

    // the line color is between black and red
    float amtValue = map( i, 
      0, exec.length(), 
      0, 1); 
    stroke(lerpColor(BLACK, RED, amtValue));

    switch (exec.charAt(i)) {
      //
    case 'w':
      tLine(lineSegment);
      break;

    case 's':
      tLine(-lineSegment);
      break; 

    case 'a':
      rotate(-HALF_PI);
      tLine(lineSegment);
      break;

    case 'd':
      rotate(HALF_PI);
      tLine(lineSegment);
      break;

    case 'p':
      penUp = !penUp; 
      break;
    }//switch
  }//for
}//func 

// ------------------------------------------------------------------------------

void tLine(int x) {
  if (penUp) 
    tStep(x); 
  else 
  tLineDraw(x);
}

void tLineDraw(int x) {
  // draw and move 
  line(0, 0, 
    x, 0);
  translate(x, 0);
}

void tStep(int x) {
  // just move (if pen is up) 
  translate(x, 0);
}

// ------------------------------------------------------------------------------

String penUpText() {
  if (penUp) 
    return"Turtle only moves.";
  else 
  return"Turtle draws: Pen down.";
}//func
//

Here is a full blown version with wasd and many other things

Turtle program.

  • Escape key brings you this help.
  • X leave program (Shift-x).
  • Space bar - small text in the main program on / off.
  • l (L) prints the commands (to save).
  • c is reset / delete all.
  • Backspace - undo last step(s)
  • Cursor keys - move the entire canvas (useful when you reached a screen border)
  • S - save (shift-s) (with date and time stamp)

The following keys control the Turtle and get recorded

  • Use wasd keys. The movement is always seen relative from the Turtle perspective. w is forward, a is left, d is right, s is backward, seen from the Turtle.
  • p Pen up / down. Useful when you want to move the Turtle to another place on the screen without drawing.
  • Use r(ed), g(reen) and b(lue) and v (black) and n (white) for the color the Turtle draws.
  • Use + / - for Stroke Weight.

Chrisir



// A String turtleCommandString gets recorded (in keyPressed()) and then evaluated (executed) in evaluateInputs().
//
// Keys:
//    Escape = HELP 
//    Space Bar
//    wasd / Backspace / c  
//    r g b Colors 
//    v / n colors
//    many more.... see Help. 

// https://discourse.processing.org/t/drawing-connected-lines-with-keystroke-commands/17947/5
// with help from Jeremy et al., see https://forum.processing.org/two/discussion/20706/how-3d-turtle-like-in-logo-but-3d-math-problem

// To Do / Wishes : 
//    Load and save turtleCommandString
//    Edit command Strings / copy paste
//    3D 
//    Splash Screen 
//    Color Selector 
//    change of length of lineSegment 

final String helpText = 
  "Turtle program. Use wasd keys. The movement is always seen relative from the Turtle perspective. w is forward, a is left, d is right, s is backward, c is reset. p Pen up/down. Esc for Help.";

final String helpTextLong = 
  "Turtle program. "
  +"\n\nEscape key brings you this help. "
  +"\nX leave program (Shift-x).\n"
  +"Space bar - small text in the main program on / off.\n"
  +"l (L) prints the commands (to save).\n"
  +"c is reset / delete all."
  +"\nBackspace - undo last step(s)"
  +"\nCursor keys - move the entire canvas (useful when you reached a screen border)"
  +"\nS - save (shift-s) (with date and time stamp)"

  +"\n\n\nThe following keys control the Turtle and get recorded \n"
  +"\n"

  +"Use wasd keys. The movement is always seen relative from the Turtle perspective. w is forward, a is left, d is right, s is backward, seen from the Turtle. "
  +"\np Pen up / down. Useful when you want to move the Turtle to another place on the screen without drawing."
  +"\nUse r(ed), g(reen) and b(lue) and v (black) and n (white) for the color the Turtle draws."
  +"\nUse + / - for Stroke Weight.   \n\n \n\n"
  +"Hit Escape key to leave the help.";

final color BLACK  = color(0);
final color WHITE  = color(255);

final color RED    = color(255, 0, 0);
final color GREEN  = color(0, 255, 0);
final color BLUE   = color(0, 0, 255);

// states 
final int NORMAL_STATE = 0; 
final int HELP_STATE   = 1; 
int state = NORMAL_STATE; 

// For the Turtle: 
color colorTurtle = WHITE; // initial color - see Help 
int strokeWeightTurtle=1; 
int lineSegment   = 30;    //length of line segment
String turtleCommandString = "";     // A String turtleCommandString gets recorded (in keyPressed()) and then evaluated (executed) in evaluateInputs().
boolean penUp=false;  // when the pen is up (true), it is not touching the ground, the Turtle is not drawing. penUp = false means the Turtle draws.   

// For the User Interface (UI):  
boolean showHelp = true; // show help text / UI 
float posCanvasX, posCanvasY;  // change with cursor  

//----------------------------------------------------------------------------

void setup() {
  size(1500, 900);
  background(111); 

  // println(helpText);
  println("");
  println(helpTextLong);
}

void draw() {
  // Depending on state 

  switch(state) {

  case NORMAL_STATE: 
    drawForStateNORMAL_STATE();
    break; 

  case HELP_STATE:
    drawForStateHELP_STATE(); 
    break;

  default:
    // Error
    break; 
    //
  }//switch
  //
}//func 

//----------------------------------------------------------------------------
// These functions are called from draw() 

void drawForStateNORMAL_STATE() {

  // clear all
  background(111); 

  // Help text and text for penUp
  showHelpText();

  // Init Turtle (reset a few parameters)
  translate((width/2) + posCanvasX, (height/2) + posCanvasY); 
  rotate(-HALF_PI);
  penUp=false;
  colorTurtle = WHITE; // reset initial color - see Help
  stroke(colorTurtle);
  strokeWeightTurtle=1;  // reset 
  strokeWeight(strokeWeightTurtle); 

  // Eval Input String
  evaluateInputs();

  // draw Turtle 
  drawTurtle();
}

void drawForStateHELP_STATE() {
  // clear all
  background(0);
  // show text 
  fill(255);
  text(helpTextLong, 
    17, 17);
}

//----------------------------------------------------------------------------
// Inputs 

void keyPressed() {

  switch(state) {

  case NORMAL_STATE: 
    keyPressedForStateNORMAL_STATE();   
    break; 

  case HELP_STATE:
    keyPressedForStateHELP_STATE(); 
    break;

  default:
    // Error
    break;
    //
  }//switch
  //
}//func 

// These functions are called from keyPressed() 

void keyPressedForStateHELP_STATE() {
  // Esc
  if (key==ESC) {
    key=0; 
    state = NORMAL_STATE;
  }//if
}//func 

void keyPressedForStateNORMAL_STATE() {
  // Many keys 

  if (key==CODED) {
    switch(keyCode) {
    case UP:
      posCanvasY--; 
      break;
    case DOWN:
      posCanvasY++; 
      break;

    case LEFT:
      posCanvasX--; 
      break;
    case RIGHT:
      posCanvasX++; 
      break;
    }//switch

    // Leave here
    return;
  } // CODED -----------------------------------------------

  // All not coded here:  

  // wasd etc. - these get recorded   
  if (key == 'w' || 
    key == 'a'  ||
    key == 's'  ||
    key == 'd' ||

    key == 'p' ||

    key == 'r' ||
    key == 'g' ||
    key == 'b' ||

    key == 'v' ||
    key == 'n' ||
    key == '+' ||
    key == '-' ) {
    // record keys ---- 
    turtleCommandString += key;
    //---
  } else if (key==BACKSPACE) {
    // shorten by 1 (undo)
    if (turtleCommandString.length()>0) {
      turtleCommandString=turtleCommandString.substring(0, turtleCommandString.length()-1);
    }//if
  } else if (key=='c') {
    // clear
    println(turtleCommandString); 
    turtleCommandString="";
  } else if (key=='l') {
    // print 
    println(turtleCommandString);
  } else if (key==' ') {
    // showHelp 
    showHelp = !showHelp;
  } else if (key=='X') {
    // print and quit
    println(turtleCommandString);
    exit();
  } else if (key=='S') {
    save(timeStamp()
      +".jpg");
  } else if (key==ESC||key=='h'||key=='H') {
    // Help 
    key=0; // kill Esc
    println(turtleCommandString);
    state=HELP_STATE;
  } // else if Esc key
  //
}//func

//----------------------------------------------------------------------------

void evaluateInputs() {

  // eval the recorded String with the Turtle Commands

  for (int i=0; i < turtleCommandString.length(); i++) {
    // println (turtleCommandString.charAt(i));

    /*
    // the line color is between black and red
     float amtValue = map( i, 
     0, turtleCommandString.length(), 
     0, 1); 
     stroke(lerpColor(BLACK, RED, amtValue));
     */

    switch (turtleCommandString.charAt(i)) {
      //
    case 'w':
      tLine(lineSegment);
      break;

    case 's':
      tLine(-lineSegment);
      break; 

    case 'a':
      rotate(-HALF_PI);
      tLine(lineSegment);
      break;

    case 'd':
      rotate(HALF_PI);
      tLine(lineSegment);
      break;

    case 'p':
      penUp = !penUp; 
      break;

      // colors -------

    case 'r':
      stroke(RED); 
      colorTurtle = RED; 
      break; 

    case 'g':
      stroke(GREEN);
      colorTurtle = GREEN; 
      break; 

    case 'b':
      stroke(BLUE); 
      colorTurtle = BLUE; 
      break;

    case 'v':
      stroke(BLACK); 
      colorTurtle = BLACK; 
      break; 

    case 'n':
      stroke(WHITE); 
      colorTurtle = WHITE; 
      break;

      //-------------------

    case '+':
      strokeWeightTurtle++;
      strokeWeight(strokeWeightTurtle); 
      break; 

    case '-':
      strokeWeightTurtle--;
      if (strokeWeightTurtle<0)
        strokeWeightTurtle=0; 
      strokeWeight(strokeWeightTurtle); 
      break;

      //-------------------
      //
    }//switch
    //
  }//for
}//func 

// ------------------------------------------------------------------------------
// Turtle functions 

void tLine(int x) {
  // Depending on penUp
  // we move or draw 
  if (penUp) 
    tStep(x); 
  else 
  tLineDraw(x);
}

void tLineDraw(int x) {
  // draw and move (pen is down, penUp=false)
  line(0, 0, 
    x, 0);
  translate(x, 0);
}

void tStep(int x) {
  // just move (if pen is up, penUp=true) 
  translate(x, 0);
}

void drawTurtle() {
  // show the Turtle itself as a triangle
  noFill(); 
  stroke(colorTurtle); 
  ellipse(-2, 0, 2, 2);
  line(0, -5, 7, 0);
  line(0, 5, 7, 0);
}//func 

// ------------------------------------------------------------------------------
// Minor functions 

void showHelpText() {
  // help text 
  if (showHelp) {
    // help text
    fill(0); 
    text(helpText, 
      17, 17);
    text("Turtle commands: "
      +turtleCommandString
      +" (Backspace to undo last step(s))", 
      17, height-17);
    // Text for pen up yes / no:  
    text(penUpText(), 
      width-135, 17);
    // Turtle color
    fill(colorTurtle); 
    text("Turtle color", 
      width-135, 17*2);
    fill(0);   
    text("Stroke Weight: "+strokeWeightTurtle, 
      width-135, 17*3);
  }
}

String penUpText() {
  // Depending on penUp
  if (penUp) 
    return"Turtle only moves.";
  else 
  return"Turtle draws: Pen down.";
}//func

// -----------------------------------------------------------------------------
// Tools: Date and time 

String timeStamp() {
  return todaysDate () 
    + "_" 
    + timeNow () ;
}

String todaysDate () {
  int d = day();    // Values from 1 - 31
  int m = month();  // Values from 1 - 12
  int y = year();   // 2003, 2004, 2005, etc.

  String Result = 
    nf(y, 2)+
    nf(m, 2)+
    nf(d, 2); 
  return( Result );
}

String timeNow () {
  int h = hour();    // Values from 1 - 23
  int m = minute();  // Values from 1 - 60
  int s = second();   // 1-60

  String Result = 
    nf(h, 2) + "" + 
    nf(m, 2) + "" + 
    nf(s, 2); 
  return( Result );
}
//

@MichelO – hope you are finding help on the forum!

When you post, please help us help you by formatting your code.

Thank you again for your generous help. Your turtle program does exactly what I want my program to do. However, I do not understand much of what is in your code. I tried to just paste pieces and edit for what I want my code to do but I am running into some issues. Here is a piece of my code:

int lineSeg=10; //length of line segment
int xPos=0;
int yPos=0;
String exec="";  // A String exec gets recorded (in keyPressed()) and then evaluated (executed) in evaluateInputs().

void setup() {
size(500,500);
background(#FFFFFF);
}

//translate
//rotate(-HALF_PI);

void draw () {
translate(width/2, height/2);
rotate (-HALF_PI);
evaluateInputs();
}

void keyPressed() {

    if (key == '1' ||
        key == '2' ||
        key == '3' ||
        key == '4' ||
        key == '5' ||
        key == '6' ||
        key == '7' ||
        key == '8' ||
        key == '9' ||
        key == '0' ) {
        exec += key; //record keys
    }
}

void evaluateInputs() {
  
    for (int i=0; i < exec.length(); i++) {
      
      float amtValue = map (i, 0, exec.length(), 0, 1);
     
      switch (exec.charAt(i)) {
        
        case '1':
        rotate(-HALF_PI);
        tLine(lineSeg);
        break;

I am getting the following error message: “The function tLine(int) does not exist.” Any idea why? From what I can tell, you don’t define it anywhere in your code, but maybe I missed something.

I just checked, it’s at the very end in version 1 and a bit before in version 2

// ------------------------------------------------------------------------------
// Turtle functions 

void tLine(int x) {
  // Depending on penUp
  // we move or draw 
  if (penUp) 
    tStep(x); 
  else 
  tLineDraw(x);
}

void tLineDraw(int x) {
  // draw and move (pen is down, penUp=false)
  line(0, 0, 
    x, 0);
  translate(x, 0);
}

void tStep(int x) {
  // just move (if pen is up, penUp=true) 
  translate(x, 0);
}

void drawTurtle() {
  // show the Turtle itself as a triangle
  noFill(); 
  stroke(colorTurtle); 
  ellipse(-2, 0, 2, 2);
  line(0, -5, 7, 0);
  line(0, 5, 7, 0);
}//func 

// ------------------------------------------------------------------------------

The basic idea is from Jeremy and you can read about it on the other discussion (the one I linked to).

Basically we use the translate/ rotate functions to steer the Turtle. The translate and rotate commands add up, hence it moves across the screen

Hello,

This may be out of sync with current discussion but sharing nonetheless.

Here is an example that draws 2 of the lines:

// Draw a square by rotating lines
// v1.0.0
// GLV 2020-02-28

int length = 50; //length of line segment
int xPos = 0;
int yPos = 0;

int count = 0;

void setup() 
  {
  size(640, 360);
  }

void draw() 
  {
  translate(width/4, height/2);
  
  push();
  translate(xPos+50*sin(0*TAU/4), yPos+50*cos(0*TAU/4));        // 0, 50
  rotate(0*TAU/4);
  line(-length, 0, length, 0);
  pop();
  
  push();
  translate(xPos+50*+sin(1*TAU/4), yPos+50*cos(1*TAU/4));       // 50, 0
  rotate(1*TAU/4);
  line(-length, 0, length, 0);
  pop();

// And so on...
  }

I saw patterns (see comments for x,y) and added some trigonometry; this may be advanced but offers another perspective.

This is not complete and I removed the last 2 sides; you can add these.

You will notice a pattern in the factors (0, 1, 2, 3) and can make a for() loop out of this.

Later you can integrate keyPressed().

I was able to write code based on this and draw a square with 4 key presses.

Have fun!

can you elaborate please?

Because, how do the movements of the Turtle (cause that’s what it is) add up?

I’d expected you say: xPos+=50; yPos+=0; turtleAngle+=Tau; etc.

In my version they add up, because I don’t use push and pop but just let translate and rotate add up (idea by Jeremy).

I mean, could you draw something like this:

Worked on it a bit, you can save and load now and have a menu

here is your version with 1 and 2 key

(and Backspace)

//translate
//rotate(-HALF_PI);

final color GREEN = color (0, 255, 0); 

int lineSeg=40; //length of line segment
int xPos=0;
int yPos=0;
String exec="";  // A String exec gets recorded (in keyPressed()) and then evaluated (executed) in evaluateInputs().

boolean penUp = false;

color colorTurtle = color(0);

void setup() {
  size(500, 500);
  background(#FFFFFF);
}

void draw () {
  background(#FFFFFF);

  fill(0);
  text(exec, 17, 17);
  
  // bring Turtle to start position
  translate(width/2, height/2);
  rotate (-HALF_PI);

  // Eval Turtle
  evaluateInputs();  

  // show Turtle 
  showTurtleItself();
}

// -----------------------------------------------------------------------

void showTurtleItself() {
  noFill(); 
  stroke(GREEN);
  strokeWeight(2); 
  ellipse(0, 0, 8, 8);
  strokeWeight(1);//reset
}

void keyPressed() {

  if (key == '1' ||
    key == '2' ||
    key == '3' ||
    key == '4' ||
    key == '5' ||
    key == '6' ||
    key == '7' ||
    key == '8' ||
    key == '9' ||
    key == '0' ) {
    exec += key; //record keys
  } 
  //------------------------
  // delete last step
  else if (key==BACKSPACE) {
    if (exec.length()>0) {
      exec=exec.substring(0, exec.length()-1);
    }//if
  }
}

void evaluateInputs() {

  for (int i=0; i < exec.length(); i++) {

    float amtValue = map (i, 0, exec.length(), 0, 1);

    switch (exec.charAt(i)) {

    case '1':
      rotate(-HALF_PI);
      tLine(lineSeg);
      break;

    case '2':
      rotate(-HALF_PI);
      tLine(lineSeg/2);
      break;
    }
  }
}

// ------------------------------------------------------------------------------
// Turtle functions 

void tLine(int x) {
  // Depending on penUp
  // we move or draw 
  if (penUp) 
    tStep(x); 
  else 
  tLineDraw(x);
}

void tLineDraw(int x) {
  // draw and move (pen is down, penUp=false)
  line(0, 0, 
    x, 0);
  translate(x, 0);
}

void tStep(int x) {
  // just move (if pen is up, penUp=true) 
  translate(x, 0);
}

void drawTurtle() {
  // show the Turtle itself as a triangle
  noFill(); 
  stroke(colorTurtle); 
  ellipse(-2, 0, 2, 2);
  line(0, -5, 7, 0);
  line(0, 5, 7, 0);
}//func 

// --------------------------------------------------------------------------

It works! I can’t thank you enough for all of your help!!!