This project assumes familiarity with using classes with Processing in Eclipse.

This project demonstrates:

Program functionality & organization

The program displays a grid and responds to clicks on boxes by displaying, changing, and removing faces within the boxes.

The FaceGrid class has the same getRow(int y), getColumn(int x), getTopY(int row), getLeftX(int column), and drawGrid() methods as in Abstracting a grid. These methods are used without worrying about how they work. The details of the methods are abstracted away.

The constants at the top of FaceGrid have been made public so they can be used by the Face class.

The FaceGrid class stores Face objects in a 2D array. The FaceGrid method draw asks each Face object to draw itself. The FaceGrid method mousePressed responds to clicks.

The Face class is responsible for drawing a face at a given row and column. The Face class maintains state, including color and whether the face is sad. The Face class uses constants and methods from the FaceGrid class to draw a face.

Program code

Face class

import processing.core.PApplet;

public class Face
{
    public static final int DIAMETER = 50;
    
    private FaceGrid parent;
    private int color;
    private boolean isSad;
    
    public Face(FaceGrid p)
    {
        parent = p;
        
        color = parent.color(
                parent.random(256),
                parent.random(256),
                parent.random(256));
        
        isSad = false;
    }
    
    public void drawSelf(int row, int column)
    {
        final int centerX = parent.getLeftX(column) + (FaceGrid.BOX_WIDTH / 2);
        final int centerY = parent.getTopY(row) + (FaceGrid.BOX_HEIGHT / 2);
        
        parent.fill(color);
        parent.ellipse(centerX, centerY, DIAMETER, DIAMETER);
        
        parent.fill(255);
        parent.ellipse(centerX - 10, centerY - 5, 5, 5);
        parent.ellipse(centerX + 10, centerY - 5, 5, 5);
        
        if(isSad)
        {
            parent.arc(centerX, centerY + 10, 15, 10,
                    PApplet.radians(180), PApplet.radians(360));
        }
        else
        {
            parent.arc(centerX, centerY + 10, 15, 10,
                    PApplet.radians(0), PApplet.radians(180));
        }
    }
    
    public boolean isSad()
    {
        return isSad;
    }
    
    public void makeSad()
    {
        isSad = true;
    }
}

FaceGrid class

import processing.core.PApplet;

public class FaceGrid extends PApplet
{
    public static final int TOP_OFFSET = 20;
    public static final int LEFT_OFFSET = 15;
    public static final int BOX_WIDTH = 75;
    public static final int BOX_HEIGHT = 75;
    public static final int ROWS = 5;
    public static final int COLUMNS = 8;
    
    private Face[][] faces;
    
    public static void main(String[] args)
    {
        PApplet.main("FaceGrid");
    }
    
    public void settings()
    {
        final int SCREEN_WIDTH = (LEFT_OFFSET * 2) + (COLUMNS * BOX_WIDTH);
        final int SCREEN_HEIGHT = (TOP_OFFSET * 2) + (ROWS * BOX_HEIGHT);
        size(SCREEN_WIDTH, SCREEN_HEIGHT);
    }
    
    public void setup()
    {
        faces = new Face[ROWS][COLUMNS];
        noLoop();
        redraw();
    }
    
    public void draw()
    {
        background(0);
        
        drawGrid();
        
        for(int row = 0; row < faces.length; row++)
        {
            for(int col = 0; col < faces[0].length; col++)
            {
                if(faces[row][col] != null)
                {
                    faces[row][col].drawSelf(row, col);
                }
            }
        }
    }
    
    public void mousePressed()
    {
        final int row = getRow(mouseY);
        final int col = getColumn(mouseX);
        
        if(row != -1 && col != -1)
        {
            if(faces[row][col] == null)
            {
                faces[row][col] = new Face(this);
            }
            else if( ! faces[row][col].isSad() )
            {
                faces[row][col].makeSad();
            }
            else
            {
                faces[row][col] = null;
            }
            
            redraw();
        }
    }
    
    // returns row corresponding to y or -1 if not an existing row
    public int getRow(int y)
    {
        if(y < getTopY(0) || y >= getTopY(ROWS))
            return -1;
        
        return (y - TOP_OFFSET) / BOX_HEIGHT;
    }
    
    // returns column corresponding to x or -1 if not an existing column
    public int getColumn(int x)
    {
        if(x < getLeftX(0) || x >= getLeftX(COLUMNS))
            return -1;
        
        return (x - LEFT_OFFSET) / BOX_WIDTH;
    }
    
    public int getTopY(int row)
    {
        return TOP_OFFSET + (row * BOX_HEIGHT);
    }
    
    public int getLeftX(int column)
    {
        return LEFT_OFFSET + (column * BOX_WIDTH);
    }
    
    public void drawGrid()
    {
        rectMode(CORNER);
        noFill();
        strokeWeight(1);
        stroke(255);
        
        for(int row = 0; row < ROWS; row++)
        {
            for(int col = 0; col < COLUMNS; col++)
            {
                rect(getLeftX(col), getTopY(row), BOX_WIDTH, BOX_HEIGHT);
            }
        }
    }
}

Help & comments

Get help from AP CS Tutor Brandon Horn

Comment on FaceGrid