// File: sprite.cxx // Written by: Suzanne Gallahar and Michael Main (March 15, 2007) // This program implements a simple game to illustrate how to animate // simple sprites. #include // Provides bgi graphics #include // Provides sqrt struct Sprite { double x, y; // Current location int color; // BGI color char letter; // Character that symbolizes sprite int leader_index; // Index of the sprite I am following bool following_mouse; // Am I following the mouse? (if true, leader_index irrelevant) double speed; // In pixels/second double personal_space; // Don't get closer than this many pixels to your leader }; int const DELAY = 75; // Delay time each time through the simloop (in ms) int const WINDOW_SIZE = 350; // BGI window length and height (in pixels) int const SNAKE_SIZE = 5; // # of sprites in snake int const OTHER_SPRITES = 3; // # of other sprites in the game int const TOTAL_SPRITES = SNAKE_SIZE + OTHER_SPRITES; void change_next_sprite(Sprite next, Sprite sprites); void change_state(Sprite sprites[], int size); void draw_next_sprite(Sprite next); void get_commands(Sprite& rudella, bool& is_icy); bool is_close(Sprite s1, Sprite s2); void redraw_screen(Sprite sprites[], int size, bool is_icy); int main() { bool is_icy = false; double time_to_freeze = 3000; //milliseconds Sprite sprites[TOTAL_SPRITES] = { {0, 0, COLOR(255,0,0), 'O', 5, false, 10, 0}, //five {0, 0, COLOR(255,0,0), '0', 0, false, 10, 12}, //parts {0, 0, COLOR(255,0,0), 'o', 1, false, 10, 12}, //of {0, 0, COLOR(255,0,0), ':', 2, false, 10, 12}, //the {0, 0, COLOR(255,0,0), '.', 3, false, 10, 12}, //snake {0, WINDOW_SIZE-20, CYAN, '*', -1, true, 20, 0}, //index 5, Our heroine, Rudella {WINDOW_SIZE-20, 0, YELLOW, '$', 6, false, 0, 1}, //index 6, The gold {WINDOW_SIZE -20, WINDOW_SIZE-20, WHITE, 'D', 7, false, 0, 1} //index 7, The exit door }; Sprite& head = sprites[0]; Sprite& rudella = sprites[5]; Sprite& gold = sprites[6]; Sprite& door = sprites[7]; // Open the graphics window with double buffering: initwindow(WINDOW_SIZE, WINDOW_SIZE, "Rudella and the Snake", 0, 0, true); // Simulation loop (each iteration simulates DELAY milliseconds): while(true) { // Get commands from the game-player: get_commands(rudella, is_icy); // Change the state of the game: change_state(sprites, TOTAL_SPRITES); // Redraw the screen and swap the drawing buffer with the visible buffer: redraw_screen(sprites, TOTAL_SPRITES, is_icy); swapbuffers( ); delay(DELAY); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Changes the state of next as if DELAY milliseconds have passed. // The second parameter is needed in case next is moving toward one of the // other sprites. void change_next_sprite(Sprite& next, Sprite sprites[]) { double target_x, target_y; // Pixel coordinates sprite is trying to reach double distance, delta_x, delta_y; // Distance from targets to current point double step_size, step_x, step_y; // # of pixels to move this bird now double ratio; // Ratio of step_size::here-->target // Figure out where the target is and how far away it is: if(next.following_mouse) { target_x = mousex(); target_y = mousey(); } else { target_x = sprites[next.leader_index].x; target_y = sprites[next.leader_index].y; } delta_x = target_x - next.x; delta_y = target_y - next.y; distance = sqrt(delta_x*delta_x + delta_y*delta_y); if (distance <= next.personal_space) return; // Compute how far to move for total step, x direction and y direction step_size = next.speed * DELAY / 1000; if (distance - step_size < next.personal_space) step_size = distance - next.personal_space; ratio = step_size/distance; step_x = ratio * delta_x; step_y = ratio * delta_y; // Move the bird! next.x += step_x; next.y += step_y; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void change_state(Sprite sprites[], int size) { int i; //Loop variable for(i=0; i(next.x), static_cast(next.y)); //Flush buffer } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void get_commands(Sprite& rudella, bool& is_icy) { if(kbhit()) { switch(getch()) { case 27: //Code for escape character rudella.x = rand() % WINDOW_SIZE; rudella.y = rand() % WINDOW_SIZE; break; case ' ': is_icy = true; break; case 'Q': case 'q': exit(EXIT_SUCCESS); break; default: break; } } if(ismouseclick(WM_LBUTTONDOWN)) { is_icy = true; clearmouseclick(WM_LBUTTONDOWN); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool is_close(Sprite s1, Sprite s2) { double delta_x, delta_y, distance; delta_x = s1.x - s2.x; delta_y = s1.y - s2.y; distance = sqrt(delta_x*delta_x + delta_y*delta_y); return (distance <= s1.personal_space) || (distance < s2.personal_space); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void redraw_screen(Sprite sprites[], int size, bool is_icy) { int i; //Loop variable clearviewport(); if(is_icy) { setfillstyle(SLASH_FILL, CYAN); bar(0, 0, WINDOW_SIZE-1, WINDOW_SIZE-1); } for(i=0; i