Repositioning my bird character

Hi all, I’m new to processing and I’m sorta stuck. I made a bird character and I want to make a duplicate right beside it without having to re-enter and adjust all the codes. I’m also a bit confused by the “translate” function; I’m sure there’s an easier way to do this :exploding_head:. Please help lol

void setup() {
 size(500,500);
 
}

void draw() {
  background(102,178,255); 
  scale(0.70);
  strokeWeight(1.5);
  fill(0,153,120);
  line(50,381,300,381);

/*Right Leg*/
line(150,220,190,300);
line(190,300,170,380);
arc(176,380,20,18,PI,TWO_PI,CLOSE);

fill(250,200,100);

/*body and head*/
 arc(140,180,150,150,0,PI,CLOSE);
 arc(220,180,50,50,0,2*PI,CLOSE);
 
 /*left Leg*/
 fill(0,153,120);
 line(120,220,150,300);
 line(150,300,110,380);
 arc(118,380,20,18,PI,TWO_PI,CLOSE);

/*eye*/
fill(255);
ellipse(225,175,20,20);
fill(0,0,153);
ellipse(227,174,10,10);
fill(255);
ellipse(229,175,5,5);

/*Lashes*/
fill(1);
strokeWeight(2);
line(220,165,218,160);
line(226,165,226,158);
line(232,166,235,162);

/*Beak*/
triangle(236,190,232,200,247,200);

/*Antena*/
noFill();
strokeWeight(1);
arc(258,148,70,85,2.95,TWO_PI);
arc(288,146,10,14,0,TWO_PI);

/*Tail*/
strokeWeight(1);
fill(255,153,153);
triangle(6,180,60,120,70,180);
fill(100,180,100);
triangle(12,178,58,126,68,180);
fill(0,204,204);
triangle(18,176,56,132,68,180);
fill(250,200,100);
triangle(24,174,54,138,70,180);

/*wings*/
strokeWeight(1.5);
fill(255,170,51);
arc(150,190,80,70,0,PI,CLOSE);
strokeWeight(2);
line(126,216,134,210);
line(144,223,146,212);
line(164,222,156,212);

}
1 Like

Hello @CharrR,

One way to think about it is to realize that everything you are drawing is based on an origin point.
When you say:

ellipse(40, 20, 3, 3);

You are saying that you want to draw an ellipse center 40 pixels on the right of the origin and 20 pixels under the origin.
And of course the origin is the top right of your screen.

Now let’s say you want instead to draw the ellipse at the position (60, 50). Of course you can simply write:

ellipse(60, 50, 3, 3);

But in that case we are back at your issue to have to rewrite everything.

What if instead we move our origin point?
As you can see, that ellipse is 20 pixels more on the right and 30 pixels more down than the previous one (40 + 20 = 60 and 20 + 30 = 50).
So drawing the previous ellipse at the same “position” from the origin but moving the origin by (20, 30) would be a solution.

One way to achieve it is to write our own function

void drawEllipseFromOrigin(float x, float y) {
  ellipse(x + 60, y + 50, 3, 3);
}

With that function the following code would draw the 2 ellipses where we wanted them:

drawEllipseFromOrigin(0, 0) // The first ellipse at position (40, 20)
drawEllipseFromOrigin(20, 30) // The second ellipse at position (60, 50)

Now imagine that instead of having 1 ellipse you have several lines, and ellipses and arc like in your bird. Then every elements would be translated and you would just need to write in only once:

void setup() {
  size(500, 500);
  background(102, 178, 255); 
  scale(0.70);
  drawBird(0, 0);
  drawBird(400, 200);
}

void drawBird(float x, float y) {
  
  strokeWeight(1.5);
  fill(0, 153, 120);
  line(x + 50, y + 381, x + 300, y + 381);
  
  /*Right Leg*/
  line(x + 150, y + 220, x + 190, y + 300);
  line(x + 190, y + 300, x + 170, y + 380);
  arc(x + 176, y + 380, 20, 18, PI, TWO_PI, CLOSE);

  fill(250, 200, 100);

  /*body and head*/
  arc(x + 140, y + 180, 150, 150, 0, PI, CLOSE);
  arc(x + 220, y + 180, 50, 50, 0, 2*PI, CLOSE);

  /*left Leg*/
  fill(0, 153, 120);
  line(x + 120, y + 220, x + 150, y + 300);
  line(x + 150, y + 300, x + 110, y + 380);
  arc(x + 118, y + 380, 20, 18, PI, TWO_PI, CLOSE);

  /*eye*/
  fill(255);
  ellipse(x + 225, y + 175, 20, 20);
  fill(0, 0, 153);
  ellipse(x + 227, y + 174, 10, 10);
  fill(255);
  ellipse(x + 229, y + 175, 5, 5);

  /*Lashes*/
  fill(1);
  strokeWeight(2);
  line(x + 220, y + 165, x + 218, y + 160);
  line(x + 226, y + 165, x + 226, y + 158);
  line(x + 232, y + 166, x + 235, y + 162);

  /*Beak*/
  triangle(x + 236, y + 190, x + 232, y + 200, x + 247, y + 200);

  /*Antena*/
  noFill();
  strokeWeight(1);
  arc(x + 258, y + 148, 70, 85, 2.95, TWO_PI);
  arc(x + 288, y + 146, 10, 14, 0, TWO_PI);

  /*Tail*/
  strokeWeight(1);
  fill(255, 153, 153);
  triangle(x + 6, y + 180, x + 60, y + 120, x + 70, y + 180);
  fill(100, 180, 100);
  triangle(x + 12, y + 178, x + 58, y + 126, x + 68, y + 180);
  fill(0, 204, 204);
  triangle(x + 18, y + 176, x + 56, y + 132, x + 68, y + 180);
  fill(250, 200, 100);
  triangle(x + 24, y + 174, x + 54, y + 138, x + 70, y + 180);

  /*wings*/
  strokeWeight(1.5);
  fill(255, 170, 51);
  arc(x + 150, y + 190, 80, 70, 0, PI, CLOSE);
  strokeWeight(2);
  line(x + 126, y + 216, x + 134, y + 210);
  line(x + 144, y + 223, x + 146, y + 212);
  line(x + 164, y + 222, x + 156, y + 212);
}

Now this works but as you can see, there is a lot of x + and y +: it is easy to make a mistake, forget one etc. and it is not easy to read.

To simplify our life, we can use, as you said the translate() function. The idea is exactly the same as what we did (moving the origin point) but instead of adding manually the x + and y +, it does it automatically for us:

void setup() {
  size(500, 500);
  background(102, 178, 255); 
  scale(0.70);
  drawBird(0, 0);
  drawBird(400, 200);
}

void drawBird(float x, float y) {
  pushMatrix();
  translate(x, y);
  
  strokeWeight(1.5);
  fill(0, 153, 120);
  line( 50, 381, 300, 381);

  /*Right Leg*/
  line( 150, 220, 190, 300);
  line( 190, 300, 170, 380);
  arc( 176, 380, 20, 18, PI, TWO_PI, CLOSE);

  fill(250, 200, 100);

  /*body and head*/
  arc( 140, 180, 150, 150, 0, PI, CLOSE);
  arc( 220, 180, 50, 50, 0, 2*PI, CLOSE);

  /*left Leg*/
  fill(0, 153, 120);
  line( 120, 220, 150, 300);
  line( 150, 300, 110, 380);
  arc( 118, 380, 20, 18, PI, TWO_PI, CLOSE);

  /*eye*/
  fill(255);
  ellipse( 225, 175, 20, 20);
  fill(0, 0, 153);
  ellipse( 227, 174, 10, 10);
  fill(255);
  ellipse( 229, 175, 5, 5);

  /*Lashes*/
  fill(1);
  strokeWeight(2);
  line( 220, 165, 218, 160);
  line( 226, 165, 226, 158);
  line( 232, 166, 235, 162);

  /*Beak*/
  triangle( 236, 190, 232, 200, 247, 200);

  /*Antena*/
  noFill();
  strokeWeight(1);
  arc( 258, 148, 70, 85, 2.95, TWO_PI);
  arc( 288, 146, 10, 14, 0, TWO_PI);

  /*Tail*/
  strokeWeight(1);
  fill(255, 153, 153);
  triangle( 6, 180, 60, 120, 70, 180);
  fill(100, 180, 100);
  triangle( 12, 178, 58, 126, 68, 180);
  fill(0, 204, 204);
  triangle( 18, 176, 56, 132, 68, 180);
  fill(250, 200, 100);
  triangle( 24, 174, 54, 138, 70, 180);

  /*wings*/
  strokeWeight(1.5);
  fill(255, 170, 51);
  arc( 150, 190, 80, 70, 0, PI, CLOSE);
  strokeWeight(2);
  line( 126, 216, 134, 210);
  line( 144, 223, 146, 212);
  line( 164, 222, 156, 212);
  
  popMatrix();
}

If you want more info about the translate() function, I advise you to go read this post where I explain it a bit more in depth:

3 Likes

ahhh this is amazing! thank you for explaining it so well and so in detail!
I’m going to try it out and see how it goes! I’ll also read up on the link you sent! :blush:

I’m hoping to eventually have my bird fly across the screen with its wing flapping, hopefully it goes well!

1 Like

Happy to help. Good luck with that =)

hey again @jb4x, sorry to bother you, but the flying thing is not working out lol so I’m trying to have my bird fly across the screen with its wings flapping, but I cant seem to figure it out.
first I created the two different characters (one with the wings up and the other with the wings down) so I could combine both the create the illusion.

void setup() {
  size(500, 500);
  background(102, 178, 255); 
  scale(0.70);
  
  
  drawBird(0, 0);
  drawBird(400, 0);
}

void drawBird(float x, float y) {
  pushMatrix();
  translate(x, y);
  
  strokeWeight(1.5);
  fill(0, 153, 120);
  

  /*Right Leg*/
  line( 150, 220, 190, 300);
  line( 190, 300, 170, 380);
  arc( 176, 380, 20, 18, PI, TWO_PI, CLOSE);

  fill(250, 200, 100);

  /*body and head*/
  arc( 140, 180, 150, 150, 0, PI, CLOSE);
  arc( 220, 180, 50, 50, 0, 2*PI, CLOSE);

  /*left Leg*/
  fill(0, 153, 120);
  line( 120, 220, 150, 300);
  line( 150, 300, 110, 380);
  arc( 118, 380, 20, 18, PI, TWO_PI, CLOSE);

  /*eye*/
  fill(255);
  ellipse( 225, 175, 20, 20);
  fill(0, 0, 153);
  ellipse( 227, 174, 10, 10);
  fill(255);
  ellipse( 229, 175, 5, 5);

  /*Lashes*/
  fill(1);
  strokeWeight(2);
  line( 220, 165, 218, 160);
  line( 226, 165, 226, 158);
  line( 232, 166, 235, 162);

  /*Beak*/
  triangle( 236, 190, 232, 200, 247, 200);

  /*Antena*/
  noFill();
  strokeWeight(1);
  arc( 258, 148, 70, 85, 2.95, TWO_PI);
  arc( 288, 146, 10, 14, 0, TWO_PI);

  /*Tail*/
  strokeWeight(1);
  fill(255, 153, 153);
  triangle( 0, 180, 62, 112, 70, 180);
  fill(100, 180, 100);
  triangle( 10, 178, 58, 122, 68, 180);
  fill(0, 204, 204);
  triangle( 18, 176, 56, 132, 68, 180);
  fill(255, 170, 51);
  triangle( 28, 174, 54, 142, 70, 180);

  popMatrix();
  
  /*wing1*/
  strokeWeight(1.5);
  fill(255, 170, 51);
  arc( 150, 190, 80, 70, 0, PI, CLOSE);
  strokeWeight(2);
  line( 126, 216, 134, 210);
  line( 144, 223, 146, 212);
  line( 164, 222, 156, 212);
  
  /*wing2*/
  strokeWeight(1.5);
  fill(255, 170, 51);
  arc( 550, 190, 80, 70, PI,TWO_PI,CLOSE);
  strokeWeight(2);
  line( 558, 170, 568, 160);
  line( 548, 170, 550, 156);
  line( 540, 170, 532, 158);
}

with this I cant figure out how to add movement, and I keep getting error messages.

so next I just kept the one bird to see if I can get it to move forward, and it worked, but it’s leaving this trail and it’s not going all the way through.

int i = 0;

void setup() {
  size(500, 500);
  background(102, 178, 255); 

}

  void draw() {
    
    //line (i,0,i,100);
  /*Right Leg*/
  line( 150+i, 220, 190+i, 300);
  line( 190+i, 300, 170+i, 380);
  arc( 176+i, 380, 20, 18, PI, TWO_PI, CLOSE);

  fill(250, 200, 100);

  /*body and head*/
  arc( 140+i, 180, 150, 150, 0, PI, CLOSE);
  arc( 220+i, 180, 50, 50, 0, 2*PI, CLOSE);

  /*left Leg*/
  fill(0, 153, 120);
  line( 120+i, 220, 150+i, 300);
  line( 150+i, 300, 110+i, 380);
  arc( 118+i, 380, 20, 18, PI, TWO_PI, CLOSE);

  /*eye*/
  fill(255);
  ellipse( 225+i, 175, 20, 20);
  fill(0, 0, 153);
  ellipse( 227+i, 174, 10, 10);
  fill(255);
  ellipse( 229+i, 175, 5, 5);

  /*Lashes*/
  fill(1);
  strokeWeight(2);
  line( 220+i, 165, 218+i, 160);
  line( 226+i, 165, 226+i, 158);
  line( 232+i, 166, 235+i, 162);

  /*Beak*/
  triangle( 236+i, 190, 232+i, 200, 247+i, 200);

  /*Antena*/
  noFill();
  strokeWeight(1);
  arc( 258+i, 148, 70, 85, 2.95, TWO_PI);
  arc( 288+i, 146, 10, 14, 0, TWO_PI);
  
   /*wing*/
  strokeWeight(1.5);
  fill(255, 170, 51);
  arc( 150+i, 190, 80, 70, 0, PI, CLOSE);
  strokeWeight(2);
  line( 126+i, 216, 134+i, 210);
  line( 144+i, 223, 146+i, 212);
  line( 164+i, 222, 156+i, 212);

  /*Tail*/
  strokeWeight(1);
  fill(255, 153, 153);
  triangle( 0+i, 180, 62+i, 112, 70+i, 180);
  fill(100, 180, 100);
  triangle( 10+i, 178, 58+i, 122, 68+i, 180);
  fill(0, 204, 204);
  triangle( 18+i, 176, 56+i, 132, 68+i, 180);
  fill(255, 170, 51);
  triangle( 28+i, 174, 54+i, 142, 70+i, 180);

  strokeWeight(1.5);
  fill(0, 153, 120);

  /*Right Leg*/
  line( 150+i, 220, 190+i, 300);
  line( 190+i, 300, 170+i, 380);
  arc( 176+i, 380, 20, 18, PI, TWO_PI, CLOSE);

  fill(250, 200, 100);

  /*body and head*/
  arc( 140+i, 180, 150, 150, 0, PI, CLOSE);
  arc( 220+i, 180, 50, 50, 0, 2*PI, CLOSE);

  /*left Leg*/
  fill(0, 153, 120);
  line( 120+i, 220, 150+i, 300);
  line( 150+i, 300, 110+i, 380);
  arc( 118+i, 380, 20, 18, PI, TWO_PI, CLOSE);

  /*eye*/
  fill(255);
  ellipse( 225+i, 175, 20, 20);
  fill(0, 0, 153);
  ellipse( 227+i, 174, 10, 10);
  fill(255);
  ellipse( 229+i, 175, 5, 5);

  /*Lashes*/
  fill(1);
  strokeWeight(2);
  line( 220+i, 165, 218+i, 160);
  line( 226+i, 165, 226+i, 158);
  line( 232+i, 166, 235+i, 162);

  /*Beak*/
  triangle( 236+i, 190, 232+i, 200, 247+i, 200);

  /*Antena*/
  noFill();
  strokeWeight(1);
  arc( 258+i, 148, 70, 85, 2.95, TWO_PI);
  arc( 288+i, 146, 10, 14, 0, TWO_PI);
  
   /*wing*/
  strokeWeight(1.5);
  fill(255, 170, 51);
  arc( 150+i, 190, 80, 70, 0, PI, CLOSE);
  strokeWeight(2);
  line( 126+i, 216, 134+i, 210);
  line( 144+i, 223, 146+i, 212);
  line( 164+i, 222, 156+i, 212);


//rect(i,50,200,50);
i=(i+1)%300;
  }

I just started learning so my processing knowledge is pretty minimal, and I can’t seem to find the solutions in the forums, so if you have some pointers, please share. what am I doing wrong? lol

First, the reason you are seeing a trail of bird is because the draw function is called over and over and draw everything on top of what already exists.
To avoid this, you need to first “erase” everything you drawn before using background()

See how the program behaves with and without the background() in draw():

void setup() {
  size(500, 500);
  background(20);
  noFill();
  strokeWeight(2);
  stroke(230);
  frameRate(20);
}

void draw() {
  //background(20);
  ellipse(random(width), random(height), 20, 20);
}

Now to come back to your initial issue on how to make the wing flap.
I think you need to start way smaller than what you have currently.
That’s how you tackle things you don’t know. You start small and then you build up on what you have learned.
Currently, every time you want to try something, you have to modify something like 70-80 lines of code. I would abandoned quite fast…

Focus on the wing. Only this. Let’s start to draw one and make it move to the right (you already know how to do that):

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  arc(150 + dx, 190, 80, 70, 0, PI, CLOSE);
  dx += 1;
}

Instead of using a variable called i I used one called dx to better represent what it does: the x offset to move the wing by.

Now, how to animate it?
One idea could be to make it smaller on the y axis and then back to its normal size again and so on. When you have periodic motion like those, it is often a good idea to use a cos or a sin function. It goes from -1 to 1 to -1 and so on.
So if we multiply the vertical dimension of the arc by sin(dx), it should open and close the wing:

  arc(150 + dx, 190, 80, sin(dx) * 70, 0, PI, CLOSE);

You can try this code but you will see 2 things:

  • It is going way to fast
  • sometimes the wings disappeared

For the first point, we can simply multiply dx by a small quantity so it will change by a smaller amount and thus making it slower.
For the second point, the reason is that the arc function doesn’t like negative values. Since sin goes from -1 to 1, we can add 1 (we can actually add a bit more than 1 to avoid 0 values) so it would go from 0 to 2 and then divide by 2 to go from 0 to 1.

The green curve is sin(x), the blue is sin(0.2x) and the red is (1 + sin(0.2x))/2

Which gives us:

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  arc(150 + dx, 190, 80, 0.5 * (1.01 + sin(0.2 * dx)) * 70, 0, PI, CLOSE);
  dx += 1;
}

But you also add some details on there. So let’s add them:

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  arc(150 + dx, 190, 80, 0.5 * (1.01 + sin(0.2 * dx)) * 70, 0, PI, CLOSE);
  line(126 + dx, 216, 134 + dx, 210);
  line(144 + dx, 223, 146 + dx, 212);
  line(164 + dx, 222, 156 + dx, 212);
  dx += 1;
}

They are there, but they don’t move with the wing… In addition it seems a bit tricky to make them move the same way…

There must be an easier solution! And there is! =)
Remember translate()? Turns out there’s also a scale() function.
Ok let’s start to do the same flappy thingy just with the wing but using the scale() function:

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  
  pushMatrix();
  scale(1, 0.5 * (1.01 + sin(0.2 * dx)));
  arc(150 + dx, 190, 80, 70, 0, PI, CLOSE);
  popMatrix();
  
  dx += 1;
}

It almost work but there is something wrong with it. It seems to shrink toward the top of the screen. The reason for that is that it scale the space from an origin point which is (0, 0), the top left corner of the screen. Since we are scaling only the y direction, it scales the shape from the top of the screen.

Ok so how we solve that?
Well we could draw our shape so the top correspond to the top of the screen:

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  
  pushMatrix();
  scale(1, 0.5 * (1.01 + sin(0.2 * dx)));
  arc(150 + dx, 0, 80, 70, 0, PI, CLOSE);
  popMatrix();
  
  dx += 1;
}

Ok, it seems to work fine now, but I really want it down!
Well… that’s what translate() is there for. We can simply draw our shape on the top of the screen, scale it and then translate it where we want it to be!
Easy enough, let’s code it:

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  
  pushMatrix();
  translate(0, 190);
  scale(1, 0.5 * (1.01 + sin(0.2 * dx)));
  arc(150 + dx, 0, 80, 70, 0, PI, CLOSE);
  popMatrix();
  
  dx += 1;
}

Yeah! it works! =)

Ok, now let’s put back the details. But be careful, now the shape is drawn at the top, not in the middle of the screen. So we need to adjust the y components of the details:

float dx;

void setup() {
  size(500, 500);
  strokeWeight(2);
  dx = 0;
}

void draw() {
  background(102, 178, 255); 
  fill(255, 170, 51);
  
  pushMatrix();
  translate(0, 190);
  scale(1, 0.5 * (1.01 + sin(0.2 * dx)));
  arc(150 + dx, 0, 80, 70, 0, PI, CLOSE);
  line(126 + dx, 26, 134 + dx, 20);
  line(144 + dx, 33, 146 + dx, 22);
  line(164 + dx, 32, 156 + dx, 22);
  popMatrix();
  
  dx += 1;
}

As you can see, now everything is working properly!

I think this is a lot to process so take your time and go step by step.
It is now up to you to try combining this with your own code.
Good luck!

1 Like

Wow, this is amazing!
firstly I agree with you about taking it step by step and not trying to take on too much! I haven’t quite studied a lot of the functions so it all sounds a bit foreign, but your guidance is so clear! I’ll definitely be referring back to these notes as I make progress!

Secondly, for the purpose of this project, I decided to stick with the first issue, which is to have the bird move across the screen. It all worked out and I was even able to add other moving figures like a cloud! (small steps hahaha) I really appreciate all your help!

Cheers!

1 Like