diff options
author | Alan Alpert <alan.alpert@nokia.com> | 2009-10-07 01:03:21 (GMT) |
---|---|---|
committer | Alan Alpert <alan.alpert@nokia.com> | 2009-10-07 01:03:21 (GMT) |
commit | 95821d745a60e60422294dd718cbed5678ef5f1f (patch) | |
tree | f842b1f053c6c8f9664415e6dd2670e4cd9be919 /examples/declarative/tutorials/samegame | |
parent | e25009d28c58b3ff7541374475f8c2c278cef02e (diff) | |
download | Qt-95821d745a60e60422294dd718cbed5678ef5f1f.zip Qt-95821d745a60e60422294dd718cbed5678ef5f1f.tar.gz Qt-95821d745a60e60422294dd718cbed5678ef5f1f.tar.bz2 |
Add SameGame based advanced tutorial
Could use some cleanup, as I didn't manage to get code snippets working
correctly. Also might benefit from being re-written by a good tutor.
Diffstat (limited to 'examples/declarative/tutorials/samegame')
39 files changed, 975 insertions, 0 deletions
diff --git a/examples/declarative/tutorials/samegame/samegame1/Block.qml b/examples/declarative/tutorials/samegame/samegame1/Block.qml new file mode 100644 index 0000000..228ac4e --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/Block.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Item { + id:block + + Image { id: img + source: "pics/redStone.png"; + anchors.fill: parent + } +} diff --git a/examples/declarative/tutorials/samegame/samegame1/Button.qml b/examples/declarative/tutorials/samegame/samegame1/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame1/pics/background.png b/examples/declarative/tutorials/samegame/samegame1/pics/background.png Binary files differnew file mode 100644 index 0000000..25e885f --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/pics/background.png diff --git a/examples/declarative/tutorials/samegame/samegame1/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame1/pics/redStone.png Binary files differnew file mode 100644 index 0000000..b099f60 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/pics/redStone.png diff --git a/examples/declarative/tutorials/samegame/samegame1/samegame.qml b/examples/declarative/tutorials/samegame/samegame1/samegame.qml new file mode 100644 index 0000000..d18718d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/samegame.qml @@ -0,0 +1,38 @@ +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: print("Implement me!"); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: Who knows?"; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} diff --git a/examples/declarative/tutorials/samegame/samegame2/Block.qml b/examples/declarative/tutorials/samegame/samegame2/Block.qml new file mode 100644 index 0000000..228ac4e --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/Block.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Item { + id:block + + Image { id: img + source: "pics/redStone.png"; + anchors.fill: parent + } +} diff --git a/examples/declarative/tutorials/samegame/samegame2/Button.qml b/examples/declarative/tutorials/samegame/samegame2/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame2/pics/background.png b/examples/declarative/tutorials/samegame/samegame2/pics/background.png Binary files differnew file mode 100644 index 0000000..25e885f --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/pics/background.png diff --git a/examples/declarative/tutorials/samegame/samegame2/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame2/pics/redStone.png Binary files differnew file mode 100644 index 0000000..b099f60 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/pics/redStone.png diff --git a/examples/declarative/tutorials/samegame/samegame2/samegame.js b/examples/declarative/tutorials/samegame/samegame2/samegame.js new file mode 100644 index 0000000..064d87e --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/samegame.js @@ -0,0 +1,59 @@ +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var tileSize = 40; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "Block.qml"; +var component; + +//Index function used instead of a 2D array +function index(xIdx,yIdx) { + return xIdx + (yIdx * maxX); +} + +function initBoard() +{ + //Calculate board size + maxX = Math.floor(background.width/tileSize); + maxY = Math.floor(background.height/tileSize); + maxIndex = maxY*maxX; + + //Initialize Board + board = new Array(maxIndex); + for(xIdx=0; xIdx<maxX; xIdx++){ + for(yIdx=0; yIdx<maxY; yIdx++){ + board[index(xIdx,yIdx)] = null; + createBlock(xIdx,yIdx); + } + } +} + +function createBlock(xIdx,yIdx){ + if(component==null) + component = createComponent(tileSrc); + + // Note that we don't wait for the component to become ready. This will + // only work if the block QML is a local file. Otherwise the component will + // not be ready immediately. There is a statusChanged signal on the + // component you could use if you want to wait to load remote files. + if(component.isReady){ + dynamicObject = component.createObject(); + if(dynamicObject == null){ + print("error creating block"); + print(component.errorsString()); + return false; + } + dynamicObject.parent = background; + dynamicObject.x = xIdx*tileSize; + dynamicObject.y = yIdx*tileSize; + dynamicObject.width = tileSize; + dynamicObject.height = tileSize; + board[index(xIdx,yIdx)] = dynamicObject; + }else{//isError or isLoading + print("error loading block component"); + print(component.errorsString()); + return false; + } + return true; +} diff --git a/examples/declarative/tutorials/samegame/samegame2/samegame.qml b/examples/declarative/tutorials/samegame/samegame2/samegame.qml new file mode 100644 index 0000000..e446fa4 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/samegame.qml @@ -0,0 +1,39 @@ +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + Script { source: "samegame.js" } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: initBoard(); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: Who knows?"; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} diff --git a/examples/declarative/tutorials/samegame/samegame3/Block.qml b/examples/declarative/tutorials/samegame/samegame3/Block.qml new file mode 100644 index 0000000..2f28923 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/Block.qml @@ -0,0 +1,19 @@ +import Qt 4.6 + +Item { + id:block + property int type: 0 + + Image { id: img + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } + anchors.fill: parent + } +} diff --git a/examples/declarative/tutorials/samegame/samegame3/Button.qml b/examples/declarative/tutorials/samegame/samegame3/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame3/Dialog.qml b/examples/declarative/tutorials/samegame/samegame3/Dialog.qml new file mode 100644 index 0000000..401d211 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/Dialog.qml @@ -0,0 +1,21 @@ +import Qt 4.6 + +Rectangle { + id: page + function forceClose() { + page.closed(); + page.opacity = 0; + } + function show(txt) { + MyText.text = txt; + page.opacity = 1; + } + signal closed(); + color: "white"; border.width: 1; width: MyText.width + 20; height: 60; + opacity: 0 + opacity: Behavior { + NumberAnimation { duration: 1000 } + } + Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" } + MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); } +} diff --git a/examples/declarative/tutorials/samegame/samegame3/pics/background.png b/examples/declarative/tutorials/samegame/samegame3/pics/background.png Binary files differnew file mode 100644 index 0000000..25e885f --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/pics/background.png diff --git a/examples/declarative/tutorials/samegame/samegame3/pics/blueStone.png b/examples/declarative/tutorials/samegame/samegame3/pics/blueStone.png Binary files differnew file mode 100644 index 0000000..bf342e0 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/pics/blueStone.png diff --git a/examples/declarative/tutorials/samegame/samegame3/pics/greenStone.png b/examples/declarative/tutorials/samegame/samegame3/pics/greenStone.png Binary files differnew file mode 100644 index 0000000..5ac14a5 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/pics/greenStone.png diff --git a/examples/declarative/tutorials/samegame/samegame3/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame3/pics/redStone.png Binary files differnew file mode 100644 index 0000000..b099f60 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/pics/redStone.png diff --git a/examples/declarative/tutorials/samegame/samegame3/samegame.js b/examples/declarative/tutorials/samegame/samegame3/samegame.js new file mode 100644 index 0000000..16b349d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/samegame.js @@ -0,0 +1,185 @@ +/* This script file handles the game logic */ +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "Block.qml"; +var component; + +//Index function used instead of a 2D array +function index(xIdx,yIdx) { + return xIdx + (yIdx * maxX); +} + +function initBoard() +{ + for(i = 0; i<maxIndex; i++){ + //Delete old blocks + if(board[i] != null) + board[i].destroy(); + } + + //Calculate board size + maxX = Math.floor(gameCanvas.width/gameCanvas.tileSize); + maxY = Math.floor(gameCanvas.height/gameCanvas.tileSize); + maxIndex = maxY*maxX; + + //Close dialogs + dialog.forceClose(); + + //Initialize Board + board = new Array(maxIndex); + gameCanvas.score = 0; + for(xIdx=0; xIdx<maxX; xIdx++){ + for(yIdx=0; yIdx<maxY; yIdx++){ + board[index(xIdx,yIdx)] = null; + createBlock(xIdx,yIdx); + } + } +} + +function createBlock(xIdx,yIdx){ + if(component==null) + component = createComponent(tileSrc); + + // Note that we don't wait for the component to become ready. This will + // only work if the block QML is a local file. Otherwise the component will + // not be ready immediately. There is a statusChanged signal on the + // component you could use if you want to wait to load remote files. + if(component.isReady){ + dynamicObject = component.createObject(); + if(dynamicObject == null){ + print("error creating block"); + print(component.errorsString()); + return false; + } + dynamicObject.type = Math.floor(Math.random() * 3); + dynamicObject.parent = gameCanvas; + dynamicObject.x = xIdx*gameCanvas.tileSize; + dynamicObject.y = yIdx*gameCanvas.tileSize; + dynamicObject.width = gameCanvas.tileSize; + dynamicObject.height = gameCanvas.tileSize; + board[index(xIdx,yIdx)] = dynamicObject; + }else{//isError or isLoading + print("error loading block component"); + print(component.errorsString()); + return false; + } + return true; +} + +var fillFound;//Set after a floodFill call to the number of tiles found +var floodBoard;//Set to 1 if the floodFill reaches off that node +//NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope +function handleClick(x,y) +{ + xIdx = Math.floor(x/gameCanvas.tileSize); + yIdx = Math.floor(y/gameCanvas.tileSize); + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + //If it's a valid tile, remove it and all connected (does nothing if it's not connected) + floodFill(xIdx,yIdx, -1); + if(fillFound <= 0) + return; + gameCanvas.score += (fillFound - 1) * (fillFound - 1); + shuffleDown(); + victoryCheck(); +} + +function floodFill(xIdx,yIdx,type) +{ + if(board[index(xIdx, yIdx)] == null) + return; + var first = false; + if(type == -1){ + first = true; + type = board[index(xIdx,yIdx)].type; + + //Flood fill initialization + fillFound = 0; + floodBoard = new Array(maxIndex); + } + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(floodBoard[index(xIdx, yIdx)] == 1 || (!first && type != board[index(xIdx,yIdx)].type)) + return; + floodBoard[index(xIdx, yIdx)] = 1; + floodFill(xIdx+1,yIdx,type); + floodFill(xIdx-1,yIdx,type); + floodFill(xIdx,yIdx+1,type); + floodFill(xIdx,yIdx-1,type); + if(first==true && fillFound == 0) + return;//Can't remove single tiles + board[index(xIdx,yIdx)].opacity = 0; + board[index(xIdx,yIdx)] = null; + fillFound += 1; +} + +function shuffleDown() +{ + //Fall down + for(xIdx=0; xIdx<maxX; xIdx++){ + fallDist = 0; + for(yIdx=maxY-1; yIdx>=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + obj = board[index(xIdx,yIdx)]; + obj.y += fallDist * gameCanvas.tileSize; + board[index(xIdx,yIdx+fallDist)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } + //Fall to the left + fallDist = 0; + for(xIdx=0; xIdx<maxX; xIdx++){ + if(board[index(xIdx, maxY - 1)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + for(yIdx=0; yIdx<maxY; yIdx++){ + obj = board[index(xIdx,yIdx)]; + if(obj == null) + continue; + obj.x -= fallDist * gameCanvas.tileSize; + board[index(xIdx-fallDist,yIdx)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } +} + +function victoryCheck() +{ + //awards bonuses for no tiles left + deservesBonus = true; + for(xIdx=maxX-1; xIdx>=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 500; + //Checks for game over + if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))) + dialog.show("Game Over. Your score is " + gameCanvas.score); +} + +//only floods up and right, to see if it can find adjacent same-typed tiles +function floodMoveCheck(xIdx, yIdx, type) +{ + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return false; + if(board[index(xIdx, yIdx)] == null) + return false; + myType = board[index(xIdx, yIdx)].type; + if(type == myType) + return true; + return floodMoveCheck(xIdx + 1, yIdx, myType) || + floodMoveCheck(xIdx, yIdx - 1, board[index(xIdx,yIdx)].type); +} diff --git a/examples/declarative/tutorials/samegame/samegame3/samegame.qml b/examples/declarative/tutorials/samegame/samegame3/samegame.qml new file mode 100644 index 0000000..ea43ab2 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/samegame.qml @@ -0,0 +1,56 @@ +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + Script { source: "samegame.js" } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + + Item { + id: gameCanvas + property int score: 0 + property int tileSize: 40 + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % tileSize); + height: parent.height - (parent.height % tileSize); + + MouseRegion { + id: gameMR + anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); + } + } + } + + Dialog { id: dialog; anchors.centerIn: parent; z: 21 } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: initBoard(); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: " + gameCanvas.score; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} diff --git a/examples/declarative/tutorials/samegame/samegame4/README b/examples/declarative/tutorials/samegame/samegame4/README new file mode 100644 index 0000000..244b205 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/README @@ -0,0 +1,10 @@ +This demo uses pictures from the KDE project (www.kde.org), +specifically the images from the KSame game. These images are + +background.png +blueStone.png +redStone.png +greenStone.png +yellowStone.png + +and are presumably under the same GPL2 license as the rest of kdegames diff --git a/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml b/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml new file mode 100644 index 0000000..a495cd0 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml @@ -0,0 +1,54 @@ +import Qt 4.6 + +Item { id:block + property bool dying: false + property bool spawned: false + property int type: 0 + property int targetX: 0 + property int targetY: 0 + + x: SpringFollow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 } + y: SpringFollow { source: targetY; spring: 2; damping: 0.2 } + + Image { id: img + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } + opacity: 0 + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + anchors.fill: parent + } + + Particles { id: particles + width:1; height:1; anchors.centerIn: parent; opacity: 0 + lifeSpan: 700; lifeSpanDeviation: 600; count:0; streamIn: false + angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 + source: { + if(type == 0){ + "pics/redStar.png"; + } else if (type == 1) { + "pics/blueStar.png"; + } else { + "pics/greenStar.png"; + } + } + } + + states: [ + State{ name: "AliveState"; when: spawned == true && dying == false + PropertyChanges { target: img; opacity: 1 } + }, + State{ name: "DeathState"; when: dying == true + PropertyChanges { target: particles; count: 50 } + PropertyChanges { target: particles; opacity: 1 } + PropertyChanges { target: particles; emitting: false } // i.e. emit only once + PropertyChanges { target: img; opacity: 0 } + } + ] +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/Button.qml b/examples/declarative/tutorials/samegame/samegame4/content/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml b/examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml new file mode 100644 index 0000000..401d211 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml @@ -0,0 +1,21 @@ +import Qt 4.6 + +Rectangle { + id: page + function forceClose() { + page.closed(); + page.opacity = 0; + } + function show(txt) { + MyText.text = txt; + page.opacity = 1; + } + signal closed(); + color: "white"; border.width: 1; width: MyText.width + 20; height: 60; + opacity: 0 + opacity: Behavior { + NumberAnimation { duration: 1000 } + } + Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" } + MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); } +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/background.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/background.png Binary files differnew file mode 100644 index 0000000..25e885f --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/background.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png Binary files differnew file mode 100644 index 0000000..ff9588f --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png Binary files differnew file mode 100644 index 0000000..bf342e0 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png Binary files differnew file mode 100644 index 0000000..cd06854 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png Binary files differnew file mode 100644 index 0000000..5ac14a5 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png Binary files differnew file mode 100644 index 0000000..0a4dffe --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png Binary files differnew file mode 100644 index 0000000..b099f60 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/star.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/star.png Binary files differnew file mode 100644 index 0000000..defbde5 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/star.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png Binary files differnew file mode 100644 index 0000000..c56124a --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png diff --git a/examples/declarative/tutorials/samegame/samegame4/content/samegame.js b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js new file mode 100755 index 0000000..cf55b59 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js @@ -0,0 +1,217 @@ +/* This script file handles the game logic */ +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var tileSize = 40; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "content/BoomBlock.qml"; +var scoresURL = "http://qtfx-nokia.trolltech.com.au/samegame/scores.php"; +var timer; +var component; + +//Index function used instead of a 2D array +function index(xIdx,yIdx) { + return xIdx + (yIdx * maxX); +} + +function timeStr(msecs) { + var secs = Math.floor(msecs/1000); + var m = Math.floor(secs/60); + var ret = "" + m + "m " + (secs%60) + "s"; + return ret; +} + +function initBoard() +{ + for(i = 0; i<maxIndex; i++){ + //Delete old blocks + if(board[i] != null) + board[i].destroy(); + } + + //Calculate board size + maxX = Math.floor(gameCanvas.width/tileSize); + maxY = Math.floor(gameCanvas.height/tileSize); + maxIndex = maxY*maxX; + + //Close dialogs + scoreName.forceClose(); + dialog.forceClose(); + + //Initialize Board + board = new Array(maxIndex); + gameCanvas.score = 0; + for(xIdx=0; xIdx<maxX; xIdx++){ + for(yIdx=0; yIdx<maxY; yIdx++){ + board[index(xIdx,yIdx)] = null; + createBlock(xIdx,yIdx); + } + } + timer = new Date(); +} + +var fillFound;//Set after a floodFill call to the number of tiles found +var floodBoard;//Set to 1 if the floodFill reaches off that node +//NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope +function handleClick(x,y) +{ + xIdx = Math.floor(x/tileSize); + yIdx = Math.floor(y/tileSize); + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + //If it's a valid tile, remove it and all connected (does nothing if it's not connected) + floodFill(xIdx,yIdx, -1); + if(fillFound <= 0) + return; + gameCanvas.score += (fillFound - 1) * (fillFound - 1); + shuffleDown(); + victoryCheck(); +} + +function floodFill(xIdx,yIdx,type) +{ + if(board[index(xIdx, yIdx)] == null) + return; + var first = false; + if(type == -1){ + first = true; + type = board[index(xIdx,yIdx)].type; + + //Flood fill initialization + fillFound = 0; + floodBoard = new Array(maxIndex); + } + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(floodBoard[index(xIdx, yIdx)] == 1 || (!first && type != board[index(xIdx,yIdx)].type)) + return; + floodBoard[index(xIdx, yIdx)] = 1; + floodFill(xIdx+1,yIdx,type); + floodFill(xIdx-1,yIdx,type); + floodFill(xIdx,yIdx+1,type); + floodFill(xIdx,yIdx-1,type); + if(first==true && fillFound == 0) + return;//Can't remove single tiles + board[index(xIdx,yIdx)].dying = true; + board[index(xIdx,yIdx)] = null; + fillFound += 1; +} + +function shuffleDown() +{ + //Fall down + for(xIdx=0; xIdx<maxX; xIdx++){ + fallDist = 0; + for(yIdx=maxY-1; yIdx>=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + obj = board[index(xIdx,yIdx)]; + obj.targetY += fallDist * tileSize; + board[index(xIdx,yIdx+fallDist)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } + //Fall to the left + fallDist = 0; + for(xIdx=0; xIdx<maxX; xIdx++){ + if(board[index(xIdx, maxY - 1)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + for(yIdx=0; yIdx<maxY; yIdx++){ + obj = board[index(xIdx,yIdx)]; + if(obj == null) + continue; + obj.targetX -= fallDist * tileSize; + board[index(xIdx-fallDist,yIdx)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } +} + +function victoryCheck() +{ + //awards bonuses for no tiles left + deservesBonus = true; + for(xIdx=maxX-1; xIdx>=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 500; + //Checks for game over + if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))){ + timer = new Date() - timer; + if(scoresURL != "") + scoreName.show("You've won! Please enter your name: "); + else + dialog.show("Game Over. Your score is " + gameCanvas.score); + } +} + +//only floods up and right, to see if it can find adjacent same-typed tiles +function floodMoveCheck(xIdx, yIdx, type) +{ + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return false; + if(board[index(xIdx, yIdx)] == null) + return false; + myType = board[index(xIdx, yIdx)].type; + if(type == myType) + return true; + return floodMoveCheck(xIdx + 1, yIdx, myType) || + floodMoveCheck(xIdx, yIdx - 1, board[index(xIdx,yIdx)].type); +} + +function createBlock(xIdx,yIdx){ + if(component==null) + component = createComponent(tileSrc); + + // Note that we don't wait for the component to become ready. This will + // only work if the block QML is a local file. Otherwise the component will + // not be ready immediately. There is a statusChanged signal on the + // component you could use if you want to wait to load remote files. + if(component.isReady){ + dynamicObject = component.createObject(); + if(dynamicObject == null){ + print("error creating block"); + print(component.errorsString()); + return false; + } + dynamicObject.type = Math.floor(Math.random() * 3); + dynamicObject.parent = gameCanvas; + dynamicObject.x = xIdx*tileSize; + dynamicObject.targetX = xIdx*tileSize; + dynamicObject.targetY = yIdx*tileSize; + dynamicObject.width = tileSize; + dynamicObject.height = tileSize; + dynamicObject.spawned = true; + board[index(xIdx,yIdx)] = dynamicObject; + }else{//isError or isLoading + print("error loading block component"); + print(component.errorsString()); + return false; + } + return true; +} + +function sendHighScore(name) { + var postman = new XMLHttpRequest() + var postData = "name="+name+"&score="+gameCanvas.score + +"&gridSize="+maxX+"x"+maxY +"&time="+Math.floor(timer/1000); + postman.open("POST", scoresURL, true); + postman.onreadystatechange = function() { + if (postman.readyState == postman.DONE) { + dialog.show("Your score has been uploaded."); + } + } + postman.send(postData); +} diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/README b/examples/declarative/tutorials/samegame/samegame4/highscores/README new file mode 100644 index 0000000..eaa00fa --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/README @@ -0,0 +1 @@ +The SameGame example can interface with a simple PHP script to store XML high score data on a remote server. We do not have a publically accessible server available for this use, but if you have access to a PHP capable webserver you can copy the files (score_data.xml, score.php, score_style.xsl) to it and alter the highscore_server variable at the top of the samegame.js file to point to it. diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml b/examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml new file mode 100755 index 0000000..c3fd90d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml @@ -0,0 +1,2 @@ +<record><score>1000000</score><name>Alan the Tester</name><gridSize>0x0</gridSize><seconds>0</seconds></record> +<record><score>6213</score><name>Alan</name><gridSize>12x17</gridSize><seconds>51</seconds></record> diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl b/examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl new file mode 100755 index 0000000..670354c --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:template match="/"> + <html> + <head><title>SameGame High Scores</title></head> + <body> + <h2>SameGame High Scores</h2> + <table border="1"> + <tr bgcolor="lightsteelblue"> + <th>Name</th> + <th>Score</th> + <th>Grid Size</th> + <th>Time, s</th> + </tr> + <xsl:for-each select="records/record"> + <xsl:sort select="score" data-type="number" order="descending"/> + <tr> + <td><xsl:value-of select="name"/></td> + <td><xsl:value-of select="score"/></td> + <td><xsl:value-of select="gridSize"/></td> + <td><xsl:value-of select="seconds"/></td> + </tr> + </xsl:for-each> + </table> + </body> + </html> +</xsl:template> +</xsl:stylesheet> diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/scores.php b/examples/declarative/tutorials/samegame/samegame4/highscores/scores.php new file mode 100755 index 0000000..3cceb2d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/scores.php @@ -0,0 +1,34 @@ +<?php + $score = $_POST["score"]; + echo "<html>"; + echo "<head><title>SameGame High Scores</title></head><body>"; + if($score > 0){#Sending in a new high score + $name = $_POST["name"]; + $grid = $_POST["gridSize"]; + $time = $_POST["time"]; + if($name == "") + $name = "Anonymous"; + //if($grid != "10x10"){ + //Need a standard, so as to reject others? + //} + $file = fopen("score_data.xml", "a"); #It's XML. Happy? + $ret = fwrite($file, "<record><score>". $score . "</score><name>" + . $name . "</name><gridSize>" . $grid . "</gridSize><seconds>" + . $time . "</seconds></record>\n"); + echo "Your score has been recorded. Thanks for playing!"; + if($ret == False) + echo "<br/> There was an error though, so don't expect to see that score again."; + }else{#Read high score list + #Now uses XSLT to display. So just print the file. With XML cruft added. + #Note that firefox at least won't apply the XSLT on a php file. So redirecting + $file = fopen("scores.xml", "w"); + $ret = fwrite($file, '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" + . '<?xml-stylesheet type="text/xsl" href="score_style.xsl"?>' . "\n" + . "<records>\n" . file_get_contents("score_data.xml") . "</records>\n"); + if($ret == False) + echo "There was an internal error. Sorry."; + else + echo '<script type="text/javascript">window.location.replace("scores.xml")</script>'; + } + echo "</body></html>"; +?> diff --git a/examples/declarative/tutorials/samegame/samegame4/samegame.qml b/examples/declarative/tutorials/samegame/samegame4/samegame.qml new file mode 100644 index 0000000..ede4362 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/samegame.qml @@ -0,0 +1,71 @@ +import Qt 4.6 +import "content" + +Rectangle { + id: Screen + width: 490; height: 720 + + Script { source: "content/samegame.js" } + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "content/pics/background.png" + fillMode: "PreserveAspectCrop" + } + + Item { + id: gameCanvas + property int score: 0 + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % tileSize); + height: parent.height - (parent.height % tileSize); + + MouseRegion { + id: gameMR + anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); + } + } + } + + Dialog { id: dialog; anchors.centerIn: parent; z: 21 } + Dialog { + id: scoreName; anchors.centerIn: parent; z: 22; + TextInput { + id: Editor + onAccepted: { + if(scoreName.opacity==1&&Editor.text!="") + sendHighScore(Editor.text); + scoreName.forceClose(); + } + anchors.verticalCenter: parent.verticalCenter + width: 72; focus: true + anchors.right: scoreName.right + } + } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: {initBoard();} + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: " + gameCanvas.score; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} |