Просмотр исходного кода

changed trajectory algorithm, added wind and random player and enemy location

jasniec 3 лет назад
Родитель
Сommit
4b2551ae48
2 измененных файлов с 148 добавлено и 93 удалено
  1. BIN
      scorchedTanks_10px.png
  2. 148 93
      scorched_tanks_game_app.c

BIN
scorchedTanks_10px.png


+ 148 - 93
scorched_tanks_game_app.c

@@ -13,16 +13,19 @@
 #define PLAYER_INIT_POWER 50
 #define ENEMY_INIT_LOCATION_X 108
 #define TANK_BARREL_LENGTH 8
-#define GRAVITY_FORCE 32
+#define GRAVITY_FORCE 0.5
 #define MIN_GROUND_HEIGHT 35
 #define MAX_GROUND_HEIGHT 55
 #define MAX_FIRE_POWER 100
 #define MIN_FIRE_POWER 0
 #define TANK_COLLIDER_SIZE 3
+#define MAX_WIND 10
+#define MAX_PLAYER_DIFF_X 20
+#define MAX_ENEMY_DIFF_X 20
 
 // That's a filthy workaround but sin(player.aimAngle) breaks it all... If you're able to fix it, please do create a PR!
 double scorched_tanks_sin[91] = {
-    0.000,  -0.017, -0.035, -0.052, -0.070, -0.087, -0.105, -0.122, -0.139, -0.156, -0.174, -0.191,
+    0.000, -0.017, -0.035, -0.052, -0.070, -0.087, -0.105, -0.122, -0.139, -0.156, -0.174, -0.191,
     -0.208, -0.225, -0.242, -0.259, -0.276, -0.292, -0.309, -0.326, -0.342, -0.358, -0.375, -0.391,
     -0.407, -0.423, -0.438, -0.454, -0.469, -0.485, -0.500, -0.515, -0.530, -0.545, -0.559, -0.574,
     -0.588, -0.602, -0.616, -0.629, -0.643, -0.656, -0.669, -0.682, -0.695, -0.707, -0.719, -0.731,
@@ -39,17 +42,18 @@ double scorched_tanks_cos[91] = {
     0.423, 0.407, 0.391, 0.375, 0.358, 0.342, 0.326, 0.309, 0.292, 0.276, 0.259, 0.242, 0.225,
     0.208, 0.191, 0.174, 0.156, 0.139, 0.122, 0.105, 0.087, 0.070, 0.052, 0.035, 0.017, 0.000};
 double scorched_tanks_tan[91] = {
-    0.000,   -0.017,  -0.035,    -0.052, -0.070, -0.087, -0.105, -0.123, -0.141,  -0.158,  -0.176,
-    -0.194,  -0.213,  -0.231,    -0.249, -0.268, -0.287, -0.306, -0.325, -0.344,  -0.364,  -0.384,
-    -0.404,  -0.424,  -0.445,    -0.466, -0.488, -0.510, -0.532, -0.554, -0.577,  -0.601,  -0.625,
-    -0.649,  -0.674,  -0.700,    -0.727, -0.754, -0.781, -0.810, -0.839, -0.869,  -0.900,  -0.932,
-    -0.966,  -1.000,  -1.036,    -1.072, -1.111, -1.150, -1.192, -1.235, -1.280,  -1.327,  -1.376,
-    -1.428,  -1.483,  -1.540,    -1.600, -1.664, -1.732, -1.804, -1.881, -1.963,  -2.050,  -2.144,
-    -2.246,  -2.356,  -2.475,    -2.605, -2.747, -2.904, -3.078, -3.271, -3.487,  -3.732,  -4.011,
-    -4.331,  -4.704,  -5.144,    -5.671, -6.313, -7.115, -8.144, -9.513, -11.429, -14.298, -19.077,
+    0.000, -0.017, -0.035, -0.052, -0.070, -0.087, -0.105, -0.123, -0.141, -0.158, -0.176,
+    -0.194, -0.213, -0.231, -0.249, -0.268, -0.287, -0.306, -0.325, -0.344, -0.364, -0.384,
+    -0.404, -0.424, -0.445, -0.466, -0.488, -0.510, -0.532, -0.554, -0.577, -0.601, -0.625,
+    -0.649, -0.674, -0.700, -0.727, -0.754, -0.781, -0.810, -0.839, -0.869, -0.900, -0.932,
+    -0.966, -1.000, -1.036, -1.072, -1.111, -1.150, -1.192, -1.235, -1.280, -1.327, -1.376,
+    -1.428, -1.483, -1.540, -1.600, -1.664, -1.732, -1.804, -1.881, -1.963, -2.050, -2.144,
+    -2.246, -2.356, -2.475, -2.605, -2.747, -2.904, -3.078, -3.271, -3.487, -3.732, -4.011,
+    -4.331, -4.704, -5.144, -5.671, -6.313, -7.115, -8.144, -9.513, -11.429, -14.298, -19.077,
     -28.627, -57.254, -90747.269};
 
-typedef struct {
+typedef struct
+{
     //    +-----x
     //    |
     //    |
@@ -58,7 +62,18 @@ typedef struct {
     uint8_t y;
 } Point;
 
-typedef struct {
+typedef struct
+{
+    //    +-----x
+    //    |
+    //    |
+    //    y
+    double x;
+    double y;
+} PointDetailed;
+
+typedef struct
+{
     unsigned char locationX;
     unsigned char hp;
     int aimAngle;
@@ -66,43 +81,54 @@ typedef struct {
     bool isShooting;
 } Tank;
 
-typedef struct {
+typedef struct
+{
     Point ground[SCREEN_WIDTH];
     Tank player;
     Tank enemy;
     bool isPlayerTurn;
-    unsigned char trajectoryY[SCREEN_WIDTH];
+    int windSpeed;
+    Point trajectory[SCREEN_WIDTH];
     unsigned char trajectoryAnimationStep;
-    Point bulletPosition;
+    PointDetailed bulletPosition;
+    PointDetailed bulletVector;
 } Game;
 
-typedef enum {
+typedef enum
+{
     EventTypeTick,
     EventTypeKey,
 } EventType;
 
-typedef struct {
+typedef struct
+{
     EventType type;
     InputEvent input;
 } ScorchedTanksEvent;
 
-int scorched_tanks_random(int min, int max) {
+int scorched_tanks_random(int min, int max)
+{
     return min + rand() % ((max + 1) - min);
 }
 
-void scorched_tanks_generate_ground(Game* game_state) {
+void scorched_tanks_generate_ground(Game *game_state)
+{
     auto lastHeight = 45;
 
-    for(unsigned char a = 0; a < SCREEN_WIDTH; a++) {
+    for (unsigned char a = 0; a < SCREEN_WIDTH; a++)
+    {
         auto diffHeight = scorched_tanks_random(-2, 3);
         auto changeLength = scorched_tanks_random(1, 6);
 
-        if(diffHeight == 0) {
+        if (diffHeight == 0)
+        {
             changeLength = 1;
         }
 
-        for(int b = 0; b < changeLength; b++) {
-            if(a + b < SCREEN_WIDTH) {
+        for (int b = 0; b < changeLength; b++)
+        {
+            if (a + b < SCREEN_WIDTH)
+            {
                 auto index = a + b;
                 auto newPoint = lastHeight + diffHeight;
                 newPoint = newPoint < MIN_GROUND_HEIGHT ? MIN_GROUND_HEIGHT : newPoint;
@@ -110,7 +136,9 @@ void scorched_tanks_generate_ground(Game* game_state) {
                 game_state->ground[index].x = index;
                 game_state->ground[index].y = newPoint;
                 lastHeight = newPoint;
-            } else {
+            }
+            else
+            {
                 a += b;
                 break;
             }
@@ -120,40 +148,37 @@ void scorched_tanks_generate_ground(Game* game_state) {
     }
 }
 
-void scorched_tanks_init_game(Game* game_state) {
-    game_state->player.locationX = PLAYER_INIT_LOCATION_X;
+void scorched_tanks_init_game(Game *game_state)
+{
+    game_state->player.locationX = PLAYER_INIT_LOCATION_X + scorched_tanks_random(0, MAX_PLAYER_DIFF_X) - MAX_PLAYER_DIFF_X / 2;
     game_state->player.aimAngle = PLAYER_INIT_AIM;
     game_state->player.firePower = PLAYER_INIT_POWER;
-    game_state->enemy.locationX = ENEMY_INIT_LOCATION_X;
+    game_state->enemy.locationX = ENEMY_INIT_LOCATION_X + scorched_tanks_random(0, MAX_ENEMY_DIFF_X) - MAX_ENEMY_DIFF_X / 2;
+
+    game_state->windSpeed = scorched_tanks_random(0, MAX_WIND);
 
     for (int x = 0; x < SCREEN_WIDTH; x++)
     {
-        game_state->trajectoryY[x] = 0;
+        game_state->trajectory[x].x = 0;
+        game_state->trajectory[x].y = 0;
     }
 
     scorched_tanks_generate_ground(game_state);
 }
 
-void scorched_tanks_calculate_trajectory(Game* game_state) {
-    if(game_state->player.isShooting) {
-        int x0 = game_state->player.locationX;
-        int y0 = game_state->ground[game_state->player.locationX].y - TANK_COLLIDER_SIZE;
-        int v0 = game_state->player.firePower;
-        int g = GRAVITY_FORCE;
-        int angle = game_state->player.aimAngle;
-
-        if(x0 + game_state->trajectoryAnimationStep > SCREEN_WIDTH ||
-           game_state->bulletPosition.x > SCREEN_WIDTH ||
-           game_state->bulletPosition.y > game_state->ground[game_state->bulletPosition.x].y) { 
-                game_state->player.isShooting = false;
-                game_state->bulletPosition.x = 0;
-                game_state->bulletPosition.y = 0;
-                return;
-        }
+void scorched_tanks_calculate_trajectory(Game *game_state)
+{
+    if (game_state->player.isShooting)
+    {
+        game_state->bulletVector.x += ((double)game_state->windSpeed - MAX_WIND / 2) / 50;
+        game_state->bulletVector.y += GRAVITY_FORCE;
+
+        game_state->bulletPosition.x += game_state->bulletVector.x;
+        game_state->bulletPosition.y += game_state->bulletVector.y;
 
-        unsigned char distanceToEnemyX = game_state->enemy.locationX - game_state->bulletPosition.x;
-        unsigned char distanceToEnemyY = game_state->ground[game_state->enemy.locationX].y - TANK_COLLIDER_SIZE - game_state->bulletPosition.y;
-        int totalDistanceToEnemy = sqrt(distanceToEnemyX*distanceToEnemyX+distanceToEnemyY*distanceToEnemyY);
+        double distanceToEnemyX = game_state->enemy.locationX - game_state->bulletPosition.x;
+        double distanceToEnemyY = game_state->ground[game_state->enemy.locationX].y - TANK_COLLIDER_SIZE - game_state->bulletPosition.y;
+        int totalDistanceToEnemy = sqrt(distanceToEnemyX * distanceToEnemyX + distanceToEnemyY * distanceToEnemyY);
 
         if (totalDistanceToEnemy <= TANK_COLLIDER_SIZE)
         {
@@ -162,27 +187,31 @@ void scorched_tanks_calculate_trajectory(Game* game_state) {
             return;
         }
 
-        auto x = game_state->trajectoryAnimationStep;
-        auto y = y0 + x * scorched_tanks_tan[angle] -
-                 g * x * x / -(2 * v0 * v0 * scorched_tanks_cos[angle] * scorched_tanks_cos[angle]);
-
-        x += x0;
-
-        if(x % 4 == 0) {
-            game_state->trajectoryY[x] = y;
+        if (game_state->bulletPosition.x > SCREEN_WIDTH ||
+            game_state->bulletPosition.y > game_state->ground[(int)round(game_state->bulletPosition.x)].y)
+        {
+            game_state->player.isShooting = false;
+            game_state->bulletPosition.x = 0;
+            game_state->bulletPosition.y = 0;
+            game_state->windSpeed = scorched_tanks_random(0, MAX_WIND);
+            return;
         }
 
-        game_state->bulletPosition.x = x;
-        game_state->bulletPosition.y = y;
-
-        game_state->trajectoryAnimationStep++;
+        if (game_state->bulletPosition.y > 0)
+        {
+            game_state->trajectory[game_state->trajectoryAnimationStep].x = round(game_state->bulletPosition.x);
+            game_state->trajectory[game_state->trajectoryAnimationStep].y = round(game_state->bulletPosition.y);
+            game_state->trajectoryAnimationStep++;
+        }
     }
 }
 
-static void scorched_tanks_render_callback(Canvas* const canvas, void* ctx) {
-    const Game* game_state = acquire_mutex((ValueMutex*)ctx, 25);
+static void scorched_tanks_render_callback(Canvas *const canvas, void *ctx)
+{
+    const Game *game_state = acquire_mutex((ValueMutex *)ctx, 25);
 
-    if(game_state == NULL) {
+    if (game_state == NULL)
+    {
         return;
     }
 
@@ -190,11 +219,13 @@ static void scorched_tanks_render_callback(Canvas* const canvas, void* ctx) {
 
     canvas_set_color(canvas, ColorBlack);
 
-    if(game_state->player.isShooting) {
+    if (game_state->player.isShooting)
+    {
         canvas_draw_dot(canvas, game_state->bulletPosition.x, game_state->bulletPosition.y);
     }
 
-    for(int a = 1; a < SCREEN_WIDTH; a++) {
+    for (int a = 1; a < SCREEN_WIDTH; a++)
+    {
         canvas_draw_line(
             canvas,
             game_state->ground[a - 1].x,
@@ -202,8 +233,9 @@ static void scorched_tanks_render_callback(Canvas* const canvas, void* ctx) {
             game_state->ground[a].x,
             game_state->ground[a].y);
 
-        if(game_state->trajectoryY[a] != 0) {
-            canvas_draw_dot(canvas, a, game_state->trajectoryY[a]);
+        if (game_state->trajectory[a].y != 0)
+        {
+            canvas_draw_dot(canvas, game_state->trajectory[a].x, game_state->trajectory[a].y);
         }
     }
 
@@ -230,7 +262,10 @@ static void scorched_tanks_render_callback(Canvas* const canvas, void* ctx) {
     canvas_draw_line(canvas, aimX1, aimY1, aimX2, aimY2);
 
     canvas_set_font(canvas, FontSecondary);
-    canvas_draw_str(canvas, 55, 10, "Scorched Tanks");
+
+    char buffer2[12];
+    snprintf(buffer2, sizeof(buffer2), "wind: %i", game_state->windSpeed - MAX_WIND / 2);
+    canvas_draw_str(canvas, 55, 10, buffer2);
 
     char buffer[12];
     snprintf(buffer, sizeof(buffer), "a: %u", game_state->player.aimAngle);
@@ -239,24 +274,26 @@ static void scorched_tanks_render_callback(Canvas* const canvas, void* ctx) {
     snprintf(buffer, sizeof(buffer), "p: %u", game_state->player.firePower);
     canvas_draw_str(canvas, 27, 10, buffer);
 
-    release_mutex((ValueMutex*)ctx, game_state);
+    release_mutex((ValueMutex *)ctx, game_state);
 }
 
-static void scorched_tanks_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
+static void scorched_tanks_input_callback(InputEvent *input_event, FuriMessageQueue *event_queue)
+{
     furi_assert(event_queue);
 
     ScorchedTanksEvent event = {.type = EventTypeKey, .input = *input_event};
     furi_message_queue_put(event_queue, &event, FuriWaitForever);
 }
 
-static void scorched_tanks_update_timer_callback(FuriMessageQueue* event_queue) {
+static void scorched_tanks_update_timer_callback(FuriMessageQueue *event_queue)
+{
     furi_assert(event_queue);
 
     ScorchedTanksEvent event = {.type = EventTypeTick};
     furi_message_queue_put(event_queue, &event, 0);
 }
 
-static void scorched_tanks_increase_power(Game* game_state)
+static void scorched_tanks_increase_power(Game *game_state)
 {
     if (game_state->player.firePower < MAX_FIRE_POWER && !game_state->player.isShooting)
     {
@@ -264,7 +301,7 @@ static void scorched_tanks_increase_power(Game* game_state)
     }
 }
 
-static void scorched_tanks_decrease_power(Game* game_state)
+static void scorched_tanks_decrease_power(Game *game_state)
 {
     if (game_state->player.firePower > MIN_FIRE_POWER && !game_state->player.isShooting)
     {
@@ -272,14 +309,18 @@ static void scorched_tanks_decrease_power(Game* game_state)
     }
 }
 
-static void scorched_tanks_aim_up(Game* game_state) {
-    if(game_state->player.aimAngle < 90 && !game_state->player.isShooting) {
+static void scorched_tanks_aim_up(Game *game_state)
+{
+    if (game_state->player.aimAngle < 90 && !game_state->player.isShooting)
+    {
         game_state->player.aimAngle++;
     }
 }
 
-static void scorched_tanks_aim_down(Game* game_state) {
-    if(game_state->player.aimAngle > 0 && !game_state->player.isShooting) {
+static void scorched_tanks_aim_down(Game *game_state)
+{
+    if (game_state->player.aimAngle > 0 && !game_state->player.isShooting)
+    {
         game_state->player.aimAngle--;
     }
 }
@@ -291,60 +332,72 @@ const NotificationSequence sequence_long_vibro = {
     NULL,
 };
 
-static void scorched_tanks_fire(Game* game_state) {
-    if(!game_state->player.isShooting) {
+static void scorched_tanks_fire(Game *game_state)
+{
+    if (!game_state->player.isShooting)
+    {
         game_state->bulletPosition.x = game_state->player.locationX;
         game_state->bulletPosition.y = game_state->ground[game_state->player.locationX].y - TANK_COLLIDER_SIZE;
+        game_state->bulletVector.x = scorched_tanks_cos[game_state->player.aimAngle] * ((double)game_state->player.firePower / 10);
+        game_state->bulletVector.y = scorched_tanks_sin[game_state->player.aimAngle] * ((double)game_state->player.firePower / 10);
         game_state->trajectoryAnimationStep = 0;
 
-        for(int x = 0; x < SCREEN_WIDTH; x++) {
-            game_state->trajectoryY[x] = 0;
+        for (int x = 0; x < SCREEN_WIDTH; x++)
+        {
+            game_state->trajectory[x].x = 0;
+            game_state->trajectory[x].y = 0;
         }
 
         game_state->player.isShooting = true;
 
-        NotificationApp* notification = furi_record_open("notification");
+        NotificationApp *notification = furi_record_open("notification");
         notification_message(notification, &sequence_long_vibro);
         notification_message(notification, &sequence_blink_white_100);
         furi_record_close("notification");
     }
 }
 
-int32_t scorched_tanks_game_app(void* p) {
+int32_t scorched_tanks_game_app(void *p)
+{
     UNUSED(p);
     srand(DWT->CYCCNT);
 
-    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(ScorchedTanksEvent));
+    FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(ScorchedTanksEvent));
 
-    Game* game_state = malloc(sizeof(Game));
+    Game *game_state = malloc(sizeof(Game));
     scorched_tanks_init_game(game_state);
 
     ValueMutex state_mutex;
-    if(!init_mutex(&state_mutex, game_state, sizeof(ScorchedTanksEvent))) {
+    if (!init_mutex(&state_mutex, game_state, sizeof(ScorchedTanksEvent)))
+    {
         FURI_LOG_E("ScorchedTanks", "cannot create mutex\r\n");
         free(game_state);
         return 255;
     }
 
-    ViewPort* view_port = view_port_alloc();
+    ViewPort *view_port = view_port_alloc();
     view_port_draw_callback_set(view_port, scorched_tanks_render_callback, &state_mutex);
     view_port_input_callback_set(view_port, scorched_tanks_input_callback, event_queue);
 
-    FuriTimer* timer =
+    FuriTimer *timer =
         furi_timer_alloc(scorched_tanks_update_timer_callback, FuriTimerTypePeriodic, event_queue);
     furi_timer_start(timer, 2000);
 
     // Open GUI and register view_port
-    Gui* gui = furi_record_open(RECORD_GUI);
+    Gui *gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
     ScorchedTanksEvent event;
-    for(bool processing = true; processing;) {
+    for (bool processing = true; processing;)
+    {
         FuriStatus event_status = furi_message_queue_get(event_queue, &event, 50);
 
-        if(event.type == EventTypeKey) { // && game->isPlayerTurn
-            if(event.input.type == InputTypeRepeat || event.input.type == InputTypeShort) {
-                switch(event.input.key) {
+        if (event.type == EventTypeKey)
+        { // && game->isPlayerTurn
+            if (event.input.type == InputTypeRepeat || event.input.type == InputTypeShort)
+            {
+                switch (event.input.key)
+                {
                 case InputKeyUp:
                     scorched_tanks_aim_up(game_state);
                     break;
@@ -365,7 +418,9 @@ int32_t scorched_tanks_game_app(void* p) {
                     break;
                 }
             }
-        } else if(event.type == EventTypeTick) {
+        }
+        else if (event.type == EventTypeTick)
+        {
             scorched_tanks_calculate_trajectory(game_state);
         }