Exemplo n.º 1
0
void Game::calculatePsychic(SceneActor *target){

    calculateCollisions(target);

    Point3f *p = target->getPosition();
    Point3f f = target->getForce();
    Point3f newF;

    //kalkulacja nowych sil
    newF.x = (f.x + target->gameState.force.x) * target->getFriction();
    newF.y = (f.y + target->gameState.force.y) * target->getFriction();

    //zdarzenie gdy sila na x przestala oddzialywac
    if(newF.x < 0.001f && newF.x > -0.001f){
        target->gameState.zeroForce = true;
        newF.x = 0;
    }

    //gdy sila na osi y przestala oddzialywac
    if(newF.y < 0.001f && newF.y > -0.001){
        newF.y = 0;
    }

    //maksymalna oddzialywana sila
    if(newF.x > 10){
        newF.x = 10;
    } else if(newF.x < -10) {
        newF.x = -10;
    }

    target->setPosition(new Point3f(p->x+newF.x, p->y+newF.y, 0));
    target->setForce(&newF);
    target->update();
    target->gameState = GameState();
}
Exemplo n.º 2
0
/**
 * main application method
 * 
 * usage / command line arguments
 * xgravity [planet count] [calculation threads]
 * 
 * @param argc
 * @param argv
 */
int main(int argc, char *argv[]) {
  
  pthread_t calcThreads[MAX_THREADS];
  pthread_barrier_t calcBarrier;
  pthread_mutex_t calcMutex = PTHREAD_MUTEX_INITIALIZER;
  calcArgs calcThreadArgs;
  int threads; // number of calculation threads to run
  
  planet *planets[MAXCOUNT];
  planet *aPlanet;
  
  double minx, maxx, miny, maxy, cx, cy, massMax, massMin, timeFactor, forceMultiplier, radiusScale;
  int pi, count; // planet iterator
  long int zoomFactor; // zoom factor
  int centerID; // id of object to use for auto centering
  int radius; // radius in pixels

  double fg, td, dist; // temporary accelerating force and direction
  
  int shownum; // show stat numbers flag
  int showforce; // show force lines flag

  int winw, winh; // window dimensions

  Display *display;
  int screen;
  Window window;
  XEvent event;
  KeySym key;
  char text[255];
  Pixmap pixmap;
  GC gc;
  Colormap colormap;
  
  XGCValues values_return;
  XFontStruct *font_info;
  GContext gid;

  
  // check for planet count in arguments
  if( argc > 1 ) {
    // first argument is planet count
    count = atoi(argv[1]);
    if( count > MAXCOUNT ) count = MAXCOUNT;
  }
  else {
    count = COUNT;
  }
  
  // check for thread count in arguments
  if( argc > 2 ) {
    // first argument is planet count
    threads = atoi(argv[2]);
    if ( threads < 1 )
    {
      threads = THREAD_COUNT;
    }
    else if ( threads > MAX_THREADS )
    {
      threads = MAX_THREADS;
    }
  }
  else {
    threads = THREAD_COUNT;
  }

  // set default control values
  timeFactor = 1; // calculation time factor in seconds
  zoomFactor = 4; // start zoomed out a bit
  forceMultiplier = 1e-8; // need a small multiplier to shrink force lines
  shownum = 0; // do not show numbers
  showforce = 0; // do not show force lines
  centerID = -1; // not centered on any planets
  winw = WINW;
  winh = WINH;
  cx = 0;
  cy = 0;

  // setup Xwindow
  display = XOpenDisplay(NULL);
  if( display == NULL) {
    printf("Cannot open display\n");
    exit(1);
  }

  screen = DefaultScreen(display);
  window = XCreateSimpleWindow(
    display, 
    RootWindow(display, screen), 
    10, 
    10, 
    winw, 
    winh, 
    1,
    WhitePixel(display, screen), 
    BlackPixel(display, screen));
  XMapWindow(display, window);
  XFlush(display);

  // show the window ID in case need to use for screen grab / cast
  printf("Window ID:%d\r\n", window);

  XSelectInput (display, window, KeyPressMask | StructureNotifyMask | ButtonPressMask);

  pixmap = XCreatePixmap(display, window, winw, winh, DefaultDepth(display, screen));
  XFlush(display);

  colormap = DefaultColormap(display, 0);
  gc = XCreateGC(display, pixmap, 0, 0);

  // define color codes
  char *colorCodes[] = {
    "#009900",
    "#4444FF",
    "#FF4400",
    "#FFFFFF",
    "#000000",
    "#FFFF00",
    "#A0A0A0",
    "#E0D1FF"
  };
  
  // create colors for palette
  XColor drawColors[COLOR_COUNT];
  for(pi = 0; pi < COLOR_COUNT; pi++)
  {
    XParseColor(display, colormap, colorCodes[pi], &drawColors[pi]);
    XAllocColor(display, colormap, &drawColors[pi]);
  }
  
  gid = XGContextFromGC(gc);
  font_info = XQueryFont(display, gid);

  XSetForeground(display, gc, drawColors[COLOR_BACKGROUND].pixel);
  XFillRectangle(display, pixmap, gc, 0, 0, winw, winh);
  XCopyArea(display, pixmap, window, gc, 0, 0, winw, winh, 0, 0);
  XFlush(display);

  
  // allocate memory for planet data
  for ( pi = 0; pi < count; pi++ ) {
    planets[pi] = (planet *) malloc(sizeof(planet));
  }
  
  // initialize planets
  randomizePlanets(planets, count);

  // initialize the thread barrier to thread count plus main
  pthread_barrier_init(&calcBarrier, NULL, threads + 1);

  // collect thread arguments into struct
  calcThreadArgs.planetData = planets;
  calcThreadArgs.count = count;
  calcThreadArgs.calcBarrier = &calcBarrier;
  calcThreadArgs.calcMutex = &calcMutex;
  
  // initialize threads
  for(pi = 0; pi < threads; pi++)
  {
    pthread_create(&calcThreads[pi], NULL, &calcWorker, &calcThreadArgs);
  }
  
  // main application loop
  while(1) {

    // keyboard events
    if( XCheckMaskEvent(display, KeyPressMask, &event) && XLookupString(&event.xkey, text, 255, &key, 0)==1 ) {
      // quit
      if (text[0]=='q') {
        XCloseDisplay(display);
        exit(0);
      }
      
      // toggle show force lines
      if( text[0] == 'f' ) {
        showforce += 1;
        if( showforce > 3 ) showforce = 0;
      }
      
      // adjust force line multiplier dimension
      if( text[0] == 'd' ) forceMultiplier = forceMultiplier / 10;
      if( text[0] == 'D' ) forceMultiplier = forceMultiplier * 10;
      
      // toggle show stat numbers
      if( text[0] == 'o' ) {
        shownum += 1;
        if( shownum > 6 ) shownum = 0;
      }
      
      // toggle calculation time factor in seconds
      else if( text[0] == 't' ) timeFactor = timeFactor / 10;
      else if( text[0] == 'T' ) timeFactor = timeFactor * 10;
      
      // zoom in
      else if( text[0] == 'z' ) {
        zoomFactor -= 1;
        if( zoomFactor < 1 ) zoomFactor = 1;
      }
      else if( text[0] == 'Z' ) {
        zoomFactor = zoomFactor / 2;
        if( zoomFactor < 1 ) zoomFactor = 1;
      }
      
      // zoom out
      else if( text[0] == 'x' ) zoomFactor += 1;
      else if( text[0] == 'X' ) zoomFactor = 2 * zoomFactor;
      
      // reset view to no zoom
      else if( text[0] == 'v' ) zoomFactor = 1;
      
      // reset center
      else if( text[0] == 'c' ) {
        cx = 0;
        cy = 0;
      }
      
      // auto zoom to show all planets
      else if( text[0] == 'a' ) {
        minx = 0;
        maxx = 0;
        miny = 0;
        maxy = 0;
        
        // use planets to find minimum and maximum position values for zoom window
        for(pi = 0; pi < count; pi++) {
          if( planets[pi]->mass > 0 ) {
            if( planets[pi]->x < minx ) minx = planets[pi]->x - 500;
            if( planets[pi]->x > maxx ) maxx = planets[pi]->x + 500;
            if( planets[pi]->y < miny ) miny = planets[pi]->y - 500;
            if( planets[pi]->y > maxy ) maxy = planets[pi]->y + 500;
          }
        }
        
        // calculate zoom factor
        if( (maxx - minx) / (double)winw > (maxy - miny) / (double)winh ) zoomFactor = (long int)((maxx - minx) / (double)winw);
        else zoomFactor = (long int)((maxy - miny) / (double)winh) + 1;

        // fractional zoom not allowed
        if( zoomFactor < 1 ) zoomFactor = 1;

        // recenter view
        cx = (double)-1.0 * (minx + (maxx - minx) / (double)2.0);
        cy = (double)-1.0 * (miny + (maxy - miny) / (double)2.0);
      }
      
      // re-randomize planets
      else if( text[0] == 'r' ) {
        randomizePlanets(planets, count);
      }
      
      // wipe all planets
      else if( text[0] == 'w' ) {
        massMax = 0;
        massMin = DBL_MAX;
        clearPlanets(planets, count);
      }
      
      else if( text[0] == 's' ) {
        // create a gravitation well
        createGravityWell(planets, count, cx, cy);
      }
      
      else if( text[0] == 'b' ) {
        // create a binary gravitation well
        createBinaryWell(planets, count, cx, cy);
      }
      
      else if( text[0] == 'h' ) {
        // create a heliocentric system
        createHeliocentricSystem(planets, count, cx, cy);
      }
      
      else if( text[0] == 'g' ) {
        // create some geocentric nonsense
        createGeocentricSystem(planets, count, cx, cy);
      }
      
      else if( text[0] == 'p' ) {
        // create Sol planetary system
        createPlanetarySystem(planets, count, cx, cy);
      }
      else if( text[0] == 'm' ) {
        // create molniya orbit
        createMolniyaOrbit(planets, count, cx, cy);
      }
    } // end of keyboard events

    // window config events
    if( XCheckMaskEvent(display, StructureNotifyMask, &event) && event.type == ConfigureNotify ) {
      if (event.xconfigure.window == window) {
        winw = event.xconfigure.width;
        winh = event.xconfigure.height;
        XFreePixmap(display, pixmap);
        XFlush(display);

        pixmap = XCreatePixmap(display, window, winw, winh, DefaultDepth(display, screen));
        XFlush(display);
      }
    }

    // mouse button events
    if( XCheckMaskEvent(display, ButtonPressMask, &event) ) {
      centerID = -1;

      // if clicked on planet then select as centerID for auto centering
      for(pi = 0; pi < count; pi++) {
        dist = sqrt(pow((cx + planets[pi]->x) / zoomFactor + (winw / 2) - event.xbutton.x, 2) + pow((cy + planets[pi]->y) / zoomFactor + (winh / 2) - event.xbutton.y, 2));
        if( dist < 4 ) {
          centerID = pi;
          continue;
        }
      }

      // if not centered on a planet then recenter to click point
      if( centerID == -1 ) {
        cx += zoomFactor * (winw / 2 - event.xbutton.x);
        cy += zoomFactor * (winh / 2 - event.xbutton.y);
      }
      // keep in mind that cx, cy is not the center coordinate, it is the direction to shift
    }


    // set calculation state on for each planet that has mass
    for(pi = 0; pi < count; pi++)
    {
      if ( planets[pi]->mass > 0 )
      {
        planets[pi]->calc = 1;
      }
    }
    
    // wait for all threads to start calculations
    pthread_barrier_wait(&calcBarrier);
    
    // wait for all threads to end calculations
    pthread_barrier_wait(&calcBarrier);
    
    // move planets after calculations
    movePlanets(timeFactor, planets, count);
    
    // calculate collisions
    calculateCollisions(planets, count);
    massMax = getMassMax(planets, count);
    massMin = getMassMin(planets, count);
        
    // clear display
    XSetForeground(display, gc, drawColors[COLOR_BACKGROUND].pixel);
    XFillRectangle(display, pixmap, gc, 0, 0, winw, winh);

    // if following a planet then recenter display on the planet
    if( centerID > -1 ) {
      cx = -1 * planets[centerID]->x;
      cy = -1 * planets[centerID]->y;
    }

    // set radius scale of kg per pixel
    radiusScale = (massMax - massMin) / (MAX_PIXEL_RADIUS - MIN_PIXEL_RADIUS);
  
    // draw each planet
    for(pi = 0; pi < count; pi++) {
      // if planet has mass and is within the display area then we draw
      if( planets[pi]->mass > 0 && 
          (cx + planets[pi]->x) / zoomFactor > -1 * (winw / 2) && (cx + planets[pi]->x) / zoomFactor < (winw / 2) && 
          (cy + planets[pi]->y) / zoomFactor > -1 * (winh / 2) && (cy + planets[pi]->y) / zoomFactor < (winh / 2) ) {
        // calculate radius relative to mass and other planets
        radius = (int)(planets[pi]->mass / radiusScale) + MIN_PIXEL_RADIUS;

        // determine color by flash or radius divisions
        if( planets[pi]->flash ) {
            XSetForeground(display, gc, drawColors[COLOR_FLASH].pixel);
            radius = radius * planets[pi]->flash;
            planets[pi]->flash -= 1;
        }
        else if( radius > 16 ) {
          // size is color for a star
          XSetForeground(display, gc, drawColors[COLOR_STAR].pixel);
        }
        else if( radius <= 16 && radius > 12 ) {
          // size is color of blue planet
          XSetForeground(display, gc, drawColors[COLOR_BLUE].pixel);
        }
        else {
          // default color for smallest is green
          XSetForeground(display, gc, drawColors[COLOR_GREEN].pixel);
        }

        // draw planet dot
        XFillArc(display, pixmap, gc, 
                 ((cx + planets[pi]->x) / zoomFactor + (winw / 2) - radius / 2), 
                 ((cy + planets[pi]->y) / zoomFactor + (winh / 2) - radius / 2), 
                 radius, radius, 0, 360 * 64);

        // draw black border
        XSetForeground(display, gc, drawColors[COLOR_BLACK].pixel);
        XDrawArc(display, pixmap, gc, 
                 ((cx + planets[pi]->x) / zoomFactor + (winw / 2) - radius / 2), 
                 ((cy + planets[pi]->y) / zoomFactor + (winh / 2) - radius / 2), 
                 radius, radius, 0, 360 * 64);

        // show force vectors
        if( showforce > 0 ) {
          switch( showforce ) {
            case 1:
              //draw gravitational force
              XSetForeground(display, gc, drawColors[COLOR_RED].pixel);
              XDrawLine(display, pixmap, gc, 
                 ((cx + planets[pi]->x) / zoomFactor + (winw / 2)),
                 ((cy + planets[pi]->y) / zoomFactor + (winh / 2)),
                 ((cx + planets[pi]->x + (planets[pi]->mass * planets[pi]->acceleration.accelerationX) * forceMultiplier) / zoomFactor + (winw / 2)),
                 ((cy + planets[pi]->y + (planets[pi]->mass * planets[pi]->acceleration.accelerationY) * forceMultiplier) / zoomFactor + (winh / 2)));

              XSetForeground(display, gc, drawColors[COLOR_BLUE].pixel);
              XDrawLine(display, pixmap, gc,
                 ((cx + planets[pi]->x) / zoomFactor + (winw / 2)),
                 ((cy + planets[pi]->y) / zoomFactor + (winh / 2)),
                 ((cx + planets[pi]->x + (planets[pi]->mass * planets[pi]->velocityX * forceMultiplier / 10)) / zoomFactor + (winw / 2)),
                 ((cy + planets[pi]->y + (planets[pi]->mass * planets[pi]->velocityY * forceMultiplier / 10)) / zoomFactor + (winh / 2)));

              break;

            case 2:
             //draw gravitational acceleration
              XSetForeground(display, gc, drawColors[COLOR_WHITE].pixel);
              XDrawLine(display, pixmap, gc,
                 ((cx + planets[pi]->x) / zoomFactor + (winw / 2)),
                 ((cy + planets[pi]->y) / zoomFactor + (winh / 2)),
                 ((cx + planets[pi]->x + (planets[pi]->acceleration.accelerationX) * forceMultiplier) / zoomFactor + (winw / 2)),
                 ((cy + planets[pi]->y + (planets[pi]->acceleration.accelerationY) * forceMultiplier) / zoomFactor + (winh / 2)));

              break;
          }
        }

        // show stat values
        if( shownum > 0 ) {
          // set text color
          XSetForeground(display, gc, drawColors[COLOR_WHITE].pixel);

          switch( shownum ) {
            // show planet id number
            case 1:
              sprintf(text, "ID:%d", pi);
              break;

            // show planet mass
            case 2:
              sprintf(text, "%2.2E kg", planets[pi]->mass);
              break;

            // show planet velocity
            case 3:
              fg = sqrt(pow(planets[pi]->velocityX, 2) + pow(planets[pi]->velocityY, 2));
              td = atan2(planets[pi]->velocityY, planets[pi]->velocityX);
              if( isinf(td) ) td = M_PI / 2;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) > 0 ) td = 0;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) < 0 ) td = M_PI;
              td = td * 180 / M_PI + 180;
              sprintf(text, "%2.2G m/s %3.0f degrees", fg, td);
              break;

            // show planet coordinates
            case 4:
              sprintf(text, "%G, %G", planets[pi]->x, planets[pi]->y);
              break;

            // show mass and velocity
            case 5:
              fg = sqrt(pow(planets[pi]->velocityX, 2) + pow(planets[pi]->velocityY, 2));
              td = atan2(planets[pi]->velocityY, planets[pi]->velocityX);
              if( isinf(td) ) td = M_PI / 2;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) > 0 ) td = 0;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) < 0 ) td = M_PI;
              td = td * 180 / M_PI + 180;
  //font_info
  //font_height = font_info->max_bounds.ascent +
  //font_info->max_bounds.descent;

              sprintf(text, "%2.2E kg", planets[pi]->mass);
              XDrawString(display, pixmap, gc, 
                          (cx + planets[pi]->x) / zoomFactor + (winw / 2), 
                          (cy + planets[pi]->y) / zoomFactor + (winh / 2) + 
                            font_info->max_bounds.ascent +
                            font_info->max_bounds.descent, 
                          text, strlen(text));
              sprintf(text, "%2.2G m/s %3.0f degrees", fg, td);

              break;

            // show inertia and acting gravitational force
            case 6:
              fg = planets[pi]->mass * sqrt(pow(planets[pi]->velocityX, 2) + pow(planets[pi]->velocityY, 2));
              td = atan2(planets[pi]->velocityY, planets[pi]->velocityX);
              if( isinf(td) ) td = M_PI / 2;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) > 0 ) td = 0;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) < 0 ) td = M_PI;
              td = td * 180 / M_PI + 180;

              sprintf(text, "   P = %2.2G Ns %3.0f degrees", fg, td);
              XDrawString(display, pixmap, gc,
                          (cx + planets[pi]->x) / zoomFactor + (winw / 2),
                          (cy + planets[pi]->y) / zoomFactor + (winh / 2) +
                            font_info->max_bounds.ascent +
                            font_info->max_bounds.descent,
                          text, strlen(text));


              fg = planets[pi]->mass * sqrt(pow(planets[pi]->acceleration.accelerationX, 2) + pow(planets[pi]->acceleration.accelerationY, 2));
              td = atan2(planets[pi]->acceleration.accelerationY, planets[pi]->acceleration.accelerationX);
              if( isinf(td) ) td = M_PI / 2;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) > 0 ) td = 0;
              if( isnan(td) && (planets[pi]->velocityX - planets[pi]->velocityX) < 0 ) td = M_PI;
              td = td * 180 / M_PI + 180;
              sprintf(text, "   Fg = %2.2G N %3.0f degrees", fg, td);

              break;

          }
          
          XDrawString(display, pixmap, gc, (cx + planets[pi]->x) / zoomFactor + (winw / 2), (cy + planets[pi]->y) / zoomFactor + (winh / 2), text, strlen(text));
        }
      }
    }

    // apply drawn bitmap
    XCopyArea(display, pixmap, window, gc, 0, 0, winw, winh, 0, 0);
    XFlush(display);

  }

  XCloseDisplay(display);

}