[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]