added fluid animation

master
Qiaoyong Zhong 11 years ago
parent e49b346e63
commit 828e0ba144

@ -2,7 +2,8 @@ TEMPLATE = app
QT += qml quick widgets QT += qml quick widgets
SOURCES += main.cpp SOURCES += main.cpp \
myclass.cpp
RESOURCES += qml.qrc RESOURCES += qml.qrc
@ -15,3 +16,6 @@ include(deployment.pri)
# Setting the application icon # Setting the application icon
RC_ICONS = 2048.ico # On Windows RC_ICONS = 2048.ico # On Windows
ICON = 2048.ico # On Mac OSX ICON = 2048.ico # On Mac OSX
HEADERS += \
myclass.h

@ -1,5 +1,7 @@
#include <QApplication> #include <QApplication>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include "myclass.h"
//#include <QDebug>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -8,5 +10,11 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml"))); engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml")));
MyClass myClass;
// qDebug() << engine.rootObjects().length();
QObject *mainWindow = engine.rootObjects()[0];
QObject::connect(mainWindow, SIGNAL(helpMenuTriggered()), &myClass, SLOT(aboutQt()));
return app.exec(); return app.exec();
} }

@ -0,0 +1,11 @@
#include "myclass.h"
#include <QApplication>
MyClass::MyClass(QObject *parent) :
QObject(parent)
{
}
void MyClass::aboutQt() {
QApplication::aboutQt();
}

@ -0,0 +1,18 @@
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0);
signals:
public slots:
void aboutQt();
};
#endif // MYCLASS_H

@ -2,5 +2,6 @@
<qresource prefix="/"> <qresource prefix="/">
<file>qml/main.qml</file> <file>qml/main.qml</file>
<file>qml/2048.js</file> <file>qml/2048.js</file>
<file>qml/Tile.qml</file>
</qresource> </qresource>
</RCC> </RCC>

@ -2,6 +2,7 @@ var score = 0;
var bestScore = 0; var bestScore = 0;
var gridSize = 4; var gridSize = 4;
var cellValues; var cellValues;
var tileItems = [];
var availableCells; var availableCells;
//var labels = "PRC"; //var labels = "PRC";
var labels = "2048"; var labels = "2048";
@ -38,23 +39,36 @@ function startupFunction() {
cellValues[i][j] = 0; cellValues[i][j] = 0;
} }
for (i = 0; i < Math.pow(gridSize, 2); i++) {
try {
tileItems[i].destroy();
} catch(e) {
}
tileItems[i] = null;
}
updateAvailableCells(); updateAvailableCells();
refreshCellViews(2); createNewTileItems(true);
updateScore(); updateScore();
console.log("Started a new game"); console.log("Started a new game");
} }
function moveKey(event) { function moveKey(event) {
var isMoved = false; var isMoved = false;
var i, j, v, v2; var i, j;
var v, v2, mrg, indices;
var oldScore = score; var oldScore = score;
switch (event.key) { switch (event.key) {
case Qt.Key_Left: case Qt.Key_Left:
for (i = 0; i < gridSize; i++) { for (i = 0; i < gridSize; i++) {
v = cellValues[i]; v = cellValues[i];
v2 = mergeVector(v); mrg = mergeVector(v);
v2 = mrg[0];
indices = mrg[1];
if (! arraysIdentical(v,v2)) { if (! arraysIdentical(v,v2)) {
isMoved = true; isMoved = true;
moveMergeTilesLeftRight(i, v, v2, indices, true);
cellValues[i] = v2; cellValues[i] = v2;
} }
} }
@ -63,10 +77,18 @@ function moveKey(event) {
for (i = 0; i < gridSize; i++) { for (i = 0; i < gridSize; i++) {
v = cellValues[i].slice(); v = cellValues[i].slice();
v.reverse(); v.reverse();
v2 = mergeVector(v); mrg = mergeVector(v);
v2 = mrg[0];
indices = mrg[1];
if (! arraysIdentical(v,v2)) { if (! arraysIdentical(v,v2)) {
isMoved = true; isMoved = true;
v.reverse();
v2.reverse(); v2.reverse();
indices.reverse();
for (j = 0; j < indices.length; j++)
indices[j] = gridSize - 1 - indices[j];
moveMergeTilesLeftRight(i, v, v2, indices, false);
cellValues[i] = v2; cellValues[i] = v2;
} }
} }
@ -74,9 +96,13 @@ function moveKey(event) {
case Qt.Key_Up: case Qt.Key_Up:
for (i = 0; i < gridSize; i++) { for (i = 0; i < gridSize; i++) {
v = cellValues.map(function(row) {return row[i];}); v = cellValues.map(function(row) {return row[i];});
v2 = mergeVector(v); mrg = mergeVector(v);
v2 = mrg[0];
indices = mrg[1];
if (! arraysIdentical(v,v2)) { if (! arraysIdentical(v,v2)) {
isMoved = true; isMoved = true;
moveMergeTilesUpDown(i, v, v2, indices, true);
for (j = 0; j < gridSize; j++) { for (j = 0; j < gridSize; j++) {
cellValues[j][i] = v2[j]; cellValues[j][i] = v2[j];
} }
@ -87,13 +113,20 @@ function moveKey(event) {
for (i = 0; i < gridSize; i++) { for (i = 0; i < gridSize; i++) {
v = cellValues.map(function(row) {return row[i];}); v = cellValues.map(function(row) {return row[i];});
v.reverse(); v.reverse();
v2 = mergeVector(v); mrg = mergeVector(v);
v2 = mrg[0];
indices = mrg[1];
if (! arraysIdentical(v,v2)) { if (! arraysIdentical(v,v2)) {
isMoved = true; isMoved = true;
v.reverse();
v2.reverse(); v2.reverse();
indices.reverse();
for (j = 0; j < gridSize; j++) { for (j = 0; j < gridSize; j++) {
indices[j] = gridSize - 1 - indices[j];
cellValues[j][i] = v2[j]; cellValues[j][i] = v2[j];
} }
moveMergeTilesUpDown(i, v, v2, indices, false);
} }
} }
break; break;
@ -101,7 +134,7 @@ function moveKey(event) {
if (isMoved) { if (isMoved) {
updateAvailableCells(); updateAvailableCells();
refreshCellViews(1); createNewTileItems(false);
if (oldScore !== score) { if (oldScore !== score) {
if (bestScore < score) { if (bestScore < score) {
bestScore = score; bestScore = score;
@ -126,32 +159,46 @@ function ind2sub(ind) {
} }
function mergeVector(v0) { function mergeVector(v0) {
var i, j;
var vlen = v0.length;
var indices = [];
// Pass 1: remove zero elements // Pass 1: remove zero elements
var v = v0.slice(); var v = [];
var i = v.length; for (i = 0; i < vlen; i++) {
while (i--) { indices[i] = v.length;
if (v[i] === 0) { if (v0[i] > 0) {
v.splice(i, 1); v.push(v0[i]);
} }
} }
// Pass 2: merge same elements // Pass 2: merge same elements
var v2 = []; var v2 = [];
while (v.length > 0) { for (i = 0; i < v.length; i++) {
if (v.length > 1 && v[0] === v[1]) { if (i === v.length - 1) {
v2.push(v[0] + 1); // The last element
score += parseInt(Math.pow(2, v[0]+1)); v2.push(v[i]);
v.splice(0, 2);
} else { } else {
v2.push(v[0]); if (v[i] === v[i+1]) {
v.splice(0, 1); // move all right-side elements to left by 1
for (j = 0; j < vlen; j++) {
if (indices[j] > v2.length)
indices[j] -= 1;
}
// Merge i-1 and i
v2.push(v[i] + 1);
score += Math.pow(2, v[i] + 1);
i++;
} else {
v2.push(v[i]);
}
} }
} }
// Fill the gaps with zeros // Fill the gaps with zeros
for (i = v2.length; i < v0.length; i++) for (i = v2.length; i < vlen; i++)
v2[i] = 0; v2[i] = 0;
return v2; return [v2, indices];
} }
function removeElementsWithValue(arr, val) { function removeElementsWithValue(arr, val) {
@ -184,37 +231,29 @@ function updateAvailableCells() {
} }
} }
function refreshCellViews(n) { function createNewTileItems(isStartup) {
var i, sub; var i, sub, nTiles;
if (isStartup) {
nTiles = 2;
} else {
nTiles = 1;
}
// Popup a new number // Popup a new number
for (i = 0; i < n; i++) { for (i = 0; i < nTiles; i++) {
var oneOrTwo = Math.random() < 0.9 ? 1: 2; var oneOrTwo = Math.random() < 0.9 ? 1: 2;
var randomCellId = availableCells[Math.floor(Math.random() * availableCells.length)]; var randomCellId = availableCells[Math.floor(Math.random() * availableCells.length)];
sub = ind2sub(randomCellId); sub = ind2sub(randomCellId);
cellValues[sub[0]][sub[1]] = oneOrTwo; cellValues[sub[0]][sub[1]] = oneOrTwo;
tileItems[randomCellId] = createTileObject(randomCellId, oneOrTwo, isStartup);
// Mark this cell as unavailable // Mark this cell as unavailable
var idx = availableCells.indexOf(randomCellId); var idx = availableCells.indexOf(randomCellId);
availableCells.splice(idx, 1); availableCells.splice(idx, 1);
} }
// Refresh the cell views
for (i = 0; i < cells.count; i++) {
sub = ind2sub(i);
var cv = cellValues[sub[0]][sub[1]];
var sty = computeTileStyle(cv);
if ( cv === 0) {
cells.itemAt(i).tileText = "";
} else {
cells.itemAt(i).tileText = labelFunc(cv);
}
cells.itemAt(i).color = sty.bgColor;
cells.itemAt(i).tileColor = sty.fgColor;
cells.itemAt(i).tileFontSize = sty.fontSize;
}
} }
function updateScore() { function updateScore() {
@ -292,3 +331,87 @@ function maxTileValue() {
} }
return mv; return mv;
} }
function createTileObject(ind, n, isStartup) {
var component;
var tile;
var sty = computeTileStyle(n);
var tileText = labelFunc(n);
component = Qt.createComponent("Tile.qml");
tile = component.createObject(tileGrid, {"x": cells.itemAt(ind).x, "y": cells.itemAt(ind).y, "color": sty.bgColor, "tileColor": sty.fgColor, "tileFontSize": sty.fontSize, "tileText": tileText});
if (! isStartup) {
tile.runNewTileAnim = true;
}
if (tile == null) {
// Error Handling
console.log("Error creating a new tile");
}
return tile;
}
function moveMergeTilesLeftRight(i, v, v2, indices, left) {
var j0, j;
for (j0 = 0; j0 < v.length; j0++) {
if (left) {
j = j0;
} else {
j = v.length - 1 - j0;
}
if (v[j] > 0 && indices[j] !== j) {
if (v2[indices[j]] > v[j] && tileItems[gridSize*i+indices[j]] !== null) {
// Move and merge
tileItems[gridSize*i+j].destroyFlag = true;
tileItems[gridSize*i+j].z = -1;
tileItems[gridSize*i+j].x = cells.itemAt(gridSize*i+indices[j]).x;
// tileItems[gridSize*i+j].destroy();
var sty = computeTileStyle(v2[indices[j]]);
tileItems[gridSize*i+indices[j]].tileText = labelFunc(v2[indices[j]]);
tileItems[gridSize*i+indices[j]].color = sty.bgColor;
tileItems[gridSize*i+indices[j]].tileColor = sty.fgColor;
tileItems[gridSize*i+indices[j]].tileFontSize = sty.fontSize;
} else {
// Move only
tileItems[gridSize*i+j].x = cells.itemAt(gridSize*i+indices[j]).x;
tileItems[gridSize*i+indices[j]] = tileItems[gridSize*i+j];
}
tileItems[gridSize*i+j] = null;
}
}
}
function moveMergeTilesUpDown(i, v, v2, indices, up) {
var j0, j;
for (j0 = 0; j0 < v.length; j0++) {
if (up) {
j = j0;
} else {
j = v.length - 1 - j0;
}
if (v[j] > 0 && indices[j] !== j) {
if (v2[indices[j]] > v[j] && tileItems[gridSize*indices[j]+i] !== null) {
// Move and merge
tileItems[gridSize*j+i].destroyFlag = true;
tileItems[gridSize*j+i].z = -1;
tileItems[gridSize*j+i].y = cells.itemAt(gridSize*indices[j]+i).y;
// tileItems[gridSize*j+i].destroy();
var sty = computeTileStyle(v2[indices[j]]);
tileItems[gridSize*indices[j]+i].tileText = labelFunc(v2[indices[j]]);
tileItems[gridSize*indices[j]+i].color = sty.bgColor;
tileItems[gridSize*indices[j]+i].tileColor = sty.fgColor;
tileItems[gridSize*indices[j]+i].tileFontSize = sty.fontSize;
} else {
// Move only
tileItems[gridSize*j+i].y = cells.itemAt(gridSize*indices[j]+i).y;
tileItems[gridSize*indices[j]+i] = tileItems[gridSize*j+i];
}
tileItems[gridSize*j+i] = null;
}
}
}

@ -0,0 +1,79 @@
import QtQuick 2.2
Rectangle {
id: tileContainer
width: 425/4
height: 425/4
radius: 3
color: "white"
property string tileText: ""
property int tileFontSize: 55
property color tileColor: "black"
property int moveAnimTime: 100
property int newTileAnimTime: 200
property bool runNewTileAnim: false
property bool destroyFlag: false
Text {
id: tileLabel
text: tileText
color: tileColor
font.pixelSize: tileFontSize
font.bold: true
anchors.centerIn: parent
Behavior on text {
PropertyAnimation {
duration: moveAnimTime
}
}
}
ParallelAnimation {
running: runNewTileAnim
NumberAnimation {
target: tileContainer
property: "opacity"
from: 0.0
to: 1.0
duration: newTileAnimTime
}
ScaleAnimator {
target: tileContainer
from: 0
to: 1
duration: newTileAnimTime
easing.type: Easing.OutQuad
}
}
Behavior on color {
ColorAnimation {
duration: moveAnimTime
}
}
Behavior on y {
NumberAnimation {
easing.type: Easing.InQuad
duration: moveAnimTime
onRunningChanged: {
if ((!running) && destroyFlag) {
tileContainer.destroy();
}
}
}
}
Behavior on x {
NumberAnimation {
easing.type: Easing.InQuad
duration: moveAnimTime
onRunningChanged: {
if ((!running) && destroyFlag) {
tileContainer.destroy();
}
}
}
}
}

@ -6,6 +6,7 @@ import QtQuick.Window 2.1
import "2048.js" as MyScript import "2048.js" as MyScript
ApplicationWindow { ApplicationWindow {
id: mainWindow
visible: true visible: true
width: 550 width: 550
height: 740 height: 740
@ -15,6 +16,8 @@ ApplicationWindow {
x: (Screen.width - width) / 2 x: (Screen.width - width) / 2
y: (Screen.height - height) / 2 y: (Screen.height - height) / 2
signal helpMenuTriggered
menuBar: MenuBar { menuBar: MenuBar {
Menu { Menu {
title: qsTr("File") title: qsTr("File")
@ -29,6 +32,14 @@ ApplicationWindow {
onTriggered: Qt.quit(); onTriggered: Qt.quit();
} }
} }
Menu {
id: helpMenu
title: qsTr("Help")
MenuItem {
text: "About Qt"
onTriggered: mainWindow.helpMenuTriggered()
}
}
} }
@ -132,6 +143,7 @@ ApplicationWindow {
radius: 6 radius: 6
Grid { Grid {
id: tileGrid
x: 15; x: 15;
y: 15; y: 15;
rows: 4; columns: 4; spacing: 15 rows: 4; columns: 4; spacing: 15
@ -143,23 +155,11 @@ ApplicationWindow {
width: 425/4; height: 425/4 width: 425/4; height: 425/4
radius: 3 radius: 3
color: helper.myColors.bggray color: helper.myColors.bggray
property string tileText: ""
property int tileFontSize: 55
property color tileColor: helper.myColors.fgdark
Text {
text: tileText
color: tileColor
font.pixelSize: tileFontSize
font.bold: true
anchors.centerIn: parent
}
} }
} }
} }
} }
MessageDialog { MessageDialog {
id: deadMessage id: deadMessage
title: "Game Over" title: "Game Over"

Loading…
Cancel
Save