Multiple transformations

Hi! I’m pretty new to coding, and am having an issue with the transformations in my code. My program is quite long so I’ve just used a rectangle as an example here. I’m trying to make the object spiral in a small circle as it shrinks down (think whirlpool/flushing motion), but I just can’t make it work. I thought my order of operations was the issue but it seems not because I’ve tried a number of combinations.

float x = 50;
float y = 50;
float rad = 0;
float move=1;
float big=1

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

void draw () {
background (150);
rect (x, y, 50, 50);
x = x+move;
y = y+move;

if (x > 200) {
move = 0.35;
pushMatrix();
translate(200, 200);
rotate (rad);
scale (big);
big = big *.1
rad = rad + 1;
popMatrix();
}
}

What am I doing wrong???

There are several things wrong.

  1. the transformations have no effect because there are no drawing commands between the push and popMatrix statements
  2. you use x and y to position the rectangle but if you use translate(200,200) then the drawing will be at 200+x, 200+y
  3. rad = rad + 1 is wrong because rotations and angles in computing are measuered in radians and this rotates the box about 53.7 degrees per frame and at 60 frames per second
  4. big = big * .1 is wrong because it is too fast after three frames (~0.05 seconds) the box will be 0.05 pixels wide.
  5. if you want the box to rotate about its centre then you need to use rectMode(CENTER)

I have corrected your code see below

float x = 50;
float y = 50;
float rad = 0;
float move=1;
float big=1;

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

void draw () {
  background (150);
  if (x > 200) {
    move = 0.35;
    pushMatrix();
    translate(200, 200);
    rotate (rad);
    scale (big);
    big = big *.99;
    rad = rad + 0.11;
    rect (0, 0, 50, 50);
    popMatrix();
  } else {
    x = x+move;
    y = y+move;
    rect (x, y, 50, 50);
  }
}

BTW welcome to the forum :grinning_face_with_smiling_eyes:

2 Likes

Thanks a million @quark! I just have a follow-up question then… I’ve been using this (array)object for other functions and this movement is just part of a string of actions… I tried to call my first class function (the one that draws the object) as my drawing command but then it gave me two objects. One of them stayed still while the other performed the transformations. I then tried adding another object from my array but it sort of gives me the same issue.
Does that makes sense? Sorry, I would show you the code but I don’t know how to isolate my problem and it has two classes and hundreds of lines (although I’m sure it could be compressed into half as many if I had a better grasp of what I was doing).
If that doesn’t make sense, thank you for your help - it got me a lot farther than I was previously!

OK there is a lot of ground to cover here and I suspect looking at your code wouldn’t help. Once you get into ‘hundreds of lines of code’ it can become a nightmare finding and correcting errors because we can’t keep all that code in our head. One solution is to use object orientation programming and create classes making it easier to understand and implement you code.

The are a lot of info about using OOP on the net and Daniel Shiffman has done some good videos using OOP which I suggest you look at.

It seems to me that what you are trying to do is animate objects independently so I have created a sketch that has a single class called Ant and in that class we have all the attributes (fields / variables) that describe the ant i.e. position, size, speed and direction of travel. It also has methods (functions) to create an Ant object, update its position and to render it. When designing the class there are two principle two primary considerations

  1. A class should be autonomous: in other words the attribute values must only be changed inside the class using the methods inside the class. For instance to change the ants position we can use the setPos method like this
ant.setPos(20,30); // correct way to change ant's position

we should not access the fields directly, so although this does the same

ant.x = 20; // bad, bad, bad :-(
ant.y = 30;

we must not do this. If we find that some fields appear to have unusual values then we only need to look at the class code because the fields are not being modified anywhere else directly.

2: Separation of responsibilities: each method should have a separate responsibility. So in this class I have separated the code that updates the ants position / size from the code that renders the ant.

Any way I hope this gives an insight into using OOP with animation, if you have questions about the code please ask.

/*
Demonstration of how to use OOP when creating animated objects.

Click anywhere to create a new ant.
*/
ArrayList<Ant> ants = new ArrayList<Ant>();

void setup(){
  size(600,400);
  ants.add(new Ant(width/2, height/2));
}

void draw(){
  background(200,255,200);
  for(Ant a : ants) a.update();
  for(Ant a : ants) a.render();
}

void mouseClicked(){
  ants.add(new Ant(mouseX, mouseY));
}

class Ant {
  // Attributes or Fields
  float x = 0, y = 0;
  float big = 0.5;
  float speed = 0.5, heading;
  int col;

  Ant(float x, float y) {
    this.x = x;
    this.y = y;
    heading = random(TWO_PI);
    speed = random(1, 2);
    col = color(random(128, 240), random(128, 240), random(128, 240));
  }

  void setPos(float x, float y){
    this.x = x;
    this.y = y;
  }
  
  void update() {
    big *= 1.0005; // grow ant
    x += speed * cos(heading); // Move ant
    y += speed * sin(heading);
    x = (x + width) % width; // Keep inside visual area
    y = (y + height) % height;
  }

  void render() {
    pushMatrix();
    translate(x, y);
    rotate(heading);
    scale(big);
    stroke(0);
    strokeWeight(1.5);
    fill(col);
    line(-10, 0, -30, -20); // Back legs
    line(-10, 0, -30, 20);
    line(-4, 0, 6, -20); // Front legs
    line(-4, 0, 6, 20);
    ellipse(-10, 0, 34, 30); // Body
    ellipse(10, 0, 15, 15);  // Head
    popMatrix();
  }
}
1 Like