// lander.cxx // Written by Dmitry and Michael. // This program is a simple lunar lander game. //--------------------------------------------------------------------------- #include #include #include using namespace std; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // The game's world coordinates are a Cartesian coordinates system in meters // with the ground level at y=0. const double G = -1.6; // Acceleration of gravity on the moon m/sec^2 const double THRUST = 0.5; // Acceleration from kicking up thruster m/sec^2 const double SIMTIME = 0.05; // Seconds to simulate in one frame of animation const int FPS = 20; // Number of frames to run per second const int SX = 851; // Width of the screen in pixels const int SY = 608; // Height of the screen in pixels const double WXMIN = -100.0; // Left side of screen in world coordinates const double WXMAX = 560.0; // Right side of screen in world coordinates const double WYMIN = -17.0; // Bottom of screen in world coordinates const double WYMAX = 373.0; // Top of screen in world coordinates const double WR = 8.0; // Ship radius in world coordinates //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Function prototypes // The draw_background function draws a picture of the moon. The landing // surface should be at world coordinate y=0. void draw_background( ); // Draw little red flames to show which thrusters are on. The lander is // at position (x,y) and the current thruster thrust is (jx, jy). void draw_jets(double x, double y, double jx, double jy); // The draw_lander function draws the lunar lander with the center at (x,y). void draw_lander(double x, double y); // Draw a small vector in a certain color. The starting point of the vector // is (x,y) in world coordinates, and the length of the vector is (ax, ay). void draw_vector(double x, double y, double ax, double ay, int color); // Allow the pilot to control the lander. The pilot can raise or lower the // thrust of the thrusters, which affects the jx and jy (jet acceleration) // values. void interact(double& jx, double& jy); // 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. int pixel(double v, double v0, double v1, int pmax); // Simulate the passage of SIMTIME seconds of time. This could change the // position (x, y) or the velocity (vx, vy) of the lander. void simulate_time (double& x, double& y, double& vx, double& vy, double jx, double jy); //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- int main( ) { double x, y; // Location of the ship in world coordinates (meters) double vx, vy; // Velocity of the ship (meters/sec) double jx, jy; // Acceleration on the ship due to jets (meters/sec^2) // Open the window with double buffering, and initialize variables: initwindow(SX, SY, "That's one small step...", 20, 20, true); x = WXMIN + 0.8*(WXMAX - WXMIN); // 80% of the way across the screen y = WYMIN + 0.8*(WYMAX - WYMIN); // 80% of the way up the screen vx = vy = jx = jy = 0; // Not moving, jets off. // The animation loop simulatates SIMTIME seconds on each iteration. while (y > 0) { // Draw the next frame: draw_background( ); draw_lander(x, y); draw_jets(x, y, jx, jy); // Double buffer and a delay so that we get FPS frames per second: swapbuffers( ); delay(1000/FPS); // Make changes by interacting with the pilot and simulating time: interact(jx, jy); simulate_time(x, y, vx, vy, jx, jy); } // Ten second delay before ending: delay(10000); return EXIT_SUCCESS; } //--------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Note: The first time this function is called, it reads the image from a // file called moon.jpg, and it stores that image in a memory location pointed // to by stored_image. Subsequent calls will just restore the image from that // memory location rather than rereading it from the file. void draw_background( ) { static void* stored_image = NULL; unsigned int storage_size; if (stored_image == NULL) { // Draw the image and make a oopy in stored_image: readimagefile("moon.jpg", 0, 0, SX, SY); storage_size = imagesize(0, 0, SX, SY); stored_image = malloc(storage_size); getimage(0, 0, SX-1, SY-1, stored_image); } else { putimage(0, 0, stored_image, COPY_PUT); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void draw_jets(double x, double y, double jx, double jy) { if (jy > 0) { draw_vector(x, (y - 2.2*WR - jy), 0, jy, RED); } if (jx > 0) { draw_vector((x - 1.1*WR - jx), y, jx, 0, RED); } else if (jx < 0) { draw_vector((x + 1.1*WR - jx), y, jx, 0, RED); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void draw_lander(double x, double y) { // The next group of constants are for drawing the lander const int R = pixel(WXMIN + WR, WXMIN, WXMAX, SX); // const int X1 = int(R*0.15); // Right edge of small inner circle const int X2 = int(R*0.27); // Right edge of the deck const int X3 = int(R*0.70); // Left edge of the right thruster const int X4 = int(R*1.00); // Right edge of the right thruster const int Y1 = int(R*1.10); // Top edge of the thrusters const int Y2 = int(R*1.25); // Top of strut connector to deck const int Y3 = int(R*1.45); // Bottom of strut connector to deck const int Y4 = int(R*1.60); // Top of strut connector to thruster const int Y5 = int(R*2.05); // Bottom of strut connector to thruster const int Y6 = int(R*2.00); // Where the decks start to curve in const int Y7 = int(R*2.20); // Bottom edge of the decks const int Y8 = int(R*2.90); // Bottom edge of the thrusters // Pixel coordinates for the saucer center: int px = pixel(x, WXMIN, WXMAX, SX); int py = pixel(y, WYMAX, WYMIN, SY); // Pixel coordinates for the deck: int deck[12] = { px-X2, py, px-X2, py+Y6, // left edge px-X1, py+Y7, px+X1, py+Y7, // bottom edge px+X2, py+Y6, px+X2, py // right edge }; // Pixel coordinates for the left and right struts: int ls[8] = {px-X1, py+Y2, px-X1, py+Y3, px-X3, py+Y5, px-X3, py+Y4}; int rs[8] = {px+X1, py+Y2, px+X1, py+Y3, px+X3, py+Y5, px+X3, py+Y4}; // Set the color for all the edges: setcolor(BLACK); // Draw the lower deck and struts:: setfillstyle(SOLID_FILL, COLOR(115, 115, 115)); fillpoly(6, deck); setfillstyle(SOLID_FILL, COLOR(156, 156, 156)); fillpoly(4, ls); fillpoly(4, rs); // Draw the saucer and the tiny circle inside of it: setfillstyle(SOLID_FILL, COLOR(156, 156, 156)); fillellipse(px, py, R, R); setfillstyle(SOLID_FILL, COLOR(184, 184, 184)); fillellipse(px, py, X1, X1); // Draw the two thrusters: setfillstyle(SOLID_FILL, COLOR(184, 184, 184)); bar3d(px - X3, py + Y1, px - X4, py + Y8, 0, true); bar3d(px + X3, py + Y1, px + X4, py + Y8, 0, true); } //----------------------------------------------------------------------------- //---------------------------------------------------------------------------- void draw_vector(double x, double y, double ax, double ay, int color) { const int DOT_SIZE = 2; int px1, py1, px2, py2; // Convert the starting point and ending points: px1 = pixel(x, WXMIN, WXMAX, SX); py1 = pixel(y, WYMAX, WYMIN, SY); px2 = pixel(x + ax, WXMIN, WXMAX, SX); py2 = pixel(y + ay, WYMAX, WYMIN, SY); // Connect the points and put a dot at the endpoint: setcolor(color); line(px1, py1, px2, py2); setfillstyle(SOLID_FILL, color); fillellipse(px2, py2, DOT_SIZE, DOT_SIZE); } //---------------------------------------------------------------------------- //----------------------------------------------------------------------------- void interact(double& jx, double& jy) { if (ismouseclick(WM_LBUTTONDOWN)) { jx -= THRUST; clearmouseclick(WM_LBUTTONDOWN); } if (ismouseclick(WM_RBUTTONDOWN)) { jx += THRUST; clearmouseclick(WM_RBUTTONDOWN); } if (kbhit( )) { switch(getch( )) { case KEY_UP: jy += THRUST; break; case KEY_DOWN: if (jy > 0) { jy -= THRUST; } break; } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int pixel(double v, double v0, double v1, int pmax) { double scale = pmax/(v1-v0); return int(scale*(v - v0)); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void simulate_time (double& x, double& y, double& vx, double& vy, double jx, double jy) { x = x + vx*SIMTIME; vx = vx + jx*SIMTIME; y = y + vy*SIMTIME; vy = vy + (jy + G)*SIMTIME; } //-----------------------------------------------------------------------------