home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w023 / 5.ddi / CELPOC.001 / GRAVITY.POC < prev    next >
Encoding:
Text File  |  1990-10-24  |  12.3 KB  |  480 lines

  1. /*****************************************************************************
  2.  * gravity.poc - Move some celestial bodies around on the screen, based
  3.  *                 loosely on the laws of gravity.
  4.  *                 (The universe according to Pete.)
  5.  *
  6.  ****************************************************************************/
  7.  
  8. #ifdef __TURBOC__
  9.   typedef short Boolean;
  10. #endif
  11.  
  12. #define    TRUE            1
  13. #define FALSE             0
  14. #define Success            0
  15.  
  16. #define REALLY_CLOSE    0.01        /* Things closer than this get adjusted  */
  17. #define NEAR_MISS        1.0            /* to NEAR_MISS to prevent collisions.   */
  18.  
  19. #define MAX_PLANETS      32            /* The reasonable max is 8, for speed.   */
  20. #define SLOWDOWN        -0.50        /* On wall-bounce, reverse & half speed. */
  21. #define Z_SCALE         20             /* Z-axis (radius) scaling.                 */
  22.  
  23.  
  24. #define EVENT_CHECK_COUNT     10        /* check user events once every 10 cycles*/
  25.  
  26. #define NO_REQUESTS             0        /* Return values from user request check */
  27. #define EXIT_REQUESTED        1
  28. #define RESTART_REQUESTED      2
  29.  
  30. typedef struct planet {
  31.      double xpos, ypos, zpos;       /* position */
  32.      double xvel, yvel, zvel;       /* velocity */
  33.      double xacc, yacc, zacc;       /* accelleration */
  34.      double pct;                      /* current % of the speed of light */
  35.      double mass;                    /* mass of the planet */
  36.      int    color;                    /* drawing color for this planet */
  37.      } PLANET;
  38.  
  39. PLANET  planets[MAX_PLANETS];
  40. PLANET  *pcur;
  41. PLANET  *pcmp;
  42.  
  43. int        idx_cur_planet;
  44. int        idx_cmp_planet;
  45.  
  46. int        num_planets = 2,
  47.         min_col,
  48.         mid_col,
  49.         max_col,
  50.         min_row,
  51.         mid_row,
  52.         max_row,
  53.         x, y, z;
  54.  
  55. Boolean walls,
  56.         fixed_center;
  57.  
  58. double    gravity_constant,
  59.         vel_constant,
  60.         percnt_light,
  61.         c2,
  62.         xd, yd, zd,
  63.         x2, y2, z2,
  64.         dist2, dist,
  65.         c2dist,
  66.         accel,
  67.         force;
  68.  
  69. int     ocolor2,
  70.         ocolor,
  71.         ofill;
  72. char     oink[16];
  73.  
  74.  
  75. char    mass_prompt[] = "Select the mass category for object number %d:";
  76.  
  77. char    *mass_buttons[] = {
  78.             "Asteroid",
  79.             "Moon",
  80.             "Planet",
  81.             "Dwarf star",
  82.             "Giant star",
  83.             "Abort",
  84.             };
  85. #define    NUM_MASS_BUTTONS 6
  86.  
  87. int        mass_ranges[] = {
  88.     1,50,750,10000,80000,250000,999999999,
  89.     };
  90.  
  91. void prg_init()
  92. /*****************************************************************************
  93.  * do one-time program setup...
  94.  *   init some of our control vars.
  95.  *     save the current state of the PJ drawing attributes we use, then
  96.  *     set those attributes the way we like them.
  97.  ****************************************************************************/
  98. {
  99.  
  100. min_col = 0;
  101. min_row = 0;
  102. GetSize(&max_col, &max_row);
  103. mid_col = max_col / 2;
  104. mid_row = max_row / 2;
  105.  
  106. c2              = 2998.0;        /* speed of light squared                */
  107. vel_constant = 5.0;            /* initial velocity (big bang speed)     */
  108. fixed_center = FALSE;        /* used to anchor first planet to centerscreen */
  109. walls          = TRUE;        /* rubber walls option */
  110.  
  111. ocolor = GetColor();
  112.  
  113. ocolor2 = GetTwoColorOn();
  114. SetTwoColorOn(TRUE);
  115.  
  116. ofill = GetFilled();
  117. SetFilled(TRUE);
  118.  
  119. GetInk(oink);
  120. SetInk("Opaque");
  121.  
  122. }
  123.  
  124. void prg_cleanup()
  125. /*****************************************************************************
  126.  * restore the state of the pj drawing attributes before exiting...
  127.  ****************************************************************************/
  128. {
  129. SetInk(oink);
  130. SetFilled(ofill);
  131. SetColor(ocolor);
  132. SetTwoColorOn(ocolor2);
  133. }
  134.  
  135.  
  136.  
  137. void draw_planet(int x, int y, int z, int index)
  138. /**************************************************************************
  139.  * draw a planet
  140.  *************************************************************************/
  141. {
  142. SetColor(planets[index].color);
  143. Circle(x, y, z/Z_SCALE);
  144. }
  145.  
  146.  
  147. int check_requests()
  148. /*****************************************************************************
  149.  * see if the user wants anything...
  150.  ****************************************************************************/
  151. {
  152. int mx, my, bl, br, key;
  153. int retval = NO_REQUESTS;
  154.  
  155. HideCursor();        /* Don't want to see mouse cursor */
  156. PollInput(&mx, &my, &bl, &br, &key);
  157. ShowCursor();
  158.  
  159. if (br)                            /* right-button is an immediate exit */
  160.     retval = EXIT_REQUESTED;
  161. else
  162.     switch(key & 0xff)
  163.         {
  164.         case 0:
  165.             break;
  166.         case  ' ':                /* space bar clears screen */
  167.             Clear();
  168.             break;
  169.         case 'w':                /* 'w' toggles walls on & off */
  170.         case 'W':
  171.             walls = !walls;
  172.             break;
  173.         case 0x1b:                /* <ESC> causes exit */
  174.             retval = EXIT_REQUESTED;
  175.             break;
  176.         default:                /* other keys restart program at prompt */
  177.             retval = RESTART_REQUESTED;
  178.             break;
  179.         }
  180.  
  181. return retval;
  182.  
  183. }
  184.  
  185. int choose_planet_color(int index)
  186. /*****************************************************************************
  187.  * allow user to choose a color for a planet...
  188.  ****************************************************************************/
  189. {
  190. return(Qcolor());
  191. }
  192.  
  193. Boolean setup_planets()
  194. /*****************************************************************************
  195.  * user has choosen a number of planets, init data structures for each...
  196.  * Return TRUE if all goes well, FALSE if user cancels.
  197.  ****************************************************************************/
  198. {
  199.     char prompt_buf[80];
  200.     int     masstype;
  201.  
  202.     /* set up initial values for each planet... */
  203.  
  204.     for (idx_cur_planet = 0, pcur = planets;
  205.          idx_cur_planet < num_planets;
  206.          idx_cur_planet++, pcur++)
  207.          {
  208.  
  209.          pcur->xacc = 0.0;
  210.          pcur->yacc = 0.0;
  211.          pcur->zacc = 0.0;
  212.  
  213.          pcur->xvel = 0.0;
  214.          pcur->yvel = 0.0;
  215.          pcur->zvel = 0.0;
  216.  
  217.          pcur->pct = 0.0;
  218.  
  219.          if (idx_cur_planet == 0)    /* First planet is mid-screen, no movement */
  220.               {
  221.               pcur->xpos = mid_col;
  222.               pcur->ypos = mid_row;
  223.               pcur->zpos = mid_col;
  224.               }
  225.          else                    /* other planets near mid-screen, w/movement */
  226.               {
  227.               x = (rand() % mid_col) + (rand() % mid_col) - mid_col;
  228.               y = (rand() % mid_row) + (rand() % mid_row) - mid_row;
  229.               z = (rand() % mid_col) + (rand() % mid_col) - mid_col;
  230.  
  231.               dist = sqrt( (x * x) + (y * y) + (z * z) );
  232.  
  233.               pcur->xvel = (x / dist) * vel_constant;
  234.               pcur->yvel = (y / dist) * vel_constant;
  235.               pcur->zvel = (z / dist) * vel_constant;
  236.  
  237.               pcur->xpos = pcur->xvel + mid_col;
  238.               pcur->ypos = pcur->yvel + mid_row;
  239.               pcur->zpos = pcur->zvel + mid_col;
  240.  
  241.               }
  242.  
  243.          /*
  244.           *    let the user choose the general category of the planet
  245.           *  (eg, asteroid, dwarf star, etc), and based on that,
  246.           *  choose a random mass within a range of values based on
  247.           *  the choosen category...
  248.           *  (This general category stuff is because we don't have a
  249.           *  dialog that gets floating point numbers.)
  250.           */
  251.  
  252.          sprintf(prompt_buf, mass_prompt, idx_cur_planet);
  253.          masstype = Qmenu(mass_buttons, NUM_MASS_BUTTONS, prompt_buf);
  254.          if (masstype == 0)
  255.              return(FALSE);
  256.  
  257.          pcur->mass = mass_ranges[masstype] +
  258.                       rand() %
  259.                       (mass_ranges[masstype+1] - mass_ranges[masstype]) ;
  260.  
  261.          pcur->color = choose_planet_color(idx_cur_planet);
  262.  
  263.          }
  264.  
  265.     /*
  266.      * draw planets in initial locations...
  267.      */
  268.  
  269.     for (idx_cur_planet = 0, pcur=planets;
  270.          idx_cur_planet < num_planets;
  271.          idx_cur_planet++,pcur++)
  272.          {
  273.          x = pcur->xpos;
  274.          y = pcur->ypos;
  275.          z = pcur->zpos;
  276.          draw_planet(x,y,z,idx_cur_planet);
  277.          }
  278. return(TRUE);
  279. }
  280.  
  281.           
  282. void main()
  283. /*****************************************************************************
  284.  *
  285.  ****************************************************************************/
  286. {
  287. int    event_counter;    /* used to check for user event once every 10 cycles */
  288.  
  289.     SetAbort(FALSE);    /* Don't abort poco program on keys... */
  290.     
  291.     prg_init();        /* go do one-time setup */
  292.  
  293. PROMPT:                /* loop point to get new values from user... */
  294.  
  295.     Clear();        /* clear screen */
  296.  
  297.     /* find out how many planets the user wants... */
  298.  
  299.     if (0 == Qnumber(&num_planets, 2, MAX_PLANETS, "Select number of planets"))
  300.         goto EXIT;
  301.  
  302.     if (num_planets < 2 || num_planets > MAX_PLANETS)
  303.         goto EXIT;
  304.  
  305.     if (!setup_planets())        /* go init data arrays */
  306.         goto EXIT;
  307.  
  308.     event_counter = EVENT_CHECK_COUNT;
  309.  
  310.     for(;;)
  311.          {
  312.  
  313.          /*
  314.           * nested loop to calc accellerations between each planet...
  315.           */
  316.  
  317.          for(idx_cur_planet = 0, pcur = planets;
  318.               idx_cur_planet < num_planets;
  319.               idx_cur_planet++, pcur++)
  320.               {
  321.               for (idx_cmp_planet = idx_cur_planet + 1,
  322.                     pcmp = &planets[idx_cur_planet+1];
  323.                    idx_cmp_planet < num_planets;
  324.                    idx_cmp_planet++, pcmp++)
  325.                    {
  326.  
  327.                    xd = pcur->xpos - pcmp->xpos;
  328.                    yd = pcur->ypos - pcmp->ypos;
  329.                    zd = pcur->zpos - pcmp->zpos;
  330.  
  331.                    dist  = sqrt( (xd * xd) + (yd * yd) + (zd * zd));
  332.  
  333.                    if (dist < REALLY_CLOSE)    /* collisions never happen in our  */
  334.                         dist = NEAR_MISS;    /* universe, only very near misses */
  335.  
  336. /* pete's latest experiment:
  337.  *   as usual, the accelleration is proportional distance, but the speed
  338.  *   of light is also factored in to account for the observed increase in
  339.  *   mass as velocity approaches c (or something like that)
  340.  */
  341.                    c2dist = c2 * dist;
  342.  
  343.                    accel = (pcmp->mass / c2dist);
  344.                    pcur->xacc += accel * (-xd / dist );
  345.                    pcur->yacc += accel * (-yd / dist );
  346.                    pcur->zacc += accel * (-zd / dist );
  347.  
  348.                    accel = (pcur->mass  / c2dist);
  349.                    pcmp->xacc += accel * (xd / dist );
  350.                    pcmp->yacc += accel * (yd / dist );
  351.                    pcmp->zacc += accel * (zd / dist );
  352.  
  353.                    } /* end cmp loop */
  354.  
  355.              /*
  356.               * apply accumulated accelleration to velocity, then
  357.               * update position based on velocity.
  358.               */
  359.  
  360. #if 0
  361.  /* another pete experiment:
  362.   *   the delta-v is factored by the current percent of c that the
  363.   *   planet is already traveling at.  (this has something to do with
  364.   *   a theory he discovered that says as you approach c it becomes
  365.   *   proportionately harder to achieve further increases in velocity,
  366.   *   or words to that effect.)
  367.   */
  368.  /*
  369.   *      (note that this has been commented out in the poco version.  it
  370.   *      actually does produce a more realistic universe.  but, like the
  371.   *      real universe, it isn't very interesting...everything just sort
  372.   *      ambles around real slowly.)
  373.   *
  374.   */
  375.               pcur->pct = 1 - ( sqrt((pcur->xvel * pcur->xvel) +
  376.                                     (pcur->yvel * pcur->yvel) +
  377.                                     (pcur->zvel * pcur->zvel))
  378.                                 *
  379.                                 sqrt((pcur->xacc * pcur->xacc) +
  380.                                      (pcur->yacc * pcur->yacc) +
  381.                                      (pcur->zacc * pcur->zacc)))
  382.                                 /
  383.                                 c2;
  384.               pcur->xvel = (pcur->xvel + pcur->xacc) * pcur->pct;
  385.               pcur->yvel = (pcur->yvel + pcur->yacc) * pcur->pct;
  386.               pcur->zvel = (pcur->zvel + pcur->zacc) * pcur->pct;
  387. #else
  388.               pcur->xvel = (pcur->xvel + pcur->xacc);
  389.               pcur->yvel = (pcur->yvel + pcur->yacc);
  390.               pcur->zvel = (pcur->zvel + pcur->zacc);
  391. #endif
  392.  
  393.  /*
  394.   * why do the acc values show up again in the following...???
  395.   * must remember to ask pete if this is kosher.
  396.   * (Hmmm, seems to work better when commented out...)
  397.   */
  398.  
  399.               x = (pcur->xpos += pcur->xvel);    // + pcur->xacc) ;
  400.               y = (pcur->ypos += pcur->yvel);    // + pcur->yacc) ;
  401.               z = (pcur->zpos += pcur->zvel);    // + pcur->zacc) ;
  402.  
  403.               pcur->xacc = 0.0;
  404.               pcur->yacc = 0.0;
  405.               pcur->zacc = 0.0;
  406.  
  407.               /*
  408.                * if our universe has rubber walls, process the bounces...
  409.                *    (implements the 'pool table' theory of the universe,
  410.                *    which admittedly hasn't gained a big following amongst
  411.                *    the heavy thinkers in the field <grin>)
  412.                */
  413.  
  414.               if (walls)
  415.                    {
  416.                    if ((x < min_col) || (x > max_col))
  417.                         {
  418.                         if (x < min_col)
  419.                             x = min_col;
  420.                         else
  421.                             x = max_col;
  422.                         pcur->xpos = x;
  423.                         pcur->xvel *= SLOWDOWN;
  424.                         }
  425.  
  426.                    if ((y < min_row) || (y > max_row))
  427.                         {
  428.                         if (y < min_row)
  429.                             y = min_row;
  430.                         else
  431.                             y = max_row;
  432.                         pcur->ypos = y;
  433.                         pcur->yvel *= SLOWDOWN;
  434.                         }
  435.  
  436.                    if ((z < min_col) || (z > max_col))
  437.                         {
  438.                         if (z < min_col)
  439.                             z = min_col;
  440.                         else
  441.                             z = max_col;
  442.                         pcur->zpos = z;
  443.                         pcur->zvel *= SLOWDOWN;
  444.                         }
  445.  
  446.                    } /* END if (walls)  */
  447.  
  448.               draw_planet(x,y,z,idx_cur_planet);
  449.  
  450.               } /* END cur loop */
  451.  
  452.         /*
  453.          * see if the user wants something...
  454.          */
  455.  
  456. #if 0    /* the counter won't work right until abort checking is fixed...*/
  457.  
  458.          if (--event_counter == 0)
  459.             {
  460.             event_counter = EVENT_CHECK_COUNT;
  461. #else
  462.             {
  463. #endif
  464.             switch (check_requests())
  465.                {
  466.                case EXIT_REQUESTED:
  467.                    goto EXIT;
  468.                case RESTART_REQUESTED:
  469.                    goto PROMPT;
  470.                }
  471.             }
  472.  
  473.          } /* END for(;;) loop */
  474.  
  475. EXIT:
  476.  
  477.     prg_cleanup();
  478.  
  479. } /* END main */
  480.