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

added time display, falling animation and dolphin deeds

Tibor Tálosi 1 год назад
Родитель
Сommit
b7fe191634
8 измененных файлов с 136 добавлено и 41 удалено
  1. 94 29
      GameLogic.cpp
  2. 19 7
      GameLogic.h
  3. 16 2
      GameLoop.cpp
  4. 1 1
      utils/Card.cpp
  5. 1 1
      utils/Card.h
  6. 4 0
      utils/Helpers.cpp
  7. 1 0
      utils/Helpers.h
  8. 0 1
      utils/List.h

+ 94 - 29
GameLogic.cpp

@@ -1,8 +1,10 @@
+#include <dolphin/helpers/dolphin_deed.h>
+#include <dolphin/dolphin.h>
 #include "GameLogic.h"
 #include "utils/Sprite.h"
 #include "assets.h"
 
-#define SOLVE_TEST
+//#define SOLVE_TEST
 
 static Sprite logo = Sprite(sprite_logo, BlackOnly);
 static Sprite solve = Sprite(sprite_solve, BlackOnly);
@@ -26,6 +28,7 @@ void GameLogic::Input(int key, InputType type) {
         } else if (key == InputKeyOk) {
             if (state == Logo) {
                 state = Intro;
+                dolphin_deed(DolphinDeedPluginGameStart);
                 return;
             }
             if (state == Solve) {
@@ -34,6 +37,7 @@ void GameLogic::Input(int key, InputType type) {
                 return;
             }
             if (state == Finish) {
+                dolphin_deed(DolphinDeedPluginGameWin);
                 state = Logo;
                 return;
             } else if (state == Intro) {
@@ -166,6 +170,16 @@ void GameLogic::PickAndPlace() {
             target[1] = 0;
         }
     }
+
+    for (uint8_t i = 0; i < 4; i++) {
+        if(foundation[i].size()==0 || foundation[i].peek_back()->value!= KING)
+            return;
+    }
+
+    buffer->clear();
+    DrawPlayScene();
+    selectedCard = 0;
+    state = Finish;
 }
 
 void GameLogic::HandleNavigation(int key) {
@@ -208,6 +222,7 @@ void GameLogic::Update(float delta) {
         case Intro:
             DoIntro(delta);
             dirty = true;
+            end = 0;
             break;
         case Play:
             DrawPlayScene();
@@ -222,9 +237,10 @@ void GameLogic::Update(float delta) {
             DrawPlayScene();
             HandleSolve(delta);
             dirty = true;
+            break;
         case Finish:
-            //todo implement the falling animation
-//            dirty = true;
+            dirty = true;
+            FallingCard(delta);
             break;
         default:
             break;
@@ -234,6 +250,8 @@ void GameLogic::Update(float delta) {
 }
 
 void GameLogic::Reset() {
+    dolphin_deed(DolphinDeedPluginGameStart);
+    delete tempCard;
     stock.deleteData();
     stock.clear();
     waste.deleteData();
@@ -293,6 +311,7 @@ GameLogic::~GameLogic() {
     waste.clear();
     hand.deleteData();
     hand.clear();
+    delete tempCard;
     for (int i = 0; i < 7; i++) {
         tableau[i].deleteData();
         tableau[i].clear();
@@ -462,8 +481,9 @@ int8_t GameLogic::FirstNonFlipped(const List<Card> &deck) {
 void GameLogic::HandleSolve(float delta) {
     if (tempCard) {
 
-        tempTime += delta * 5;
+        tempTime += delta * 8;
         Vector finalPos{56 + (float) target[0] * 18, 2};
+        if(tempTime>1) tempTime=1;
         Vector localpos = Vector::Lerp(tempPos, finalPos, tempTime);
         tempCard->Render((uint8_t) localpos.x, (uint8_t) localpos.y, false, buffer);
         if (finalPos.distance(localpos) < 0.01) {
@@ -480,6 +500,7 @@ void GameLogic::HandleSolve(float delta) {
 
         if (size == 4) {
             buffer->clear();
+            selectedCard = 0;
             DrawPlayScene();
             state = Finish;
             return;
@@ -558,48 +579,92 @@ void GameLogic::HandleSolve(float delta) {
 }
 
 void GameLogic::QuickSolve() {
+    if (tempCard) {
+        delete tempCard;
+        tempCard = nullptr;
+    }
+
     waste.deleteData();
     waste.clear();
     stock.deleteData();
     stock.clear();
-    for(uint8_t i=0;i<7;i++){
+    for (uint8_t i = 0; i < 7; i++) {
         tableau[i].deleteData();
         tableau[i].clear();
     }
 
+    int foundations[4] = {0, 0, 0, 0};
+    for (int j = 0; j < 4; j++) {
+        if (foundation[j].size() > 0) {
+            foundations[foundation[j].peek_front()->suit] = 1;
+        }
+    }
+
+    for (int j = 0; j < 4; j++) {
+        if (foundations[j] == 0) {
+            //seed the foundation
+            foundation[j].push_back(new Card(j, ACE));
+            foundation[j].peek_back()->exposed = true;
+        }
+    }
+
     for (uint8_t i = 0; i < 4; i++) {
         auto &fnd = foundation[i];
-        if (foundation[i].size() == 0) {
-            //find the missing suit
-            int foundations[4] = {0, 0, 0, 0};
-            int index = 0;
-            for (int j = 0; j < 4; j++) {
-                if (foundation[j].size() > 0) {
-                    foundations[foundation[j].peek_front()->suit] = 1;
-                    index = j;
-                }
-            }
-            for (int j = 0; j < 4; j++) {
-                if (foundations[j] == 0) {
-                    target[0] = (float) j;
-                    fnd = foundation[index];
-                    //seed the foundation
-                    fnd.push_back(new Card(j, ACE));
-                    fnd.peek_back()->exposed= true;
-                    fnd.push_back(new Card(j, TWO));
-                    fnd.peek_back()->exposed= true;
-                    break;
-                }
-            }
-            break;
+        if (fnd.peek_back()->value == ACE) {
+            fnd.push_back(new Card(fnd.peek_back()->suit, TWO));
+            fnd.peek_back()->exposed = true;
         }
 
         while (fnd.peek_back()->value != KING) {
             fnd.push_back(new Card(fnd.peek_back()->suit, fnd.peek_back()->value + 1));
-            fnd.peek_back()->exposed= true;
+            fnd.peek_back()->exposed = true;
         }
     }
     buffer->clear();
     DrawPlayScene();
+    selectedCard = 0;
     state = Finish;
 }
+
+void GameLogic::FallingCard(float delta) {
+    UNUSED(delta);
+    if (tempCard) {
+        if ((furi_get_tick() - tempTime) > 12) {
+            tempTime = furi_get_tick();
+            tempPos.x += velocity.x;
+            tempPos.y -= velocity.y;
+
+            if (tempPos.y > 41) {
+                velocity.y *= -0.8;
+                tempPos.y = 41;
+            } else {
+                velocity.y -= 1;
+                if (velocity.y < -10) velocity.y = -10;
+            }
+            tempCard->Render((int8_t) tempPos.x, (int8_t) tempPos.y, false, buffer);
+            if (tempPos.x < -18 || tempPos.x > 128) {
+                delete tempCard;
+                tempCard = nullptr;
+            }
+        }
+    } else {
+        float r1 = 2.0 * (float) (rand() % 2) - 1.0; // random number in range -1 to 1
+        if (r1 == 0) r1 = 0.1;
+        float r2 = inverse_tanh(r1);
+
+        velocity.x = (float) (tanh(r2)) * (rand() % 3 + 1);
+
+        if (velocity.x == 0) velocity.x = 1;
+        velocity.y = (rand() % 3 + 1);
+        if (foundation[selectedCard].size() > 0) {
+            tempCard = foundation[selectedCard].pop_back();
+            tempCard->exposed = true;
+            tempPos.x = 56 + selectedCard * 18;
+            tempPos.y = 2;
+            selectedCard = (uint8_t) (selectedCard + 1) % 4;
+        } else {
+            state = Logo;
+            return;
+        }
+    }
+}

+ 19 - 7
GameLogic.h

@@ -11,7 +11,6 @@ enum GameState {
 };
 
 class GameLogic {
-    GameState state = Logo;
 
     List<Card> hand = List<Card>();
     RenderBuffer *buffer;
@@ -22,36 +21,49 @@ class GameLogic {
     List<Card> tableau[7] = {List<Card>(), List<Card>(), List<Card>(), List<Card>(), List<Card>(), List<Card>(),
                              List<Card>()};
     int8_t selection[2] = {0, 0};
-    int8_t selectedCard=0;
+    int8_t selectedCard = 0;
     Card *tempCard;
     Vector tempPos = {0, 0};
-    float tempTime=0;
+    float tempTime = 0;
     int8_t target[2] = {0, -1};
-    bool readyToRender= false;
+    bool readyToRender = false;
+    Vector velocity;
+public:
+    GameState state = Logo;
+    bool dirty = true;
     double startTime;
     double end;
-public:
-    bool dirty= true;
 
     GameLogic(RenderBuffer *buffer, InputEventHandler *inputHandler);
+
     ~GameLogic();
+
     void Update(float delta);
 
     void Input(int key, InputType type);
 
     void Reset();
+
     void GenerateDeck();
+
     bool CanSolve();
 
     void DoIntro(float delta);
+
     void DrawPlayScene();
+
     void HandleSolve(float delta);
+
     void QuickSolve();
 
-    bool isReady(){return readyToRender;}
+    void FallingCard(float delta);
+
+    bool isReady() const { return readyToRender; }
+
     void DrawColumn(uint8_t x, uint8_t y, uint8_t selected, int8_t column);
 
     void HandleNavigation(int key);
+
     void PickAndPlace();
 
     int8_t FirstNonFlipped(const List<Card> &deck);

+ 16 - 2
GameLoop.cpp

@@ -54,9 +54,9 @@ int32_t GameLoop::render_thread(void *ctx) {
 
     return 0;
 }
+char timeString[24];
 
 void GameLoop::Start() {
-    dolphin_deed(DolphinDeedPluginGameStart);
     if (!render_mutex) {
         return;
     }
@@ -67,8 +67,22 @@ void GameLoop::Start() {
         if (logic->isReady()) {
             furi_mutex_acquire(render_mutex, FuriWaitForever);
             buffer->render(canvas);
-            canvas_commit(canvas);
+
+            if(logic->end>0 &&logic->state == Logo){
+                int diff = logic->end - logic->startTime;
+                if(diff>0) {
+                    int hours = diff / 3600000;
+                    int minutes = (diff % 3600000) / 60000;
+                    int seconds = (diff % 60000) / 1000;
+                    snprintf(timeString, sizeof(timeString), "Completed: %02d:%02d:%02d", hours, minutes, seconds);
+                    canvas_set_font(canvas, FontSecondary);
+                    canvas_draw_str_aligned(canvas, 60, 5, AlignCenter, AlignTop, timeString);
+                }
+            }
+
+
             furi_mutex_release(render_mutex);
+            canvas_commit(canvas);
         }
         furi_thread_yield();
     }

+ 1 - 1
utils/Card.cpp

@@ -28,7 +28,7 @@ static Sprite suits[] = {
 
 static Sprite backSide = Sprite(sprite_pattern_big, BlackOnly);
 
-void Card::Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit) {
+void Card::Render(int8_t x, int8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit) {
     uint8_t height = y + fmin(size_limit, 22);
 
     if (exposed) {

+ 1 - 1
utils/Card.h

@@ -28,7 +28,7 @@ struct Card {
 
     Card(uint8_t s, uint8_t v) : suit(s), value((CardValue) v) {}
 
-    void Render(uint8_t x, uint8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit = 22);
+    void Render(int8_t x, int8_t y, bool selected, RenderBuffer *buffer, uint8_t size_limit = 22);
 
     static void RenderEmptyCard(uint8_t x, uint8_t y, RenderBuffer *buffer);
 

+ 4 - 0
utils/Helpers.cpp

@@ -31,3 +31,7 @@ LogTimer::LogTimer(const char *n) : name(n) {
 LogTimer::~LogTimer() {
     FURI_LOG_D("App", "%s took %fms", name, furi_get_tick() - start);
 }
+
+float inverse_tanh(double x) {
+    return 0.5f * (float)log((1 + x) / (1 - x));
+}

+ 1 - 0
utils/Helpers.h

@@ -19,6 +19,7 @@ char *get_basename(const char *path);
 #endif
 
 void check_ptr(void *p, const char *file, int line, const char *func);
+float inverse_tanh(double x);
 
 float lerp(float a, float b, float t);
 

+ 0 - 1
utils/List.h

@@ -264,7 +264,6 @@ public:
         return current->data;
     }
 
-    //TODO: removes more than should
     T *extract(size_t index) {
         if (index > size()) {
             FURI_LOG_E("List", "Out of range");