#include "out/pengers.h" #include "out/hand.c" #include "out/coin.c" #define GREEN 0xff00ff00 #define RED 0xff0000ff #define BLUE 0xffff0000 #define BLACK 0xff000000 #define EPSILON 0.000001f #define GRAVITY 12 #define AIR_RESISTANCE 5 const unsigned int width = 800; const unsigned int height = 600; unsigned int BUFFER[width * height]; int id = 0; int dir = 0; // importer depuis js int get_scale(void); float random(void); // flemme de coder un algo random, je recup celui de js (Math.random) float sqrtf(float val); // pareil void coin_point(void); typedef struct v2 { float x, y; } v2; // position du penger au milieu v2 penger_pos = {width/2, height/2}; v2 velocity = {0, 0}; v2 mouse = {0, 0}; float get_pos_x(void) { return penger_pos.x - pengers_width[id]; } float get_pos_y(void) { return penger_pos.y - pengers_height[id]; } typedef struct Player { int rid, id, x, y, dir; } Player; #define MAX_PLAYERS 50 Player players[MAX_PLAYERS] = {0}; int nb_players = 0; void deco_player(int rid) { for (int i = 0; i < nb_players; i++) { if (players[i].rid == rid) { players[i].rid = -1; return; } } } void draw_player(int rid, int id, int x, int y, int dir) { if (nb_players >= MAX_PLAYERS) return; for (int i = 0; i < nb_players; i++) { if (players[i].rid == rid) { players[i].id = id; players[i].x = x; players[i].y = y; players[i].dir = dir; return; } } players[nb_players].rid = rid; players[nb_players].id = id; players[nb_players].x = x; players[nb_players].y = y; players[nb_players].dir = dir; nb_players++; } v2 v2_diff(v2 vec1, v2 vec2) { return (v2) { .x = vec1.x - vec2.x, .y = vec1.y - vec2.y, }; } v2 v2_normalize(v2 vec) { v2 result = {0}; float length = sqrtf((vec.x*vec.x) + (vec.y*vec.y)); if (length > 0) { float ilength = 1.0f/length; result.x = vec.x*ilength; result.y = vec.y*ilength; } return result; } v2 v2_scale(v2 vec, int scale) { return (v2) { .x = vec.x * scale, .y = vec.y * scale, }; } // keyboard code definit par js typedef enum Key { SHIFT = 16, SPACE = 32, ARROW_LEFT = 37, ARROW_RIGHT = 39, ARROW_UP = 38, ARROW_DOWN = 40, D = 68, Q = 81, KEY_COUNT, } Key; Key keys[KEY_COUNT] = {0}; void key_pressed(int key) { if (key < 0 || key >= KEY_COUNT) return; keys[key] = 1; } void key_released(int key) { if (key < 0 || key >= KEY_COUNT) return; keys[key] = 0; } typedef struct Collision { int x, y, width, height; } Collision; #define NB_COLLISIONS 64 Collision collisions[NB_COLLISIONS] = {}; int nb_collisions = 0; Collision collision_union(Collision rec1, Collision rec2) { Collision overlap = { 0 }; int left = (rec1.x > rec2.x)? rec1.x : rec2.x; int right1 = rec1.x + rec1.width; int right2 = rec2.x + rec2.width; int right = (right1 < right2)? right1 : right2; int top = (rec1.y > rec2.y)? rec1.y : rec2.y; int bottom1 = rec1.y + rec1.height; int bottom2 = rec2.y + rec2.height; int bottom = (bottom1 < bottom2)? bottom1 : bottom2; if ((left < right) && (top < bottom)) { overlap.x = left; overlap.y = top; overlap.width = right - left; overlap.height = bottom - top; } return overlap; } Collision collision_rec(Collision fix, int i, int scale) { Collision col = collision_union(fix, (Collision) { .x = penger_pos.x - pengers_width[id]*scale/2, .y = penger_pos.y - pengers_height[id]*scale/2, .width = pengers_width[id]*scale, .height = pengers_height[id]*scale, }); if (col.width == 0 && col.height == 0) return col; if (col.width == 1 && col.height == 1) return col; float div = -1.8; if (col.width <= col.height) { if (fix.x + fix.width == col.x + col.width) penger_pos.x = fix.x + fix.width + pengers_width[id]*scale/2; else if (fix.x == col.x) penger_pos.x = col.x - pengers_width[id]*scale/2 + 1; velocity.x /= div; } else { if (fix.y + fix.height == col.y + col.height) penger_pos.y = fix.y + fix.height + pengers_height[id]*scale/2; else if (fix.y == col.y) penger_pos.y = col.y - pengers_height[id]*scale/2 + 1; velocity.y /= div; } return col; } void reset_collisions() { nb_collisions = 0; } void add_collisions(int x, int y, int width, int height) { if (nb_collisions >= NB_COLLISIONS) return; collisions[nb_collisions++] = (Collision) { .x = x, .y = y, .width = width, .height = height, }; } void set_velocity(float x, float y) { velocity = (v2){x, y}; } void set_mouse(float x, float y) { mouse = (v2){x, y}; } int rand(int min, int max) { return min + random() * (max - min); } void rebondi(v2 *pos, int scale) { float div = -1.8; if (pos->x - pengers_width[id]*scale/2 < 0) { pos->x = pengers_width[id]*scale/2; velocity.x /= div; } if (pos->y - pengers_height[id]*scale/2 < 0) { pos->y = pengers_height[id]*scale/2; velocity.y /= div; } if (pos->x + pengers_width[id]*scale/2 >= width) { pos->x = width - pengers_width[id]*scale/2; velocity.x /= div; } if (pos->y + pengers_height[id]*scale/2 >= height) { pos->y = height - pengers_height[id]*scale/2; velocity.y /= div; } } int collision(v2 point, int x, int y, int w, int h) { return (point.x >= x && point.x < x + w && point.y >= y && point.y < y + h); } void set_default_map() { nb_collisions = 0; collisions[nb_collisions++] = (Collision) { .x = 100, .y = 400, .width = 50, .height = 100, }; collisions[nb_collisions++] = (Collision) { .x = 150, .y = 450, .width = 500, .height = 50, }; collisions[nb_collisions++] = (Collision) { .x = 650, .y = 400, .width = 50, .height = 100, }; collisions[nb_collisions++] = (Collision) { .x = 280, .y = 200, .width = 75, .height = 75, }; collisions[nb_collisions++] = (Collision) { .x = 445, .y = 200, .width = 75, .height = 75, }; } #define MAX_COIN 20 v2 coins[MAX_COIN] = {0}; int coin_collected[MAX_COIN] = {0}; int nb_coins = 0; void reset_coins() { for (int i = 0; i < nb_coins; i++) coin_collected[i] = 0; nb_coins = 0; } void add_coin(int x, int y) { if (nb_coins >= MAX_COIN) return; coins[nb_coins++] = (v2) { .x = x, .y = y, }; } void init() { pengers_init(); set_default_map(); } void draw(float dt) { int scale = get_scale(); // position du penger en haut a gauche de l'image v2 penger_origin = {0}; penger_origin.x = penger_pos.x - pengers_width[id]*scale/2; penger_origin.y = penger_pos.y - pengers_height[id]*scale/2; // jump static int jumped = 0; if (keys[SPACE] && !jumped) { jumped = 1; velocity.y = -5; velocity.x += rand(-2, 2); } else if (!keys[SPACE]) { jumped = 0; } // mouse push if (collision(mouse, penger_origin.x, penger_origin.y, pengers_width[id]*scale, pengers_height[id]*scale)) { v2 force = v2_diff(penger_pos, mouse); force = v2_normalize(force); force = v2_scale(force, 5); velocity.x += force.x; velocity.y += force.y; } if ((!keys[ARROW_LEFT] || !keys[Q]) && (!keys[ARROW_RIGHT] || !keys[D])) { penger_pos.x += velocity.x; } if (id == 28) // fatger id velocity.y += GRAVITY * dt * 7; else velocity.y += GRAVITY * dt; penger_pos.y += velocity.y; if (velocity.x <= -0.1) velocity.x += AIR_RESISTANCE * dt; else if (velocity.x >= 0.1) velocity.x -= AIR_RESISTANCE * dt; else velocity.x = 0; penger_pos.x += velocity.x; // movement int x_collide = 0; float speed = 100.0f * dt; if (keys[SHIFT]) speed /= 2.0f; if (keys[ARROW_RIGHT] || keys[D]) { penger_pos.x += speed; if (velocity.x < 0) { velocity.x *= -1; x_collide = 1; } else if (velocity.x >= -EPSILON) velocity.x = speed; } if (keys[ARROW_LEFT] || keys[Q]) { penger_pos.x -= speed; if (velocity.x > 0) { velocity.x *= -1; x_collide = 1; } else if (velocity.x <= EPSILON) velocity.x = -speed; } // background for (int i = 0; i < width * height; i++) BUFFER[i] = GREEN; rebondi(&penger_pos, scale); for (int i = 0; i < nb_collisions; i++) { Collision col = collision_rec(collisions[i], i, scale); x_collide = x_collide || (col.height > 1); } for (int i = 0; i < nb_coins; i++) { if (coin_collected[i]) continue; Collision coin = { .x = coins[i].x, .y = coins[i].y, .width = coin_width, .height = coin_height }; Collision peng = { .x = penger_pos.x - pengers_width[id]*scale/2, .y = penger_pos.y - pengers_height[id]*scale/2, .width = pengers_width[id]*scale, .height = pengers_height[id]*scale, }; Collision col = collision_union(coin, peng); if (col.width > 0 || col.height > 0) { coin_collected[i] = 1; coin_point(); } } // dessine le penger des autres joueur for (int p = 0; p < nb_players; p ++) { Player player = players[p]; if (player.rid == -1) continue; int scale = 2; for (int y = 0; y < pengers_height[player.id]; y++) { for (int i = 0; i < pengers_width[player.id]; i++) { int real_i = i; if (player.dir == -1) real_i = pengers_width[player.id]-i-1; if (pengers_img[player.id][y*pengers_width[player.id] + real_i] <= 0x00FFFFFF) // pixel transparant continue; for (int s1 = 0; s1 < scale; s1++) { for (int s2 = 0; s2 < scale; s2++) { int idx_x = player.x + i*scale+s1; int idx_y = player.y + y*scale+s2; if (idx_x < 0 || idx_x >= width || idx_y < 0 || idx_y >= height) continue; BUFFER[idx_y*width + idx_x] = pengers_img[player.id][y*pengers_width[player.id] + real_i]; } } } } } // dessine le penger sur le canva for (int y = 0; y < pengers_height[id]; y++) { for (int i = 0; i < pengers_width[id]; i++) { int i_for_reverse_pixel_rendering_it_s_craazy = 0; static int last_dir = 1; if ((velocity.x < -EPSILON && !x_collide) || last_dir == -1) { i_for_reverse_pixel_rendering_it_s_craazy = pengers_width[id]-i-1; last_dir = -1; } if ((velocity.x > EPSILON && !x_collide) || last_dir == 1) { i_for_reverse_pixel_rendering_it_s_craazy = i; last_dir = 1; } dir = last_dir; if (pengers_img[id][y*pengers_width[id] + i_for_reverse_pixel_rendering_it_s_craazy] <= 0x00FFFFFF) // pixel transparant continue; for (int s1 = 0; s1 < scale; s1++) { for (int s2 = 0; s2 < scale; s2++) { int idx_x = penger_origin.x + i*scale+s1; int idx_y = penger_origin.y + y*scale+s2; if (idx_x < 0 || idx_x >= width || idx_y < 0 || idx_y >= height) continue; BUFFER[idx_y*width + idx_x] = pengers_img[id][y*pengers_width[id] + i_for_reverse_pixel_rendering_it_s_craazy]; } } } } // dessine les coins for (int c = 0; c < nb_coins; c++) { if (coin_collected[c]) continue; int scale = 2; for (int y = 0; y < coin_height; y++) { for (int i = 0; i < coin_width; i++) { if (coin_img[y][i] <= 0x00FFFFFF) // pixel transparant continue; int idx_x = coins[c].x + i; int idx_y = coins[c].y + y; if (idx_x < 0 || idx_x >= width || idx_y < 0 || idx_y >= height) continue; BUFFER[idx_y*width + idx_x] = coin_img[y][i]; } } } // draw collisions box for (int i = 0; i < nb_collisions; i++) { for (int y = collisions[i].y; y < collisions[i].y + collisions[i].height; y++) { for (int x = collisions[i].x; x < collisions[i].x + collisions[i].width; x++) { if ((y/2 + x/3)%8 < 4) BUFFER[y*width + x] = BLUE; else BUFFER[y*width + x] = RED; } } } // draw hand for (int y = 0; y < hand_height; y++) { for (int x = 0; x < hand_width; x++) { if (hand_img[y][x] <= 0x00FFFFFF) // pixel transparant continue; int idx_x = x + mouse.x; int idx_y = y + mouse.y; if (idx_x < 0 || idx_x >= width || idx_y < 0 || idx_y >= height) continue; BUFFER[idx_y*width + idx_x] = hand_img[y][x]; } } }