diff --git a/CMakeLists.txt b/CMakeLists.txt index b49ebf6..100e1c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,56 +1,84 @@ cmake_minimum_required(VERSION 3.28) project(Prog3B) + set(EXECUTABLE_NAME Prog3B) -# Generate compile_commands.json +# ------------------------------------------------- +# Global settings +# ------------------------------------------------- set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) - +# ------------------------------------------------- +# Main executable +# ------------------------------------------------- set(SRC_FILES src/main.cpp src/gamecube.cpp src/gamematrix.cpp ) + add_executable(${EXECUTABLE_NAME} ${SRC_FILES}) + target_include_directories(${EXECUTABLE_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/includes ${CMAKE_CURRENT_LIST_DIR}/raylib ) - +# ------------------------------------------------- +# Tests executable +# ------------------------------------------------- set(TEST_FILES - src/tests.cpp src/gamematrix.cpp ) + add_executable(tests ${TEST_FILES}) + target_include_directories(tests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/includes ) - -if(WIN32) +# ------------------------------------------------- +# Platform specific linking +# ------------------------------------------------- +if (WIN32) message(STATUS "Configuring for Windows") + target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/windows/libraylib.a - opengl32 gdi32 winmm + opengl32 + gdi32 + winmm ) -elseif(APPLE) - message(STATUS "Configuring for MacOS") +elseif (APPLE) + + message(STATUS "Configuring for macOS") target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/mac_x86/libraylib.a - "-framework IOKit" "-framework Cocoa" "-framework OpenGL" + "-framework IOKit" ) -else() - # --- Linux --- + +else () + message(STATUS "Configuring for Linux") + target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/linux/libraylib.a - GL X11 m + GL + X11 + m + pthread + dl ) -endif() \ No newline at end of file + + target_link_libraries(tests PRIVATE + m + ) + +endif () diff --git a/includes/gamecube.h b/includes/gamecube.h index bbe0028..71cd8b6 100644 --- a/includes/gamecube.h +++ b/includes/gamecube.h @@ -31,4 +31,5 @@ private: bool flippingForward = false; bool flippingBackward = false; float rotation = 0.0f; -}; \ No newline at end of file +}; + diff --git a/includes/gamematrix.h b/includes/gamematrix.h index d074dc0..88d7b90 100644 --- a/includes/gamematrix.h +++ b/includes/gamematrix.h @@ -25,3 +25,11 @@ public: ); }; +enum class GameState +{ + Idle, // kein Würfel offen, Eingabe erlaubt + OneFlipped, // ein Würfel offen + CheckingMatch, // zwei Würfel vollständig aufgeklappt, Vergleich läuft + LockInput // Würfel drehen gerade – Eingabe kurz blockiert +}; + diff --git a/src/gamematrix.cpp b/src/gamematrix.cpp index c78b8d3..f2d0579 100644 --- a/src/gamematrix.cpp +++ b/src/gamematrix.cpp @@ -5,13 +5,10 @@ #include "../includes/gamematrix.h" // Matrixmultiplikation - - // Rotationsmatrix um Achse x/y/z -static std::array,4> rot3D(double angle_deg, char axis); - +//static std::array,4> rot3D(double angle_deg, char axis); // Verschiebung -static std::array,4> translate(const std::array& pos); +//static std::array,4> translate(const std::array& pos); diff --git a/src/main.cpp b/src/main.cpp index 0cdaad1..80b8a77 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,16 @@ #include "gamecube.h" #include #include -//Funktion innitGame - //Anzahl der Paare(pairCount*2) +#include +//enum game +//Ab Zeile 114 if game won +//Ab Zeile 148 checking match? + + +// ----------------------------------------------------------- +// Initialisierung +// ----------------------------------------------------------- + void innitGame(int pairCount, std::vector &cubes, std::vector &positions ) @@ -65,8 +73,6 @@ void innitGame(int pairCount, // ----------------------------------------------------------- int main() { - - //NEU Counter int counter = 0; @@ -88,8 +94,8 @@ int main() // ------------------------------------------------------- // Spielvariablen // ------------------------------------------------------- - // Nur 3 Farben für 3 Paare - int pairCount = 6; // <-- vorerst fixe Anzahl + // Nur 3 Farben für 3 Paare + int pairCount = 2; // <-- vorerst fixe Anzahl std::vector positions; std::vector cubes; @@ -104,27 +110,48 @@ int main() float flipSpeed = 5.0f; // Drehgeschwindigkeit bool gameWon = false; + GameState state = GameState::Idle; //legen wir fest, in welchem Zustand das Spiel startet + // ----------------------------------------------------------- // Hauptspielschleife // ----------------------------------------------------------- + while (!WindowShouldClose()) { + // Klick-Erkennung - if (!gameWon && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - //Neu Counter - counter++; + if (!gameWon + && (state == GameState::Idle || state == GameState::OneFlipped) + && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + + // nur im Idle- oder OneFlipped-Zustand wird reagiert<------------------------------------------------- + //Wenn einer Dreht, clicken blockieren + // ... Vector2 mouse = GetMousePosition(); - for (auto &c : cubes) + for (auto &c : cubes) //Hier die State Logik { - if (!c.IsFlipped() && !c.IsMatched()) + std::cout<<("State missing"); + if (!c.IsFlipped() && !c.IsMatched()) //<--------------- Zustandwechsel anpassen { - Vector2 screenPos = GetWorldToScreen({c.GetPosition().x, c.GetPosition().y, c.GetPosition().z}, camera); + Vector2 screenPos = GetWorldToScreen( + {c.GetPosition().x, c.GetPosition().y, c.GetPosition().z}, camera); - if (fabs(mouse.x - screenPos.x) < 40 && fabs(mouse.y - screenPos.y) < 40) - c.FlipForward(); + if (fabs(mouse.x - screenPos.x) < 40 && + fabs(mouse.y - screenPos.y) < 40) + { + c.FlipForward(); //<-----Animation Start + //Neu Counter + counter++; + + if (state == GameState::Idle) //Neu (Ü4) + state = GameState::OneFlipped; + else + state = GameState::LockInput; + + break; // 🔒 nur EIN Würfel pro Klick + } } } } @@ -137,8 +164,10 @@ int main() // Sobald ein Würfel vollständig umgedreht ist → merken if (c.IsFlipped() && !c.IsMatched()) { - if (!first) first = &c; - else if (!second && &c != first) second = &c; + if (!first) + first = &c; + else if (!second && &c != first) + second = &c; } } @@ -150,7 +179,9 @@ int main() Color col1 = first->GetColor(); Color col2 = second->GetColor(); - if (col1.r == col2.r && col1.g == col2.g && col1.b == col2.b) + if (col1.r == col2.r && + col1.g == col2.g && + col1.b == col2.b) { first->SetMatched(true); second->SetMatched(true); @@ -163,9 +194,12 @@ int main() first = second = nullptr; + state = GameState::Idle; //neu } - // Gewinnprüfung + // ----------------------------- + // WIN CHECK + // ----------------------------- if (!gameWon) gameWon = std::all_of(cubes.begin(), cubes.end(), [](const gamecube &c){ return c.IsMatched(); }); diff --git a/src/test.cpp b/src/test.cpp new file mode 100644 index 0000000..9f43e03 --- /dev/null +++ b/src/test.cpp @@ -0,0 +1,211 @@ +// +// Created by gamer on 14.12.2025. +// +#include "gamecube.h" +#include +#include +#include + +// ----------------------------------------------------------- +// GameState – Zustandsmaschine +// ----------------------------------------------------------- +enum class GameState +{ + Idle, // kein Würfel offen + OneFlipped, // ein Würfel offen + LockInput, // Animation läuft + CheckingMatch // Vergleich +}; + +// ----------------------------------------------------------- +// Initialisierung +// ----------------------------------------------------------- +void innitGame(int pairCount, + std::vector &cubes, + std::vector &positions) +{ + cubes.clear(); + positions.clear(); + + int total = pairCount * 2; + int cols = ceil(sqrt(total)); + int rows = (total + cols - 1) / cols; + float spacing = 2.2f; + + for (int r = 0; r < rows; r++) + for (int c = 0; c < cols; c++) + if ((int)positions.size() < total) + positions.push_back({ + (c - cols / 2.0f) * spacing, + 0, + (r - rows / 2.0f) * spacing + }); + + std::vector colorPool; + for (int i = 0; i < pairCount; i++) + { + Color col = { + (unsigned char)(rand() % 256), + (unsigned char)(rand() % 256), + (unsigned char)(rand() % 256), + 255 + }; + colorPool.push_back(col); + colorPool.push_back(col); + } + + for (int i = total - 1; i > 0; --i) + std::swap(colorPool[i], colorPool[rand() % (i + 1)]); + + for (int i = 0; i < total; i++) + cubes.emplace_back(positions[i], colorPool[i]); +} + +// ----------------------------------------------------------- +// MAIN +// ----------------------------------------------------------- +int main() +{ + srand(time(NULL)); + InitWindow(800, 600, "3D Memory Game – Stable Version"); + SetTargetFPS(60); + + Camera3D camera{}; + camera.position = {6, 6, 6}; + camera.target = {0, 0, 0}; + camera.up = {0, 1, 0}; + camera.fovy = 45; + camera.projection = CAMERA_PERSPECTIVE; + + int pairCount = 2; + std::vector positions; + std::vector cubes; + innitGame(pairCount, cubes, positions); + + gamecube *first = nullptr; + gamecube *second = nullptr; + + float flipSpeed = 5.0f; + bool gameWon = false; + int counter = 0; + + GameState state = GameState::Idle; + + // ----------------------------------------------------------- + // GAME LOOP + // ----------------------------------------------------------- + while (!WindowShouldClose()) + { + // ----------------------------- + // INPUT (nur wenn erlaubt) + // ----------------------------- + if (!gameWon && + (state == GameState::Idle || state == GameState::OneFlipped) && + IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + Vector2 mouse = GetMousePosition(); + + for (auto &c : cubes) + { + if (!c.IsFlipped() && !c.IsMatched()) + { + Vector2 screenPos = GetWorldToScreen( + {c.GetPosition().x, c.GetPosition().y, c.GetPosition().z}, + camera); + + if (fabs(mouse.x - screenPos.x) < 40 && + fabs(mouse.y - screenPos.y) < 40) + { + c.FlipForward(); + counter++; + + if (state == GameState::Idle) + state = GameState::OneFlipped; + else + state = GameState::LockInput; + + break; // 🔒 nur EIN Würfel pro Klick + } + } + } + } + + // ----------------------------- + // UPDATE – Animation + // ----------------------------- + for (auto &c : cubes) + { + c.Update(flipSpeed); + + if (c.IsFlipped() && !c.IsMatched()) + { + if (!first) + first = &c; + else if (!second && &c != first) + second = &c; + } + } + + // ----------------------------- + // Animation beendet → Vergleich + // ----------------------------- + if (state == GameState::LockInput && first && second) + state = GameState::CheckingMatch; + + // ----------------------------- + // MATCHING + // ----------------------------- + if (state == GameState::CheckingMatch) + { + Color a = first->GetColor(); + Color b = second->GetColor(); + + if (a.r == b.r && a.g == b.g && a.b == b.b) + { + first->SetMatched(true); + second->SetMatched(true); + } + else + { + first->FlipBackward(); + second->FlipBackward(); + } + + first = second = nullptr; + state = GameState::Idle; + } + + // ----------------------------- + // WIN CHECK + // ----------------------------- + if (!gameWon) + gameWon = std::all_of( + cubes.begin(), + cubes.end(), + [](const gamecube &c) + { return c.IsMatched(); }); + + // ----------------------------- + // DRAW + // ----------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + BeginMode3D(camera); + + for (auto &c : cubes) + c.Draw(); + + EndMode3D(); + + if (gameWon) + DrawText("Congrats! You found all pairs!", 140, 260, 30, DARKBLUE); + else + DrawText("Flip 2 cubes - find matching pairs!", 10, 10, 20, DARKGRAY); + + DrawText(TextFormat("Moves: %i", counter / 2), 10, 40, 20, DARKGRAY); + EndDrawing(); + } + + CloseWindow(); + return 0; +} diff --git a/src/testmain.cpp b/src/testmain.cpp new file mode 100644 index 0000000..0e2ac11 --- /dev/null +++ b/src/testmain.cpp @@ -0,0 +1,163 @@ +#include "gamecube.h" +#include +#include +//Funktion innitGame + //Anzahl der Paare(pairCount*2) +void innitGame() +{ + + +} +// ----------------------------------------------------------- +// 3D Memory Game – Hauptprogramm +// ----------------------------------------------------------- +int main() +{ + + + //NEU Counter + int counter = 0; + + + // Zufall initialisieren + srand(time(NULL)); + + // Fenster und Kamera + InitWindow(800, 600, "3D Memory Game with Matrix3D Library"); + SetTargetFPS(60); + + Camera3D camera{}; + camera.position = {6.0f, 6.0f, 6.0f}; + camera.target = {0.0f, 0.0f, 0.0f}; + camera.up = {0.0f, 1.0f, 0.0f}; + camera.fovy = 45.0f; + camera.projection = CAMERA_PERSPECTIVE; + + + + + // Nur 3 Farben für 3 Paare <---------------------------------------------------------- + Color colors[] = { RED, GREEN, BLUE }; + + // 6 Karten-Positionen im 3x2 Raster + std::vector positions = {{-2, 0, -2}, {0, 0, -2}, {2, 0, -2},{-2, 0, 0}, {0, 0, 0}, {2, 0, 0}}; + + // Farben doppelt in einen Pool legen und mischen + std::vector colorPool; + for (int i = 0; i < 3; i++) + { + colorPool.push_back(colors[i]); + colorPool.push_back(colors[i]); + } + + // Fisher-Yates Shuffle mit rand() + for (int i = colorPool.size() - 1; i > 0; --i) + { + int j = rand() % (i + 1); // Zufallsindex von 0 bis i + std::swap(colorPool[i], colorPool[j]); + } + + // Karten/Würfel erstellen + std::vector cubes; + for (int i = 0; i < 6; i++) + cubes.emplace_back(positions[i], colorPool[i]); //<------------------------------------------------------------ + + + + + + + gamecube* first = nullptr; + gamecube* second = nullptr; + float flipSpeed = 5.0f; // Drehgeschwindigkeit + bool gameWon = false; + + // ----------------------------------------------------------- + // Hauptspielschleife + // ----------------------------------------------------------- + while (!WindowShouldClose()) + { + // Klick-Erkennung + if (!gameWon && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + //Neu Counter + counter++; + + Vector2 mouse = GetMousePosition(); + + for (auto &c : cubes) + { + if (!c.IsFlipped() && !c.IsMatched()) + { + Vector2 screenPos = GetWorldToScreen({c.GetPosition().x, c.GetPosition().y, c.GetPosition().z}, camera); + + if (fabs(mouse.x - screenPos.x) < 40 && fabs(mouse.y - screenPos.y) < 40) + c.FlipForward(); + } + } + } + + // Animation aller Würfel + for (auto &c : cubes) + { + c.Update(flipSpeed); + + // Sobald ein Würfel vollständig umgedreht ist → merken + if (c.IsFlipped() && !c.IsMatched()) + { + if (!first) first = &c; + else if (!second && &c != first) second = &c; + } + } + + // Matching-Logik + if (first && second) + { + //counter hier macht umdrehungen + + Color col1 = first->GetColor(); + Color col2 = second->GetColor(); + + if (col1.r == col2.r && col1.g == col2.g && col1.b == col2.b) + { + first->SetMatched(true); + second->SetMatched(true); + } + else + { + first->FlipBackward(); + second->FlipBackward(); + } + + + first = second = nullptr; + } + + // Gewinnprüfung + if (!gameWon) + gameWon = std::all_of(cubes.begin(), cubes.end(), [](const gamecube &c){ return c.IsMatched(); }); + + // ----------------------------------------------------------- + // Zeichnen + // ----------------------------------------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + BeginMode3D(camera); + + for (auto &c : cubes) + c.Draw(); + + EndMode3D(); + if (gameWon) + DrawText("Congrats! You found all pairs!", 150, 260, 30, DARKBLUE); + else + DrawText("Flip 2 cubes - find matching pairs!", 10, 10, 20, DARKGRAY); + //Neu Counter + DrawText(TextFormat("Counter: %i",counter/2),10,40,20,DARKGRAY); //counter//2 da sonst doppelt + + EndDrawing(); + } + + CloseWindow(); + return 0; +} \ No newline at end of file