How to Draw a Cloud in Processing
Hi and welcome to stackoverflow. Your question has multiple questions in it:
What I am trying to make is 3 hot air balloons (at different positions), move from the bottom to the top and 3 clouds (at different positions) move from right to left.
I would also like the ellipse on the balloons change colors when you click them with the mouse.
In the future please stick to one question at a time (so it's easier for other people to search for in the future). It's also much easier to code anything when you break it down into steps:
- 3 hot air balloons at different positions
- move from the bottom to the top (and 3 clouds (at different positions) move from right to left.)
- when you click ballons with the mouse...
- ... balloons change colors
1. different positions Let's start with different positions: once this works for one, it should work for more. There are multiple ways to write this, however, since you mentioned you're new to programming let's keep this as basic as possible (although code won't be too elegant)
Looking at the setGradient()
function, you must already be somewhat familiar with defining and calling a function with arguments. You can apply the same logic to the balloon()
function: simply add x,y arguments so you can draw a balloon at a given position. Calling the same function with different coordinates should result in multiple balloons drawing with independent position. This means you will need x,y position variables for each balloon, but more on that later. One important note is that you currently are hard coding the coordinates for each shape of the balloon. To move something on screen, you need to translate it, which means adding or subtracting a value from it's current position. You could something like this:
void balloon(int x,int y) { fill(217, 105, 95); noStroke(); ellipse(x+95, y+100, 90, 90); stroke(242, 191, 128); line(x+59, y+127, x+130, y+127); line(x+59, y+127, x+80, y+170); line(x+130, y+127, x+109, y+170); beginShape(); noStroke(); fill(x+242, y+191, 128); triangle(x+80, y+170, x+95, y+170, x+88, y+183); fill(203, 140, 103); triangle(x+88, y+183, x+103, y+183, x+95, y+170); fill(191, 131, 96); triangle(x+95, y+170, x+103, y+183, x+110, y+170); fill(140, 55, 70); triangle(x+59, y+127, x+77, y+127, x+69, y+143); triangle(x+85, y+127, x+95, y+143, x+105, y+127); triangle(x+113, y+127, x+121, y+143, x+130, y+127); endShape(); }
then calling balloon(mouseX,mouseY);
in draw()
would make the balloon follow the mouse.
That's one way to do it, but obviously it gets pretty tedious pretty fast. What if you could move everything that being drawn in one call ? You can, using translate(), but there's a catch: it will move everything else you draw after calling it. This means the second balloon's position would be relative to the 1st balloon's position and so on. To make it independent, you could translate()
back from the 1st ballon's position to 0,0, then translate()
again to the 2nd ballon's position, but again, this will get tedious. Again, there's something in Processing to help with that: pushMatrix()/popMatrix()
. These functions allow you to nest a coordinate system inside Processing's main one. Any transformation (translation,rotation,scale) you do within pushMatrix()/popMatrix()
calls will be independent of the rest of the program. Imagine nesting/grouping shapes in an editor like Illustrator/Photoshop so you can manipulate them independently or together. This a very loose definition. Be sure to check out the 2D Transformations Processing tutorial. It covers this in detail, including nesting shapes and making robots :)
Here's how the same functionality from above could be achieved using pushMatrix()/popMatrix()
and translate()
:
// hot air balloon shape void balloon(int x,int y) { //isolate coordinate system pushMatrix(); //translate just this baloon translate(x,y); fill(217, 105, 95); noStroke(); ellipse(95, 100, 90, 90); stroke(242, 191, 128); line(59, 127, 130, 127); line(59, 127, 80, 170); line(130, 127, 109, 170); beginShape(); noStroke(); fill(242, 191, 128); triangle(80, 170, 95, 170, 88, 183); fill(203, 140, 103); triangle(88, 183, 103, 183, 95, 170); fill(191, 131, 96); triangle(95, 170, 103, 183, 110, 170); fill(140, 55, 70); triangle(59, 127, 77, 127, 69, 143); triangle(85, 127, 95, 143, 105, 127); triangle(113, 127, 121, 143, 130, 127); endShape(); popMatrix(); //pop back to the Processing's original coordinate system }
Notice that there's an offset between the cursor and balloon. That is because all the shapes are drawn to the right and lower (larger x,y values). Imagine the cursor as the balloon's "anchor point". The coordinates of the drawn shapes need to be offset towards a different position. Given that you want to click a balloon's circle, you could use the circle's center as the ballon's "anchor"/origin:
void balloon(float x,float y) { //isolate coordinate system pushMatrix(); //translate just this baloon translate(x,y); fill(217, 105, 95); noStroke(); ellipse(0, 0, 90, 90); stroke(242, 191, 128); line(59-95, 27, 130-95, 27); line(59-95, 27, 80-95, 70); line(130-95, 27, 109-95, 70); beginShape(); noStroke(); fill(242, 191, 128); triangle(80-95, 70, 0, 70, 88-95, 83); fill(203, 140, 103); triangle(88-95, 83, 103-95, 83, 0, 70); fill(191, 131, 96); triangle(0, 70, 103-95, 83, 110-95, 70); fill(140, 55, 70); triangle(59-95, 27, 77-95, 27, 69-95, 43); triangle(85-95, 27, 0, 43, 105-95, 27); triangle(113-95, 27, 121-95, 43, 130-95, 27); endShape(); popMatrix(); //pop back to the Processing's original coordinate system }
Notice how the x,y coordinates have values subtracted (based on the old ellipse's location).
Now you should be able to easily draw 3 balloons at 3 different positions. All you have to do is setup variables for different coordinates(for each balloon) and call the balloon function 3 times:
float ballon1X; float ballon1Y; float ballon2X; float ballon2Y; float ballon3X; float ballon3Y; void setup() { size(500, 500); //define colors for gradient background b1 = color(139, 211, 242); b2 = color(212, 221, 198); // noLoop(); //randomize X positions ballon1X = random(100,width-100); ballon2X = random(100,width-100); ballon3X = random(100,width-100); //randomize y positions, keeping in mind they rise from the bottom ballon1Y = random(height/2); ballon2Y = random(height/2); ballon3Y = random(height/2); } int Y_AXIS = 1; int X_AXIS = 2; color b1, b2; void draw() { //gradient background setGradient(0, 0, 500, 500, b1, b2, Y_AXIS); setGradient(0, 500, 540, 500, b2, b1, X_AXIS); balloon(ballon1X,ballon1Y); balloon(ballon2X,ballon2Y); balloon(ballon3X,ballon3Y); cloud(); } //cloud shape void cloud() { beginShape(); noStroke(); fill(204, 206, 207); triangle(180, 50, 195, 50, 188, 35); triangle(195, 50, 188, 65, 202, 65); fill(189, 192, 193); triangle(188, 35, 195, 50, 202, 35); triangle(180, 50, 195, 50, 188, 65); triangle(202, 65, 195, 50, 209, 50); fill(255); triangle(195, 50, 209, 50, 202, 35); triangle(215, 35, 209, 50, 222, 50); triangle(215, 65, 202, 65, 209, 50); fill(224, 231, 234); triangle(209, 50, 202, 35, 215, 35); triangle(209, 50, 215, 65, 222, 50); endShape(); } // hot air balloon shape void balloon(float x,float y) { //isolate coordinate system pushMatrix(); //translate just this baloon translate(x,y); fill(217, 105, 95); noStroke(); ellipse(0, 0, 90, 90); stroke(242, 191, 128); line(59-95, 27, 130-95, 27); line(59-95, 27, 80-95, 70); line(130-95, 27, 109-95, 70); beginShape(); noStroke(); fill(242, 191, 128); triangle(80-95, 70, 0, 70, 88-95, 83); fill(203, 140, 103); triangle(88-95, 83, 103-95, 83, 0, 70); fill(191, 131, 96); triangle(0, 70, 103-95, 83, 110-95, 70); fill(140, 55, 70); triangle(59-95, 27, 77-95, 27, 69-95, 43); triangle(85-95, 27, 0, 43, 105-95, 27); triangle(113-95, 27, 121-95, 43, 130-95, 27); endShape(); popMatrix(); //pop back to the Processing's original coordinate system } //gradient background void setGradient(int x, int y, float w, float h, color b1, color b2, int axis ) { noFill(); if (axis == Y_AXIS) { // Top to bottom gradient for (int i = y; i <= y+h; i++) { float inter = map(i, y, y+h, 0, 1); color b = lerpColor(b1, b2, inter); stroke(b); line(x, i, x+w, i); } } }
2. moving bottom to top
In terms of moving from bottom to you, since there are position variables available, it's simply a matter or simply updating the y coordinates over time. Moving bottom to top will mean decreasing the y position:
void draw() { //decrease ballons y position -> bottom to top ballon1Y -= 0.25; ballon2Y -= 0.75; ballon3Y -= 1.15; //gradient background setGradient(0, 0, 500, 500, b1, b2, Y_AXIS); setGradient(0, 500, 540, 500, b2, b1, X_AXIS); balloon(ballon1X,ballon1Y); balloon(ballon2X,ballon2Y); balloon(ballon3X,ballon3Y); cloud(); }
3. when you click balloons with the mouse...
You can use the mousePressed() for the click. To figure out if a balloon was clicked you could use a bit of trigonometry (Pythagoras theorem) to determine the distance between the mouse position and the balloon position and Processing's got your back yet again with the dist() function. It takes 4 arguments (2 pairs of x,y coordinates (from-to)) and returns one number: the distance. If the distance from the mouse to the ballon is smaller than the ballon's radius, then the mouse is inside the balloon. Similar to how the balloon1X,balloon1Y
variables were added, a ballonSize
variable can be added so it can be easily re-used both for balloon drawing and clicking calculations. Here's a simple example randomizing the 1st balloon's coordinates if it's clicked:
void mouseReleased(){ //check if the distance between the mouse cursor and the balloon is smaller than the ballon radius (size / 2) if(dist(mouseX,mouseY,balloon1X,balloon1Y) < balloonSize / 2){ balloon1X = random(100,width-100); balloon1Y = random(height/2); } }
4. ... balloons change colors This last step should now be trivial since the balloon()
could be modified to use x,y,size
arguments/parameters. It's just a matter of adding a color variable as well which can be updated if the balloon is clicked.
Here is a sketch covering all 4 questions:
float balloon1X; float balloon1Y; float balloon2X; float balloon2Y; float balloon3X; float balloon3Y; float balloonSize = 90; color balloon1Color = color(217, 105, 95); color balloon2Color = color(217, 105, 95); color balloon3Color = color(217, 105, 95); void setup() { size(500, 500); //define colors for gradient background b1 = color(139, 211, 242); b2 = color(212, 221, 198); // noLoop(); //randomize X positions balloon1X = random(100,width-100); balloon2X = random(100,width-100); balloon3X = random(100,width-100); //randomize y positions, keeping in mind they rise from the bottom balloon1Y = random(height/2); balloon2Y = random(height/2); balloon3Y = random(height/2); } int Y_AXIS = 1; int X_AXIS = 2; color b1, b2; void draw() { //decrease ballons y position -> bottom to top balloon1Y -= 0.25; balloon2Y -= 0.75; balloon3Y -= 1.15; //gradient background setGradient(0, 0, 500, 500, b1, b2, Y_AXIS); setGradient(0, 500, 540, 500, b2, b1, X_AXIS); balloon(balloon1X,balloon1Y,balloonSize,balloon1Color); balloon(balloon2X,balloon2Y,balloonSize,balloon2Color); balloon(balloon3X,balloon3Y,balloonSize,balloon3Color); cloud(); } //cloud shape void cloud() { beginShape(); noStroke(); fill(204, 206, 207); triangle(180, 50, 195, 50, 188, 35); triangle(195, 50, 188, 65, 202, 65); fill(189, 192, 193); triangle(188, 35, 195, 50, 202, 35); triangle(180, 50, 195, 50, 188, 65); triangle(202, 65, 195, 50, 209, 50); fill(255); triangle(195, 50, 209, 50, 202, 35); triangle(215, 35, 209, 50, 222, 50); triangle(215, 65, 202, 65, 209, 50); fill(224, 231, 234); triangle(209, 50, 202, 35, 215, 35); triangle(209, 50, 215, 65, 222, 50); endShape(); } // hot air balloon shape void balloon(float x,float y,float size,color fillColor) { //isolate coordinate system pushMatrix(); //translate just this baloon translate(x,y); fill(fillColor); noStroke(); ellipse(0, 0, size, size); stroke(242, 191, 128); line(59-95, 27, 130-95, 27); line(59-95, 27, 80-95, 70); line(130-95, 27, 109-95, 70); beginShape(); noStroke(); fill(242, 191, 128); triangle(80-95, 70, 0, 70, 88-95, 83); fill(203, 140, 103); triangle(88-95, 83, 103-95, 83, 0, 70); fill(191, 131, 96); triangle(0, 70, 103-95, 83, 110-95, 70); fill(140, 55, 70); triangle(59-95, 27, 77-95, 27, 69-95, 43); triangle(85-95, 27, 0, 43, 105-95, 27); triangle(113-95, 27, 121-95, 43, 130-95, 27); endShape(); popMatrix(); //pop back to the Processing's original coordinate system } void mouseReleased(){ //check if the distance between the mouse cursor and the balloon is smaller than the ballon radius (size / 2) if(dist(mouseX,mouseY,balloon1X,balloon1Y) < balloonSize / 2){ //randomize balloon 1 color balloon1Color = color(random(127,255),random(127,255),random(127,255)); } } //gradient background void setGradient(int x, int y, float w, float h, color b1, color b2, int axis ) { noFill(); if (axis == Y_AXIS) { // Top to bottom gradient for (int i = y; i <= y+h; i++) { float inter = map(i, y, y+h, 0, 1); color b = lerpColor(b1, b2, inter); stroke(b); line(x, i, x+w, i); } } }
You can run the demo here using p5.js, how nice is that ?! (click the slowest balloon)
var balloon1X; var balloon1Y; var balloon2X; var balloon2Y; var balloon3X; var balloon3Y; var balloonSize = 90; var balloon1Color; var balloon2Color; var balloon3Color; function setup() { createCanvas(500, 500); //define colors for gradient background b1 = color(139, 211, 242); b2 = color(212, 221, 198); // noLoop(); //randomize X positions balloon1X = random(100,width-100); balloon2X = random(100,width-100); balloon3X = random(100,width-100); //randomize y positions, keeping in mind they rise from the bottom balloon1Y = random(height); balloon2Y = random(height); balloon3Y = random(height); balloon1Color = color(217, 105, 95); balloon2Color = color(217, 105, 95); balloon3Color = color(217, 105, 95); } var Y_AXIS = 1; var X_AXIS = 2; var b1, b2; function draw() { //decrease ballons y position -> bottom to top balloon1Y -= 0.25; balloon2Y -= 0.75; balloon3Y -= 1.15; //gradient background setGradient(0, 0, 500, 500, b1, b2, Y_AXIS); setGradient(0, 500, 540, 500, b2, b1, X_AXIS); balloon(balloon1X,balloon1Y,balloonSize,balloon1Color); balloon(balloon2X,balloon2Y,balloonSize,balloon2Color); balloon(balloon3X,balloon3Y,balloonSize,balloon3Color); cloud(); } //cloud shape function cloud() { beginShape(); noStroke(); fill(204, 206, 207); triangle(180, 50, 195, 50, 188, 35); triangle(195, 50, 188, 65, 202, 65); fill(189, 192, 193); triangle(188, 35, 195, 50, 202, 35); triangle(180, 50, 195, 50, 188, 65); triangle(202, 65, 195, 50, 209, 50); fill(255); triangle(195, 50, 209, 50, 202, 35); triangle(215, 35, 209, 50, 222, 50); triangle(215, 65, 202, 65, 209, 50); fill(224, 231, 234); triangle(209, 50, 202, 35, 215, 35); triangle(209, 50, 215, 65, 222, 50); endShape(); } // hot air balloon shape function balloon(x,y,size,fillColor) { //isolate coordinate system push(); //translate just this baloon translate(x,y); fill(fillColor); noStroke(); ellipse(0, 0, size, size); stroke(242, 191, 128); line(59-95, 27, 130-95, 27); line(59-95, 27, 80-95, 70); line(130-95, 27, 109-95, 70); beginShape(); noStroke(); fill(242, 191, 128); triangle(80-95, 70, 0, 70, 88-95, 83); fill(203, 140, 103); triangle(88-95, 83, 103-95, 83, 0, 70); fill(191, 131, 96); triangle(0, 70, 103-95, 83, 110-95, 70); fill(140, 55, 70); triangle(59-95, 27, 77-95, 27, 69-95, 43); triangle(85-95, 27, 0, 43, 105-95, 27); triangle(113-95, 27, 121-95, 43, 130-95, 27); endShape(); pop(); //pop back to the Processing's original coordinate system } function mouseReleased(){ //check if the distance between the mouse cursor and the balloon is smaller than the ballon radius (size / 2) if(dist(mouseX,mouseY,balloon1X,balloon1Y) < balloonSize / 2){ //randomize balloon 1 color balloon1Color = color(random(127,255),random(127,255),random(127,255)); } } //gradient background function setGradient(x, y, w, h, b1, b2, axis ) { noFill(); if (axis == Y_AXIS) { // Top to bottom gradient for (var i = y; i <= y+h; i++) { var inter = map(i, y, y+h, 0, 1); var b = lerpColor(b1, b2, inter); stroke(b); line(x, i, x+w, i); } } }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.22/p5.min.js"></script>
Now you should understand how to animate a coordinate variable over time for an independent drawing, which means you can apply the same principles to draw clouds at independent coordinates and move them right to left. Also, you can add the remaining two if conditions in the mouseReleased()
event to change colours for the other two balloons.
Depending on where you get to with your Processing course, you might want to consider these next steps:
- Using PVector to store positions (one variable per balloon instead of two)
- Using for loops for multiple balloons/clouds (instead of copy/pasted function calls).
- Encapsulating code into a Balloon and a separate Cloud class(drawing, coordinates, colour, position, etc.). Check out Daniel Shiffman's Objects tutorials for more details.
With the above you should be able to put together a nice, easy to manage program that can animate the pretty balloons and clouds smoothly and make the parallax effect more obvious. Have fun!
How to Draw a Cloud in Processing
Source: https://stackoverflow.com/questions/35241299/in-processing-how-to-make-a-custom-function-move
Post a Comment for "How to Draw a Cloud in Processing"