This was a challenging assignment! Mainly because I had a game I wanted to do in mind, and after spending a lot of time on getting the basics to work I realized it might need more practice and time than what I have now, so I changed the direction of my assignment and decided to go with a more “artwork” focused approach.
Recently I’ve been thinking about the ‘paint by numbers notebooks’ I used to have as a child and how accessible they made creating artwork that is above my artistic skills. This made me want to buy a ‘paint by numbers’ set, but also I asked if I could use the same approach to create artwork on processing.
I realized I can do a similar approach but with pixels! I made a class called “square” which represents each square in a grid, and then used a 2D array list that contains different combinations of numbers of squares to be filled.
My class has a display function, and a fill function that relies on a boolean variable.
For the drawing, I decided to go for a heart that is filling gradually with every number the user inputs from their keyboard. At the final level, when the heart is full, it goes from black to a mix of random shades of red and pink which is controlled by the mouseX movement to a certain extent (to avoid the colors being too random).
After finalizing the logic, which depends on creating an array of square objects and then displaying and referencing them as a grid. I went to figure out the square numbers needed in my 2D array for each heart stage. For this part, I used pixilart.com and created a grid of the same size as mine then compared the square values.
I settled on bigger pixels, but since the code contains, row, column, and square number variables, it is easy to change the grid appearance and square size.
I think the program has the potential to be more complex or contain more user interaction, I would love any suggestions!
Have a look at my main code:
Square[] allSquares; //declaring an array of objects that consists of the squares that will be in the grid // 2D Array of the different heart level drawings, each inner list contains the number of the pixel that should be filled int[][] heartLevels = { {2,3,4,11,15,21,26,32,37,43,48,53,58,62,67,71,76,81,85,92,93,94}, //empty heart {2,3,4,11,15,21,26,32,37,43,47,48,53,57,58,62,67,71,76,81,85,92,93,94}, //initially filled heart (Level 1) {2,3,4,11,15,21,25,26,32,35,36,37,43,45,46,47,48,53,55,56,57,58,62,65,66,67,71,75,76,81,85,92,93,94}, // medium full heart (Level 2) {2,3,4,11,13,14,15,21,23,24,25,26,32,33,34,35,36,37,43,44,45,46,47,48,53,54,55,56,57,58,62,63,64,65,66,67,71,73,74,75,76,81,83,84,85,92,93,94}, // almost full heart (Level 3) {2,3,4,11,12,13,14,15,21,22,23,24,25,26,32,33,34,35,36,37,43,44,45,46,47,48,53,54,55,56,57,58,62,63,64,65,66,67,71,72,73,74,75,76,81,82,83,84,85,92,93,94}}; // full heart // a boolean to create the color effect for the full heart boolean fullHeart; // declaring and initializing the column and row number for the grid int cols = 10; int rows = 10; void setup(){ size(500,500); background(255); //creating the grid array, the array size corresponds to the dimension of the grid allSquares = new Square[cols*rows]; //initializing and declaring an index variable to create different objects every time the nested loop runs int index = 0; //a nested loop that goes through each column and row to create a grid of objects for (int c = 0; c < cols; c++){ for (int r = 0; r < rows; r++){ // creating the objects, the arguments of the class are X location, Y location, Width, Height, and index //we multiply c and r by 50 because it corresponds to the square dimension, so if my x is 2 and y is 2, the square will be at 100,100. allSquares[index] = new Square(c*50,r*50,50,50,index); index+=1; } } fullHeart = false; //initializing the color effect variable with false } void draw(){ //a loop that displays the grid for(int i = 0; i < cols*rows; i++){ allSquares[i].display(); //an if statement that checks which heart we are creating by checking if the fullHeart bool is true, it is changed to true below, when the key is pressed. if (fullHeart == true){ for (int j = 0; j < heartLevels[4].length; j++){ //accessing the heart color variable defined in the square class, and altering it for the color effect //using random within a small range to generate the different shades of red, and applying interaction through mouseX allSquares[heartLevels[4][j]].heartColor = color(random(mouseX,255), random(0,90),random(90,100)); //interacting with user through changing the R random bottom range using mouseX. //filling the squares, it keeps changing because it is in the draw function allSquares[heartLevels[4][j]].fillingSquare(true); } } } } void keyPressed(){ //key pressed function that displays different heart shapes based on the number pressed if (key == '0'){ //zero gives an empty screen for(int i = 0; i < cols*rows; i++){ fullHeart = false; //this boolean is set to false for every key that does not correspond to a full heart allSquares[i].fillingSquare(false); //First loop goes through all the squares in the object list and unfills them to remove the effect of other shapes, this loop is repeated for all the other keys } } if (key == '1'){ for(int i = 0; i < cols*rows; i++){ //same loop allSquares[i].fillingSquare(false); } for (int i = 0; i < heartLevels[0].length; i++){ fullHeart = false; allSquares[heartLevels[0][i]].heartColor = color(0); //sets the color variable from the class to black allSquares[heartLevels[0][i]].fillingSquare(true); ////fills every pixel that corresponds to values in the first heart shape list with black } } //the same repeats for the next if conditions else if (key == '2'){ for(int i = 0; i < cols*rows; i++){ allSquares[i].fillingSquare(false); } for (int i = 0; i < heartLevels[1].length; i++){ fullHeart = false; allSquares[heartLevels[1][i]].heartColor = color(0); allSquares[heartLevels[1][i]].fillingSquare(true); } } else if(key=='3'){ for(int i = 0; i < cols*rows; i++){ allSquares[i].fillingSquare(false); } for (int i = 0; i < heartLevels[2].length; i++){ fullHeart = false; allSquares[heartLevels[2][i]].heartColor = color(0); allSquares[heartLevels[2][i]].fillingSquare(true); } } else if(key=='4'){ for(int i = 0; i < cols*rows; i++){ allSquares[i].fillingSquare(false); } for (int i = 0; i < heartLevels[3].length; i++){ fullHeart = false; allSquares[heartLevels[3][i]].heartColor = color(0); allSquares[heartLevels[3][i]].fillingSquare(true); } } else if(key=='5'){ for(int i = 0; i < cols*rows; i++){ allSquares[i].fillingSquare(false); } for (int i = 0; i < heartLevels[4].length; i++){ fullHeart = true; //this turns on the random color fill in the draw function allSquares[heartLevels[4][i]].fillingSquare(true); //and based on those colors fills the squares } } }
and my Square Class:
class Square{ //initializing variables that will be used throughout the class int squareX , squareY; //square x and y location int squareW , squareH; int squareNo; //the number of the pixel on the grid boolean filled; //the boolean that determines which pixels on the screen are filled color heartColor; //a color variable to control the color of the pixel color gridStroke = color(203,197,197); // color of grid lines Square(int tempX, int tempY, int tempW, int tempH, int tempSquareNoMinus1){ //constructor, takes X location, Y location, Width, Height, and the index as arguments //setting the constructor arguments to permanent variables squareX = tempX; squareY = tempY; squareW = tempW; squareH = tempH; squareNo = tempSquareNoMinus1 + 1; // 1 is added to the index as the counting of squares starts at 1, not zero. } void display(){ //function that displays the square on the screen stroke(gridStroke); strokeWeight(0.25); noFill(); rect(squareX , squareY , squareW , squareH); } void fillingSquare(boolean filled){ //a function that fills the pixels based on a filled? boolean if (filled == true){ fill(heartColor); } else{ //if the boolean is false the square is filled with white and redrawn fill(255); } rect(squareX,squareY,squareW,squareH); } }