diff --git a/.vscode/settings.json b/.vscode/settings.json index 5281033..502ca39 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,7 @@ "limits": "c", "base.h": "c", "cars.h": "c", - "sdl_image.h": "c" + "sdl_image.h": "c", + "collisions.h": "c" } } \ No newline at end of file diff --git a/Makefile b/Makefile index b9c110b..d50fcb2 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ test: bin/back mem: bin/back valgrind --leak-check=full ./bin/back -bin/back: obj/main.o obj/display.o obj/base.o obj/cars.o obj/rooms.o obj/structure.o +bin/back: obj/main.o obj/display.o obj/base.o obj/collisions.o obj/cars.o obj/rooms.o obj/structure.o mkdir -p bin $(CC) $(FLAGS) $^ $(LFLAGS) -o $@ @@ -23,6 +23,7 @@ obj/display.o: src/display.c obj/base.o: src/base.c obj/cars.o: src/cars.c obj/rooms.o: src/rooms.c +obj/collisions.o: src/collisions.c obj/structure.o: src/structure.c .PHONY: clean mrproper diff --git a/bin/back b/bin/back index c554c1c..261582f 100755 Binary files a/bin/back and b/bin/back differ diff --git a/obj/base.o b/obj/base.o index bf82826..e91f559 100644 Binary files a/obj/base.o and b/obj/base.o differ diff --git a/obj/cars.o b/obj/cars.o index 51b433c..a5fb509 100644 Binary files a/obj/cars.o and b/obj/cars.o differ diff --git a/obj/collisions.o b/obj/collisions.o new file mode 100644 index 0000000..04c0f78 Binary files /dev/null and b/obj/collisions.o differ diff --git a/obj/display.o b/obj/display.o index 16e98fd..d5ccc1c 100644 Binary files a/obj/display.o and b/obj/display.o differ diff --git a/obj/main.o b/obj/main.o index 90fde72..54aec2c 100644 Binary files a/obj/main.o and b/obj/main.o differ diff --git a/obj/rooms.o b/obj/rooms.o index ae6c694..d4ad35f 100644 Binary files a/obj/rooms.o and b/obj/rooms.o differ diff --git a/obj/structure.o b/obj/structure.o index c16ecee..495b56d 100644 Binary files a/obj/structure.o and b/obj/structure.o differ diff --git a/src/base.c b/src/base.c index 83e760f..749ab3b 100644 --- a/src/base.c +++ b/src/base.c @@ -71,4 +71,17 @@ double distance_pt(int x1, int x2, int y1, int y2) { return sqrt(to_double(pw(x2 - x1, 2) + pw(y2 - y1, 2))); } int max(int a, int b) {return (a>b)?(a):(b);} -int min(int a, int b) {return (a %lf", nPl, theta); return (ptf){ - .fx = ROOM_SIZE/2.0+cos(theta*PI/180.0 - PI/2.0*(START_DIR))*ROOM_SIZE/4.0, - .fy = ROOM_SIZE/2.0+sin(theta*PI/180.0 - PI/2.0*(START_DIR))*ROOM_SIZE/4.0 + .fx = ROOM_SIZE/2.0+cos(theta*PI/180.0 - PI/2.0*(START_DIR-1))*ROOM_SIZE/3.3, + .fy = ROOM_SIZE/2.0+sin(theta*PI/180.0 - PI/2.0*(START_DIR-1))*ROOM_SIZE/3.3 }; } @@ -31,9 +31,12 @@ car* init_car(int nPl, int nTotPl) { res->itm = NULL; res->nCoins = 0; res->pos = get_position(nPl, nTotPl); + res->lastPos = (ptf){.fx = res->pos.fx, .fy = res->pos.fy}; res->chx = START_CHX; res->chy = START_CHY; - res->vel = (ptf){.fx = 0.0, .fy = 0.0}; + //res->vel = (ptf){.fx = 0.0, .fy = 0.0}; + double theta = (2.0*MAX_THETA_SPAWN*nPl/((nTotPl-1==0)?(1):(nTotPl-1)) - 1.0*MAX_THETA_SPAWN); + res->vel = (ptf){.fx = (rand()%100-50.0)/100.0*2.0*MAX_SPEED, .fy = (rand()%100-50.0)/100.0*2.0*MAX_SPEED}; return res; } diff --git a/src/collisions.c b/src/collisions.c new file mode 100644 index 0000000..01e7ac4 --- /dev/null +++ b/src/collisions.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "structure.h" +#include "cars.h" +#include "base.h" +#include "collisions.h" + +// use after updating the position +void updateChunk(int nPl) { + car* c = players[nPl].c; + if(c->pos.fx < 0.0) { + c->pos.fx += 1.0*ROOM_SIZE; + c->chx -= 1; + } + if(c->pos.fx >= 1.0*ROOM_SIZE) { + c->pos.fx -= 1.0*ROOM_SIZE; + c->chx += 1; + } + if(c->pos.fy < 0.0) { + c->pos.fy += 1.0*ROOM_SIZE; + c->chy -= 1; + } + if(c->pos.fy >= 1.0*ROOM_SIZE) { + c->pos.fy -= 1.0*ROOM_SIZE; + c->chy += 1; + } +} + +ptf get_absolute_coords(int nPl) { + return (ptf){ + .fx = players[nPl].c->pos.fx + ROOM_SIZE*players[nPl].c->chx, + .fy = players[nPl].c->pos.fy + ROOM_SIZE*players[nPl].c->chy + }; +} + +// -------------------------------------------------------------------------------- // +// make the player move DT (does not take friction into consideration) + +// start and finish +void move_on_ENDS(int nPl) { + car* c = players[nPl].c; + c->pos.fx += c->vel.fx*DT; + c->pos.fy += c->vel.fy*DT; + if( + (START_DIR != 3 && c->pos.fx-PLAYER_R/2 <= 0.0 && c->vel.fx < 0.0) || + (START_DIR == 3 && c->pos.fx-PLAYER_R/2 <= 0.0 && c->vel.fx < 0.0 && (c->pos.fy-PLAYER_R/2 <= ROOM_SIZE*DIST_EDGE || c->pos.fy+PLAYER_R/2 >= ROOM_SIZE*(1.0-DIST_EDGE))) + ) { // left wall + c->vel.fx *= -1.0; + c->pos.fx += 2.0*c->vel.fx*DT; + c->vel.fx *= RESTITUTION_WALL; + } + if( + (START_DIR != 1 && c->pos.fx+PLAYER_R/2 >= 1.0*ROOM_SIZE && c->vel.fx > 0.0) || + (START_DIR == 1 && c->pos.fx+PLAYER_R/2 >= 1.0*ROOM_SIZE && c->vel.fx > 0.0 && (c->pos.fy-PLAYER_R/2 <= ROOM_SIZE*DIST_EDGE || c->pos.fy+PLAYER_R/2 >= ROOM_SIZE*(1.0-DIST_EDGE))) + ) { // right wall + c->vel.fx *= -1.0; + c->pos.fx += 2.0*c->vel.fx*DT; + c->vel.fx *= RESTITUTION_WALL; + } + if( + (START_DIR != 0 && c->pos.fy-PLAYER_R/2 <= 0.0 && c->vel.fy < 0.0) || + (START_DIR == 0 && c->pos.fy-PLAYER_R/2 <= 0.0 && c->vel.fy < 0.0 && (c->pos.fx-PLAYER_R/2 <= ROOM_SIZE*DIST_EDGE || c->pos.fx+PLAYER_R/2 >= ROOM_SIZE*(1.0-DIST_EDGE))) + ) { // top wall + c->vel.fy *= -1.0; + c->pos.fy += 2.0*c->vel.fy*DT; + c->vel.fy *= RESTITUTION_WALL; + } + if( + (START_DIR != 2 && c->pos.fy+PLAYER_R/2 >= 1.0*ROOM_SIZE && c->vel.fy > 0.0) || + (START_DIR == 2 && c->pos.fy+PLAYER_R/2 >= 1.0*ROOM_SIZE && c->vel.fy > 0.0 && (c->pos.fx-PLAYER_R/2 <= ROOM_SIZE*DIST_EDGE || c->pos.fx+PLAYER_R/2 >= ROOM_SIZE*(1.0-DIST_EDGE))) + ) { // bottom wall + c->vel.fy *= -1.0; + c->pos.fy += 2.0*c->vel.fy*DT; + c->vel.fy *= RESTITUTION_WALL; + } +} + +void move_on_STR_V(int nPl) { + car* c = players[nPl].c; + c->pos.fx += c->vel.fx*DT; + c->pos.fy += c->vel.fy*DT; + if(c->pos.fx-PLAYER_R/2 <= ROOM_SIZE*DIST_EDGE && c->vel.fx < 0.0) { // left wall + c->vel.fx *= -1.0; + c->pos.fx += 2.0*c->vel.fx*DT; + c->vel.fx *= RESTITUTION_WALL; + } + if(c->pos.fx+PLAYER_R/2 >= ROOM_SIZE*(1.0-DIST_EDGE) && c->vel.fx > 0.0) { // right wall + c->vel.fx *= -1.0; + c->pos.fx += 2.0*c->vel.fx*DT; + c->vel.fx *= RESTITUTION_WALL; + } +} + +void move_on_STR_H(int nPl) { + car* c = players[nPl].c; + c->pos.fx += c->vel.fx*DT; + c->pos.fy += c->vel.fy*DT; + if(c->pos.fy-PLAYER_R/2 <= ROOM_SIZE*DIST_EDGE && c->vel.fy < 0.0) { // top wall + c->vel.fy *= -1.0; + c->pos.fy += 2.0*c->vel.fy*DT; + c->vel.fy *= RESTITUTION_WALL; + } + if(c->pos.fy+PLAYER_R/2 >= ROOM_SIZE*(1.0-DIST_EDGE) && c->vel.fy > 0.0) { // bottom wall + c->vel.fy *= -1.0; + c->pos.fy += 2.0*c->vel.fy*DT; + c->vel.fy *= RESTITUTION_WALL; + } +} + +void bumpOtherCars(int nPl) { + for(int p = 0; p < nPlayers; p++) { + if(p != nPl) { + double sep = distance( + get_absolute_coords(p), + get_absolute_coords(nPl) + ); + if(sep <= PLAYER_R) { + // p_total is multiplied by RESTITUTION_PLAYER + ptf director = normalize((ptf){ + .fx = players[p].c->pos.fx - players[nPl].c->pos.fx, + .fy = players[p].c->pos.fy - players[nPl].c->pos.fy + }); + double speed_P = norm(players[p].c->vel); + double speed_N = norm(players[nPl].c->vel); + + players[p].c->vel.fx = director.fx*RESTITUTION_PLAYER*(speed_P - speed_P/2.0 + speed_N/2.0); + players[p].c->vel.fy = director.fy*RESTITUTION_PLAYER*(speed_P - speed_P/2.0 + speed_N/2.0); + + players[nPl].c->vel.fx = -director.fx*RESTITUTION_PLAYER*(speed_N + speed_P/2.0 - speed_N/2.0); + players[nPl].c->vel.fy = -director.fy*RESTITUTION_PLAYER*(speed_N + speed_P/2.0 - speed_N/2.0); + } + } + } +} + +void apply_friction(int nPl) { + players[nPl].c->vel.fx *= (1.0 - FRICTION*DT); + players[nPl].c->vel.fy *= (1.0 - FRICTION*DT); +} + +// -- // + +// return true iif the car has moved +bool updateCar(level* lvl, int nPl) { + if(norm(players[nPl].c->vel) >= DV) { + switch (lvl->map[players[nPl].c->chy][players[nPl].c->chx]){ + case NONE: + fprintf(stderr, "[player %d] Is in an empty chunk (at %d %d)\n", nPl, players[nPl].c->chx, players[nPl].c->chy); + return false; + + case START: + case END: + move_on_ENDS(nPl); + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + case STR_V: + move_on_STR_V(nPl); + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + case STR_H: + move_on_STR_H(nPl); + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + case TURN_NE: + + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + case TURN_NW: + + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + case TURN_SE: + + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + case TURN_SW: + + bumpOtherCars(nPl); + apply_friction(nPl); + updateChunk(nPl); + return true; + + default: + return false; + } + } else { + return false; + } +} + +// return true if at least one car moved +bool updateCars(level* lvl) { + bool res = false; + for(int p = 0; p < nPlayers; p++) { + bool rr = updateCar(lvl, p); + res = res || rr; + } + return res; +} \ No newline at end of file diff --git a/src/collisions.h b/src/collisions.h new file mode 100644 index 0000000..27e217d --- /dev/null +++ b/src/collisions.h @@ -0,0 +1,6 @@ +#ifndef COLLISIONS_H +#define COLLISIONS_H + +bool updateCars(level* lvl); + +#endif \ No newline at end of file diff --git a/src/display.c b/src/display.c index 406c02b..a7b4a08 100644 --- a/src/display.c +++ b/src/display.c @@ -24,7 +24,7 @@ void updateRenderer(SDL_Renderer* renderer) { } void resetRenderer(SDL_Renderer* renderer) { - SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); } @@ -518,6 +518,13 @@ void renderPlayers(SDL_Renderer* renderer, int cx, int cy, int range, int rsize) void renderMap(SDL_Renderer* renderer, level* lvl, int cx, int cy, int range, int rsize) { renderCircles(renderer, lvl, cx, cy, range, rsize); renderStraights(renderer, lvl, cx, cy, range, rsize); + for(int x = -range; x <= range; x++) { + for(int y = -range; y <= range; y++) { + if((cx+x == START_CHX && cy+y == START_CHY) || (cx+x == FINISH_CHX && cy+y == FINISH_CHY)) { + SDL_RenderDrawCircle(renderer, (WIDTH)/2+rsize*(y), (HEIGHT)/2+rsize*(x), (int)(ROOM_SIZE/2.0 + ROOM_SIZE/3.3), 192, 192, 192, 255); + } + } + } renderPlayers(renderer, cx, cy, range, rsize); } diff --git a/src/main.c b/src/main.c index 6ed88aa..3e1261d 100644 --- a/src/main.c +++ b/src/main.c @@ -14,10 +14,32 @@ #include "structure.h" #include "base.h" #include "display.h" +#include "collisions.h" #include "rooms.h" #include "cars.h" -const int N_PLAYERS = 4; +const int N_PLAYERS = 6; +double elapsed = 0.0; + +bool halt = false; +void playerActions() { + SDL_Event event; + while(SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_SPACE: + halt = true; + break; + + default: + break; + } + } + } +} int main() { srand(time(NULL)); @@ -40,15 +62,39 @@ int main() { level* test = parse_level("levels/test.txt"); init_all(N_PLAYERS); - //for(int p = 0; p < N_PLAYERS; p++) { - // printf("[%d], (at [%d %d] (%lf %lf))\n", p, players[p].c->chx, players[p].c->chy, players[p].c->pos.fx, players[p].c->pos.fy); - //} + printf("Starting direction : "); + if(START_DIR == 0) { + printf("North\n"); + } else if(START_DIR == 1) { + printf("East\n"); + } else if(START_DIR == 2) { + printf("South\n"); + } else if(START_DIR == 3) { + printf("West\n"); + } else { + printf("???\n"); + } - renderMap(rend, test, 1, 1, 2, 250); - updateRenderer(rend); + while(!halt) { + resetRenderer(rend); + renderMap(rend, test, 1, 1, 2, 250); + if(elapsed <= 0.7) { + placeRectToRenderer(rend, 0, 0, 50, 50, 255, 255, 32, 192); + } else if(updateCars(test)) { + placeRectToRenderer(rend, 0, 0, 50, 50, 32, 255, 32, 192); + } else { + placeRectToRenderer(rend, 0, 0, 50, 50, 255, 32, 32, 192); + } + updateRenderer(rend); + elapsed += DT; + //for(int p = 0; p < N_PLAYERS; p++) { + // printf("[%d], (at [%d %d] (%lf %lf) (%lf %lf))\n", p, players[p].c->chx, players[p].c->chy, players[p].c->pos.fx, players[p].c->pos.fy, players[p].c->vel.fx, players[p].c->vel.fy); + //} + //printf("\n"); + usleep((int)(1000000*DT)); + playerActions(); + } - int n; - scanf("%d", &n); // ---------------------------- // free_digits(digits); free_digits(letters); @@ -61,9 +107,8 @@ int main() { } /* TODO : - - add display - - add collisions - - add level parsing/generation + - add collisions (4/10) + - add level generation - add player input parsing (and some dumb code to test it) - add function that gives players the necessary data to play - check seg faults diff --git a/src/rooms.c b/src/rooms.c index b069358..cee6765 100644 --- a/src/rooms.c +++ b/src/rooms.c @@ -17,6 +17,8 @@ int START_CHX; int START_CHY; +int FINISH_CHX; +int FINISH_CHY; int START_DIR; bool is_digit(char c) { @@ -108,23 +110,26 @@ level* parse_level(char* path) { if(ch == 'S') { START_CHX = l; START_CHY = c; + } else if(ch == 'E') { + FINISH_CHX = l; + FINISH_CHY = c; } } } printf("\n"); if(START_CHX-1 >= 0 && lvl->map[START_CHX-1][START_CHY] != NONE) { - START_DIR = 3; - } - if(START_CHX+1 < lvl->lines && lvl->map[START_CHX+1][START_CHY] != NONE) { - START_DIR = 1; - } - if(START_CHY-1 >= 0 && lvl->map[START_CHX][START_CHY-1] != NONE) { START_DIR = 0; } - if(START_CHY+1 < lvl->cols && lvl->map[START_CHX][START_CHY+1] != NONE) { + if(START_CHX+1 < lvl->lines && lvl->map[START_CHX+1][START_CHY] != NONE) { START_DIR = 2; } + if(START_CHY-1 >= 0 && lvl->map[START_CHX][START_CHY-1] != NONE) { + START_DIR = 3; + } + if(START_CHY+1 < lvl->cols && lvl->map[START_CHX][START_CHY+1] != NONE) { + START_DIR = 1; + } return lvl; } diff --git a/src/structure.c b/src/structure.c index 6e634ad..297855e 100644 --- a/src/structure.c +++ b/src/structure.c @@ -7,18 +7,20 @@ const int WIDTH = 1000; const int HEIGHT = 1000; const int ROOM_SIZE = 100; -const int MAX_SPEED = 66; +const int MAX_SPEED = 150; // m/s const double DIST_EDGE = 0.2; const double START_EDGE = 0.05; -const int RESTITUTION_WALL = 0.8; -const int RESTITUTION_PLAYER = 0.8; +const double RESTITUTION_WALL = 0.8; +const double RESTITUTION_PLAYER = 0.8; const int PLAYER_R = 10; -const int MAX_THETA_SPAWN = 60; // degrees +const int MAX_THETA_SPAWN = 60; // degrees const int BARRIERS = 1; const double BARRIER_WIDTH = 0.05; const double FRICTION = 0.75; -const double DV = 0.01; +const double DV = 1.0; // m/s +const double DT = 1.0/100.0; +const double EPSILON = 1.0/4096.0; \ No newline at end of file diff --git a/src/structure.h b/src/structure.h index d3bc5c6..19f616d 100644 --- a/src/structure.h +++ b/src/structure.h @@ -26,6 +26,7 @@ typedef struct item_t { typedef struct car_t { ptf pos; // remains in [0, ROOM_SIZE[ + ptf lastPos; int chx; int chy; ptf vel; @@ -74,6 +75,8 @@ extern const int MAX_SPEED; extern int START_CHX; extern int START_CHY; +extern int FINISH_CHX; +extern int FINISH_CHY; extern int START_DIR; // (0, 1, 2, 3) = (N, E, S, W) extern const int MAX_THETA_SPAWN; @@ -81,12 +84,14 @@ extern const int PLAYER_R; // radius extern const double DIST_EDGE; extern const double START_EDGE; -extern const int RESTITUTION_WALL; -extern const int RESTITUTION_PLAYER; +extern const double RESTITUTION_WALL; +extern const double RESTITUTION_PLAYER; extern const int BARRIERS; extern const double BARRIER_WIDTH; extern const double FRICTION; extern const double DV; +extern const double DT; +extern const double EPSILON; #endif \ No newline at end of file