#include #include #include #include #include "game.h" #define SPEED (0.0005 / TICK) #define ROTATE (0.03 / TICK) #define BULL_SPEED (0.4 / TICK) #define MAX_SPEED (0.1 / TICK) #define MAX_ROTATE (0.3 / TICK) // Цифры взяты с потолка, но вроде неплохо подобраны #define G 6.6719199e-11 #define M_STAR 3e8 #define M_SHIP 0.001 Player g_player[MAX_PLAYERS]; Bullet g_bullet[MAX_BULLETS]; static bool svmode; void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr, int shoot) { assert(id < MAX_PLAYERS); g_player[id] = (Player) { .updated = true, .live = live, .x = x, .y = y, .r = r, .vx = vx, .vy = vy, .vr = vr, }; } void g_bullet_set(unsigned int id, unsigned int owner, bool live, float x, float y, float vx, float vy, int tick) { assert(id < MAX_BULLETS); assert(owner < MAX_PLAYERS); g_bullet[id] = (Bullet) { .live = live, .owner = owner, .x = x, .y = y, .vx = vx, .vy = vy, .tick = tick, }; } static int freebullet() { for(int i = 0; i < MAX_BULLETS; i++) if(!g_bullet[i].live) return i; return -1; } static void moveplayer(int id, float speed) { if(fabs(g_player[id].vx) < MAX_SPEED) g_player[id].vx += speed * cos(g_player[id].r * 2 * M_PI); if(fabs(g_player[id].vy) < MAX_SPEED) g_player[id].vy += speed * sin(g_player[id].r * 2 * M_PI); } static void roteplayer(int id, float speed) { g_player[id].vr += speed; if(fabs(g_player[id].vr) > MAX_ROTATE) g_player[id].vr = copysignf(MAX_ROTATE, g_player[id].vr); } static void fireplayer(int id) { int j = freebullet(); if(j < 0) return; if(g_player[id].shoot < PLAYER_SHOOT) return; g_player[id].shoot = 0; if(svmode) { float vx = BULL_SPEED * cos(g_player[id].r * 2 * M_PI); float vy = BULL_SPEED * sin(g_player[id].r * 2 * M_PI); g_bullet_set(j, id, true, g_player[id].x, g_player[id].y, vx, vy, 0); } } static void checkspacebound(float * a) { float x = *a; if(x < -1 || x > 1) x = copysign(fmodf(x, 1) + 1, -1 * x); *a = x; } static float length(float x1, float y1, float x2, float y2) { return sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2)); } static bool collide(float x1, float y1, float r1, float x2, float y2, float r2) { return ((length(x1, y1, x2, y2) - r1 - r2) <= 0); } static void gravity(float * vx, float * vy, float x, float y) { *vx += copysign(G * M_STAR * M_SHIP / length(0, 0, x, y), x * -1); *vy += copysign(G * M_STAR * M_SHIP / length(0, 0, x, y), y * -1); } void g_player_does(unsigned int id, DoesBits code) { assert(id < MAX_PLAYERS); if(code.up) moveplayer(id, SPEED); if(code.down) moveplayer(id, -SPEED); if(code.left) roteplayer(id, -ROTATE); if(code.right) roteplayer(id, ROTATE); if(code.fire) fireplayer(id); } void g_update() { for(int i = 0; i < MAX_PLAYERS; i++) { if(g_player[i].live) { g_player[i].updated = true; g_player[i].x += g_player[i].vx; g_player[i].y += g_player[i].vy; g_player[i].r += g_player[i].vr; gravity(&g_player[i].vx, &g_player[i].vy, g_player[i].x, g_player[i].y); checkspacebound(&g_player[i].x); checkspacebound(&g_player[i].y); ++g_player[i].shoot; if(g_player[i].shoot > PLAYER_SHOOT) g_player[i].shoot = PLAYER_SHOOT; if(collide(g_player[i].x, g_player[i].y, PLAYER_SIZE, 0, 0, STAR_SIZE)) g_player[i].live = false; } } for(int i = 0; i < MAX_BULLETS; i++) { if(g_bullet[i].live) { g_bullet[i].updated = true; g_bullet[i].tick += 1; g_bullet[i].x += g_bullet[i].vx; g_bullet[i].y += g_bullet[i].vy; checkspacebound(&g_bullet[i].x); checkspacebound(&g_bullet[i].y); gravity(&g_bullet[i].vx, &g_bullet[i].vy, g_bullet[i].x, g_bullet[i].y); for(int j = 0; j < MAX_PLAYERS; j++) if(g_player[j].live) if(collide(g_bullet[i].x, g_bullet[i].y, 0.0001, g_player[j].x, g_player[j].y, PLAYER_SIZE)) if(j != g_bullet[i].owner) g_player[j].live = false; if(g_bullet[i].tick > BULLET_TIME) g_bullet[i].live = false; } } } void g_init(bool server_mode) { svmode = server_mode; // TODO memset & co }