DEADSOFTWARE

Добавлена стрельба
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Thu, 30 Mar 2017 22:06:51 +0000 (01:06 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Thu, 30 Mar 2017 22:06:51 +0000 (01:06 +0300)
client.c
game.c
game.h
netwar.c
protocol.h
server.c

index defe5ec757891aad33ee0c4d92dc8d3338163b1d..c1c9a557c7368229b647ebea1467f47c2d6c0207 100644 (file)
--- a/client.c
+++ b/client.c
@@ -38,6 +38,19 @@ static void cl_update_svplayer(ProtocolMessage m) {
        );
 }
 
+static void cl_update_svbullet(ProtocolMessage m) {
+       g_bullet_set(
+               m.sv.sbul.id,
+               m.sv.sbul.owner,
+               m.sv.sbul.live,
+               b2f(m.sv.sbul.x),
+               b2f(m.sv.sbul.y),
+               b2f(m.sv.sbul.vx),
+               b2f(m.sv.sbul.vy),
+               m.sv.sbul.tick
+       );
+}
+
 void cl_connect(const char * host, uint16_t port) {
        if(SDLNet_ResolveHost(&addr, host, (port) ? (port) : (DEFAULT_PORT)) != 0) {
                SDL_Log("Unable to resolve host: %s\n", SDLNet_GetError());
@@ -80,6 +93,7 @@ void cl_recv() {
        case SV_INFO: cl_update_svinfo(m); break;
        case SV_KILL: cl_kill_client(m); break;
        case SV_SPLR: cl_update_svplayer(m); break;
+       case SV_SBUL: cl_update_svbullet(m); break;
        default:      SDL_Log("invalid message %i", m.type);
        }
 }
diff --git a/game.c b/game.c
index cbc8e156ce5ff24ec6ef70e1a9150f34052f8a3d..219141884dd23ba9a59b2643135c78fcd83568e5 100644 (file)
--- a/game.c
+++ b/game.c
@@ -8,35 +8,77 @@
 
 #define SPEED  0.00006
 #define ROTATE 0.00004
+#define BULL_SPEED 0.008
 
 Player g_player[MAX_PLAYERS];
+Bullet g_bullet[MAX_BULLETS];
+
+void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr) {
+       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) {
        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);
 }
 
+static void roteplayer(int id, float speed) {
+       g_player[id].vr += speed;
+}
+
+static void fireplayer(int id) {
+       int j = freebullet();
+       if(j < 0)
+               return;
+
+       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 = abs(x);
+               x = fabs(x);
        else if(x > 1)
                x = -x;
        *a = x;
 }
 
-void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr) {
-       assert(id < MAX_PLAYERS);
-       g_player[id] = (Player) {
-               .updated = true,
-               .live    = live,
-               .x       = x,
-               .y       = y,
-               .r       = r,
-               .vx      = vx,
-               .vy      = vy,
-               .vr      = vr,
-       };
+static bool collide(float x1, float y1, float r1, float x2, float y2, float r2) {
+       float l = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
+       return ((l - r1 - r2) <= 0);
 }
 
 void g_player_does(unsigned int id, DoesCode code) {
@@ -45,9 +87,9 @@ void g_player_does(unsigned int id, DoesCode code) {
        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;
+       case DOES_LEFT:  roteplayer(id, -ROTATE); break;
+       case DOES_RIGHT: roteplayer(id, ROTATE); break;
+       case DOES_FIRE:  fireplayer(id); break;
        }
 }
 
@@ -62,4 +104,25 @@ void g_update() {
                        checkspacebound(&g_player[i].y);
                }
        }
+
+       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);
+
+                       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;
+               }
+       }
 }
diff --git a/game.h b/game.h
index 17c2b68dfafec9a26463c9db8624a2fd732069c9..7bf9d1e5621aa8838cb760bb39e4e0df0e54820e 100644 (file)
--- a/game.h
+++ b/game.h
@@ -2,8 +2,10 @@
 
 #include "protocol.h"
 
-#define MAX_PLAYERS 64
-#define TICK_DELAY  (1000 / 60)
+#define MAX_PLAYERS 32
+#define MAX_BULLETS (MAX_PLAYERS * 8)
+#define TICK_DELAY  (1000 / 30)
+#define BULLET_TIME (TICK_DELAY * 6)
 #define PLAYER_SIZE 0.01785
 
 typedef struct Player {
@@ -16,8 +18,22 @@ typedef struct Player {
        bool  updated;
 } Player;
 
+typedef struct Bullet {
+       /* public */
+       bool  live;
+       int   owner;
+       float x, y;
+       float vx, vy;
+       int   tick;
+
+       /* internal */
+       bool updated;
+} Bullet;
+
 extern Player g_player[MAX_PLAYERS];
+extern Bullet g_bullet[MAX_BULLETS];
 
 void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr);
+void g_bullet_set(unsigned int id, unsigned int owner, bool live, float x, float y, float vx, float vy, int tick);
 void g_player_does(unsigned int id, DoesCode code);
 void g_update();
index 2419456d87d0dea2265c5f9e47422286359258ab..b18f8ac9d7a5f288d546dcacbd8de65f30a3629e 100644 (file)
--- a/netwar.c
+++ b/netwar.c
@@ -110,6 +110,19 @@ static void paintwindow() {
                        SDL_RenderDrawLines(renderer, pixship, count);
        }
 
+       for(int i = 0; i < MAX_BULLETS; i++) {
+               if(g_bullet[i].owner == cl_playerid)
+                       SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00);
+               else
+                       SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0x00);
+
+               int x = g_bullet[i].x * WIDTH  / 2;
+               int y = g_bullet[i].y * HEIGHT / 2;
+
+               if(g_bullet[i].live)
+                       SDL_RenderDrawPoint(renderer, cx + x, cy + y);
+       }
+
        SDL_RenderPresent(renderer);
 }
 
@@ -144,6 +157,8 @@ int main(int argc, char ** argv) {
                        if(event.type == SDL_QUIT)
                                goto cleanup;
 
+               cl_recv();
+
                if(currTime - lastTime >= TICK_DELAY) {
                        keyboardhandle();
                        g_update();
@@ -151,8 +166,6 @@ int main(int argc, char ** argv) {
                }
                currTime = SDL_GetTicks();
 
-               cl_recv();
-
                paintwindow();
 
                SDL_Delay(1);
index 26815532050839457926e8bb89b51c21bd170a71..a20c773d16fbe0751ac5fcb6b6f9da3c4f05b233 100644 (file)
@@ -6,7 +6,7 @@
 #include <string.h>
 
 #define DEFAULT_PORT     29386
-#define PROTOCOL_VERSION 0
+#define PROTOCOL_VERSION 1
 #define PROTOCOL_F8FRAC  (1 << 7)
 
 #define PACKED __attribute__((__packed__))
@@ -21,6 +21,7 @@ typedef enum {
        SV_INFO = 128,
        SV_KILL = 139,
        SV_SPLR = 130,
+       SV_SBUL = 131,
 } MessageType;
 
 typedef enum {
@@ -67,6 +68,16 @@ typedef struct PACKED SvSplr {
        uint8_t vx, vy, vr;
 } SvSplr;
 
+typedef struct PACKED SvSbul {
+       uint8_t type;
+       uint8_t id;
+       uint8_t owner;
+       uint8_t live;
+       uint8_t x, y;
+       uint8_t vx, vy;
+       uint8_t tick;
+} SvSbul;
+
 typedef union ClMessage {
        uint8_t type;
        ClInfo  info;
@@ -79,6 +90,7 @@ typedef union SvMessage {
        SvInfo  info;
        SvKill  kill;
        SvSplr  splr;
+       SvSbul  sbul;
 } SvMessage;
 
 typedef union ProtocolMessage {
@@ -99,6 +111,7 @@ static inline int  MessageTypeSize(MessageType type) {
        case SV_INFO: return sizeof(SvInfo);
        case SV_KILL: return sizeof(SvKill);
        case SV_SPLR: return sizeof(SvSplr);
+       case SV_SBUL: return sizeof(SvSbul);
        default:      return sizeof(ProtocolMessage);
        }
 }
@@ -162,6 +175,20 @@ static inline ProtocolMessage sv_splr(int clid, bool live, float x, float y, flo
        };
 }
 
+static inline ProtocolMessage sv_sbul(int id, int owner, bool live, float x, float y, float vx, float vy, int tick) {
+       return (ProtocolMessage) (SvMessage) (SvSbul) {
+               .type  = SV_SBUL,
+               .id    = id,
+               .owner = owner,
+               .live  = live,
+               .x     = f2b(x),
+               .y     = f2b(y),
+               .vx    = f2b(vx),
+               .vy    = f2b(vy),
+               .tick  = tick,
+       };
+}
+
 #undef PACKED
 
 #endif /* PROTOCOL_H_INCLUDED */
index ea28583e06de04a2ead618e666593f6e92e2dc22..d6cbfcc3b3c07cb1670bb914466dd414dca5136d 100644 (file)
--- a/server.c
+++ b/server.c
@@ -48,6 +48,15 @@ static void sv_sync_client(int id, bool full) {
        for(int i = 0; i < clientlimit; i++)
                if(full || g_player[i].updated)
                        SendMessage(sock, client[id].address, sv_splr(i, g_player[i].live, g_player[i].x, g_player[i].y, g_player[i].r, g_player[i].vx, g_player[i].vy, g_player[i].vr));
+
+       for(int i = 0; i < MAX_BULLETS; i++)
+               if(full || g_bullet[i].updated)
+                       SendMessage(sock, client[id].address, sv_sbul(i, g_bullet[i].owner, g_bullet[i].live, g_bullet[i].x, g_bullet[i].y, g_bullet[i].vx, g_bullet[i].vy, g_bullet[i].tick));
+}
+
+static void sv_spawn_player(int id) {
+       assert(id >= 0);
+       g_player_set(id, true, randfm(), randfm(), randfm(), 0, 0, 0);
 }
 
 static void sv_kill_player(int id, bool send, const char * msg) {
@@ -66,6 +75,9 @@ static void sv_move_player(int id, ProtocolMessage m) {
        assert(id >= 0);
        assert(client[id].connected);
 
+       if(!g_player[id].live)
+               sv_spawn_player(id);
+
        g_player_does(id, m.cl.does.code);
 }
 
@@ -92,7 +104,7 @@ static void sv_register_player(IPaddress address, ProtocolMessage m) {
        SDL_Log("Player %s (%i) connected", client[i].name, i);
        SendMessage(sock, address, sv_info(name, i, clientlimit));
 
-       g_player_set(i, true, randfm(), randfm(), randfm(), 0, 0, 0);
+       sv_spawn_player(i);
        sv_sync_client(i, true);
 }
 
@@ -114,9 +126,12 @@ static void sv_send() {
        for(int i = 0; i < clientlimit; i++)
                if(client[i].connected)
                        sv_sync_client(i, false);
-       
+
        for(int i = 0; i < clientlimit; i++)
                g_player[i].updated = false;
+
+       for(int i = 0; i < MAX_BULLETS; i++)
+               g_bullet[i].updated = false;
 }
 
 void sv_start(uint16_t port) {