Home Game Development Raycaster rotation problem

Raycaster rotation problem

0
Raycaster rotation problem

[ad_1]

I am following lodevs tutorial on Raycasting https://lodev.org/cgtutor/raycasting.html.
I was kinda successfull but for some reason while implementing a 2D Topdown view of the map and the player i have a rotation problem.
When rotating left in the raycaster view i rotate left. But in the topdown view i rotate to the right. I still am looking in the correct direction where i am supposed to be looking but this irritates me and i dont know why this is.
Here is a link to visualize what i mean: https://youtu.be/c26RObAi2Os.

#include "main.h"
#include "SDL2/SDL_render.h"

int pixels[SCREEN_HEIGHT][SCREEN_WIDTH];
uint textures[8][TEX_WIDTH * TEX_HEIGHT];

int worldMap[MAP_HEIGHT][MAP_WIDTH] = {
    {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7},
    {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 7},
    {4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7},
    {4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7},
    {4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 7},
    {4, 0, 4, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 0, 7, 7, 7, 7, 7},
    {4, 0, 5, 0, 0, 0, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 7, 0, 0, 0, 7, 7, 7, 1},
    {4, 0, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 0, 0, 8},
    {4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 1},
    {4, 0, 8, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 0, 0, 8},
    {4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 7, 7, 7, 1},
    {4, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 1},
    {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
    {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
    {6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
    {4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 6, 0, 6, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3},
    {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2},
    {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 5, 0, 0, 2, 0, 0, 0, 2},
    {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2},
    {4, 0, 6, 0, 6, 0, 0, 0, 0, 4, 6, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 2},
    {4, 0, 0, 5, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2},
    {4, 0, 6, 0, 6, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 5, 0, 0, 2, 0, 0, 0, 2},
    {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2},
    {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3}};

static Player player = {.pos = {.x = 11.5, .y = 11.5},
                        .dir = {.x = -1, .y = 0},
                        .plane = {.x = 0, .y = 0.66}};

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *buffer = NULL;
void initSDL() {
  // Initialize SDL
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
    exit(1);
  }

  window =
      SDL_CreateWindow("Wulf", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                       SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
  if (window == NULL) {
    printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
    exit(1);
  }

  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
  buffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
                             SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH,
                             SCREEN_HEIGHT);
}

void destroySDL() {
  SDL_DestroyWindow(window);
  SDL_Quit();
}

void render() {
  int w = SCREEN_WIDTH / 2;
  int h = SCREEN_HEIGHT;

  for (int x = 0; x < w; x++) {
    // das berechnet welchem x punkt der pixel x auf der
    // kameraebene entspricht links von der richtung in der
    // die der spieler schaut ist der Wert negativ rechts
    // davon ist er positiv und in der mitte ist er NULL es
    // wird also die kameraebene auf den bildschirm gemappt
    double cameraX = 2 * (x / (double)w) - 1;
    double rayDirX = player.dir.x + player.plane.x * cameraX;
    double rayDirY = player.dir.y + player.plane.y * cameraX;

    int mapX = (int)player.pos.x;
    int mapY = (int)player.pos.y;

    double sideDistX;
    double sideDistY;

    double deltaDistX = (rayDirX == 0) ? 1e30 : fabs(1.0f / rayDirX);
    double deltaDistY = (rayDirY == 0) ? 1e30 : fabs(1.0f / rayDirY);
    double perpWallDist;

    int stepX;
    int stepY;

    int hit = 0;
    int side;

    if (rayDirX < 0) {
      stepX = -1;
      sideDistX = (player.pos.x - mapX) * deltaDistX;
    } else {
      stepX = 1;
      sideDistX = (mapX + 1.0 - player.pos.x) * deltaDistX;
    }
    if (rayDirY < 0) {
      stepY = -1;
      sideDistY = (player.pos.y - mapY) * deltaDistY;
    } else {
      stepY = 1;
      sideDistY = (mapY + 1.0 - player.pos.y) * deltaDistY;
    }

    // perform DDA
    while (hit == 0) {
      // jump to next map square, either in x-direction, or in y-direction
      if (sideDistX < sideDistY) {
        sideDistX += deltaDistX;
        mapX += stepX;
        side = 0;
      } else {
        sideDistY += deltaDistY;
        mapY += stepY;
        side = 1;
      }
      // Check if ray has hit a wall
      if (worldMap[mapY][mapX] > 0)
        hit = 1;
    }
    // Calculate distance projected on camera direction (Euclidean distance
    // would give fisheye effect!)
    perpWallDist =
        side == 0 ? (sideDistX - deltaDistX) : (sideDistY - deltaDistY);

    // Calculate height of line to draw on screen
    int lineHeight = (int)(h / perpWallDist);

    // calculate lowest and highest pixel to fill in current stripe
    int drawStart = -lineHeight / 2 + h / 2;
    if (drawStart < 0)
      drawStart = 0;
    int drawEnd = lineHeight / 2 + h / 2;
    if (drawEnd >= h)
      drawEnd = h - 1;
    // texturing calculations
    int texNum = worldMap[mapY][mapX] - 1;

    // calculate value of wallX
    // where exactly the wall was hit betwen 0 and 1 => uniform grid world
    double wallX = side == 0 ? player.pos.y + perpWallDist * rayDirY
                             : player.pos.x + perpWallDist * rayDirX;
    wallX -= floor((wallX));

    // x coordinate on the texture
    int texX = (int)(wallX * (double)TEX_WIDTH);
    if (side == 0 && rayDirX > 0)
      texX = TEX_WIDTH - texX - 1;
    if (side == 1 && rayDirY < 0)
      texX = TEX_WIDTH - texX - 1;

    // SDL_Log("y0:%i y1:%i: color:%i",drawStart,drawEnd ,color);
    double step = 1.0 * TEX_HEIGHT / lineHeight;
    // Starting texture coordinate
    double texPos = (drawStart - (float)h / 2 + (float)lineHeight / 2) * step;
    for (int y = drawStart; y < drawEnd; y++) {
      // Cast the texture coordinate to integer, and mask with (TEX_HEIGHT - 1)
      // in case of overflow
      int texY = (int)texPos & (TEX_HEIGHT - 1);
      texPos += step;
      Uint32 color = textures[texNum][TEX_HEIGHT * texY + texX];
      // make color darker for y-sides: R, G and B byte each divided through two
      // with a "shift" and an "and"
      if (side == 1)
        color = (color >> 1) & 8355711;
      pixels[y][x] = color;
    }
  }
}

void render2D() {
  int offset = SCREEN_WIDTH / 2;
  for (int y = 0; y < MAP_HEIGHT; y++) {
    for (int x = 0; x < MAP_WIDTH; x++) {
      if (worldMap[y][x] != 0) {
        int offsetY = y * TILE_HEIGHT;
        int offsetX = offset + x * (TILE_WIDTH);
        for (int ty = 0; ty < TILE_HEIGHT - 1; ty++) {
          for (int tx = 0; tx < (TILE_WIDTH - 1); tx++) {
            pixels[offsetY + ty][offsetX + tx] = 0x5088ff;
          }
        }
      }
    }
  }
}

void drawPlayer2D() {
  int py = player.pos.y * TILE_HEIGHT;
  int px = player.pos.x * (int)TILE_WIDTH + SCREEN_WIDTH / 2.0;
  int dx = player.dir.x * 3 + px;
  int dy = player.dir.y * 3 + py;
  SDL_Rect r = {.x = px - 5, .y = py - 5, .w = 10, .h = 10};
  SDL_Rect d = {.x = dx - 3, .y = dy - 3, .w = 6, .h = 6};

  SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
  SDL_RenderFillRect(renderer, &r);
  SDL_SetRenderDrawColor(renderer, 255, 125, 255, 255);
  SDL_RenderFillRect(renderer, &d);
}

void rotate(float rot) {
  const v2 d = player.dir, p = player.plane;
  player.dir.x = d.x * cos(rot) - d.y * sin(rot);
  player.dir.y = d.x * sin(rot) + d.y * cos(rot);
  player.plane.x = p.x * cos(rot) - p.y * sin(rot);
  player.plane.y = p.x * sin(rot) + p.y * cos(rot);
}

void generateTextures() {
  memset(textures, 0, sizeof(textures));
  for (int y = 0; y < TEX_HEIGHT; y++) {
    for (int x = 0; x < TEX_WIDTH; x++) {
      int xorcolor = (x * 256 / TEX_WIDTH) ^ (y * 256 / TEX_HEIGHT);
      // int xcolor = x * 256 / TEX_WIDTH;
      int ycolor = y * 256 / TEX_HEIGHT;
      int xycolor = y * 128 / TEX_HEIGHT + x * 128 / TEX_WIDTH;
      textures[0][TEX_WIDTH * y + x] =
          65536 * 254 *
          (x != y && x != TEX_WIDTH - y); // flat red texture with black cross
      textures[1][TEX_WIDTH * y + x] =
          xycolor + 256 * xycolor + 65536 * xycolor; // sloped greyscale
      textures[2][TEX_WIDTH * y + x] =
          256 * xycolor + 65536 * xycolor; // sloped yellow gradient
      textures[3][TEX_WIDTH * y + x] =
          xorcolor + 256 * xorcolor + 65536 * xorcolor; // xor greyscale
      textures[4][TEX_WIDTH * y + x] = 256 * xorcolor;  // xor green
      textures[5][TEX_WIDTH * y + x] =
          65536 * 192 * (x % 16 && y % 16);            // red bricks
      textures[6][TEX_WIDTH * y + x] = 65536 * ycolor; // red gradient
      textures[7][TEX_WIDTH * y + x] =
          128 + 256 * 128 + 65536 * 128; // flat grey texture
    }
  }
}

void playerBoundsCheck() {
  if (player.pos.x >= MAP_WIDTH) {
    player.pos.x = MAP_WIDTH - 10;
  } else if (player.pos.x < 0) {
    player.pos.x = 10;
  }
  if (player.pos.y >= MAP_HEIGHT) {
    player.pos.y = MAP_HEIGHT - 10;
  } else if (player.pos.y < 0) {
    player.pos.y = 10;
  }
}

int main() {
  initSDL();
  generateTextures();
  int pitch = SCREEN_WIDTH * sizeof(int);
  void *rawPixels = NULL;

  SDL_Event e;
  double time = 0;
  double oldTime = 0;
  bool quit = false;
  while (!quit) {
    while (SDL_PollEvent(&e)) {
      if (e.type == SDL_QUIT)
        quit = true;
    }

    oldTime = time;
    time = SDL_GetTicks();
    double frameTime = (time - oldTime) / 1000.0;
    const float rotspeed = 5.0f * frameTime, movespeed = 5.0f * frameTime;

    const uint8_t *keystate = SDL_GetKeyboardState(NULL);
    if (keystate[SDL_SCANCODE_LEFT]) {
      rotate(-rotspeed);
    }

    if (keystate[SDL_SCANCODE_RIGHT]) {
      rotate(+rotspeed);
    }

    if (keystate[SDL_SCANCODE_UP]) {
      player.pos.x += player.dir.x * movespeed;
      player.pos.y += player.dir.y * movespeed;
      playerBoundsCheck();
    }

    if (keystate[SDL_SCANCODE_DOWN]) {
      player.pos.x -= player.dir.x * movespeed;
      player.pos.y -= player.dir.y * movespeed;
      playerBoundsCheck();
    }

    SDL_RenderClear(renderer);
    SDL_LockTexture(buffer, NULL, &rawPixels, &pitch);

    memset(pixels, 0, sizeof(pixels));
    render();
    render2D();

    memcpy(rawPixels, pixels, pitch * SCREEN_HEIGHT);
    SDL_UnlockTexture(buffer);
    rawPixels = NULL;
    SDL_RenderCopy(renderer, buffer, NULL, NULL);
    drawPlayer2D();

    SDL_RenderPresent(renderer);
  }

  return 0;
}

[ad_2]

Previous article Game Design Aspect: Dear Daughter: A Quarantine Essay
Next article All Cult Stash locations and puzzle solutions in Alan Wake 2
Hello there! My name is YoleeTeam, and I am thrilled to welcome you to AmazonianGames.com. As the premier destination for all things related to Amazon Games' universe, we are dedicated to providing you with the most exciting and immersive gaming experiences out there. From captivating visuals to exhilarating gameplay, our website is packed with comprehensive insights, updates, and reviews to keep you ahead of the game. Whether you're a seasoned gamer or new to the scene, I am here to guide you through this virtual frontier. If you have any questions or suggestions, feel free to reach out to me at john@yoleesolutions.com. Embark on your Amazon gaming journey today with AmazonianGames.com and let the adventure begin!