212 lines
5.9 KiB
C++
212 lines
5.9 KiB
C++
//
|
||
// Created by gamer on 14.12.2025.
|
||
//
|
||
#include "gamecube.h"
|
||
#include <algorithm>
|
||
#include <ctime>
|
||
#include <iostream>
|
||
|
||
// -----------------------------------------------------------
|
||
// 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<gamecube> &cubes,
|
||
std::vector<Vec3> &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<Color> 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<Vec3> positions;
|
||
std::vector<gamecube> 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;
|
||
}
|