DEADSOFTWARE

Исправлено падение скорости после разгона от звезды, изменён баланс, звезда выглядит...
[netwar.git] / game.c
1 #include <SDL2/SDL.h>
3 #include <assert.h>
4 #include <stdbool.h>
5 #include <math.h>
7 #include "game.h"
9 #define SPEED (0.015 / TICK)
10 #define ROTATE (0.03 / TICK)
11 #define BULL_SPEED (0.4 / TICK)
13 #define MAX_SPEED (0.3 / TICK)
14 #define MAX_ROTATE (0.3 / TICK)
16 // Цифры взяты с потолка, но вроде неплохо подобраны
17 #define G 6.673e-4
18 #define M_STAR 8.0
19 #define M_SHIP 0.1
21 Player g_player[MAX_PLAYERS];
22 Bullet g_bullet[MAX_BULLETS];
24 static bool svmode;
26 void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr, int shoot) {
27 assert(id < MAX_PLAYERS);
28 g_player[id] = (Player) {
29 .updated = true,
30 .live = live,
31 .x = x,
32 .y = y,
33 .r = r,
34 .vx = vx,
35 .vy = vy,
36 .vr = vr,
37 };
38 }
40 void g_bullet_set(unsigned int id, unsigned int owner, bool live, float x, float y, float vx, float vy, int tick) {
41 assert(id < MAX_BULLETS);
42 assert(owner < MAX_PLAYERS);
43 g_bullet[id] = (Bullet) {
44 .live = live,
45 .owner = owner,
46 .x = x,
47 .y = y,
48 .vx = vx,
49 .vy = vy,
50 .tick = tick,
51 };
52 }
54 static int freebullet() {
55 for(int i = 0; i < MAX_BULLETS; i++)
56 if(!g_bullet[i].live)
57 return i;
58 return -1;
59 }
61 static void moveplayer(int id, float speed) {
62 if(fabs(g_player[id].vx) < MAX_SPEED)
63 g_player[id].vx += speed * cos(g_player[id].r * 2 * M_PI);
64 if(fabs(g_player[id].vy) < MAX_SPEED)
65 g_player[id].vy += speed * sin(g_player[id].r * 2 * M_PI);
66 }
68 static void roteplayer(int id, float speed) {
69 g_player[id].vr += speed;
70 if(fabs(g_player[id].vr) > MAX_ROTATE)
71 g_player[id].vr = copysignf(MAX_ROTATE, g_player[id].vr);
72 }
74 static void fireplayer(int id) {
75 int j = freebullet();
76 if(j < 0)
77 return;
79 if(g_player[id].shoot < PLAYER_SHOOT)
80 return;
82 g_player[id].shoot = 0;
84 if(svmode) {
85 float vx = BULL_SPEED * cos(g_player[id].r * 2 * M_PI);
86 float vy = BULL_SPEED * sin(g_player[id].r * 2 * M_PI);
87 g_bullet_set(j, id, true, g_player[id].x, g_player[id].y, vx, vy, 0);
88 }
89 }
91 static void checkspacebound(float * a) {
92 float x = *a;
93 if(x < -1 || x > 1)
94 x = copysign(fmodf(x, 1) + 1, -1 * x);
95 *a = x;
96 }
98 static float length(float x1, float y1, float x2, float y2) {
99 return sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
102 static bool collide(float x1, float y1, float r1, float x2, float y2, float r2) {
103 return ((length(x1, y1, x2, y2) - r1 - r2) <= 0);
106 static void gravity(float * vx, float * vy, float x, float y) {
107 *vx += copysign(G * M_STAR * M_SHIP / length(0, 0, x, y), x * -1);
108 *vy += copysign(G * M_STAR * M_SHIP / length(0, 0, x, y), y * -1);
111 void g_player_does(unsigned int id, DoesBits code) {
112 assert(id < MAX_PLAYERS);
114 if(code.up)
115 moveplayer(id, SPEED);
116 if(code.down)
117 moveplayer(id, -SPEED);
118 if(code.left)
119 roteplayer(id, -ROTATE);
120 if(code.right)
121 roteplayer(id, ROTATE);
122 if(code.fire)
123 fireplayer(id);
126 void g_update() {
127 for(int i = 0; i < MAX_PLAYERS; i++) {
128 if(g_player[i].live) {
129 g_player[i].updated = true;
130 g_player[i].x += g_player[i].vx;
131 g_player[i].y += g_player[i].vy;
132 g_player[i].r += g_player[i].vr;
134 gravity(&g_player[i].vx, &g_player[i].vy, g_player[i].x, g_player[i].y);
136 checkspacebound(&g_player[i].x);
137 checkspacebound(&g_player[i].y);
139 ++g_player[i].shoot;
140 if(g_player[i].shoot > PLAYER_SHOOT)
141 g_player[i].shoot = PLAYER_SHOOT;
143 if(collide(g_player[i].x, g_player[i].y, PLAYER_SIZE, 0, 0, STAR_SIZE))
144 g_player[i].live = false;
148 for(int i = 0; i < MAX_BULLETS; i++) {
149 if(g_bullet[i].live) {
150 g_bullet[i].updated = true;
151 g_bullet[i].tick += 1;
152 g_bullet[i].x += g_bullet[i].vx;
153 g_bullet[i].y += g_bullet[i].vy;
155 checkspacebound(&g_bullet[i].x);
156 checkspacebound(&g_bullet[i].y);
158 //gravity(&g_bullet[i].vx, &g_bullet[i].vy, g_bullet[i].x, g_bullet[i].y);
160 for(int j = 0; j < MAX_PLAYERS; j++)
161 if(g_player[j].live)
162 if(collide(g_bullet[i].x, g_bullet[i].y, 0.0001, g_player[j].x, g_player[j].y, PLAYER_SIZE))
163 if(j != g_bullet[i].owner)
164 g_player[j].live = false;
166 if(g_bullet[i].tick > BULLET_TIME)
167 g_bullet[i].live = false;
172 void g_init(bool server_mode) {
173 svmode = server_mode;
174 // TODO memset & co