Search code examples
csdlgame-enginevertex

I can not get vertices to rotate correctly around a player


I am creating a classic shooter style game from scratch using C and SDL. I seem to run into an issue I can't figure out.

When I try to rotate the world geometry around the player it seems that it is not rotating correctly.

In theory the distance between the player and the vertex should remain constant after I perform the rotation, but it seems it doesn't in my code.

I've included relevant parts of my code below and a gif of what is happening.

I'd like to understand whats going on here and some guidance on how I can fix it.

recording

for (unsigned s = 0; s < sect->npoints; s++)
{
  // Transform vertex relative to the player view.
  // This will move the room relative to the player.
  float vx1 = sect->vertex[s].x - player.where.x;
  float vx2 = sect->vertex[s+1].x - player.where.x;
  float vy1 = sect->vertex[s].y - player.where.y;
  float vy2 = sect->vertex[s+1].y - player.where.y;

  float test1 = vx1 * vx1 + vy1 * vy1;
  float test2 = vx2 * vx2 + vy2 * vy2;
            
            
  printf("%f %f\n", sqrt(test1), sqrt(test2));
                
  // Rotate the room to the correct orientation using geometry of rotation
  // We want to find t (tx1, tz1) coordinates given the players current orientation.
  // P == player,  v == the vertex in the sector
  // )8 == the angle of the player
  //
  // We can get tx1 = vx1 * player cos - vy1 * player sin
  // and get tz1 = vx1 * player sin - vy1 * player cos
  //  |............................
  // ^|...t (tx1, tz1).............
  // ||../........v (vx1, vy1).....
  // y|./..........................
  // 0|P)8.........................
  //  L-----------------------------
  //   0 x -->
  float pcos = player.anglecos;
  float psin = player.anglesin;
            
  float tx1 = vx1 * psin - vy1 * pcos;
  float tz1 = vx1 * pcos - vy1 * psin;
  float tx2 = vx2 * psin - vy2 * pcos;
  float tz2 = vx2 * pcos - vy2 * psin;

  test1 = tx1 * tx1 + tz1 * tz1;
  test2 = tx2 * tx2 + tz2 * tz2;

  printf("%f %f %f\n\n", sqrt(test1), sqrt(test2), player.angle);

  ...
  // Perform the perspective transformation.
  // This will make sure the correct field of view is being used.
  // TOOD: Adjustible FOV
  float xscale1 = hfov / tz1;
  float yscale1 = vfov / tz1;
  float xscale2 = hfov / tz2;
  float yscale2 = vfov / tz2;

  int x1 = ScreenWidth / 2 - (int)(tx1 * xscale1);
  int x2 = ScreenWidth / 2 - (int)(tx2 * xscale2);
  ...
  int ya = (x - x1) * (y2a-y1a) / (x2-x1) + y1a;
  int yb = (x - x1) * (y2b-y1b) / (x2-x1) + y1b;
                
                
  int cya = clamp(ya, ytop[x], ybottom[x]); // top
  int cyb = clamp(yb, ytop[x], ybottom[x]); // bottom
  rendervline(x, cya, cyb, wall_color);
}

...
// Elsewhere where I handle movement

// mouse aiming
int x, y;
SDL_GetRelativeMouseState(&x,&y);
player.angle += x * 0.03f;

...   
    
player.anglesin = sinf(player.angle);
player.anglecos = cosf(player.angle);

And some sample output for the distance between player and a vertex of an edge.

28.635642 31.304952
29.442936 29.505904 0.070000

Solution

  • I was close the issue was I was subtracting instead of adding for calculating the z axis.

      float tx1 = vx1 * psin - vy1 * pcos;
      float tz1 = vx1 * pcos - vy1 * psin;
      float tx2 = vx2 * psin - vy2 * pcos;
      float tz2 = vx2 * pcos - vy2 * psin;
    
    

    This should have been this.

      float tx1 = vx1 * psin - vy1 * pcos;
      float tz1 = vx1 * pcos + vy1 * psin;
      float tx2 = vx2 * psin - vy2 * pcos;
      float tz2 = vx2 * pcos + vy2 * psin;