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?

2 Likes

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

1 Like

oh, it’s harder than I thought…

I am sorry

1 Like

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 );
}
//
2 Likes

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

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

2 Likes

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.

2 Likes

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 

// ------------------------------------------------------------------------------
1 Like

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

1 Like

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!

1 Like

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

1 Like

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 

// --------------------------------------------------------------------------
1 Like

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

1 Like