1

I'm having this Processing issue where I'm trying to make my ariplane do a 180 turn-over right before it gets to the end of the drawing... It looks fairly simple but I just can't get it to work. Help would be much appreciated.

As I have other shapes (not showned in code below) I finally managed to use pushMatrix(); & popMatrix(); to only impact the airplane. Although rotating it brings me sideways.

int globalX = 0;
int globalY = 600;
int vitesse = 3;

void setup() {
  size(800, 600);
  rectMode(CENTER);
}

void draw() {
  background(255);

  pushMatrix();
  bouger();
  tourner();
  dessinerAvion(globalX, globalY);
  popMatrix();
}

void bouger() {
  // Change the x location by vitesse
  //globalX = globalX + vitesse;
  globalY = globalY - vitesse;
}

void tourner() {
  if (globalY < 0) {
    for (int i = 10; i > 0; i = i-1) {
      rotate(PI/3.0);
      //rotate(radians(10));
    }
    for (int i = 10; i > 0; i = i-1) {
      rotate(PI/3.0);
      //rotate(radians(10));
      vitesse = vitesse * -1;
    }
  }
}

void dessinerAvion(int x, int y) {
  rectMode(CENTER);

  // corps
  fill(156,21,21);
  ellipse(x + 250, y + 100, 50, 100);
  rect(x + 250, y + 200, 50, 250,60);

  // reacteur gauche
  rect(x + 125, y + 225, 25, 50, 75);
  // reacteur droite
  rect(x + 375, y + 225, 25, 50, 75);

  fill(210,14,14);
  // aile gauche
  quad(x + 75, y + 275, x + 75, y + 250, x + 225, y + 175, x + 225, y + 250);
  // aile droite
  quad(x + 425, y + 275, x + 425, y + 250, x + 275, y + 175, x + 275, y + 250);
  
  fill(112,14,14);
  // ailette gauche
  triangle(x + 225, y + 290, x + 226, y + 310, x + 175, y + 310);
  // ailette droites
  triangle(x + 275, y + 290, x + 274, y + 310, x + 325, y + 310);
  // aile verticale arrière
  triangle(x + 250, y + 285, x + 248, y + 310, x + 252, y + 310);
}

1 Answers1

2

Matrix are weird animals. They let you take a bunch of shapes and translate, rotate or scale them all at once, but only through playing with the coordinate system, which implies that the way you draw the shapes that you'll process will have a huge impact on how they react.

This is your plane on a neutral grid (by which I mean that globalX and globalY are 0):

Plane on a grid!

Every square on this grid has a 20 pixels side. As you can see, your plane is far from the [0, 0] point, which is the start of the coordinate system it's drawn into. Also, when you modify it's coordinates, you're doing it through modifying it's coordinates, as we can see on this line of code:

void dessinerAvion(int x, int y)

The problem here is that applying a geometric transformation to an object with these coordinates can be counterintuitive. To simplify the matter, imagine the whole coordinate system that the plane use as if it was an image, like a png. The top left of the image is the [0, 0] point. When you change the plane's y coordinates for a higher number, your png image gets taller. If you change the x coordinate of the plane for a bigger number, the png image gets wider. You get the general idea.

When you apply a rotation to the plane, it's the entire 'png image', the entire coordinate system, that gets rotated. It's the same for any other transformation, too. Now, experimentally, look at what happens if I do this:

for(float i=0; i<20; i+=1) {
  pushMatrix();
  rotate(PI/i);
  dessinerAvion(0, 0);
  popMatrix();
}

Airplane rotating!

As you can see, the plane isn't rotating on itself. It's the whole coordinate system that rotates, pivoting on the [0, 0] point, and it brings the plane with itself. That's the deal with matrix: they keep a lot of geometry waaay more simple, but you have to work accordingly.

Which brings me back to the previous point: you're updating the coordinates where you draw the plane. Then you use a matrix. Your updated plane will rotate in an unexpected way because you apply 2 different logic to your transformations: on one hand you modify coordinates (which is fine), while on the other you apply a transformation on a matrix (which is fine too). The issue is to mix those without acknowledging their differences.

Honestly, unless you have a specific thing in mind, you shouldn't mix those to move a single object.

The obvious solution to the first part of this issue would be to translate the plane instead of moving it's coordinates:

void draw() {
  background(255);
  bouger(); // updating coordinates, this doesn't need to be in the matrix block

  pushMatrix();
  //tourner();
  translate(globalX, globalY);
  dessinerAvion(0, 0); // zero here as the translation is doing that part of the job now
  popMatrix();
}

Now you should see... well, you should see no difference at all. That's normal. The real difference is not in how the sketch appears, but how it's processed behind the scenes. Now your plane is a static object on which we apply geometric transformations.

Now to the other part of your problem: animating an object. Well, to be honest the animation part is quite easy, but there's a lot of work to do beforehand, more precisely to fix the plane's original coordinates so they are easier to manage. Let me explain:

If you look at the first image where I show the plane without any geometric transformation, you'll notice that the left wing starts at about ~75 pixels from the 0 point, and that the nose of the plane is ~45 pixels away from the 0 on the y axis. Currently, that's the rotation's anchor point. If you want to rotate the plane in a gracious manner, you'll have to fix this. There are many ways to proceed, follow me.

Take notes, because for some reason very few people will explain in simple words how to rotate on an anchor point using a matrix.

To rotate a shape on a specific anchor point, you have to proceed as follow:

  1. pushMatrix
  2. translate to the shape's destination
  3. rotate
  4. draw the shape using [0, 0] as it's anchor point
  5. popMatrix

So if you want to rotate your plane on itself, thus deciding on an angle then moving it to it's destination before you draw the plane, you act as follow:

void draw() {
  background(255);

  // grid
  stroke(0);
  for (int i=0; i<height; i+=20) {
    line(0, i, width, i);
  }
  for (int i=0; i<width; i+=20) {
    line(i, 0, i, height);
  }

  pushMatrix();
  translate(200, 200); // for the demonstration only
  globalAngle--;
  rotate(radians(globalAngle)); // I'm lazy and I don't want to do this in radians so I use degrees and convert them
  dessinerAvion(-250, -200); // the center of the plane is the [250, 200] point. That's my anchor point.
  popMatrix();
}

Which gives us this result:

Rotating plane

Now, using the first translate, you can draw the plane wherever you want, and you can use the rotation to make it face any direction you want it to face.

Using these, it would be real easy to make the plane cross the screen back and forth:

void draw() {
  background(255);
  drawGrid();

  // implementing the "u-turn"
  globalY -= vitesse;
  if (globalY < -200) {
    globalX -= 200;
    globalAngle = 180;
    vitesse = -vitesse;
  }

  // drawing the sketch
  pushMatrix();
  translate(globalX, globalY);
  rotate(radians(globalAngle));
  dessinerAvion(-250, -200);
  popMatrix();
}

Out-of-screen u-turn

Now, if we want to watch the plane turn, we have several options. You can rotate the plane frame by frame while plotting it's course. That's a good option. But I'm lazy, as previously stated, so instead I'll move the anchor point somewhere left of the plane and use it to rotate around it in a gracious manner:

void draw() {
  background(255);
  drawGrid();

  pushMatrix();
  translate(globalX, globalY);
  tourner();
  bouger();
  dessinerAvion(0, -200); // this coordinate sets my anchor point
  popMatrix();
}

void tourner() {
  if (globalY < 300) { // starting the u-turn
    vitesse = 0; // The plane won't move while it's rotating... except for the rotation itself
    globalAngle--; // rotating counterclockwise 1 degree per frame
    if (globalAngle<-180) { // u-turn completed
      globalAngle = -180;
      vitesse = -3;
    }
  }

  rotate(radians(globalAngle));
}

Visible u-turn

I think that does it. I hope this helps. I'll lurk around in case you have questions about this answer.

Have fun!

laancelot
  • 3,138
  • 2
  • 14
  • 21
  • First off... many many thnx for your reply. For someone that lazy I must say you're pretty active when replying. I will have to re-read your post a few more times as it doesn't yet work as expected. Starting with the hiden u-turn the plan appears already turned 180 degree and then things doesn't really fall into place. But your explanations are so well made that I'll revisit once again as maybie I did something wrong somewhre. – Vincent Fortier Nov 29 '22 at 12:08
  • 1
    I eneded-up having it all to work, it was both my anchor point which was wrong along with my starting angle set at 180 degree. Once set properly all the examples flew in just as explained.The only remaining thing not working is, when doing a u-turn within the frame, the airplane stops after the u-turn instead of continuing down as expected. Further playing with it it became obvious in the code that setting `vitesse = -vitesse` is wrong as it was previously set to `0`. Changing that to `-3` solved it. Again, many many thnx! – Vincent Fortier Nov 29 '22 at 12:25
  • 1
    One last comment, drawing a point/circle on the "anchor" point would have further helped in identifying where it actually is and how this works. Again, thnx :) – Vincent Fortier Nov 29 '22 at 12:49
  • Thanks for your comments, I'm taking notes! – laancelot Nov 29 '22 at 13:19