Ver Fonte

First game implementation

Add movements, cactus spawn and lose condition
Rrycbarm há 2 anos atrás
pai
commit
d6dca031b5
1 ficheiros alterados com 96 adições e 19 exclusões
  1. 96 19
      trexrunner.c

+ 96 - 19
trexrunner.c

@@ -2,17 +2,25 @@
 #include <furi_hal.h>
 #include <gui/gui.h>
 #include <gui/icon_i.h>
+#include <gui/elements.h>
 #include <input/input.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "assets_icons.h"
 
-#define DINO_START_X 0
+#define DINO_START_X 10
 #define DINO_START_Y 42
 
-#define FPS 60
+#define FPS 20
 
-#define DINO_RUNNING_MS_PER_FRAME 100
+#define DINO_RUNNING_MS_PER_FRAME 500
+
+#define GRAVITY 60
+#define JUMP_SPEED 30
+
+#define CACTUS_W 8
+#define CACTUS_H 10
 
 typedef enum {
     EventTypeTick,
@@ -29,15 +37,31 @@ typedef struct {
     uint32_t last_tick;
     const Icon* dino_icon;
     int dino_frame_ms;
+    FuriMutex* mutex;
+
+    // Dino info
+    float y_position;
+    float y_speed;
+    int y_acceleration;
+
+    // Cactus info
+    int cactus_position;
+    float cactus_speed;
+    int has_cactus;
+
+    int lost;
 } GameState;
 
 static void timer_callback(void *ctx) {
-    GameState *game_state = acquire_mutex((ValueMutex *) ctx, 25);
+    GameState *game_state = ctx;
+    furi_mutex_acquire(game_state->mutex, FuriWaitForever);
+
     if (game_state == NULL) {
         return;
     }
 
     uint32_t ticks_elapsed = furi_get_tick() - game_state->last_tick;
+    game_state->last_tick = furi_get_tick();
     int delta_time_ms = ticks_elapsed * 1000 / furi_kernel_get_tick_frequency();
 
     // dino update
@@ -51,8 +75,39 @@ static void timer_callback(void *ctx) {
         }
         game_state->dino_frame_ms = 0;
     }
+    
+    // Compute dino dynamics
+    game_state->y_acceleration = game_state->y_acceleration - GRAVITY * delta_time_ms / 1000;
+    game_state->y_speed = game_state->y_speed + game_state->y_acceleration * delta_time_ms / 1000;
+    game_state->y_position = game_state->y_position - game_state->y_speed * delta_time_ms / 1000;
+
+    // Touch ground
+    if (game_state->y_position >= DINO_START_Y) {
+        game_state->y_acceleration = 0;
+        game_state->y_speed = 0;
+        game_state->y_position = DINO_START_Y;
+    }
 
-    release_mutex((ValueMutex *) ctx, game_state);
+    // Update Cactus state
+    if (game_state->has_cactus){
+        game_state->cactus_position = game_state->cactus_position - game_state->cactus_speed *  delta_time_ms / 1000;
+        if (game_state->cactus_position <= CACTUS_W + 1) {
+            game_state->has_cactus = 0;
+            game_state->cactus_position = 120;
+        }
+    } 
+    // Create cactus (not random)
+    else {
+        game_state->has_cactus = 1;
+        game_state->cactus_position = 120;
+        game_state->cactus_speed = 15;
+    }
+
+    // Lose condition
+    if ((game_state->y_position + 22 >= (64 - CACTUS_H)) && ((DINO_START_X+20) >= game_state->cactus_position) && (DINO_START_X <= (game_state->cactus_position + CACTUS_W)))
+        game_state->lost = 1;
+
+    furi_mutex_release(game_state->mutex);
 }
 
 static void input_callback(InputEvent *input_event, FuriMessageQueue *event_queue) {
@@ -63,33 +118,45 @@ static void input_callback(InputEvent *input_event, FuriMessageQueue *event_queu
 }
 
 static void render_callback(Canvas *const canvas, void *ctx) {
-    const GameState *game_state = acquire_mutex((ValueMutex *) ctx, 25);
+    const GameState *game_state = ctx;
+    furi_mutex_acquire(game_state->mutex, FuriWaitForever);
+
     if (game_state == NULL) {
         return;
     }
 
-//  canvas_draw_xbm(canvas, 0, 0, dino_width, dino_height, dino_bits);
-    canvas_draw_icon(canvas, DINO_START_X, DINO_START_Y, game_state->dino_icon);
+    if(!game_state->lost){
+        canvas_draw_icon(canvas, DINO_START_X, game_state->y_position, game_state->dino_icon);
 
-    release_mutex((ValueMutex *) ctx, game_state);
+        if (game_state->has_cactus)
+            canvas_draw_triangle(canvas, game_state->cactus_position, 63, CACTUS_W, CACTUS_H, CanvasDirectionBottomToTop);
+    } else {
+        canvas_set_font(canvas, FontPrimary);
+        canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignBottom, "You lost :c");
+    }
+    
+    furi_mutex_release(game_state->mutex);
 }
 
 static void game_state_init(GameState *const game_state) {
     game_state->last_tick = furi_get_tick();
     game_state->dino_frame_ms = 0;
     game_state->dino_icon = &I_Dino;
+    game_state->y_acceleration = game_state->y_speed = 0;
+    game_state->y_position = DINO_START_Y;
+    game_state->has_cactus = 0;
+    game_state->lost = 0;
+    game_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
 }
 
-int32_t trexrunner_app(void *p) {
-    UNUSED(p);
+int32_t trexrunner_app() {
 
     FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
 
     GameState *game_state = malloc(sizeof(GameState));
     game_state_init(game_state);
 
-    ValueMutex state_mutex;
-    if (!init_mutex(&state_mutex, game_state, sizeof(game_state))) {
+    if (!game_state->mutex) { 
         FURI_LOG_E("T-rex runner", "cannot create mutex\r\n");
         free(game_state);
         return 255;
@@ -98,9 +165,9 @@ int32_t trexrunner_app(void *p) {
 
     // Set system callbacks
     ViewPort *view_port = view_port_alloc();
-    view_port_draw_callback_set(view_port, render_callback, &state_mutex);
+    view_port_draw_callback_set(view_port, render_callback, game_state);
     view_port_input_callback_set(view_port, input_callback, event_queue);
-    game_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex);
+    game_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, game_state);
 
     furi_timer_start(game_state->timer, (uint32_t) furi_kernel_get_tick_frequency() / FPS);
 
@@ -109,23 +176,30 @@ int32_t trexrunner_app(void *p) {
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
     PluginEvent event;
-    for (bool processing = true; processing;) {
+    for (bool processing = true; processing && !game_state->lost;) {
         FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
-//    Minesweeper* minesweeper_state = (Minesweeper*)acquire_mutex_block(&state_mutex);
         if (event_status == FuriStatusOk) {
             // press events
             if (event.type == EventTypeKey) {
                 if (event.input.type == InputTypeShort) {
                     switch (event.input.key) {
                         case InputKeyUp:
+                            //if (game_state->y_position == DINO_START_Y)
+                                game_state->y_position -= 10;
                             break;
                         case InputKeyDown:
+                            //if (game_state->y_position == DINO_START_Y)
+                                game_state->y_position += 10;
                             break;
                         case InputKeyLeft:
                             break;
                         case InputKeyRight:
                             break;
                         case InputKeyOk:
+                            if (game_state->y_position == DINO_START_Y)
+                                game_state->y_speed = JUMP_SPEED;       
+                            break;
+                        case InputKeyMAX:
                             break;
                         case InputKeyBack:
                             // Exit the app
@@ -138,8 +212,11 @@ int32_t trexrunner_app(void *p) {
             // event timeout
             ;
         }
+        if (game_state->lost){
+            furi_message_queue_get(event_queue, &event, 1500); //Sleep to show  the "you lost" message
+        }
         view_port_update(view_port);
-        release_mutex(&state_mutex, game_state);
+        furi_mutex_release(game_state->mutex);
     }
 
     view_port_enabled_set(view_port, false);
@@ -147,7 +224,7 @@ int32_t trexrunner_app(void *p) {
     furi_record_close("gui");
     view_port_free(view_port);
     furi_message_queue_free(event_queue);
-    delete_mutex(&state_mutex);
+    furi_mutex_free(game_state->mutex);
     furi_timer_free(game_state->timer);
     free(game_state);