added collisions for straight paths

This commit is contained in:
Alexandre 2025-05-15 13:50:54 +02:00
parent 435a1ae63e
commit 281d243827
20 changed files with 352 additions and 32 deletions

View File

@ -7,6 +7,7 @@
"limits": "c", "limits": "c",
"base.h": "c", "base.h": "c",
"cars.h": "c", "cars.h": "c",
"sdl_image.h": "c" "sdl_image.h": "c",
"collisions.h": "c"
} }
} }

View File

@ -10,7 +10,7 @@ test: bin/back
mem: bin/back mem: bin/back
valgrind --leak-check=full ./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 mkdir -p bin
$(CC) $(FLAGS) $^ $(LFLAGS) -o $@ $(CC) $(FLAGS) $^ $(LFLAGS) -o $@
@ -23,6 +23,7 @@ obj/display.o: src/display.c
obj/base.o: src/base.c obj/base.o: src/base.c
obj/cars.o: src/cars.c obj/cars.o: src/cars.c
obj/rooms.o: src/rooms.c obj/rooms.o: src/rooms.c
obj/collisions.o: src/collisions.c
obj/structure.o: src/structure.c obj/structure.o: src/structure.c
.PHONY: clean mrproper .PHONY: clean mrproper

BIN
bin/back

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
obj/collisions.o Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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))); return sqrt(to_double(pw(x2 - x1, 2) + pw(y2 - y1, 2)));
} }
int max(int a, int b) {return (a>b)?(a):(b);} int max(int a, int b) {return (a>b)?(a):(b);}
int min(int a, int b) {return (a<b)?(a):(b);} int min(int a, int b) {return (a<b)?(a):(b);}
double norm(ptf p) {
return sqrt(p.fx*p.fx + p.fy*p.fy);
}
double distance(ptf p1, ptf p2) {
return norm((ptf){.fx = p2.fx - p1.fx, .fy = p2.fy - p1.fy});
}
ptf normalize(ptf p) {
double nr = norm(p);
return (ptf){.fx = p.fx/nr, .fy = p.fy/nr};
}

View File

@ -11,4 +11,8 @@ double to_double(int n);
int pw(int x, int n); int pw(int x, int n);
double distance_pt(int x1, int x2, int y1, int y2); double distance_pt(int x1, int x2, int y1, int y2);
double norm(ptf p);
double distance(ptf p1, ptf p2);
ptf normalize(ptf p);
#endif #endif

View File

@ -21,8 +21,8 @@ ptf get_position(int nPl, int nTotPl) {
double theta = (2.0*MAX_THETA_SPAWN*nPl/((nTotPl-1==0)?(1):(nTotPl-1)) - 1.0*MAX_THETA_SPAWN); double theta = (2.0*MAX_THETA_SPAWN*nPl/((nTotPl-1==0)?(1):(nTotPl-1)) - 1.0*MAX_THETA_SPAWN);
//printf("%d --> %lf", nPl, theta); //printf("%d --> %lf", nPl, theta);
return (ptf){ return (ptf){
.fx = ROOM_SIZE/2.0+cos(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))*ROOM_SIZE/4.0 .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->itm = NULL;
res->nCoins = 0; res->nCoins = 0;
res->pos = get_position(nPl, nTotPl); res->pos = get_position(nPl, nTotPl);
res->lastPos = (ptf){.fx = res->pos.fx, .fy = res->pos.fy};
res->chx = START_CHX; res->chx = START_CHX;
res->chy = START_CHY; 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; return res;
} }

228
src/collisions.c Normal file
View File

@ -0,0 +1,228 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <unistd.h>
#include <termios.h>
#include <limits.h>
#include <time.h>
#include <sys/time.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#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;
}

6
src/collisions.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef COLLISIONS_H
#define COLLISIONS_H
bool updateCars(level* lvl);
#endif

View File

@ -24,7 +24,7 @@ void updateRenderer(SDL_Renderer* renderer) {
} }
void resetRenderer(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); 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) { void renderMap(SDL_Renderer* renderer, level* lvl, int cx, int cy, int range, int rsize) {
renderCircles(renderer, lvl, cx, cy, range, rsize); renderCircles(renderer, lvl, cx, cy, range, rsize);
renderStraights(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); renderPlayers(renderer, cx, cy, range, rsize);
} }

View File

@ -14,10 +14,32 @@
#include "structure.h" #include "structure.h"
#include "base.h" #include "base.h"
#include "display.h" #include "display.h"
#include "collisions.h"
#include "rooms.h" #include "rooms.h"
#include "cars.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() { int main() {
srand(time(NULL)); srand(time(NULL));
@ -40,15 +62,39 @@ int main() {
level* test = parse_level("levels/test.txt"); level* test = parse_level("levels/test.txt");
init_all(N_PLAYERS); init_all(N_PLAYERS);
//for(int p = 0; p < N_PLAYERS; p++) { printf("Starting direction : ");
// 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); 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); while(!halt) {
updateRenderer(rend); 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(digits);
free_digits(letters); free_digits(letters);
@ -61,9 +107,8 @@ int main() {
} }
/* TODO : /* TODO :
- add display - add collisions (4/10)
- add collisions - add level generation
- add level parsing/generation
- add player input parsing (and some dumb code to test it) - add player input parsing (and some dumb code to test it)
- add function that gives players the necessary data to play - add function that gives players the necessary data to play
- check seg faults - check seg faults

View File

@ -17,6 +17,8 @@
int START_CHX; int START_CHX;
int START_CHY; int START_CHY;
int FINISH_CHX;
int FINISH_CHY;
int START_DIR; int START_DIR;
bool is_digit(char c) { bool is_digit(char c) {
@ -108,23 +110,26 @@ level* parse_level(char* path) {
if(ch == 'S') { if(ch == 'S') {
START_CHX = l; START_CHX = l;
START_CHY = c; START_CHY = c;
} else if(ch == 'E') {
FINISH_CHX = l;
FINISH_CHY = c;
} }
} }
} }
printf("\n"); printf("\n");
if(START_CHX-1 >= 0 && lvl->map[START_CHX-1][START_CHY] != NONE) { 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; 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; 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; return lvl;
} }

View File

@ -7,18 +7,20 @@ const int WIDTH = 1000;
const int HEIGHT = 1000; const int HEIGHT = 1000;
const int ROOM_SIZE = 100; 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 DIST_EDGE = 0.2;
const double START_EDGE = 0.05; const double START_EDGE = 0.05;
const int RESTITUTION_WALL = 0.8; const double RESTITUTION_WALL = 0.8;
const int RESTITUTION_PLAYER = 0.8; const double RESTITUTION_PLAYER = 0.8;
const int PLAYER_R = 10; const int PLAYER_R = 10;
const int MAX_THETA_SPAWN = 60; // degrees const int MAX_THETA_SPAWN = 60; // degrees
const int BARRIERS = 1; const int BARRIERS = 1;
const double BARRIER_WIDTH = 0.05; const double BARRIER_WIDTH = 0.05;
const double FRICTION = 0.75; 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;

View File

@ -26,6 +26,7 @@ typedef struct item_t {
typedef struct car_t { typedef struct car_t {
ptf pos; // remains in [0, ROOM_SIZE[ ptf pos; // remains in [0, ROOM_SIZE[
ptf lastPos;
int chx; int chx;
int chy; int chy;
ptf vel; ptf vel;
@ -74,6 +75,8 @@ extern const int MAX_SPEED;
extern int START_CHX; extern int START_CHX;
extern int START_CHY; 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 int START_DIR; // (0, 1, 2, 3) = (N, E, S, W)
extern const int MAX_THETA_SPAWN; extern const int MAX_THETA_SPAWN;
@ -81,12 +84,14 @@ extern const int PLAYER_R; // radius
extern const double DIST_EDGE; extern const double DIST_EDGE;
extern const double START_EDGE; extern const double START_EDGE;
extern const int RESTITUTION_WALL; extern const double RESTITUTION_WALL;
extern const int RESTITUTION_PLAYER; extern const double RESTITUTION_PLAYER;
extern const int BARRIERS; extern const int BARRIERS;
extern const double BARRIER_WIDTH; extern const double BARRIER_WIDTH;
extern const double FRICTION; extern const double FRICTION;
extern const double DV; extern const double DV;
extern const double DT;
extern const double EPSILON;
#endif #endif