// File: puppy.cxx Mar 9, 2011 // Written by: Michael Main // Email: main@colorado.edu // The purpose of the program is to draw a flock of flying puppies. // But the real purpose is to motivate arrays. //----------------------------------------------------------------------- // Directives: #include #include #include #include using namespace std; //----------------------------------------------------------------------- //----------------------------------------------------------------------- // These are named constants that tell the size of things. const int S = 500; // Window width and height in pixels const double WMAX = 100; // World coordinates go from -WMAX to +WMAX const double MOUSE_SIZE = 3; // Radius of the mouse const double PUPPY_SIZE = 4; // Size of each puppy const int MANY_PUPS = 9001; // Number of puppies in the flock const double SIMTIME = 0.1; // Time simulated in each iteration const int FPS = 10; // Iterations per second //----------------------------------------------------------------------- //--------------------------------------------------------------------- // double distance(double x0, double y0, double x1, double y1); // Returns the distance between (x0, y0) and (x1, y1) double distance(double x0, double y0, double x1, double y1); // Draw a narrow triangle with center at x,y, distance to head equal to // d, and heading (in radians) given by heading. void draw_triangle(double x, double y, double d, double heading); // This function draws a filled circle. The center of the circle // is specified in this coordinate system as wx, wy, and its radius in // world coordinates is given by d. The fill color is given by the c // parameter. void fill_circle(double wx, double wy, double d, int c); // pixel(v, v0, v1, pmax) converts v from an interval that ranges from v0 to v1 // into an integer interval that ranges from 0 to pmax. Note that when v = v0, // the answer is always 0, and when v = v1, the answer is always pmax. // Example 1: Suppose an x-coordinate called x ranges from -2 (on the left // side of the screen) to +3 (on the right side of the screen), and // we want to figure out the corresponding pixel x coordinate for a screen // that is 400 pixel wide. Then call pixel(x, -2, 3, 400). // Example 2: Suppose a y-coordinate called y ranges from +4 (on the top // of the screen) to -2 (on the bottom of the screen), and // we want to figure out the corresponding pixel y coordinate for a screen // that is 300 pixels tall. Then call pixel(y, 4, -2, 300). Note that in this // case v0 > v1 since we want bigger coordinates at the top of the screen. int pixel(double v, double v0, double v1, int pmax); // Set the coordinates of a puppy to a random spot, and set the velocities // to zero: void randomize(double& pup_x, double& pup_y, double& vx, double& vy); // Simulate a small amount of time in the life of a puppy that is // moving toward a given target point: void simulate_puppy( double& pup_x, double& pup_y, double& vx, double&vy, double target_x, double target_y ); // world(p, v0, v1, pmax) converts p from an interval that ranges from 0 to // pmax into a double number interval that ranges from v0 to v1. double world(int p, double v0, double v1, int pmax); //----------------------------------------------------------------------- //----------------------------------------------------------------------- int main () { // Store information about locations and velocities in f // Information about the master is always at index [0] // Information about puppy i is at index [i] double x[MANY_PUPS+1]; // x[0] is master's x coordinate double y[MANY_PUPS+1]; // y[0] is master's y coordinate double vx[MANY_PUPS+1]; // vx[0] is master's vx velocity double vy[MANY_PUPS+1]; // vx[0] is master's vy velocity int i; // Loop index // Initialize the graphics window initwindow(S, S, "I Love Puppies", 0, 0, true); // Randomize the positions of the puppies: for (i = 1; i <= MANY_PUPS; ++i) { randomize(x[i], y[i], vx[i], vy[i]); } while (true) { // 1. Alter positions and velocities: x[0] = world(mousex(), -WMAX, +WMAX, S); y[0] = world(mousey(), +WMAX, -WMAX, S); // Puppy 1 follows [0] // Puppies 2 and 3 follow [1] // Puppies 4 and 5 follow [2] // and so on... for (i = 1; i <= MANY_PUPS; ++i) { simulate_puppy(x[i], y[i], vx[i], vy[i], x[i/2], y[i/2]); } // 2. Draw the world: clearviewport( ); fill_circle(x[0], y[0], MOUSE_SIZE, YELLOW); for (i = 1; i <= MANY_PUPS; ++i) { draw_triangle(x[i], y[i], PUPPY_SIZE, atan2(vy[i], vx[i])); } // 3. Swapbuffers and delay swapbuffers( ); delay(1000/FPS); } return EXIT_SUCCESS; } //--------------------------------------------------------------------- //---------------------------------------------------------------------------- double distance(double x0, double y0, double x1, double y1) { double dx = x1 - x0; double dy = y1 - y0; return sqrt(dx*dx + dy*dy); } //---------------------------------------------------------------------------- //--------------------------------------------------------------------- void draw_triangle(double x, double y, double d, double heading) { const double TWIXT = 2.8; // Radians twixt head and other vertices double x1, y1, x2, y2, x3, y3; // vertices' coordinates int px1, py1, px2, py2, px3, py3; // vertices' pixel coordinates // Compute the coordinates: x1 = x + d*cos(heading); y1 = y + d*sin(heading); x2 = x + d*cos(heading - TWIXT); y2 = y + d*sin(heading - TWIXT); x3 = x + d*cos(heading + TWIXT); y3 = y + d*sin(heading + TWIXT); // Convert to pixels: px1 = pixel(x1, -WMAX, +WMAX, S); py1 = pixel(y1, +WMAX, -WMAX, S); px2 = pixel(x2, -WMAX, +WMAX, S); py2 = pixel(y2, +WMAX, -WMAX, S); px3 = pixel(x3, -WMAX, +WMAX, S); py3 = pixel(y3, +WMAX, -WMAX, S); // Draw the lines of the triangle: line(px1, py1, px2, py2); line(px2, py2, px3, py3); line(px3, py3, px1, py1); } //----------------------------------------------------------------------- //----------------------------------------------------------------------- void fill_circle(double wx, double wy, double d, int c) { int px, py; // Pixel coordinates of the next point on curve int pixel_size; // Radius of circle in pixels pixel_size = pixel(d, -WMAX, +WMAX, S) - pixel(0, -WMAX, +WMAX, S); px = pixel(wx, -WMAX, +WMAX, S); py = pixel(wy, +WMAX, -WMAX, S); setfillstyle(SOLID_FILL, c); fillellipse(px, py, pixel_size, pixel_size); } //----------------------------------------------------------------------- //----------------------------------------------------------------------- int pixel(double v, double v0, double v1, int pmax) { return int(((v - v0)/(v1 - v0)) * pmax); } //----------------------------------------------------------------------- //----------------------------------------------------------------------- void randomize(double& pup_x, double& pup_y, double& vx, double& vy) { pup_x = (rand( )/double(RAND_MAX))*2*WMAX - WMAX; pup_y = (rand( )/double(RAND_MAX))*2*WMAX - WMAX; vx = 0; vy = 0; } //---------------------------------------------------------------------- //---------------------------------------------------------------------- void simulate_puppy( double& pup_x, double& pup_y, double& vx, double&vy, double target_x, double target_y ) { // The puppy's velocity is always along the line that connects him to // his target. The magnitude of this velocity is (d-LIMIT), where // d is the distance to the target and LIMIT is a number we define // here: const double LIMIT = 6*PUPPY_SIZE; double d; // Distance between puppy and master double angle; // Angle of the line connecting puppy to master d = distance(pup_x, pup_y, target_x, target_y); angle = atan2(target_y - pup_y, target_x - pup_x); vx = (d-LIMIT)*cos(angle); vy = (d-LIMIT)*sin(angle); // Previous location + new velocity displacement + rand noise pup_x = pup_x + vx*SIMTIME + rand() % 3 - 1; pup_y = pup_y + vy*SIMTIME + rand() % 3 - 1; } //---------------------------------------------------------------------- //---------------------------------------------------------------------- double world(int p, double v0, double v1, int pmax) { double fraction = double(p)/double(pmax); double distance_from_v0 = fraction*(v1 - v0); return v0 + distance_from_v0; } //----------------------------------------------------------------------