Loading...
Logo
Processing Forum
This class represents an "endless" grid that is supposed to scroll under a player ship in a game.  It rotates when the player turns.  There's a strange thing that happens, though; processor usage shoots way up whenever the grid is at 45deg angles to the window edges!  If I am drawing and throwing away the same number of lines per frame, why should the angle matter at all?
Copy code
  1. class GridField{
      float gridSpacing;
      float hLinOrig;
      float vLinOrig;
      float xOffset;
      float yOffset;
      float directionRads;
      float renderLen;
      int index; float measure;
      float raw;
     
      GridField(float spacing, float xStart, float yStart){
        gridSpacing = spacing; xOffset = xStart; yOffset = yStart;
        directionRads = 0.0;
        renderLen = max(WINWIDTH,WINHEIGHT) * 1.5;
        calc_first_lines(xStart, yStart);
        index = 0;
      }
     
      void calc_first_lines(float iX, float iY){
        hLinOrig = - yOffset % gridSpacing;
        vLinOrig = - xOffset % gridSpacing;
      }
     
      void move(float dX, float dY){
        xOffset += dX; yOffset += dY;
      }
     
      void turn(float dir){
        raw = directionRads + dir;
        if(raw < 0){
          directionRads = TWO_PI + raw;
        }else if(raw > TWO_PI){
          directionRads = raw - TWO_PI;
        }else{directionRads = raw;}
        //if(abs(directionRads) > HALF_PI && yOffset > 0){yOffset *= -1;}//else
        //if(abs(directionRads) < HALF_PI && yOffset < 0){yOffset *= -1;}
      }
     
      void place(float iX, float iY, float iBearing){
        xOffset = iX; yOffset = iY; directionRads = iBearing;
      }
     
      void update(){
        pushMatrix();
          //rotate(directionRads);
          translate(wreckerXAnchor,wreckerYAnchor);
          rotate(directionRads);
          index = 1; measure = index * gridSpacing;
          calc_first_lines(xOffset, yOffset);
          line(-0.5 * renderLen, hLinOrig, 0.5 * renderLen, hLinOrig);
          line(vLinOrig, -0.5 * renderLen, vLinOrig, 0.5 * renderLen);
          while(measure < renderLen / 2){
            // draw horizontal lines
            line(-0.5 * renderLen, hLinOrig + measure, 0.5 * renderLen, hLinOrig + measure);
            line(-0.5 * renderLen, hLinOrig - measure, 0.5 * renderLen, hLinOrig - measure);
            // draw vertical lines
            line(vLinOrig + measure, -0.5 * renderLen, vLinOrig + measure, 0.5 * renderLen);
            line(vLinOrig - measure, -0.5 * renderLen, vLinOrig - measure, 0.5 * renderLen);
            // increment for next set of lines
            index++; measure = index * gridSpacing;
          }
          //println(vLinOrig); print(hLinOrig);
          //println(directionRads);
        popMatrix();
      }
    }

Replies(6)

no setup(), no draw() no wreckerXAnchor(). hard to debug stuff if we can't run it...

so, i'm guessing. there's an increment somewhere that you're applying to somethng and at the above angles it gets very small. no trig at all in the example though so i can't tell.

we need to see more, really.
Alright, you can see the sketch in action here; where you can also view and download the code if you so choose.
I will paste what I feel are the most relevant PDE files here as well.  Open your System Performance window and watch the CPU when you turn to 45deg.  It's baffling to me!

This is the main file for the sketch:

Copy code
  1. /**
      * Hoverdrive
      * a top-down drving sim for the A Game By Its Cover competition
      * Square Crow, July 2010
      */
     
    /**
      LOG
      ===
      YYYY-MM-DD: Changes made or new information about the project
     
      TO DO
      =====
      * A bulleted list of changes and features to make
      */
     
    // * Globals *
    int WINWIDTH = 400;  // = 400;
    int WINHEIGHT = 600; // = 400;
    boolean[] KEYS = {false, false, false}; // Holds key states
                   //{up,    left,  right}
    int turnDir = 0; // holds first turn key logged in case of simultaneous LEFT/RIGHT              

    // * Objects and Vars *
    Wrecker Player;
    GridField Ground;
    float[] movement;
    float wreckerXAnchor;
    float wreckerYAnchor;

    // * Setup *

    void setup(){
      size(WINWIDTH,WINHEIGHT);
      //noStroke();
      smooth(); //remove for faster performance
      frameRate(24);
      //noLoop(); // used only for static pictures
      Player = new Wrecker(0.0, 0.0, 0.0, 6.0);
      wreckerXAnchor = 200.0;
      wreckerYAnchor = 400.0;
      Player.win_place(wreckerXAnchor, wreckerYAnchor);
      Ground = new GridField(50.0,0.0,0.0);
      movement = new float[2];
    }

    // * Main Loop *

    void draw(){
      background(150); // repaint background, for animation
      if(KEYS[0]){
        Player.move();
        Ground.move(Player.get_dPos_x(), Player.get_dPos_y());
      }
      if(KEYS[1] || KEYS[2]){
        Player.turn(turnDir * PI/45);
        Ground.turn(-turnDir * PI/45);
      }
      //Ground.place(Player.get_xPos(), Player.get_yPos(), -Player.get_bearing());
      Ground.update();
      Player.update();
    }

    // * Definitions *

    void keyPressed(){
      if(keyCode == UP){KEYS[0] = true;}
      if(keyCode == LEFT && !KEYS[2]){KEYS[1] = true; turnDir = -1;}
      if(keyCode == RIGHT && !KEYS[1]){KEYS[2] = true; turnDir = 1;}
    }

    void keyReleased(){
      if(keyCode == UP){KEYS[0] = false;}
      if(keyCode == LEFT){KEYS[1] = false;}
      if(keyCode == RIGHT){KEYS[2] = false;}
    }
This file is used to draw the player ship, but does not seem relevant to the problem, based on the behavior I have seen:

Copy code
  1. /*
    ==========================================================
     vShape: VERTEX SHAPE
    ==========================================================
    */
     
    class vShape{
      float cenX; float cenY; // center of the shape
      float bearing; // facing direction in rad, 0 == UP
      float[][] template; // [vertexNumber][{dX, dY, radius, angle}]
      float[][] vertices; // last stored position
      int index = 0; // for manual init of points
      color shapeColor = color(255);
     
      vShape(int numPoints, float iX, float iY){
        // contructor for manual init of points
        template = new float[numPoints][4];
        vertices = new float[numPoints][2];
        cenX = iX; cenY = iY;
        bearing = 0;
      }
     
      void make_rect(float iWidth, float iHeight){
        // helper function makes rectangle iWidth by iHeight
        // You must first instantiate a cShape with 4 points
        add_vertex(-iWidth/2, -iHeight/2);
        add_vertex(iWidth/2, -iHeight/2);
        add_vertex(iWidth/2, iHeight/2);
        add_vertex(-iWidth/2, iHeight/2);
      }
     
      void add_vertex(float dX, float dY){
        if(index < template.length){
          template[index][0] = dX; template[index][1] = dY;
          // relative pos expressed as a vector
          template[index][2] = sqrt(pow(dX,2) + pow(dY,2)); // calc radius
          float quadrant_offset = 0;
          float raw = atan(-dX/dY);
          if(dX > 0 && dY > 0){quadrant_offset = -PI;} else
          if(dX < 0 && dY > 0){quadrant_offset = PI;}
          template[index][3] = raw + quadrant_offset; // calc theta
          index++;
        } else {println("cShape.add_vertex: attepted to add too many vertices!");}
      }
     
      void add_vertex_as_vector(float radius, float theta){
        // In the case that it is easier to express vertices as a vertex from the center
        if(index < template.length){
          template[index][0] = -1; template[index][1] = -1; //never used again
          // relative pos expressed as a vector
          template[index][2] = radius;
          template[index][3] = theta;
          index++;
        } else {println("cShape.add_vertex_as_vector: attepted to add too many vertices!");}
      }
     
      void calc_points(){
        // calculate and store absolute position of points in the shape
        for(int i = 0; i < template.length; i++){
          vertices[i][0] = cenX + template[i][2] * sin(bearing+template[i][3]);
          vertices[i][1] = cenY + template[i][2] * cos(bearing+template[i][3]) * -1;
        }
      }
     
      void set_bearing(float newTheta){
        // set bearing to a specified angle
        bearing = normalize_2PI(newTheta);
        //calc_points();
      }
     
      void change_bearing(float dTheta){
        // change bearing by a specified amount
        bearing = normalize_2PI(bearing + dTheta);
        //calc_points();
      }
     
      void set_center(float iX, float iY){
        // set the absolute position of figure center
        cenX = iX; cenY = iY;
        calc_points();
      }
     
      void move(float dX, float dY){
        // move the figure center by a specified amount
        cenX += dX;
        cenY += dY;
      }
     
      void move_vector(float distance){
        // move the figure center in direction of bearing by amount
        cenX += distance * sin(bearing);
        cenY += distance * cos(bearing) * -1;
      }
     
      float normalize_2PI(float raw){
        // Normalize bearing to range 0 - 2*PI
        float rtnBearing = 0;
        if(raw < 0){
          rtnBearing = 2*PI + raw;
        }else if(raw > 2*PI){
          rtnBearing = raw - 2*PI;
        }else{rtnBearing = raw;}
        return rtnBearing;
      }
     
      void set_color(int inColor){
        shapeColor = color(inColor);
      }
     
      void set_color(int R, int G, int B){
        shapeColor = color(R, G, B);
      }
     
      void paint(){
        calc_points(); // calculate any transformations made this frame
        fill(shapeColor);
        beginShape();
        for(int i = 0; i < template.length; i++){
          vertex(vertices[i][0],vertices[i][1]);
        }
        vertex(vertices[0][0],vertices[0][1]); // close the loop
        endShape();
      }
    }

Here is Agent class, which Wrecker extends (it doesn't add much):

Copy code
  1. class Agent{
      float xPos; float yPos; // position
      float[] dPos = new float[2]; // move by {dX, dY}
      float bearing; // facing direction in rad, 0 == UP
      float speed; // default movement speed in direction of bearing
     
      Agent(float ix, float iy, float brng, float spd){
        xPos = ix; yPos = iy;
        bearing = brng;
        speed = spd;
        dPos[0] = 0;
        dPos[1] = -speed;
      }
     
      float[] components(float scalar, float theta){
        float[] comp = new float[2];
        comp[0] = scalar * sin(theta);
        comp[1] = scalar * cos(theta) * -1;
        return comp;
      }
     
      void change_bearing(float dTheta){
        // Normalize bearing to range 0 - 2*PI
        float raw = bearing + dTheta;
        if(raw < 0){
          bearing = 2*PI + raw;
        }else if(raw > 2*PI){
          bearing = raw - 2*PI;
        }else{bearing = raw;}
      }
       
      void turn(float turnRate){
        change_bearing(turnRate);
        dPos = components(speed, bearing);
      }
     
      void place(float iX, float iY){
        xPos = iX; yPos = iY;
      }
     
      void move(){
        xPos += dPos[0];
        yPos += dPos[1];
      }
     
      float get_xPos(){return xPos;}
      float get_yPos(){return yPos;}
      float get_bearing(){return bearing;}
     
      float get_dPos_x(){return dPos[0];}
      float get_dPos_y(){return dPos[1];}
     
      void update(){
        // write an update() method for child classes
      }
     
      void paint(){
        // write a paint() method for child classes
      }
    }
The 'slowdown' is 'strange' because in actual fact there is no slowdown: it's just a perceived slowdown.  I tried your code, drawing the frameRate to the screen: there's no significant difference whatever angle the background is at and I see no significant spike in processor usage at a 45 degree angle...

Having said that I'm not sure why you stifle the frameRate at 24fps.  It would look smoother if you increased the frameRate and slowed down the motion by reducing the turn and speed variables...
Thanks, blindfish.  I am marking your response as having answered the question even though you flatly denied events that happened on my own computer. 

Your response led me to install the official Oracle Java for 64bit Linux, rather than the 32bit IcedTea version.  With Tea, I could actually see my processor peg at 100% when I was running this sketch.  Not so with the official version.  There is a good reason Processing 1.2 warns against using Iced Tea.  There is still a small rise in CPU load near 45deg, but I am ignoring it because there is no longer a slowdown.  I was killing myself with repeated line-by-line reviews looking for the problem, oops!

It makes me wonder what sort of peculiarities within Iced Tea might have caused the issue!

Core 2 Duo 2GHz running XP: always ran fine
AMD Sempron 2Ghz 64b running Ubuntu 10.04 Lynx: slowdown fixed by using official Oracle Java

Therefore I would like to take this chance to share the following with Processing/Linux users:
* Oracle Java runs better than Iced Tea for graphics, it also helps to pick the version appropriate to your architecture.
* Oracle Java 64b works fine for browser applets.  The Java download has a strange warning not to use the 64b for applets, but this is apparently false.
Obviously I could only report the behaviour of your code from my perspective...  If nothing else I confirmed that the issue was local to your installation; so glad to be of (some) service :)
ok, i can see now that your using atan() and the atan reference page does mention +/- PI/2 specifically

http://processing.org/reference/atan_.html

which makes me suspicious.

does it work any better using atan2() (which does the same thing)?

and yes, it's useful if people put operating system, processing version and java details when they post problems. it shouldn't matter, but often it does.