CMSC 110 Introduction to Computing

Spring 2015

Professor Blank

Assignment #7: SimWorld

Due before start of class on Monday, April 6, 2015.

NO CREDIT FOR LATE SUBMISSIONS

Task: Create a Simulated Creature that roams around a Simulated World:

  • an animated scene that exhibits movement and captures one's attention for an extended period

Specifics:

  • You should use a canvas that is 640 by 480 pixels.
  • Your creature should have internal state
  • Your creature will move around, changing position and state
  • Objects should draw themselves in the correct position
  • Work individually on this project

Grading:

  1. Originality and creativity, 50%
  2. Proper use of Objects, 50%

Hand in:

  • Submit your homework via the "Submit" button.

Details

For this assignment, your mission is to create a SimCreature that will live in a sim world.

For an example of this, I will use Dog.

Dog should have at least four methods:

  1. a constructor with no arguments, that puts them in a random position.
  2. a constructor with three arguments, that puts them in (x, y, z).
  3. an update method to figure out where they should move next, and to update their internal states.
  4. a draw method that draws them in their current position, in current state.

The basic prototype would therefore look like:

class Dog {
    ...
    Dog() {
        ...
    }
    Dog(float x, float y, float z) {
        ...
    }
    void update() {
        ...
    }
    void draw() {
        ...
    }
}

Where there are ellipses, you will fill out the code.

To make a bunch of these objects, we need to do three things:

  1. create a global array or list to put them in
  2. create the array
  3. create each of the objects

That might look like this:

Dog [] dogs;

void setup() {
    dogs = new Dog[5];
    for (int i = 0; i < dogs.length; i++) {
        dogs[i] = new Dog();
    }
}

In this example, I created a global array named dogs, then created an array of length 5, and then created 5 instances of the Dog class. Note that the global array is created outside any function, but the creation of the array, and instances occurs in the setup() function.

Finally, we need to update and redraw the dogs. We do that

void draw() {
    for (int i = 0; i < dogs.length; i++) {
        dogs[i].update();
        dogs[i].draw();
    }
}

SimWorld

Now, a bit of a wrinkle. The location of these objects will roam around a new coordinate system that has x from -1 to 1, y from -1 to 1, and z from -1 to 1. (-1,-1,-1) will be in the front, bottom, left-hand corner, and (1,1,1) will be in the back, top, right-hand corner. Furthermore, as you go back further on the z axis, the object will get smaller.

So, the further away (higher z value) the smaller the object will appear.

We add two more methods to make this easy on us:

  1. coordinates(x, y, z) - returns the screen coordinates [x,y] of the z, y, z position
  2. scale(size, z) - returns how big this size would look at the objects depth

Code

In the following simulations, click and drag to change the view. Dragging up (closer) and down (further away) changes the viewer distance; dragging left (smaller) and right (larger) changes the field of view/vision.

In [4]:
Dog [] dogs;

// fov is the “field of vision/view”. Suggest values between 128 and 256. 
// view_distance is the distance from the object to the viewer.
float fov = 100;
float viewer_distance = 1.5;

class Dog {
    float x;
    float y;
    float z;
    Dog(float x, float y, float z) {
        this.x = x; 
        this.y = y; 
        this.z = z; 
    }
    Dog() {
        this.x = random(2) - 1;
        this.y = -1;
        this.z = random(2) - 1;
    }
    void update() {
        // ...
    }
    void draw() {
        // get the screen coordinates of the object:
        float [] pos = this.coordinates(this.x, this.y, this.z);
        // normally, just ellipse(x, y, 20, 20);
        // but, scaling sizes and putting in correct location:
        ellipse(pos[0], 
                pos[1], 
                this.scale(20, this.z), 
                this.scale(20, this.z));
    }

    float scale(float size, float depth) {
        float factor = fov / (viewer_distance + depth);
        return size * factor/100.0;
    }

    float [] coordinates(float x1, float y1, float z1) {
        // Transforms this 3D point to 2D using a perspective projection.
        // fov is the “field of vision/view”. Suggest values between 128 and 256. 
        // view_distance is the distance from the object to the viewer.
        float factor = fov / (viewer_distance + z1);
        x2 = x1 * factor + width / 2;
        y2 = -y1 * factor + height / 2;
        return new float [] {x2, y2};
    }
}

void setup() {
    size(500, 500);
    dogs = new Dog[20];
    /*
    for (int i = 0; i < dogs.length; i++) {
        dogs[i] = new Dog();
    }
    */
    dogs[0] = new Dog(-1, -1, 1);
    dogs[1] = new Dog(-1, -1, 0.5);
    dogs[2] = new Dog(-1, -1, 0.0);
    dogs[3] = new Dog(-1, -1, -0.5);
    dogs[4] = new Dog(-1, -1, -1);
    
    dogs[5] = new Dog(-1, 1, 1);
    dogs[6] = new Dog(-1, 1, 0.5);
    dogs[7] = new Dog(-1, 1, 0.0);
    dogs[8] = new Dog(-1, 1, -0.5);
    dogs[9] = new Dog(-1, 1, -1);

    dogs[10] = new Dog(1, 1, 1);
    dogs[11] = new Dog(1, 1, 0.5);
    dogs[12] = new Dog(1, 1, 0.0);
    dogs[13] = new Dog(1, 1, -0.5);
    dogs[14] = new Dog(1, 1, -1);

    dogs[15] = new Dog(1, -1, 1);
    dogs[16] = new Dog(1, -1, 0.5);
    dogs[17] = new Dog(1, -1, 0.0);
    dogs[18] = new Dog(1, -1, -0.5);
    dogs[19] = new Dog(1, -1, -1);
}

float m_x;
float m_y;
float m_fov;
float m_viewer_distance;

void mousePressed() {
    m_x = mouseX;
    m_y = mouseY;
    m_fov = fov;
    m_viewer_distance = viewer_distance;
}

void mouseDragged() {
    fov = m_fov + m_fov * (mouseX - m_x)/width;
    viewer_distance = m_viewer_distance + m_viewer_distance * (mouseY - m_y)/height;
}

void draw() {
    background();
    for (int i = 0; i < dogs.length; i++) {
        dogs[i].update();
        dogs[i].draw();
    }
}
Sketch #4:

Sketch #4 state: Loading...
In [17]:
Dog [] dogs;

// fov is the “field of vision/view”. Suggest values between 128 and 256. 
// view_distance is the distance from the object to the viewer.
float fov = 100;
float viewer_distance = 1.5;

class Dog {
    float x;
    float y;
    float z;
    Dog(float x, float y, float z) {
        this.x = x; 
        this.y = y; 
        this.z = z; 
    }
    Dog() {
        this.x = random(2) - 1;
        this.y = -1;
        this.z = random(2) - 1;
    }
    void update() {
        // ...
    }
    void draw() {
        // get the screen coordinates of the object:
        float [] pos = this.coordinates(this.x, this.y, this.z);
        // normally, just ellipse(x, y, 20, 20);
        // but, scaling sizes and putting in correct location:
        ellipse(pos[0], 
                pos[1], 
                this.scale(20, this.z), 
                this.scale(20, this.z));
    }

    float scale(float size, float depth) {
        float factor = fov / (viewer_distance + depth);
        return size * factor/100.0;
    }

    float [] coordinates(float x1, float y1, float z1) {
        // Transforms this 3D point to 2D using a perspective projection.
        // fov is the “field of vision/view”. Suggest values between 128 and 256. 
        // view_distance is the distance from the object to the viewer.
        float factor = fov / (viewer_distance + z1);
        x2 = x1 * factor + width / 2;
        y2 = -y1 * factor + height / 2;
        return new float [] {x2, y2};
    }
}

void setup() {
    size(500, 500);
    dogs = new Dog[100];
    for (int i = 0; i < dogs.length; i++) {
        dogs[i] = new Dog();
    }
}

float m_x;
float m_y;
float m_fov;
float m_viewer_distance;

void mousePressed() {
    m_x = mouseX;
    m_y = mouseY;
    m_fov = fov;
    m_viewer_distance = viewer_distance;
}

void mouseDragged() {
    fov = m_fov + m_fov * (mouseX - m_x)/width;
    viewer_distance = m_viewer_distance + m_viewer_distance * (mouseY - m_y)/height;
}

void draw() {
    background();
    for (int i = 0; i < dogs.length; i++) {
        dogs[i].update();
        dogs[i].draw();
    }
}
Sketch #17:

Sketch #17 state: Loading...
In [16]:
Dog [] dogs;

// fov is the “field of vision/view”. Suggest values between 128 and 256. 
// view_distance is the distance from the object to the viewer.
float fov = 100;
float viewer_distance = 1.5;

class Dog {
    float x;
    float y;
    float z;
    Dog(float x, float y, float z) {
        this.x = x; 
        this.y = y; 
        this.z = z; 
    }
    Dog() {
        this.x = random(2) - 1;
        this.y = -1;
        this.z = random(2) - 1;
    }
    void update() {
        // ...
    }
    void draw() {
        // get the screen coordinates of the object:
        float [] pos = this.coordinates(this.x, this.y, this.z);
        // normally, just ellipse(x, y, 20, 20);
        // but, scaling sizes and putting in correct location:
        ellipse(pos[0], 
                pos[1], 
                this.scale(20, this.z), 
                this.scale(20, this.z));
    }

    float scale(float size, float depth) {
        float factor = fov / (viewer_distance + depth);
        return size * factor/100.0;
    }

    float [] coordinates(float x1, float y1, float z1) {
        // Transforms this 3D point to 2D using a perspective projection.
        // fov is the “field of vision/view”. Suggest values between 128 and 256. 
        // view_distance is the distance from the object to the viewer.
        float factor = fov / (viewer_distance + z1);
        x2 = x1 * factor + width / 2;
        y2 = -y1 * factor + height / 2;
        return new float [] {x2, y2};
    }
}

float m_x;
float m_y;
float m_fov;
float m_viewer_distance;

void mousePressed() {
    m_x = mouseX;
    m_y = mouseY;
    m_fov = fov;
    m_viewer_distance = viewer_distance;
}

void mouseDragged() {
    fov = m_fov + m_fov * (mouseX - m_x)/width;
    viewer_distance = m_viewer_distance + m_viewer_distance * (mouseY - m_y)/height;
}

void sortDogs() {
    for (int i = 0; i < dogs.length - 1; i++) {
        for (int j = i + 1; j < dogs.length; j++) {
            if (dogs[i].z < dogs[j].z) {
                Dog tmp = dogs[i];
                dogs[i] = dogs[j];
                dogs[j] = tmp;
            }
        }
    }
}

void setup() {
    size(500, 500);
    background();
    dogs = new Dog[100];
    for (int i = 0; i < dogs.length; i++) {
        dogs[i] = new Dog();
    }
 }

void draw() {
    background();
    for (int i = 0; i < dogs.length; i++) {
        dogs[i].update();
        sortDogs();
        dogs[i].draw();
    }
}
Sketch #16:

Sketch #16 state: Loading...
In [18]:
Dog [] dogs;

// fov is the “field of vision/view”. Suggest values between 128 and 256. 
// view_distance is the distance from the object to the viewer.
float fov = 100;
float viewer_distance = 1.5;

class Dog {
    float x;
    float y;
    float z;
    Dog(float x, float y, float z) {
        this.x = x; 
        this.y = y; 
        this.z = z; 
    }
    Dog() {
        this.x = random(2) - 1;
        this.y = -1;
        this.z = random(2) - 1;
    }
    void update() {
        // ...
        //this.x += .01;
    }
    void draw() {        
        // get the screen coordinates of the object:
        float [] pos = this.coordinates(this.x, this.y, this.z);
        // normally, just ellipse(x, y, 20, 20);
        // but, scaling sizes and putting in correct location:
        rectMode(CENTER);
        fill(255);
        w = this.scale(40, this.z);
        h = this.scale(20, this.z);
        u = this.scale(5, this.z);
        
        rect(pos[0], 
             pos[1], 
             w, 
             h);
        rect(pos[0] - w/2 + u, 
             pos[1] + h/2 + u, 
             u, 
             2 * u);

    }

    float scale(float size, float depth) {
        float factor = fov / (viewer_distance + depth);
        return size * factor/100.0;
    }

    float [] coordinates(float x1, float y1, float z1) {
        // Transforms this 3D point to 2D using a perspective projection.
        // fov is the “field of vision/view”. Suggest values between 128 and 256. 
        // view_distance is the distance from the object to the viewer.
        float factor = fov / (viewer_distance + z1);
        x2 = x1 * factor + width / 2;
        y2 = -y1 * factor + height / 2;
        return new float [] {x2, y2};
    }
}

float m_x;
float m_y;
float m_fov;
float m_viewer_distance;

void mousePressed() {
    m_x = mouseX;
    m_y = mouseY;
    m_fov = fov;
    m_viewer_distance = viewer_distance;
}

void mouseDragged() {
    fov = m_fov + m_fov * (mouseX - m_x)/width;
    viewer_distance = m_viewer_distance + m_viewer_distance * (mouseY - m_y)/height;
}

void sortDogs() {
    for (int i = 0; i < dogs.length - 1; i++) {
        for (int j = i + 1; j < dogs.length; j++) {
            if (dogs[i].z < dogs[j].z) {
                Dog tmp = dogs[i];
                dogs[i] = dogs[j];
                dogs[j] = tmp;
            }
        }
    }
}

void setup() {
    fov = 100;
    viewer_distance = 1.5;
    size(500, 500);
    background();
    dogs = new Dog[10];
    for (int i = 0; i < dogs.length; i++) {
        dogs[i] = new Dog();
    }
 }

void draw() {
    background();
    float [] c1 = dogs[0].coordinates(-1, -1, -1);
    float [] c2 = dogs[0].coordinates(-1,  1, -1);
    float [] c3 = dogs[0].coordinates( 1, -1, -1);
    float [] c4 = dogs[0].coordinates( 1,  1, -1);
    
    line(c1[0], c1[1], c2[0], c2[1]);
    line(c2[0], c2[1], c4[0], c4[1]);
    line(c3[0], c3[1], c4[0], c4[1]);
    line(c1[0], c1[1], c3[0], c3[1]);
    
    float [] b1 = dogs[0].coordinates(-1, -1, 1);
    float [] b2 = dogs[0].coordinates(-1,  1, 1);
    float [] b3 = dogs[0].coordinates( 1, -1, 1);
    float [] b4 = dogs[0].coordinates( 1,  1, 1);
    
    line(b1[0], b1[1], b2[0], b2[1]);
    line(b2[0], b2[1], b4[0], b4[1]);
    line(b3[0], b3[1], b4[0], b4[1]);
    line(b1[0], b1[1], b3[0], b3[1]);

    line(b1[0], b1[1], c1[0], c1[1]);
    line(b2[0], b2[1], c2[0], c2[1]);
    line(b3[0], b3[1], c3[0], c3[1]);
    line(b4[0], b4[1], c4[0], c4[1]);
    
    for (int i = 0; i < dogs.length; i++) {
        dogs[i].update();
        sortDogs();
        dogs[i].draw();
    }
}
Sketch #18:

Sketch #18 state: Loading...

As shown in the last example, you can use any of the Processing drawing functions (polygon, rect, oval, etc) but you must use this.coordinates() to get the location of any x,y point.