
Mini Project 2. Interactive Drawing
Project title: Christmas Tree Generator
Link: https://editor.p5js.org/Xiaozao/sketches/IOs1LhPbt
Brief Description and concept:
When we learned about kid pix in class, Moon said that we can create some stamps like those in kid pix. The shape stamps enable the kids to create perfect squares, triangles, and circles with a click.

And then I started thinking about customizing the shapes you draw. With a preset function created by the programmer, the user can create shapes of customized width and height. Just like how we draw in software such as Photoshop.
Then I thought of writing a preset function for drawing triangles, so the users can create their own Christmas trees by putting together several triangles. This is called the shape mode.
And they can also add more decorations to the tree by drawing with their mouse outside the shape mode.
Demo:
/* GUIDELINE:
* Click “Draw shape” to draw triangles.
* Click again to exit draw shape mode.
* Click “Decoration” to add decorations to your tree.
* Click again to exit decoration mode.
* When you’re outside the special modes,
* press ‘y’ to use the yellow pen,
* and press ‘b’ to use the brown pen.
* Start creating your own Christmas tree!
*/

Coding:
The key of my code is to create the customized triangle function.
The final goal should be like this:
* from the Internet
The first challenge was how to record the start point of the mouse. In the class, we learned mouseIsPressed/mousePressed. However, during the full course of interaction, my mouse is always pressed from beginning to end. If I assign mouse position in the function mousePressed, then the position will change as I dragged the mouse, then how can the computer remember where the starting point was?
I searched “mouse” in the reference, and surprisingly found that there were more mouse-related functions: Pressed, Dragged, Released, Clicked. And then I found an example code in p5js that made use of Pressed, Dragged, and Released functions in a sequence. I realized that we can actually break down the user interaction process into 3 steps: Press, drag and release instead of describing it as “always pressed”.
* from the Internet
So, we can record the starting mouse position in the mousePressed function, and keep updating the current mouse position in the mouseDragged function, to know the exact boundary of our customized shape.
I refreshed the background every frame so that we can move around our mouse to change the size of the shape without leaving history marks on the canvas.

However, drawing only one triangle for a beautiful Christmas tree is not enough! But it leads to another question: Since I refresh the background every frame, the last triangle will be soon covered by the new triangle and refreshed background.
I thought of the arrays I learned in ICS. Therefore I created 4 arrays to store all the previously drawn triangles, and run a drawTriangles() function every frame to draw all the triangles in the array, and it worked! It feels really nice to apply what I learned in CS here. And I feel since I’m a CS major and have some coding background, I should work even harder to make my code worth every class I had taken. I’m trying to do so.
function drawTriangles() {
for (let i = 0; i < xStart_array.length; i++) {
triangle(
(1 / 2) * (mouseX_array[i] + xStart_array[i]),
yStart_array[i],
xStart_array[i],
mouseY_array[i],
mouseX_array[i],
mouseY_array[i]
);
}
}

Okay, so the next step is to combine the shape_drawing mode with the normal sketching mode, and switch between them freely. I defined a boolean variable called shape_mode, and a callback function of a button object. So every time I pressed the button, shape_mode will be assigned its reversed value (T to F to T…), and only if shape_mode == true, we can proceed within the mouse functions.
Since the mouse-related functions are separate from draw() and non-reusable within a frame, instead of adjusting mouse movements under if statements, we should set if statements inside mouse-related functions.
e.g.
function mousePressed() {
if (shape_mode == true) {
xStart = mouseX;
yStart = mouseY;
}
}
And I let drawTriangles() function run only if (shape_mode == true), so that after exiting the shape_mode, the triangles won’t overlap the other things you draw.


Ok, so things are almost done. After that, I added a few features and a decoration stamp to make it a better Christmas tree generator!

Reflection:
I have written quite a bit of word in the code section, and some of them have already answered the question in slides. So I will be brief in this section.
- Variables are used to store information to be referenced and manipulated in your sketch. Describe how you used variables and their purpose in your sketch.

I used xStart and yStart to store the starting mouse position, boolean variables to switch the states, and arrays to store a set of triangles.
2. Conditions allow us to control what the program does and perform different actions based on “if” logic statements. They enable the user to interact with the program. Describe the interactive methods you applied in your program, utilizing conditionals.
I inserted if statements inside the mouse-related functions to create a kind of state machine that enabled the user to enter and exit a special mode.
3. What are the differences between key and keyCode?
key: ‘r’ ‘g’ ‘b’
keyCode: special keys such as ENTER, CONTROL
4. More findings:
– if (mouseIsPressed) v.s. function mousePressed()
The first one records a status and the second one records a move.
– if (keyCode == ENTER) v.s. if keyCode == ENTER && keyIsPressed
The first one will continue working after the key is released while the second one doesn’t. The second one is more suitable for clearing the background.
5. Feelings:
Sometimes it’s harder to achieve a very simple but user-friendly approach!
Leave a Reply