index cbc8e156ce5ff24ec6ef70e1a9150f34052f8a3d..2370692abdad4904825a910b65828b03821394a3 100644 (file)
--- a/game.c
+++ b/game.c
#include "game.h"
-#define SPEED 0.00006
-#define ROTATE 0.00004
+#define SPEED (0.0005 / TICK)
+#define ROTATE (0.03 / TICK)
+#define BULL_SPEED (0.4 / TICK)
-Player g_player[MAX_PLAYERS];
+#define MAX_SPEED (0.1 / TICK)
+#define MAX_ROTATE (0.3 / TICK)
-static void moveplayer(int id, float speed) {
- g_player[id].vx += speed * cos(g_player[id].r * 2 * M_PI);
- g_player[id].vy += speed * sin(g_player[id].r * 2 * M_PI);
-}
+// Цифры взяты с потолка, но вроде неплохо подобраны
+#define G 6.6719199e-11
+#define M_STAR 3e8
+#define M_SHIP 0.001
-static void checkspacebound(float * a) {
- float x = *a;
- if(x < -1)
- x = abs(x);
- else if(x > 1)
- x = -x;
- *a = x;
-}
+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) {
+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,
@@ -39,18 +37,92 @@ void g_player_set(unsigned int id, bool live, float x, float y, float r, float v
};
}
-void g_player_does(unsigned int id, DoesCode code) {
- assert(id < MAX_PLAYERS);
- g_player[id].updated = true;
- switch(code) {
- case DOES_UP: moveplayer(id, SPEED); break;
- case DOES_DOWN: moveplayer(id, -SPEED); break;
- case DOES_LEFT: g_player[id].vr -= ROTATE; break;
- case DOES_RIGHT: g_player[id].vr += ROTATE; break;
- case DOES_FIRE: break;
+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].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
+}