diff --git a/Jeu_2048/CMakeLists.txt b/Jeu_2048/CMakeLists.txt index 852865407cc83bcb77216aa5baab5b1ac52db201..7e2d4ed8338ceb213d00c795f1ac97ce14d5b4e2 100644 --- a/Jeu_2048/CMakeLists.txt +++ b/Jeu_2048/CMakeLists.txt @@ -23,6 +23,8 @@ qt_add_qml_module(appJeu_2048 QML_FILES Menu_de_Controle.qml SOURCES game2048.h game2048.cpp QML_FILES Case.qml + QML_FILES + QML_FILES ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. diff --git a/Jeu_2048/Case.qml b/Jeu_2048/Case.qml index e457f67cf386dde98c7572b9e9f1e6d5fbe77522..3344943b4ee56930ed0b1cdadfef7964148a8392 100644 --- a/Jeu_2048/Case.qml +++ b/Jeu_2048/Case.qml @@ -1,30 +1,46 @@ import QtQuick +import QtQuick.Controls + +Rectangle { + id: rectangle + width: 100 + height: 100 + radius: 8 -Item { - property alias _textText: _text.text - property alias _textColor: _text.color - property alias _textFontpixelSize: _text.font.pixelSize property alias rectangleColor: rectangle.color property alias rectangleX: rectangle.x property alias rectangleY: rectangle.y - Rectangle { - id: rectangle - x: 0 - y: 0 - width: 100 - height: 100 - visible: true - color: "#c9c6ac" - radius: 16 + property alias _textText: textItem.text + property alias _textColor: textItem.color + property alias _textFontpixelSize: textItem.font.pixelSize + + property int value: 0 - Text { - id: _text - text: qsTr("") - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: 20 - anchors.horizontalCenter: parent.horizontalCenter - font.family: "Tahoma" + color: { + switch(value) { + case 0: return "#cdc1b4"; // Case vide + case 2: return "#eee4da"; + case 4: return "#ede0c8"; + case 8: return "#f2b179"; + case 16: return "#f59563"; + case 32: return "#f67c5f"; + case 64: return "#f65e3b"; + case 128: return "#edcf72"; + case 256: return "#edcc61"; + case 512: return "#edc850"; + case 1024: return "#edc53f"; + case 2048: return "#edc22e"; + default: return "#3c3a32"; } } + Text { + id: textItem + anchors.centerIn: parent + text: value === 0 ? "" : value + font.pixelSize: 30 + font.bold: true + color: value <= 4 ? "#776e65" : "white" + font.family: "Tahoma" + } } diff --git a/Jeu_2048/Main.qml b/Jeu_2048/Main.qml index ee6e3a930b4a2588e4c452693237ffa6a08e543c..c5f776bbb609dd7fb7d44a3f004aa7251aff0f34 100644 --- a/Jeu_2048/Main.qml +++ b/Jeu_2048/Main.qml @@ -1,86 +1,115 @@ -import QtQuick +import QtQuick 2.15 +import QtQuick.Controls 2.15 Window { - id: window - visible: true - color: "#ffffff" + id: mainItem width: 600 height: 900 - title: qsTr("2048") - - Rectangle { - id: rectangle - y: 100 - width: 400 - height: 200 - color: "#edcc5f" - radius: 30 - anchors.horizontalCenter: parent.horizontalCenter - - Text { - id: _text - x: 69 - color: "#ffffff" - text: qsTr("2048") - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: 80 - font.weight: Font.Bold - font.family: "Tahoma" - anchors.horizontalCenter: parent.horizontalCenter - } - } + visible: true - Rectangle { - id: rectangle1 - x: 100 - y: 350 - width: 400 - height: 500 - color: "#3c3a33" - radius: 15 - - Rectangle { - id: rectangle2 - y: 20 - width: 360 - height: 100 - color: "#c9c6ac" - radius: 15 - anchors.horizontalCenter: parent.horizontalCenter - } + StackView { + id: stackView + anchors.fill: parent - Rectangle { - id: rectangle3 - y: 140 - width: 360 - height: 100 - color: "#c9c6ac" - radius: 15 - anchors.horizontalCenterOffset: 0 - anchors.horizontalCenter: parent.horizontalCenter - } + initialItem: Item { + width: 600 + height: 900 - Rectangle { - id: rectangle4 - y: 260 - width: 360 - height: 100 - color: "#c9c6ac" - radius: 15 - anchors.horizontalCenterOffset: 0 - anchors.horizontalCenter: parent.horizontalCenter - } + Rectangle { + anchors.fill: parent + color: "#f9f6f2" + + Column { + anchors.centerIn: parent + spacing: 40 + + Rectangle { + width: 300 + height: 100 + color: "#edcc5f" + radius: 15 + + Text { + anchors.centerIn: parent + text: "2048" + font.pixelSize: 50 + color: "white" + font.bold: true + } + } + + Rectangle { + width: 300 + height: 60 + color: "#bbada0" + radius: 10 + + Text { + anchors.centerIn: parent + text: "Nouvelle Partie" + font.pixelSize: 24 + color: "white" + } + + MouseArea { + anchors.fill: parent + onClicked: stackView.push("Partie.qml") + } + } + + Rectangle { + width: 300 + height: 60 + color: "#bbada0" + radius: 10 + + Text { + anchors.centerIn: parent + text: "Personnalisation" + font.pixelSize: 24 + color: "white" + } + + MouseArea { + anchors.fill: parent + onClicked: stackView.push("Menu_de_Controle.qml") + } + } + + Rectangle { + width: 300 + height: 60 + color: "#bbada0" + radius: 10 + + Text { + anchors.centerIn: parent + text: "Scores" + font.pixelSize: 24 + color: "white" + } + } + + Rectangle { + width: 300 + height: 60 + color: "#bbada0" + radius: 10 + + Text { + anchors.centerIn: parent + text: "Quitter" + font.pixelSize: 24 + color: "white" + } - Rectangle { - id: rectangle5 - x: 20 - y: 380 - width: 360 - height: 100 - color: "#c9c6ac" - radius: 15 - anchors.horizontalCenterOffset: 0 - anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + anchors.fill: parent + onClicked: Qt.quit() + } + } + } + } } } } diff --git a/Jeu_2048/Partie.qml b/Jeu_2048/Partie.qml index 780420b936440ab438331b53544e3f9840b87baa..d9eb731c8db8b0885acffc2ef807be7e4983936b 100644 --- a/Jeu_2048/Partie.qml +++ b/Jeu_2048/Partie.qml @@ -1,10 +1,14 @@ import QtQuick +import QtQuick.Controls + Item { id: _item width: 600 height: 900 - property alias _text3Text: current_score.text + Component.onCompleted: _item.forceActiveFocus() + + Rectangle { id: background @@ -18,264 +22,105 @@ Item { height: 500 color: "#a49381" radius: 15 - anchors.horizontalCenterOffset: 0 anchors.horizontalCenter: parent.horizontalCenter - Case { - id: case1 - x: 20 - y: 20 - } - - Case { - id: case2 - x: 140 - y: 20 - } - - Case { - id: case3 - x: 260 - y: 20 - } - - Case { - id: case4 - x: 380 - y: 20 - } - - Case { - id: case5 - x: 20 - y: 140 - } - - Case { - id: case6 - x: 140 - y: 140 - } - - Case { - id: case7 - x: 260 - y: 140 - } - - Case { - id: case8 - x: 380 - y: 140 - } - - Case { - id: case9 - x: 20 - y: 260 - } - - Case { - id: case10 - x: 140 - y: 260 - } - - Case { - id: case11 - x: 260 - y: 260 - } - - Case { - id: case12 - x: 380 - y: 260 - } - - Case { - id: case13 - x: 20 - y: 380 - } - - Case { - id: case14 - x: 140 - y: 380 - } - - Case { - id: case15 - x: 260 - y: 380 - } + Grid { + columns: 4 + spacing: 10 + anchors.centerIn: parent - Case { - id: case16 - x: 380 - y: 375 + Repeater { + model: game.board.length + Case { + value: game.board[index] + } + } } } + Rectangle { id: icon_rectangle - x: 50 - y: 50 - width: 200 - height: 150 - color: "#edcc5f" - radius: 15 + x: 50; y: 50; width: 200; height: 150 + color: "#edcc5f"; radius: 15 Text { id: icon_text - width: 200 - height: 150 - color: "#ffffff" - text: qsTr("2048") - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: 50 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.family: "Tahoma" - font.bold: true - anchors.horizontalCenter: parent.horizontalCenter + anchors.centerIn: parent + color: "#ffffff"; text: "2048" + font.pixelSize: 50; font.bold: true; font.family: "Tahoma" } } Rectangle { id: score_rectangle - x: 270 - y: 50 - width: 130 - height: 65 - color: "#3c3a33" - radius: 15 + x: 270; y: 50; width: 130; height: 65 + color: "#3c3a33"; radius: 15 - Text { - id: score_text - y: 2 - color: "#c1c1c1" - text: qsTr("Score") - font.pixelSize: 20 - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } + Text { text: "Score"; y: 2; color: "#c1c1c1"; font.pixelSize: 20; anchors.horizontalCenter: parent.horizontalCenter } - Text { - id: current_score - y: 28 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 25 - font.weight: Font.ExtraBold - font.family: "Tahoma" - anchors.horizontalCenter: parent.horizontalCenter - } + Text { id: current_score; y: 28; color: "#ffffff"; text: game.score; font.pixelSize: 25; font.family: "Tahoma"; anchors.horizontalCenter: parent.horizontalCenter } } Rectangle { - id: best_rectangle - x: 420 - y: 50 - width: 130 - height: 65 - color: "#3c3a33" - radius: 15 - Text { - id: best_text - y: 2 - color: "#c1c1c1" - text: qsTr("Best") - font.pixelSize: 20 - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } + id: best_score_rectangle + x: 420; y: 50; width: 130; height: 65 + color: "#8f7a66"; radius: 15 - Text { - id: best_score - y: 28 - color: "#ffffff" - text: qsTr("0") - font.pixelSize: 25 - font.weight: Font.ExtraBold - font.family: "Tahoma" - anchors.horizontalCenter: parent.horizontalCenter - } + Text { text: "Best"; y: 2; color: "#c1c1c1"; font.pixelSize: 20; anchors.horizontalCenter: parent.horizontalCenter } + + Text { id: best_score; y: 28; color: "#ffffff"; text: game.bestScore; font.pixelSize: 25; font.family: "Tahoma"; anchors.horizontalCenter: parent.horizontalCenter } } Rectangle { id: new_rectangle - x: 270 - y: 135 - width: 130 - height: 65 - color: "#f65e3d" - radius: 15 + x: 270; y: 125; width: 130; height: 65 + color: "#f65e3d"; radius: 15 - Text { - id: new_text - color: "#ffffff" - text: qsTr("NEW") - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: 30 - font.family: "Tahoma" - font.weight: Font.ExtraBold - anchors.horizontalCenter: parent.horizontalCenter - } + Text { text: "NEW"; color: "#ffffff"; font.pixelSize: 30; font.family: "Tahoma"; anchors.centerIn: parent } MouseArea { - id: new_mouse_area - x: 0 - y: 0 - width: 130 - height: 65 - } + anchors.fill: parent + onClicked: { + game.resetGame() + join_the_numbers_text.text = "Join the numbers and get the 2048 tile!" + } + } } - Rectangle { - id: undo_rectangle - x: 420 - y: 135 - width: 130 - height: 65 - color: "#f65e3d" - radius: 15 - Text { - id: undo_text - color: "#ffffff" - text: qsTr("UNDO") - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: 30 - font.weight: Font.ExtraBold - font.family: "Tahoma" - anchors.horizontalCenter: parent.horizontalCenter - } + id: menu_rectangle + x: 420; y: 125; width: 130; height: 65 + color: "#6a9eda"; radius: 15 - MouseArea { - id: undo_mouse_area - x: 0 - y: 0 - width: 130 - height: 65 - } + Text { text: "MENU"; color: "#ffffff"; font.pixelSize: 30; font.family: "Tahoma"; anchors.centerIn: parent } + + MouseArea { anchors.fill: parent; onClicked: console.log("Menu clicked") /* À implémenter */ } } Text { id: join_the_numbers_text - x: 50 - y: 225 - width: 500 - height: 50 - text: qsTr("Join the numbers and get the 2048 tile!") - font.pixelSize: 20 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.bold: true - } - + x: 50; y: 225; width: 500; height: 50 + text: "Join the numbers and get the 2048 tile!" + font.pixelSize: 20; font.bold: true; horizontalAlignment: Text.AlignHCenter + Connections { + target: game + function onGameOver() { + join_the_numbers_text.text = "Game Over !" + console.log("Signal GAME OVER reçu") + } + } + } } + focus: true + Keys.onPressed: function(event) { + switch(event.key) { + case Qt.Key_Left: game.moveLeft(); break; + case Qt.Key_Right: game.moveRight(); break; + case Qt.Key_Up: game.moveUp(); break; + case Qt.Key_Down: game.moveDown(); break; + } + } } diff --git a/Jeu_2048/game2048.cpp b/Jeu_2048/game2048.cpp index 5f9d183607261e99dbb881a100ee6149e33fa10a..063072c9f707de11df9cd188153da6fa5d0bb8e4 100644 --- a/Jeu_2048/game2048.cpp +++ b/Jeu_2048/game2048.cpp @@ -1,8 +1,11 @@ #include "game2048.h" +#include <QDebug> #include <QRandomGenerator> + Game2048::Game2048(QObject *parent) - : QObject(parent), m_score(0) { + : QObject(parent), m_score(0), m_bestScore(0) +{ resetGame(); } @@ -26,6 +29,10 @@ int Game2048::score() const { return m_score; } +int Game2048::bestScore() const { + return m_bestScore; +} + QVector<int> Game2048::board() const { QVector<int> flatBoard; for (int i = 0; i < 4; i++) @@ -65,6 +72,10 @@ bool Game2048::moveLeft() { if(m_board[i][j]!=0 && m_board[i][j]==m_board[i][j+1]) { m_board[i][j]*=2; m_score+=m_board[i][j]; + if (m_score > m_bestScore) { + m_bestScore = m_score; + emit bestScoreChanged(); + } m_board[i][j+1]=0; moved=true; } @@ -101,6 +112,10 @@ bool Game2048::moveRight() { if(m_board[i][j]!=0 && m_board[i][j]==m_board[i][j-1]) { m_board[i][j]*=2; m_score+=m_board[i][j]; + if (m_score > m_bestScore) { + m_bestScore = m_score; + emit bestScoreChanged(); + } m_board[i][j-1]=0; moved=true; } @@ -137,6 +152,10 @@ bool Game2048::moveUp() { if(m_board[i][j]!=0 && m_board[i][j]==m_board[i+1][j]) { m_board[i][j]*=2; m_score+=m_board[i][j]; + if (m_score > m_bestScore) { + m_bestScore = m_score; + emit bestScoreChanged(); + } m_board[i+1][j]=0; moved=true; } @@ -174,6 +193,10 @@ bool Game2048::moveDown() { if(m_board[i][j]!=0 && m_board[i][j]==m_board[i-1][j]) { m_board[i][j]*=2; m_score+=m_board[i][j]; + if (m_score > m_bestScore) { + m_bestScore = m_score; + emit bestScoreChanged(); + } m_board[i-1][j]=0; moved=true; } @@ -194,26 +217,35 @@ bool Game2048::moveDown() { return moved; } + + bool Game2048::canMove() const { - for (int i=0; i<4; i++){ - for (int j=0; j<4; j++){ - if (m_board[i][j]==0){ + // Vérifie s'il reste des cases vides + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + if (m_board[i][j] == 0) return true; - } - if (i<3 && m_board[i][j]==m_board[i+1][j]){ + + // Vérifie s'il y a des cases fusionnables horizontalement + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + if (m_board[i][j] == m_board[i][j + 1]) return true; - } - if (j<3 && m_board[i][j]==m_board[i][j+1]){ + + // Vérifie s'il y a des cases fusionnables verticalement + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 4; ++j) + if (m_board[i][j] == m_board[i + 1][j]) return true; - } - } - } - return true; + + // Aucun coup possible + return false; } void Game2048::updateGameState() { if (!canMove()) { + qDebug() << "🎯 Signal gameOver émis depuis le C++ !"; emit gameOver(); } } diff --git a/Jeu_2048/game2048.h b/Jeu_2048/game2048.h index d5f5b61a8f63d65ef30901f2a8424fa40774c267..9ab072533835d7c20312a3bff214b80b6463444e 100644 --- a/Jeu_2048/game2048.h +++ b/Jeu_2048/game2048.h @@ -8,9 +8,10 @@ class Game2048 : public QObject { Q_OBJECT Q_PROPERTY(int score READ score NOTIFY scoreChanged) Q_PROPERTY(QVector<int> board READ board NOTIFY boardChanged) + Q_PROPERTY(int bestScore READ bestScore NOTIFY bestScoreChanged) public: - explicit Game2048(QObject *parent = nullptr); + explicit Game2048(QObject *parent = nullptr); // Exposer méthodes QML Q_INVOKABLE void resetGame(); @@ -20,16 +21,19 @@ public: Q_INVOKABLE bool moveDown(); int score() const; + int bestScore() const; QVector<int> board() const; // Convertir tableau 2D en vecteur plat pour QML signals: void scoreChanged(); + void bestScoreChanged(); void boardChanged(); void gameOver(); private: int m_board[4][4]; int m_score; + int m_bestScore; void initBoard(); void spawnTile();