From fab0cfb277148a8cbb819858af5942816f88fb7e Mon Sep 17 00:00:00 2001 From: attilavs2 Date: Tue, 22 Oct 2024 12:27:16 +0200 Subject: [PATCH] fixs et raycast --- CMakeLists.txt | 3 +- eng/game.c | 14 ++-- eng/map.c | 4 +- eng/moteur.c | 15 ++-- eng/sprites.c | 157 +++++++++++++++++++++++++++++++++++++++--- eng/utils.c | 4 ++ include/C3D/config.h | 3 +- include/C3D/fixed.h | 2 +- include/C3D/game.h | 5 ++ include/C3D/sprites.h | 3 + include/C3D/utils.h | 12 ++++ src/main.c | 22 +++--- 12 files changed, 205 insertions(+), 39 deletions(-) create mode 100644 eng/utils.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a13d0c0..4593da5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES #sources du moteur eng/moteur.c eng/map.c + eng/utils.c eng/sprites.c eng/game.c ) @@ -35,7 +36,7 @@ fxconv_declare_assets(${ASSETS} WITH_METADATA) add_executable(Copy3DEngine ${SOURCES} ${ASSETS}) target_compile_options(Copy3DEngine PRIVATE -Wall -Wextra -Ofast) -target_include_directories(Copy3DEngine PRIVATE "include/C3D/") +target_include_directories(Copy3DEngine PRIVATE "include/") target_compile_definitions(Copy3DEngine PRIVATE NAMEOFGAME="${NAMEOFGAME}" AUTHOR="${AUTHOR}") target_link_libraries(Copy3DEngine Gint::Gint) target_link_libraries(Copy3DEngine LibProf::LibProf) diff --git a/eng/game.c b/eng/game.c index 33317f1..b065faa 100644 --- a/eng/game.c +++ b/eng/game.c @@ -5,12 +5,13 @@ #include #include -#include "fixed.h" -#include "map.h" -#include "game.h" -#include "utils.h" -#include "moteur.h" -#include "sprites.h" +#include "C3D/fixed.h" +#include "C3D/map.h" +#include "C3D/game.h" +#include "C3D/utils.h" +#include "C3D/moteur.h" +#include "C3D/sprites.h" +#include "C3D/config.h" int lhook_c = 0; RcLogicFunc *logic_hooks[HINDEX_S]; @@ -46,3 +47,4 @@ void do_logic(RcGame *game, int delta){ } } } + diff --git a/eng/map.c b/eng/map.c index 12d3cc1..6fee952 100644 --- a/eng/map.c +++ b/eng/map.c @@ -2,8 +2,8 @@ #include -#include "map.h" -#include "moteur.h" +#include "C3D/map.h" +#include "C3D/moteur.h" uint8_t __attribute__((section(".rodata"))) map_test[map_w][map_h] = { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3}, diff --git a/eng/moteur.c b/eng/moteur.c index 2310d95..8df3ff7 100644 --- a/eng/moteur.c +++ b/eng/moteur.c @@ -12,12 +12,11 @@ #include #include -#include "fixed.h" - -#include "moteur.h" -#include "map.h" -#include "game.h" -#include "config.h" +#include "C3D/fixed.h" +#include "C3D/moteur.h" +#include "C3D/map.h" +#include "C3D/game.h" +#include "C3D/config.h" // moteur.c : // ici se trouvent tout ce qui concerne les graphismes, mouvement et collisions @@ -28,8 +27,8 @@ fixed_t zbuf[viewport_w]; void move(RcGame *game) { extern int frame_time; - fixed_t moveSpeed = fmul(fix(frame_time), 0x148); //frame_time * fix(carrés/seconde/1000) là carrés/seconde = 5 - fixed_t rotSpeed = fmul(fix(frame_time), 0x83); //frame_time * fix(radians/seconde/1000) là radians/seconde = 2 + fixed_t moveSpeed = fmul(fix(frame_time)/1000, 0x148); //frame_time * fix(carrés/seconde/1000) là carrés/seconde = 5 + fixed_t rotSpeed = fmul(fix(frame_time)/1000, 0x83); //frame_time * fix(radians/seconde/1000) là radians/seconde = 2 fixed_t c_rotSpeed = fix(cos(f2float(rotSpeed))); fixed_t s_rotSpeed = fix(sin(f2float(rotSpeed))); diff --git a/eng/sprites.c b/eng/sprites.c index 5b27ba4..5da31d9 100644 --- a/eng/sprites.c +++ b/eng/sprites.c @@ -2,15 +2,17 @@ #include #include +#include #include #include -#include "fixed.h" -#include "game.h" -#include "sprites.h" -#include "moteur.h" -#include "config.h" -#include "utils.h" +#include "C3D/fixed.h" +#include "C3D/game.h" +#include "C3D/sprites.h" +#include "C3D/moteur.h" +#include "C3D/map.h" +#include "C3D/config.h" +#include "C3D/utils.h" extern fixed_t zbuf[viewport_w]; @@ -32,7 +34,7 @@ void remove_sprite(GUNUSED Sprite *sprite){ //TODO } -//Lodev's sprite projection, translated +//Lodev's sprite projection, translated to use my functions and fixed point void project_sprite(bopti_image_t *tex_index[], Sprite *sprite, RcActor *player){ @@ -59,8 +61,6 @@ void project_sprite(bopti_image_t *tex_index[], Sprite *sprite, RcActor *player) sprite_pos_y = 0; int sprite_pos_x = -sprite_h / 2 + screen_x; - if(sprite_pos_x < 0) - sprite_pos_x = 0; int sprite_end_x = sprite_h / 2 + screen_x; if(sprite_end_x > viewport_w) sprite_end_x = viewport_w; @@ -81,10 +81,10 @@ void project_sprite(bopti_image_t *tex_index[], Sprite *sprite, RcActor *player) continue; if(x > viewport_w) break; - int tex_x = ffloor((x-sprite_pos_x) * fdiv(fix(TSIZE), fix(sprite_w))); + int tex_x = ffloor(fixabs(x-sprite_pos_x) * fdiv(fix(TSIZE), fix(sprite_w))); tex_x %= TSIZE; - draw_stripe(tex_index[4], 0, sprite_pos_y, sprite_size, tex_x, x); + draw_stripe(tex_index[sprite->tex], 0, sprite_pos_y, sprite_size, tex_x, x); } } @@ -120,3 +120,138 @@ void draw_sprites(bopti_image_t *tex_index[], RcActor *player){ project_sprite(tex_index, spr, player); } } + +//Returns distance (-1 if no hit), hit is set to the hit sprite +//or NULL if no hit (can be passed NULL) +fixed_t raycast(RcGame *game, RcActor *origin, Sprite **hit){ + fixed_t posX = origin->pos.x; + fixed_t posY = origin->pos.y; + fixed_t dirX = origin->dir.x; + fixed_t dirY = origin->dir.y; + fixed_t planeX = origin->plane.x; + fixed_t planeY = origin->plane.y; + uint8_t *map_test = game->current_map->dat; + + fixed_t cameraX; + fixed_t rayDirX; + fixed_t rayDirY; + fixed_t sideDistX;//length of ray from current position to next x or y-side + fixed_t sideDistY; + fixed_t deltaDistX; + fixed_t deltaDistY; + fixed_t perpWallDist; + int x = viewport_w/2; + int mapX; + int mapY; + int stepX; //what direction to step in x or y-direction (either +1 or -1) + int stepY; + int side = 0; //was a NS or a EW wall hit? + + //int v_offset = 0; + fixed_t h_offset = 0; + + //calculate ray position and direction + cameraX = fdiv(fix(x*2), fix(viewport_w)) - 0xFFFF + h_offset; //x-coordinate in camera space + + rayDirX = dirX + fmul(planeX, cameraX); + rayDirY = dirY + fmul(planeY, cameraX); + + //which box of the map we're in + mapX = ffloor(posX); + mapY = ffloor(posY); + + // length of ray from one x or y-side to next x or y-side + // these are derived as: + // deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX)) + // deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY)) + // which can be simplified to abs(|rayDir| / rayDirX) and abs(|rayDir| / rayDirY) + // where |rayDir| is the length of the vector (rayDirX, rayDirY). Its length, + // unlike (dirX, dirY) is not 1, however this does not matter, only the + // ratio between deltaDistX and deltaDistY matters, due to the way the DDA + // stepping further below works. So the values can be computed as below. + // Division through zero is prevented, even though technically that's not + // needed in C++ with IEEE 754 floating point values. + //Fcalva : It is with fp32s ! + + rayDirX = rayDirX == 0 ? 1 : rayDirX; + rayDirY = rayDirY == 0 ? 1 : rayDirY; + + deltaDistX = abs(fdiv(0xFFFF, rayDirX)); + deltaDistY = abs(fdiv(0xFFFF, rayDirY)); + if(deltaDistX > max_dist) deltaDistX = max_dist; + if(deltaDistY > max_dist) deltaDistY = max_dist; + + //calculate step and initial sideDist + if (rayDirX < 0) { + stepX = -1; + sideDistX = fmul(posX - fix(mapX), deltaDistX); + } + else { + stepX = 1; + sideDistX = fmul( fix(mapX + 1) - posX, deltaDistX); + } + + if (rayDirY == 0) { + stepY = 0; + sideDistY = 0; + } + else if (rayDirY < 0) { + stepY = -1; + sideDistY = fmul(posY - fix(mapY), deltaDistY); + } + else { + stepY = 1; + sideDistY = fmul( fix(mapY + 1) - posY, deltaDistY); + } + int coll = 0; + //perform DDA + while(true) { + //Check if the ray is out of range/bounds + if (sideDistX >= max_dist || sideDistY >= max_dist || mapX < 0 || mapY < 0 || mapY >= map_w || mapX >= map_h) { + coll = 0; + break; + } + //Otherwise check if ray has hit a wall + if (map_test[mapX*map_w+mapY] > 0) { + coll = 0; + break; + } + for(int i = 0; i < spritec; i++){ + Sprite *act = sprite_index[i]; + if(ffloor(act->pos.x) == mapX && ffloor(act->pos.y) == mapY){ + if(hit) *hit = act; + coll = 1; + goto outerbreak; + } + } + //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; + } + continue; + outerbreak: break; + } + //Calculate distance projected on camera direction. This is the shortest distance from the point where the wall is + //hit to the camera plane. Euclidean to center camera point would give fisheye effect! + //This can be computed as (mapX - posX + (1 - stepX) / 2) / rayDirX for side == 0, or same formula with Y + //for size == 1, but can be simplified to the code below thanks to how sideDist and deltaDist are computed: + //because they were left scaled to |rayDir|. sideDist is the entire length of the ray above after the multiple + //steps, but we subtract deltaDist once because one step more into the wall was taken above. + if(coll){ + if (side == 0) + perpWallDist = (sideDistX - deltaDistX); + else + perpWallDist = (sideDistY - deltaDistY); + } + else { + perpWallDist = -1; + } + return perpWallDist; +} diff --git a/eng/utils.c b/eng/utils.c new file mode 100644 index 0000000..0d2092b --- /dev/null +++ b/eng/utils.c @@ -0,0 +1,4 @@ +#include + +#include "C3D/fixed.h" +#include "C3D/game.h" diff --git a/include/C3D/config.h b/include/C3D/config.h index c7b4331..13ad996 100644 --- a/include/C3D/config.h +++ b/include/C3D/config.h @@ -26,7 +26,8 @@ #define SINDEX_S 64 //Game logic hooks #define HINDEX_S 16 - +//Game entities +#define EINDEX_S 32 //===== Paramètres de debug ===== diff --git a/include/C3D/fixed.h b/include/C3D/fixed.h index 360d74a..3d46aae 100644 --- a/include/C3D/fixed.h +++ b/include/C3D/fixed.h @@ -89,7 +89,7 @@ static inline fixed_t fease(fixed_t x) } static inline fixed_t fixabs(fixed_t x){ - return x & 0x7FFFFFFF; + return x > 0 ? x:-x; } static inline fixed_t fV2d_dotp(V2d u, V2d v){ diff --git a/include/C3D/game.h b/include/C3D/game.h index af2dd82..3bf7de9 100644 --- a/include/C3D/game.h +++ b/include/C3D/game.h @@ -7,6 +7,7 @@ typedef struct { V2d pos; + Rect coll; int tex; } Sprite; @@ -21,9 +22,13 @@ typedef struct { } RcMap; + +//Extension of Sprite, keep all first items common typedef struct { V2d pos; + Rect coll; + int tex; V2d dir; V2d plane; diff --git a/include/C3D/sprites.h b/include/C3D/sprites.h index 805ccb3..627847f 100644 --- a/include/C3D/sprites.h +++ b/include/C3D/sprites.h @@ -17,3 +17,6 @@ void clear_sprites(); void draw_sprites(bopti_image_t *tex_index[], RcActor *player); +//Returns distance (-1 if no hit), hit is set to the hit sprite +//or NULL if no hit (can be passed NULL) +fixed_t raycast(RcGame *game, RcActor *origin, Sprite **hit); diff --git a/include/C3D/utils.h b/include/C3D/utils.h index 142a40d..eda678f 100644 --- a/include/C3D/utils.h +++ b/include/C3D/utils.h @@ -4,6 +4,18 @@ #pragma once #include +#include + +#include "fixed.h" #define min(x, xmin) (x > xmin ? xmin:x) +typedef struct { + int x0,x1; + int y0,y1; +} Rect; + +static bool rect_rect_coll(Rect *a, Rect *b){ + bool r = a->x0 >= b->x0 && a->x1 <= b->x1; + r = r && a->y0 >= b->y0; +} diff --git a/src/main.c b/src/main.c index 45125c8..865bd28 100644 --- a/src/main.c +++ b/src/main.c @@ -11,13 +11,13 @@ #include #include -#include "fixed.h" +#include "C3D/fixed.h" -#include "game.h" -#include "sprites.h" -#include "moteur.h" -#include "map.h" -#include "config.h" +#include "C3D/game.h" +#include "C3D/sprites.h" +#include "C3D/moteur.h" +#include "C3D/map.h" +#include "C3D/config.h" //====== Copy3DEngine ===== // Git du moteur : https://git.planet-casio.com/Fcalva/Copy3DEngine @@ -79,6 +79,10 @@ void keys_get(){ frame_time_timer--; if (keydown(KEY_EXIT)) game.flags.exit = 1; + if(keydown(KEY_F2)){ + dprint(0,0,3,"%d",raycast(&game, &game.player, NULL)); + } + #ifdef debug //if (keydown(KEY_TAN)) end_screen(); #endif @@ -154,7 +158,7 @@ int main(){ keys_get(); - do_logic(&game, frame_time*1000); + do_logic(&game, frame_time); draw_walls( #if debug @@ -165,7 +169,7 @@ int main(){ draw_sprites(tex_index, &game.player); - if (disp_frame_time == 1) dprint( 0, 0, C_BLACK, "%d ms", frame_time); + if (disp_frame_time == 1) dprint( 0, 0, C_BLACK, "%d ms", frame_time/1000); #if debug dprint( 1, 27, C_BLACK, "pX %d", game.player.pos.x); @@ -178,7 +182,7 @@ int main(){ dupdate(); prof_leave(frame); - frame_time = (int)prof_time(frame)/1000; + frame_time = (int)prof_time(frame); first_frame = 0; }