// File: rocket.cxx // This program simulates a falling object with a rocket. #include #include #include using namespace std; // Physics constants const double LATERAL_PROP = .5; // Proportion const double GRAVITY = -9.8; // m/s^2 const double LANDER_WEIGHT = 1000; // kg const double MAX_FUEL = 0.25*LANDER_WEIGHT; // kg const double THRUST_Y = -2*GRAVITY*(LANDER_WEIGHT + MAX_FUEL);// kg m/s^2 const double THRUST_X = THRUST_Y * LATERAL_PROP; // kg m/s^2 const double MAX_X = 500; // m const double MAX_Y = 1000; // m const double INITIAL_SPEED_X = 0; // m/s const double INITIAL_SPEED_Y = 0; // m/s const double BURN_RATE_Y = MAX_FUEL / 30; // kg/s const double BURN_RATE_X = BURN_RATE_Y * LATERAL_PROP; // kg/s const double MAX_LANDING_SPEED = 9.0; // m/s const int TIME_SLICE_MS = 100; // ms const double TIME_SLICE_S = TIME_SLICE_MS/1000.0; // s // Graphical constants const int WINDOW_SIZE_X = 851; const int WINDOW_SIZE_Y = 608; const int GROUND_ZERO_Y = 566; const int ROCKET_SIZE_X = 86; const int ROCKET_SIZE_Y = 113; const int BACKGROUND_BYTES = 2069656; // From the imagesize bgi function const int ROCKET_BYTES = 38896; // From the imagesize bgi function // These functions shows the current state of the lander. void display_background( ); void display_rocket( double x, double y, // Position bool main_thruster, // Thrusters on? bool left_thruster, bool right_thruster ); void display( int time, // Simulation time double x, double y, // Position double vx, double vy, // Velocity double fuel, // Remaining fuel bool main_thruster, // Thrusters on? bool left_thruster, bool right_thruster ); // The return value of fuel_use is the amount of fuel that a rocket // uses during one time slice double fuel_use(bool is_on, double burn_rate, double fuel); // The return value of rocket_acceleration is the acceleration // in m/(sec^2) of a particular rocket. double rocket_acceleration(bool is_on, double force, double mass); // This function checks to see whether the user has done anything // to change the state of the thrusters (on or off). void interact(bool& main_thruster, bool& left_thruster, bool& right_thruster); // This function lets you turn the thrusters on or off with mouse clicks. // But the middle mouse click doesn't work on my machine. void deal_with_mouse(bool& thruster, int turn_on, int turn_off); int main( ) { // State variables bool main_thruster = false; // Main thruster bool left_thruster = false; // Left thruster bool right_thruster = false; // Right thruster double remaining_fuel = MAX_FUEL; // Remaining fuel double mass; // Mass of lander + fuel double x = 0; // X position double y = MAX_Y; // Y position double x_velocity = INITIAL_SPEED_X; // Lander's X velocity double y_velocity = INITIAL_SPEED_Y; // Lander's Y velocity double x_acc = 0; // Lander's X acceleration double y_acc = 0; // Lander's X acceleration int current_time = 0; // Current time (ms) initwindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "Crash the Ship!", 0, 0, true); bgiout.precision(1); bgiout.setf(ios::fixed, ios::floatfield); while (y > 0) { // 1. Modify state variables based on user input: interact(main_thruster, left_thruster, right_thruster); // 2. Modify state variables based on time passing: remaining_fuel -= fuel_use(main_thruster, BURN_RATE_Y, remaining_fuel); remaining_fuel -= fuel_use(left_thruster, BURN_RATE_X, remaining_fuel); remaining_fuel -= fuel_use(right_thruster, BURN_RATE_X, remaining_fuel); mass = LANDER_WEIGHT + remaining_fuel; x_acc = rocket_acceleration(left_thruster, THRUST_X, mass) - rocket_acceleration(right_thruster, THRUST_X, mass); y_acc = GRAVITY + rocket_acceleration(main_thruster, THRUST_Y, mass); x += x_velocity * TIME_SLICE_S + 0.5 * x_acc * TIME_SLICE_S * TIME_SLICE_S; y += y_velocity * TIME_SLICE_S + 0.5 * y_acc * TIME_SLICE_S * TIME_SLICE_S; x_velocity += x_acc * TIME_SLICE_S; y_velocity += y_acc * TIME_SLICE_S; current_time += TIME_SLICE_MS; // 3. Display the current state: clearviewport( ); display( current_time, x, y, x_velocity, y_velocity, remaining_fuel, main_thruster, left_thruster, right_thruster ); swapbuffers( ); // 4. Delay for the required time: delay(TIME_SLICE_MS); } while (toupper(getch( )) != 'Q') delay (TIME_SLICE_MS); return 0; } void display( int time, // Simulation time double x, double y, // Position double vx, double vy, // Velocity double fuel, // Remaining fuel bool main_thruster, // Thrusters on? bool left_thruster, bool right_thruster ) { display_background( ); display_rocket(x, y, main_thruster, left_thruster, right_thruster); bgiout << "Lander information: \n" << "Time: " << time << "ms\n" << "Position (x: " << x << "m, y: " << y << "m)\n" << "Velocity (x: " << vx << "m/s, y: " << vy << "m/s)\n" << "Remaining fuel: " << fuel << "kg\n" << "Thrusters: (" << "main:" << main_thruster << ", left:" << left_thruster << ", right:" << right_thruster << ")\n" << endl; outstreamxy(10, 10); } void display_background( ) { static bool first = true; // True if this is the first drawing static void* buffer; // Variable sized location for the image if (first) { buffer = malloc(BACKGROUND_BYTES); readimagefile("bg.bmp",0, 0, WINDOW_SIZE_X-1, WINDOW_SIZE_Y-1); getimage(0, 0, WINDOW_SIZE_X-1, WINDOW_SIZE_Y-1, buffer); first = false; } else { putimage(0, 0, buffer, COPY_PUT); } } void display_rocket( double x, double y, // Position bool main_thruster, // Thrusters on? bool left_thruster, bool right_thruster ) { static bool first = true; // True if this is the first drawing static void* buffer[8]; // Variable sized location for the image int pixel_x, pixel_y; // Location to draw the rocket int index; // Loop control variable char filename[12] = "rocket?.bmp"; pixel_x = int(x*WINDOW_SIZE_X/(2*MAX_X) + WINDOW_SIZE_X/2.0); pixel_y = int(-y*GROUND_ZERO_Y/MAX_Y + GROUND_ZERO_Y); if (first) { for (index = 0; index < 8; ++index) { buffer[index] = malloc(ROCKET_BYTES); filename[6] = '0' + index; readimagefile(filename ,0, 0, ROCKET_SIZE_X-1, ROCKET_SIZE_Y-1); getimage(0, 0, ROCKET_SIZE_X-1, ROCKET_SIZE_Y-1, buffer[index]); } first = false; clearviewport( ); } // Figure out which of the 8 images to use... index = 4*main_thruster + 2*left_thruster + 1*right_thruster; putimage(pixel_x-ROCKET_SIZE_X/2, pixel_y-ROCKET_SIZE_Y/2, buffer[index], OR_PUT); } double fuel_use(bool is_on, double burn_rate, double fuel) { if (is_on) return min(burn_rate * TIME_SLICE_S, fuel); else return 0; } double rocket_acceleration(bool is_on, double force, double mass) { if (is_on) return force / mass; else return 0; } void interact (bool& main_thruster, bool& left_thruster, bool& right_thruster) { if (kbhit( )) { switch (getch( )) { case KEY_UP: main_thruster = !main_thruster; break; case KEY_LEFT: right_thruster = !right_thruster; break; case KEY_RIGHT: left_thruster = !left_thruster; break; } } deal_with_mouse(main_thruster, WM_MBUTTONDOWN, WM_MBUTTONUP); deal_with_mouse(right_thruster, WM_LBUTTONDOWN, WM_LBUTTONUP); deal_with_mouse(left_thruster, WM_RBUTTONDOWN, WM_RBUTTONUP); } void deal_with_mouse(bool& thruster, int turn_on, int turn_off) { if (ismouseclick(turn_on)) { thruster = true; clearmouseclick(turn_on); } if (ismouseclick(turn_off)) { thruster = false; clearmouseclick(turn_off); } }