trexrunner.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <gui/icon_i.h>
  5. #include <input/input.h>
  6. #include <stdlib.h>
  7. #include "assets_icons.h"
  8. #define DINO_START_X 0
  9. #define DINO_START_Y 42
  10. #define FPS 60
  11. #define DINO_RUNNING_MS_PER_FRAME 100
  12. typedef enum {
  13. EventTypeTick,
  14. EventTypeKey,
  15. } EventType;
  16. typedef struct {
  17. EventType type;
  18. InputEvent input;
  19. } PluginEvent;
  20. typedef struct {
  21. FuriTimer *timer;
  22. uint32_t last_tick;
  23. const Icon* dino_icon;
  24. int dino_frame_ms;
  25. } GameState;
  26. static void timer_callback(void *ctx) {
  27. GameState *game_state = acquire_mutex((ValueMutex *) ctx, 25);
  28. if (game_state == NULL) {
  29. return;
  30. }
  31. uint32_t ticks_elapsed = furi_get_tick() - game_state->last_tick;
  32. int delta_time_ms = ticks_elapsed * 1000 / furi_kernel_get_tick_frequency();
  33. // dino update
  34. game_state->dino_frame_ms += delta_time_ms;
  35. // TODO: switch by dino state
  36. if (game_state->dino_frame_ms >= DINO_RUNNING_MS_PER_FRAME) {
  37. if (game_state->dino_icon == &I_DinoRun0) {
  38. game_state->dino_icon = &I_DinoRun1;
  39. } else {
  40. game_state->dino_icon = &I_DinoRun0;
  41. }
  42. game_state->dino_frame_ms = 0;
  43. }
  44. release_mutex((ValueMutex *) ctx, game_state);
  45. }
  46. static void input_callback(InputEvent *input_event, FuriMessageQueue *event_queue) {
  47. furi_assert(event_queue);
  48. PluginEvent event = {.type = EventTypeKey, .input = *input_event};
  49. furi_message_queue_put(event_queue, &event, FuriWaitForever);
  50. }
  51. static void render_callback(Canvas *const canvas, void *ctx) {
  52. const GameState *game_state = acquire_mutex((ValueMutex *) ctx, 25);
  53. if (game_state == NULL) {
  54. return;
  55. }
  56. // canvas_draw_xbm(canvas, 0, 0, dino_width, dino_height, dino_bits);
  57. canvas_draw_icon(canvas, DINO_START_X, DINO_START_Y, game_state->dino_icon);
  58. release_mutex((ValueMutex *) ctx, game_state);
  59. }
  60. static void game_state_init(GameState *const game_state) {
  61. game_state->last_tick = furi_get_tick();
  62. game_state->dino_frame_ms = 0;
  63. game_state->dino_icon = &I_Dino;
  64. }
  65. int32_t trexrunner_app(void *p) {
  66. UNUSED(p);
  67. FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
  68. GameState *game_state = malloc(sizeof(GameState));
  69. game_state_init(game_state);
  70. ValueMutex state_mutex;
  71. if (!init_mutex(&state_mutex, game_state, sizeof(game_state))) {
  72. FURI_LOG_E("T-rex runner", "cannot create mutex\r\n");
  73. free(game_state);
  74. return 255;
  75. }
  76. // BEGIN IMPLEMENTATION
  77. // Set system callbacks
  78. ViewPort *view_port = view_port_alloc();
  79. view_port_draw_callback_set(view_port, render_callback, &state_mutex);
  80. view_port_input_callback_set(view_port, input_callback, event_queue);
  81. game_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex);
  82. furi_timer_start(game_state->timer, (uint32_t) furi_kernel_get_tick_frequency() / FPS);
  83. // Open GUI and register view_port
  84. Gui *gui = furi_record_open("gui");
  85. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  86. PluginEvent event;
  87. for (bool processing = true; processing;) {
  88. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
  89. // Minesweeper* minesweeper_state = (Minesweeper*)acquire_mutex_block(&state_mutex);
  90. if (event_status == FuriStatusOk) {
  91. // press events
  92. if (event.type == EventTypeKey) {
  93. if (event.input.type == InputTypeShort) {
  94. switch (event.input.key) {
  95. case InputKeyUp:
  96. break;
  97. case InputKeyDown:
  98. break;
  99. case InputKeyLeft:
  100. break;
  101. case InputKeyRight:
  102. break;
  103. case InputKeyOk:
  104. break;
  105. case InputKeyBack:
  106. // Exit the app
  107. processing = false;
  108. break;
  109. }
  110. }
  111. }
  112. } else {
  113. // event timeout
  114. ;
  115. }
  116. view_port_update(view_port);
  117. release_mutex(&state_mutex, game_state);
  118. }
  119. view_port_enabled_set(view_port, false);
  120. gui_remove_view_port(gui, view_port);
  121. furi_record_close("gui");
  122. view_port_free(view_port);
  123. furi_message_queue_free(event_queue);
  124. delete_mutex(&state_mutex);
  125. furi_timer_free(game_state->timer);
  126. free(game_state);
  127. return 0;
  128. }