/* Scott Jones * CSE142, Spring 2000 * Section BI * Homework 4 * Originally Landscape * Now Monkey Target Practice * */ #include "gp142.h" #include #include #include /* * is included so the current time can be accessed * to initialize the random number generator. */ /* Logical constants */ #define TRUE 1 #define FALSE 0 /* * For many of the GP142 functions, a line width of * zero means to fill the shape being drawn. The * constant FILL is used in function calls when a solid * shape is desired. */ #define FILL 0 /* * Symbolic constants. Change as needed. */ /* Menu buttons: */ /* Top-left coordinates of button palette */ #define MENU_TOP (GP142_YMAX - 5) #define MENU_LEFT (-GP142_XMAX + 5) /* Height and width of buttons in pixels */ #define BUTTON_HEIGHT 25 #define BUTTON_WIDTH 100 /* Number of buttons */ #define NUM_BUTTONS 4 /* Possible locations of mouse clicks: */ /* Mouse click in some button */ #define BUTTON_CLICK 1 /* Mouse click elsewhere */ #define OTHER_CLICK 0 /* Coordinates of objects in the drawing */ /* y-coordinate of the top of the ground in the landscape */ #define HORIZON (- 2 * (GP142_YMAX / 10)) /* Other constants pertaining to objects in the scene */ #define MONKEY_RADIUS 20 #define TARGET_SPEED 5 #define UP 1 #define DOWN -1 #define MAX_WIND 10 #define MAX_MONKEYS 5 #define MONKEY_SPEED 10 #define NUM_BANANAS 15 #define BANANA_SPEED 8 /***************************************************************************** FUNCTION PROTOTYPES *****************************************************************************/ /* Initialize random number generator. [Ignore or */ /* remove if your program doesn't use random numbers.] */ void initialize_random_numbers(); /* Draw the background, including the monkeys, target, cannon, and bananas */ void draw_landscape(int gun_x, int gun_y, int target_x, int target_y, int num_monkeys, int monkey_x[], int monkey_y[], int num_hits, int num_bananas, int banana_x[], int banana_y[]); /* Update monkey coordinates monkey_x, monkey_y for one tick */ void move_monkey(int *monkey_x, int *monkey_y); /* Update target coordinate target_y for one tick */ void move_target(int *target_y, int target_direction); /* Update banana coordinates for one tick */ void move_banana(int *banana_x, int *banana_y, int wind_speed); /* Draw buttons */ void draw_buttons(void); /*Draw a monkey */ void draw_monkey(int monkey_x, int monkey_y); /* Return kind of mouse click (in a button, etc.) */ int classify_mouse_click(int mouse_x, int mouse_y); /* Process button click at location x, y. React appropriately, depending on the requested event */ void handle_button(int x, int y, int *target_direction, int *wind_speed, int *num_bananas, int banana_x[], int banana_y[]); /* Process the press of a key on the keyboard and react appropriately */ void handle_keypress(int key_pressed, int *gun_y, int gun_x, int monkey_x[], int monkey_y[], int *num_monkeys); /* Shoot a monkey out of the cannon */ void launch_monkey(int monkey_x[], int monkey_y[], int *num_monkeys, int gun_x, int gun_y); /* Counts hits on target and deletes monkeys that are off the screen */ void handle_monkeys(int monkey_x[], int monkey_y[], int *num_monkeys, int *num_hits, int target_x, int target_y); /* creates some bananas to drop */ void make_bananas(int num_bananas, int banana_x[], int banana_y[]); /* draw a banana at banana_x, banana_y */ void draw_banana(int banana_x, int banana_y); /* Display error message if internal error is detected. */ void something_is_wrong (void); /* return a random number between low and high */ int mrand(int low, int high); /***************************************************************************** MAIN *****************************************************************************/ /* * Main program contents: * - Major program variables that persist throughout execution * - Event loop that processes GP142 events until the user quits, * and updates variables and redraws the window as needed. */ int main(void) { /* Event handling and buttons: */ int quit; /* = "user has selected quit" */ int event; /* the most recent GP142 event */ char key_pressed; /* last keyboard character from key event */ int mouse_x, mouse_y; /* x and y coordinates of latest mouse event*/ int click_kind; /* kind of mouse click (button, etc.) */ /* Information about the moving items : */ int gun_x, gun_y; /* screen x and y coordinates */ int num_monkeys = 0; /* number of monkeys on the screen */ int monkey_x[6], monkey_y[6]; /* screen x and y coordinates */ int target_x, target_y; /* screen x and y coordinates */ int target_direction; /* whether target moves up or down */ int banana_x[NUM_BANANAS]; /* x coordinate of the bananas */ int banana_y[NUM_BANANAS]; /* y coordinate of the bananas */ int num_bananas = 0; /* number of bananas */ int wind_speed = 0; /* speed of wind */ int num_hits = 0; /* number of times hitting target */ /* for use in loops */ int i; /* Initialize random number generator */ initialize_random_numbers(); /* Initialize graphics package, clear the window, */ /* turn logging off, and start animation. */ GP142_open(); GP142_logging(LOG_OFF); GP142_clear(); GP142_animate(ANI_RUN); /* set initial location of the gun */ gun_x = -4*(GP142_XMAX/5); gun_y = HORIZON; /* set initial location of the target */ target_x = 4*(GP142_XMAX/5); target_y = HORIZON; target_direction = UP; /* Draw background, buttons, gun, bananas, monkeys, and target */ draw_landscape(gun_x, gun_y, target_x, target_y, num_monkeys, monkey_x, monkey_y, num_hits, num_bananas, banana_x, banana_y); draw_buttons(); /* * Main event loop: * ---- ----- ----- * Wait for the next user action, decode it, and call an * appropriate function to handle it. Repeat until the * user selects quit. */ quit = FALSE; while (!quit) { /* get next event */ event = GP142_await_event(&mouse_x, &mouse_y, &key_pressed); /* perform appropriate action depending on kind of event */ switch (event) { case GP142_QUIT: /* Quit selected */ quit = TRUE; break; case GP142_KBD: /* Key pressed. */ handle_keypress(key_pressed, &gun_y, gun_x, monkey_x, monkey_y, &num_monkeys); break; case GP142_MOUSE: /* Mouse click. Determine if in a menu button */ /* or elsewhere and process accordingly. */ click_kind = classify_mouse_click(mouse_x, mouse_y); if (click_kind == BUTTON_CLICK) { handle_button(mouse_x, mouse_y, &target_direction, &wind_speed, &num_bananas, banana_x, banana_y); } break; case GP142_PERIODIC: /* Timer interval event. Update everything that needs the change */ /* as time advances. Location updates should go here! */ move_target(&target_y, target_direction); /* update monkey locations */ for (i=0; i MENU_LEFT) && (mouse_x < MENU_LEFT + BUTTON_WIDTH) && (mouse_y < MENU_TOP) && (mouse_y > (MENU_TOP - NUM_BUTTONS * BUTTON_HEIGHT))) return BUTTON_CLICK; else return OTHER_CLICK; } /* Process button click at location x, y. React appropriately */ void handle_button(int x, int y, int *target_direction, int *wind_speed, int *num_bananas, int banana_x[], int banana_y[]) { int buttonNum; /* number of selected button */ /* Complain if x coordinate couldn't be inside a button */ if (x < MENU_LEFT || x > MENU_LEFT + BUTTON_WIDTH) { something_is_wrong(); return; } /* Convert y coordinate to button number from top. */ buttonNum = (MENU_TOP - y)/BUTTON_HEIGHT; switch(buttonNum) { case 0: /* drop bananas */ *num_bananas = NUM_BANANAS; make_bananas(*num_bananas, banana_x, banana_y); break; case 1: /* reverse direction of target movement */ *target_direction = -1 * (*target_direction); break; case 2: /* increase wind speed*/ if (*wind_speed < MAX_WIND) *wind_speed = *wind_speed + 2; break; case 3: /* decrease wind speed */ if (*wind_speed > -MAX_WIND) *wind_speed = *wind_speed - 2; break; default: /*Bad news if this is ever reached! */ GP142_animate(ANI_HALT); something_is_wrong(); break; } } /* Process use of the keyboard */ void handle_keypress(int key_pressed, int *gun_y, int gun_x, int monkey_x[], int monkey_y[], int *num_monkeys) { switch (key_pressed) { case ' ': /* launch a monkey */ launch_monkey(monkey_x, monkey_y, num_monkeys, gun_x, *gun_y); break; case 'w': case 'W': /* move cannon up */ if (*gun_y <= GP142_YMAX - NUM_BUTTONS * BUTTON_HEIGHT - 30) *gun_y = *gun_y + 5 * UP; break; case 's': case 'S': /* move cannon down */ if (*gun_y >= -GP142_YMAX + 30) *gun_y = *gun_y + 5 * DOWN; break; default: break; } /* end switch */ } /* Counts hits on target and deletes monkeys that are off the screen */ void handle_monkeys(int monkey_x[], int monkey_y[], int *num_monkeys, int *num_hits, int target_x, int target_y) { int i, j; for (i=0; i< *num_monkeys; i++) { if ((abs(monkey_x[i] - target_x) < 30) && (abs(monkey_y[i]- target_y) < 50)) { *num_hits = *num_hits + 1; for(j=i; j < *num_monkeys-1; j++) { monkey_x[j] = monkey_x[j+1]; monkey_y[j] = monkey_y[j+1]; } *num_monkeys = *num_monkeys - 1; } else if (monkey_x[i] > GP142_XMAX) { for(j=i; j < *num_monkeys-1; j++) { monkey_x[j] = monkey_x[j+1]; monkey_y[j] = monkey_y[j+1]; } *num_monkeys = *num_monkeys - 1; } } /*end for */ } /***************************************************************************** ANIMATED OBJECTS *****************************************************************************/ /* Update target coordinate target_y for one tick */ void move_target(int *target_y, int target_dir) { *target_y = *target_y + target_dir * TARGET_SPEED; if (*target_y >= GP142_YMAX + 30) *target_y = - *target_y; else if (*target_y <= -GP142_YMAX -30) *target_y = - *target_y; } /* Move the monkey to the right */ void move_monkey(int *monkey_x, int *monkey_y) { *monkey_x = *monkey_x + 10; } /* Update banana coordinates for one tick */ void move_banana(int *banana_x, int *banana_y, int wind_speed) { *banana_y = *banana_y - BANANA_SPEED; *banana_x = *banana_x + wind_speed; } /* Shoot a monkey from the cannon */ void launch_monkey(int monkey_x[], int monkey_y[], int *num_monkeys, int gun_x, int gun_y) { if (*num_monkeys < MAX_MONKEYS) { *num_monkeys = *num_monkeys + 1; monkey_x[*num_monkeys-1] = gun_x + 60; monkey_y[*num_monkeys-1] = gun_y; } } /*Draw a monkey */ void draw_monkey(int monkey_x, int monkey_y) { GP142_circleXY(BROWN, monkey_x, monkey_y, MONKEY_RADIUS); GP142_circleXY(BROWN, monkey_x + MONKEY_RADIUS, monkey_y+3, 12); GP142_circleXY(BROWN, monkey_x - MONKEY_RADIUS, monkey_y+3, 12); GP142_circleXY(WHITE, monkey_x - MONKEY_RADIUS/3, monkey_y+MONKEY_RADIUS/2, 3); GP142_circleXY(WHITE, monkey_x + MONKEY_RADIUS/3, monkey_y+MONKEY_RADIUS/2, 3); GP142_circleXY(BLACK, monkey_x - MONKEY_RADIUS/3, monkey_y+MONKEY_RADIUS/2, 1); GP142_circleXY(BLACK, monkey_x + MONKEY_RADIUS/3, monkey_y+MONKEY_RADIUS/2, 1); GP142_triangleXY(RED, monkey_x, monkey_y-1, monkey_x+3, monkey_y+3, monkey_x-3, monkey_y+3, FILL); GP142_circleXY(PINK, monkey_x, monkey_y-8, 6); GP142_rectangleXY(BROWN, monkey_x-MONKEY_RADIUS/2, monkey_y-2, monkey_x+MONKEY_RADIUS/2, monkey_y-9, FILL); GP142_rectangleXY(BLACK, monkey_x-MONKEY_RADIUS/2, monkey_y-9, monkey_x+MONKEY_RADIUS/2, monkey_y-10, FILL); } /* creates some bananas to drop */ void make_bananas(int num_bananas, int banana_x[], int banana_y[]) { int i; /* used in for loop */ for(i=0; i