home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * gravity.poc - Move some celestial bodies around on the screen, based
- * loosely on the laws of gravity.
- * (The universe according to Pete.)
- *
- ****************************************************************************/
-
- #ifdef __TURBOC__
- typedef short Boolean;
- #endif
-
- #define TRUE 1
- #define FALSE 0
- #define Success 0
-
- #define REALLY_CLOSE 0.01 /* Things closer than this get adjusted */
- #define NEAR_MISS 1.0 /* to NEAR_MISS to prevent collisions. */
-
- #define MAX_PLANETS 32 /* The reasonable max is 8, for speed. */
- #define SLOWDOWN -0.50 /* On wall-bounce, reverse & half speed. */
- #define Z_SCALE 20 /* Z-axis (radius) scaling. */
-
-
- #define EVENT_CHECK_COUNT 10 /* check user events once every 10 cycles*/
-
- #define NO_REQUESTS 0 /* Return values from user request check */
- #define EXIT_REQUESTED 1
- #define RESTART_REQUESTED 2
-
- typedef struct planet {
- double xpos, ypos, zpos; /* position */
- double xvel, yvel, zvel; /* velocity */
- double xacc, yacc, zacc; /* accelleration */
- double pct; /* current % of the speed of light */
- double mass; /* mass of the planet */
- int color; /* drawing color for this planet */
- } PLANET;
-
- PLANET planets[MAX_PLANETS];
- PLANET *pcur;
- PLANET *pcmp;
-
- int idx_cur_planet;
- int idx_cmp_planet;
-
- int num_planets = 2,
- min_col,
- mid_col,
- max_col,
- min_row,
- mid_row,
- max_row,
- x, y, z;
-
- Boolean walls,
- fixed_center;
-
- double gravity_constant,
- vel_constant,
- percnt_light,
- c2,
- xd, yd, zd,
- x2, y2, z2,
- dist2, dist,
- c2dist,
- accel,
- force;
-
- int ocolor2,
- ocolor,
- ofill;
- char oink[16];
-
-
- char mass_prompt[] = "Select the mass category for object number %d:";
-
- char *mass_buttons[] = {
- "Asteroid",
- "Moon",
- "Planet",
- "Dwarf star",
- "Giant star",
- "Abort",
- };
- #define NUM_MASS_BUTTONS 6
-
- int mass_ranges[] = {
- 1,50,750,10000,80000,250000,999999999,
- };
-
- void prg_init()
- /*****************************************************************************
- * do one-time program setup...
- * init some of our control vars.
- * save the current state of the PJ drawing attributes we use, then
- * set those attributes the way we like them.
- ****************************************************************************/
- {
-
- min_col = 0;
- min_row = 0;
- GetSize(&max_col, &max_row);
- mid_col = max_col / 2;
- mid_row = max_row / 2;
-
- c2 = 2998.0; /* speed of light squared */
- vel_constant = 5.0; /* initial velocity (big bang speed) */
- fixed_center = FALSE; /* used to anchor first planet to centerscreen */
- walls = TRUE; /* rubber walls option */
-
- ocolor = GetColor();
-
- ocolor2 = GetTwoColorOn();
- SetTwoColorOn(TRUE);
-
- ofill = GetFilled();
- SetFilled(TRUE);
-
- GetInk(oink);
- SetInk("Opaque");
-
- }
-
- void prg_cleanup()
- /*****************************************************************************
- * restore the state of the pj drawing attributes before exiting...
- ****************************************************************************/
- {
- SetInk(oink);
- SetFilled(ofill);
- SetColor(ocolor);
- SetTwoColorOn(ocolor2);
- }
-
-
-
- void draw_planet(int x, int y, int z, int index)
- /**************************************************************************
- * draw a planet
- *************************************************************************/
- {
- SetColor(planets[index].color);
- Circle(x, y, z/Z_SCALE);
- }
-
-
- int check_requests()
- /*****************************************************************************
- * see if the user wants anything...
- ****************************************************************************/
- {
- int mx, my, bl, br, key;
- int retval = NO_REQUESTS;
-
- HideCursor(); /* Don't want to see mouse cursor */
- PollInput(&mx, &my, &bl, &br, &key);
- ShowCursor();
-
- if (br) /* right-button is an immediate exit */
- retval = EXIT_REQUESTED;
- else
- switch(key & 0xff)
- {
- case 0:
- break;
- case ' ': /* space bar clears screen */
- Clear();
- break;
- case 'w': /* 'w' toggles walls on & off */
- case 'W':
- walls = !walls;
- break;
- case 0x1b: /* <ESC> causes exit */
- retval = EXIT_REQUESTED;
- break;
- default: /* other keys restart program at prompt */
- retval = RESTART_REQUESTED;
- break;
- }
-
- return retval;
-
- }
-
- int choose_planet_color(int index)
- /*****************************************************************************
- * allow user to choose a color for a planet...
- ****************************************************************************/
- {
- return(Qcolor());
- }
-
- Boolean setup_planets()
- /*****************************************************************************
- * user has choosen a number of planets, init data structures for each...
- * Return TRUE if all goes well, FALSE if user cancels.
- ****************************************************************************/
- {
- char prompt_buf[80];
- int masstype;
-
- /* set up initial values for each planet... */
-
- for (idx_cur_planet = 0, pcur = planets;
- idx_cur_planet < num_planets;
- idx_cur_planet++, pcur++)
- {
-
- pcur->xacc = 0.0;
- pcur->yacc = 0.0;
- pcur->zacc = 0.0;
-
- pcur->xvel = 0.0;
- pcur->yvel = 0.0;
- pcur->zvel = 0.0;
-
- pcur->pct = 0.0;
-
- if (idx_cur_planet == 0) /* First planet is mid-screen, no movement */
- {
- pcur->xpos = mid_col;
- pcur->ypos = mid_row;
- pcur->zpos = mid_col;
- }
- else /* other planets near mid-screen, w/movement */
- {
- x = (rand() % mid_col) + (rand() % mid_col) - mid_col;
- y = (rand() % mid_row) + (rand() % mid_row) - mid_row;
- z = (rand() % mid_col) + (rand() % mid_col) - mid_col;
-
- dist = sqrt( (x * x) + (y * y) + (z * z) );
-
- pcur->xvel = (x / dist) * vel_constant;
- pcur->yvel = (y / dist) * vel_constant;
- pcur->zvel = (z / dist) * vel_constant;
-
- pcur->xpos = pcur->xvel + mid_col;
- pcur->ypos = pcur->yvel + mid_row;
- pcur->zpos = pcur->zvel + mid_col;
-
- }
-
- /*
- * let the user choose the general category of the planet
- * (eg, asteroid, dwarf star, etc), and based on that,
- * choose a random mass within a range of values based on
- * the choosen category...
- * (This general category stuff is because we don't have a
- * dialog that gets floating point numbers.)
- */
-
- sprintf(prompt_buf, mass_prompt, idx_cur_planet);
- masstype = Qmenu(mass_buttons, NUM_MASS_BUTTONS, prompt_buf);
- if (masstype == 0)
- return(FALSE);
-
- pcur->mass = mass_ranges[masstype] +
- rand() %
- (mass_ranges[masstype+1] - mass_ranges[masstype]) ;
-
- pcur->color = choose_planet_color(idx_cur_planet);
-
- }
-
- /*
- * draw planets in initial locations...
- */
-
- for (idx_cur_planet = 0, pcur=planets;
- idx_cur_planet < num_planets;
- idx_cur_planet++,pcur++)
- {
- x = pcur->xpos;
- y = pcur->ypos;
- z = pcur->zpos;
- draw_planet(x,y,z,idx_cur_planet);
- }
- return(TRUE);
- }
-
-
- void main()
- /*****************************************************************************
- *
- ****************************************************************************/
- {
- int event_counter; /* used to check for user event once every 10 cycles */
-
- SetAbort(FALSE); /* Don't abort poco program on keys... */
-
- prg_init(); /* go do one-time setup */
-
- PROMPT: /* loop point to get new values from user... */
-
- Clear(); /* clear screen */
-
- /* find out how many planets the user wants... */
-
- if (0 == Qnumber(&num_planets, 2, MAX_PLANETS, "Select number of planets"))
- goto EXIT;
-
- if (num_planets < 2 || num_planets > MAX_PLANETS)
- goto EXIT;
-
- if (!setup_planets()) /* go init data arrays */
- goto EXIT;
-
- event_counter = EVENT_CHECK_COUNT;
-
- for(;;)
- {
-
- /*
- * nested loop to calc accellerations between each planet...
- */
-
- for(idx_cur_planet = 0, pcur = planets;
- idx_cur_planet < num_planets;
- idx_cur_planet++, pcur++)
- {
- for (idx_cmp_planet = idx_cur_planet + 1,
- pcmp = &planets[idx_cur_planet+1];
- idx_cmp_planet < num_planets;
- idx_cmp_planet++, pcmp++)
- {
-
- xd = pcur->xpos - pcmp->xpos;
- yd = pcur->ypos - pcmp->ypos;
- zd = pcur->zpos - pcmp->zpos;
-
- dist = sqrt( (xd * xd) + (yd * yd) + (zd * zd));
-
- if (dist < REALLY_CLOSE) /* collisions never happen in our */
- dist = NEAR_MISS; /* universe, only very near misses */
-
- /* pete's latest experiment:
- * as usual, the accelleration is proportional distance, but the speed
- * of light is also factored in to account for the observed increase in
- * mass as velocity approaches c (or something like that)
- */
- c2dist = c2 * dist;
-
- accel = (pcmp->mass / c2dist);
- pcur->xacc += accel * (-xd / dist );
- pcur->yacc += accel * (-yd / dist );
- pcur->zacc += accel * (-zd / dist );
-
- accel = (pcur->mass / c2dist);
- pcmp->xacc += accel * (xd / dist );
- pcmp->yacc += accel * (yd / dist );
- pcmp->zacc += accel * (zd / dist );
-
- } /* end cmp loop */
-
- /*
- * apply accumulated accelleration to velocity, then
- * update position based on velocity.
- */
-
- #if 0
- /* another pete experiment:
- * the delta-v is factored by the current percent of c that the
- * planet is already traveling at. (this has something to do with
- * a theory he discovered that says as you approach c it becomes
- * proportionately harder to achieve further increases in velocity,
- * or words to that effect.)
- */
- /*
- * (note that this has been commented out in the poco version. it
- * actually does produce a more realistic universe. but, like the
- * real universe, it isn't very interesting...everything just sort
- * ambles around real slowly.)
- *
- */
- pcur->pct = 1 - ( sqrt((pcur->xvel * pcur->xvel) +
- (pcur->yvel * pcur->yvel) +
- (pcur->zvel * pcur->zvel))
- *
- sqrt((pcur->xacc * pcur->xacc) +
- (pcur->yacc * pcur->yacc) +
- (pcur->zacc * pcur->zacc)))
- /
- c2;
- pcur->xvel = (pcur->xvel + pcur->xacc) * pcur->pct;
- pcur->yvel = (pcur->yvel + pcur->yacc) * pcur->pct;
- pcur->zvel = (pcur->zvel + pcur->zacc) * pcur->pct;
- #else
- pcur->xvel = (pcur->xvel + pcur->xacc);
- pcur->yvel = (pcur->yvel + pcur->yacc);
- pcur->zvel = (pcur->zvel + pcur->zacc);
- #endif
-
- /*
- * why do the acc values show up again in the following...???
- * must remember to ask pete if this is kosher.
- * (Hmmm, seems to work better when commented out...)
- */
-
- x = (pcur->xpos += pcur->xvel); // + pcur->xacc) ;
- y = (pcur->ypos += pcur->yvel); // + pcur->yacc) ;
- z = (pcur->zpos += pcur->zvel); // + pcur->zacc) ;
-
- pcur->xacc = 0.0;
- pcur->yacc = 0.0;
- pcur->zacc = 0.0;
-
- /*
- * if our universe has rubber walls, process the bounces...
- * (implements the 'pool table' theory of the universe,
- * which admittedly hasn't gained a big following amongst
- * the heavy thinkers in the field <grin>)
- */
-
- if (walls)
- {
- if ((x < min_col) || (x > max_col))
- {
- if (x < min_col)
- x = min_col;
- else
- x = max_col;
- pcur->xpos = x;
- pcur->xvel *= SLOWDOWN;
- }
-
- if ((y < min_row) || (y > max_row))
- {
- if (y < min_row)
- y = min_row;
- else
- y = max_row;
- pcur->ypos = y;
- pcur->yvel *= SLOWDOWN;
- }
-
- if ((z < min_col) || (z > max_col))
- {
- if (z < min_col)
- z = min_col;
- else
- z = max_col;
- pcur->zpos = z;
- pcur->zvel *= SLOWDOWN;
- }
-
- } /* END if (walls) */
-
- draw_planet(x,y,z,idx_cur_planet);
-
- } /* END cur loop */
-
- /*
- * see if the user wants something...
- */
-
- #if 0 /* the counter won't work right until abort checking is fixed...*/
-
- if (--event_counter == 0)
- {
- event_counter = EVENT_CHECK_COUNT;
- #else
- {
- #endif
- switch (check_requests())
- {
- case EXIT_REQUESTED:
- goto EXIT;
- case RESTART_REQUESTED:
- goto PROMPT;
- }
- }
-
- } /* END for(;;) loop */
-
- EXIT:
-
- prg_cleanup();
-
- } /* END main */
-