In order to accomplish this you have
to model what you want to accomplish.
You know that your sketch runs at (let's say) 30 frames per second. So you know that your void draw() will be runnign 30 frames per second. So
Again it's easier to represnt things mechanically.
The confusion you see is because what want to see finally on the screen is the RENDERING of your model. But not your model yourself.
For example if you think of bouncing ball sketch, then what you see is a rendring of a bouncing ball. However what happens.
- BouncingBallModel model = new BouncingBall(width, height);
- /**
- * I do not like using draw() method directly, because it's name suggests
- * that it's drawing what happens every step. Which is not true.
- * On every step there're two actions which are happening:
- model_update();
- &
- model_render();
- * If you think of the bouncing ball as an example, then in model_update() we will update the coordinates
- * of the ball.
- * And in model_render() we will render the ball at the coordinates calculated in the previous step.
- This is why I just call them in draw, and then continue thinking abstractly in terms of model&rendering of the model.
- */
- void draw(){
- model_update();
- model_render();
- }
- /**
- * Here we will execute code which
- * will update THE MODEL which we see on the screen.
- */
- void model_update(){
- }
- /**
- * Here we will execute code, which will
- * simply RENDER the already updated earlier model, without modifying it.
- */
- void model_render(){
- }
So again, if we want to have complete example with bouncing ball, then it may look like this:
- void setup(){
- size(400,300);
- background(0);
- noStroke();
- ballModel = new BouncingBallModel(width, height); // here we initialize model which model coordinates of the ball bouncing in the rectangle of given width and height.
}
- BouncingBallModel ballModel; // this is just convenience class which you can copy/paste into separate tab.
- // we don't write code directly in draw(), but in mode_xxxx() methods,
- // but just because FOR HUMANS it's more convenient to think about what happens
- // as of two steps (update model and render model). For computer or Java it makes no difference
- // where we put the code.
- void draw(){
- model_update();
- model_render();
- }
- /**
- * Here we will execute code which
- * will update THE MODEL which we see on the screen.
- */
- void model_update(){
- ballModel.update(); // this is convenience method, which calculates next coordinate of the bouncing ball
- }
- /**
- * Here we will execute code, which will
- * simply RENDER the already updated earlier model, without modifying it.
- */
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
- background(0);
- fill(255);
- ellipse(ball_x, ball_y, 20,20);
- }
And the sketch would give you the following result:
This sketch is simple, but it's good for the illustration of the principle of separation of the model from rendering.
This separtion is really good, because now by modifying
only rendering part (model_render() method), we can get different effects. Let's say we change code of model_render() to this:
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
- // background(0);
- fill(255);
- rect(ball_x, ball_y, 20,20);
- }
Now we get a white square moving around and it's not erased eveyr frame, so it leaves trail.
We can even randomize the size of the square like this:
// code
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
- // background(0);
- fill(255);
- float rand_side_length = random(20, 40);
- rect(ball_x, ball_y, rand_side_length, rand_side_length);
- }
to get effect like this:
you can even make image fly around the screen just by modifying model_render():
- // just put image "apple2.png" into the data folder of your sketch.
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
- // background(0);
- PImage ballImage = loadImage("apple2.png"); // for simplicity of example, i load image every from from disk
- imageMode(CENTER);
- background(0);
- image(ballImage, ball_x, ball_y);
- }
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
- // background(0);
- PImage ballImage = loadImage("apple2.png");
- imageMode(CENTER);
- background(0);
- image(ballImage, ball_x, ball_y);
- }
Or we can fade the screen to get the trail of an image:
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
-
- // fade screen for nicer effect
- fill(0, 2);
- rect(0,0, width, height);
- PImage ballImage = loadImage("apple2.png");
- imageMode(CENTER);
-
- image(ballImage, ball_x, ball_y);
- }
So you can see, that just by playing with
model_render() you can achieve pretty good effects. However just modifying the renderer of the model has certain limitations.
Limitation 1:
What if you want your image to rotate?
if you want to rotate image by
random angle you can still use model_render() and perform it like this:
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
-
- // fade screen for nicer effect
- fill(0, 2);
- rect(0,0, width, height);
-
- PImage ballImage = loadImage("apple2.png");
- imageMode(CENTER);
- float randomRotationAngle = random(PI*2); // returns random angle from [0..PI*2]
-
- // this code just draws _rotated_ image at given coordinates.
- pushMatrix();
- translate(ball_x, ball_y);
- rotate(randomRotationAngle);
- image(ballImage, 0, 0);
- popMatrix();
- }
to get:
But what if you want SMOOTH ANGLE ROTATION??? What if you want the apple to rotate slowly and smoothly, but not sproadically like in sketch:
??
Then you run exactly into limitation of playing only with
model_render() . In order to smoothly change angle of the apple to rotate it, you need to store this angle somewhere... from the first glance you can do it this way:
float angleOfApple = 0;
void model_render(){
float ball_x = ballModel.getX();
float ball_y = ballModel.getY();
// fade screen for nicer effect
fill(0, 2);
rect(0,0, width, height);
PImage ballImage = loadImage("apple2.png");
imageMode(CENTER);
// float randomRotationAngle = random(PI*2); // returns random angle from [0..PI*2]
angleOfApple = angleOfApple + 0.1; // each step we turn 0.1 radians which is approx 6 degrees
// this code just draws _rotated_ image at given coordinates.
pushMatrix();
translate(ball_x, ball_y);
// rotate(randomRotationAngle);
rotate(angleOfApple);
image(ballImage, 0, 0);
popMatrix();
}
Now the sketch does what we wanted: allows ball to fly and change angle smootly around the screen, and it may seem that we have achieved success. But despite it's counter-intuitive: we
commited a huge failure. We didn't follow the principle of separation of
model update and
model rendering. And despite working now, it will lead to great confusion, diffuculty in modifying sketch and trying new things and thus limiting creativity.
The evil of this problem is that it's hard to notice for an untrained eye and "
sketch does what i want, right?". The problem is that now model_update() is not
just renders model but it actually "modifies" model. When we decided to introduce rotation angle (or chanching color or radius) of an object, it IS A CHANGE OF THE MODEL not of the rendering. As human you perceive what's happening on the screen as "objects flying around screen". Which is not completely true. From computer perspective what you see on the screen is a RENDERING of underlying MODEL. If you want a good visualization of what model is than maybe this is what could help:
In the model of "bouncingBall" all there is : just two coordinates X and Y [222.0, 172.0] which are changing to simulate flying and bouncing. When you make apple rotate, than visually for you "object of apple is rotating" but that's not how computer or processing sees it. For computer what happens is:
"the model of bouncing ball now includes one more parameter (
angle) which is changes overtime by small value to simulate rotation
So now if we "x-ray the model" it may look like the picture below. You can see that angle value is chaning by approx 0.1 radian each step.
Now you can also see that ANGLE BELONGS TO MODEL NOT THE RENDERER! And because of that it should not be modified inside of of model_render() method.
So what would be the right way to simulate rotation?
The right way is:
a) include angle inside of the model of the object
b) update the model only from model_update()
c) the method model_render() only fetches information from the model and creatively displays it, but doesn't modify it.
The proper code would be something like:
- void model_render(){
- float ball_x = ballModel.getX();
- float ball_y = ballModel.getY();
-
- // here we request the angle from the model. In model_render() we're only concerned
- // to fetch it and display (the model) and don't care how these things are calculated.
- float angleOfApple = ballModel.getAngle();
-
- // fade screen for nicer effect
- fill(0, 2);
- rect(0,0, width, height);
-
- PImage ballImage = loadImage("apple2.png");
- imageMode(CENTER);
- // this code just draws _rotated_ image at given coordinates.
- pushMatrix();
- translate(ball_x, ball_y);
- rotate(angleOfApple);
- image(ballImage, 0, 0);
- popMatrix();
- }
But enough of introduction, let's see HOW DOES THIS APPLY TO YOUR RECTANGLE DRAWING PROBLEM: