SameGame refactor
authorAlan Alpert <alan.alpert@nokia.com>
Wed, 10 Aug 2011 03:24:37 +0000 (13:24 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 15 Aug 2011 01:48:53 +0000 (03:48 +0200)
A little more imperative with dialogs controlled from script, but better
separation of GameArea and UI. Also removes old highscore script that
was never used.

Change-Id: Ib244acc90b0fc92b3a6534169e429b6acef0838e
Reviewed-on: http://codereview.qt.nokia.com/2798
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>

examples/declarative/samegame/SamegameCore/BoomBlock.qml
examples/declarative/samegame/SamegameCore/Dialog.qml
examples/declarative/samegame/SamegameCore/GameArea.qml [new file with mode: 0644]
examples/declarative/samegame/SamegameCore/NameInputDialog.qml [new file with mode: 0644]
examples/declarative/samegame/SamegameCore/qmldir [deleted file]
examples/declarative/samegame/SamegameCore/samegame.js
examples/declarative/samegame/highscores/README [deleted file]
examples/declarative/samegame/highscores/score_data.xml [deleted file]
examples/declarative/samegame/highscores/score_style.xsl [deleted file]
examples/declarative/samegame/highscores/scores.php [deleted file]
examples/declarative/samegame/samegame.qml

index 2d8fdba..4f8ef70 100644 (file)
@@ -47,6 +47,7 @@ Item {
     property bool dying: false
     property bool spawned: false
     property int type: 0
+    property ParticleSystem particleSystem
 
     Behavior on x {
         enabled: spawned;
index aea6ac7..eddc5ca 100644 (file)
@@ -43,6 +43,7 @@ import QtQuick 2.0
 
 Rectangle {
     id: page
+    anchors.centerIn: parent
 
     property Item text: dialogText
     property bool open: false
diff --git a/examples/declarative/samegame/SamegameCore/GameArea.qml b/examples/declarative/samegame/SamegameCore/GameArea.qml
new file mode 100644 (file)
index 0000000..967e299
--- /dev/null
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Particles 2.0
+import "samegame.js" as Logic
+
+Item {
+    id: gameCanvas
+    property int score: 0
+    property int blockSize: 40
+    property ParticleSystem ps: particleSystem
+    Image {
+        id: background
+        anchors.fill: parent
+        z: -1
+        source: "pics/background.png"
+        fillMode: Image.PreserveAspectCrop
+    }
+
+    width: 480
+    height: 800
+    MouseArea {
+        anchors.fill: parent; onClicked: Logic.handleClick(mouse.x,mouse.y);
+    }
+    ParticleSystem{ 
+        id: particleSystem;
+        z:2
+        ImageParticle {
+            particles: ["red"]
+            color: Qt.darker("red");//Actually want desaturated...
+            source: "pics/particle.png"
+            colorVariation: 0.4
+            alpha: 0.1
+        }
+        ImageParticle {
+            particles: ["green"]
+            color: Qt.darker("green");//Actually want desaturated...
+            source: "pics/particle.png"
+            colorVariation: 0.4
+            alpha: 0.1
+        }
+        ImageParticle {
+            particles: ["blue"]
+            color: Qt.darker("blue");//Actually want desaturated...
+            source: "pics/particle.png"
+            colorVariation: 0.4
+            alpha: 0.1
+        }
+        anchors.fill: parent
+    }
+}
+
diff --git a/examples/declarative/samegame/SamegameCore/NameInputDialog.qml b/examples/declarative/samegame/SamegameCore/NameInputDialog.qml
new file mode 100644 (file)
index 0000000..9b27d2f
--- /dev/null
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Dialog {
+    id: nameInputDialog
+
+    property int initialWidth: 0
+    property alias name: nameInputText.text
+
+    anchors.centerIn: parent
+    z: 22;
+
+    Behavior on width {
+        NumberAnimation {} 
+        enabled: nameInputDialog.initialWidth != 0
+    }
+
+    signal accepted(string name)
+    onClosed: {
+        if (nameInputText.text != "")
+            accepted(name);
+    }
+    Text {
+        id: dialogText
+        anchors { left: nameInputDialog.left; leftMargin: 20; verticalCenter: parent.verticalCenter }
+        text: "You won! Please enter your name: "
+    }
+    MouseArea {
+        anchors.fill: parent
+        onClicked: {
+            if (nameInputText.text == "")
+                nameInputText.openSoftwareInputPanel();
+            else
+                nameInputDialog.forceClose();
+        }
+    }
+
+    TextInput {
+        id: nameInputText
+        anchors { verticalCenter: parent.verticalCenter; left: dialogText.right }
+        focus: visible
+        autoScroll: false
+        maximumLength: 24
+        onTextChanged: {
+            var newWidth = nameInputText.width + dialogText.width + 40;
+            if ( (newWidth > nameInputDialog.width && newWidth < screen.width) 
+                    || (nameInputDialog.width > nameInputDialog.initialWidth) )
+                nameInputDialog.width = newWidth;
+        }
+        onAccepted: {
+            nameInputDialog.forceClose();
+        }
+    }
+}
diff --git a/examples/declarative/samegame/SamegameCore/qmldir b/examples/declarative/samegame/SamegameCore/qmldir
deleted file mode 100644 (file)
index e17b1f5..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-BoomBlock BoomBlock.qml
-Button Button.qml
-Dialog Dialog.qml
index 4c5cbe5..8c15af7 100755 (executable)
@@ -1,4 +1,5 @@
 /* This script file handles the game logic */
+.pragma library
 
 var maxColumn = 10;
 var maxRow = 15;
@@ -8,7 +9,10 @@ var blockSrc = "BoomBlock.qml";
 var scoresURL = "";
 var gameDuration;
 var component = Qt.createComponent(blockSrc);
-var highScoreBar = 0;
+var highScoreBar = -1;
+var gameCanvas;
+var nameInputDialog = null;
+var dialog = null;
 
 // Index function used instead of a 2D array
 function index(column, row)
@@ -24,8 +28,9 @@ function timeStr(msecs)
     return ret;
 }
 
-function startNewGame()
+function startNewGame(gc)
 {
+    gameCanvas = gc;
     // Delete blocks from previous game
     for (var i = 0; i < maxIndex; i++) {
         if (board[i] != null)
@@ -38,8 +43,10 @@ function startNewGame()
     maxIndex = maxRow * maxColumn;
 
     // Close dialogs
-    nameInputDialog.forceClose();
-    dialog.forceClose();
+    if(nameInputDialog != null)
+        nameInputDialog.forceClose();
+    if(dialog != null)
+        dialog.forceClose();
 
     // Initialize Board
     board = new Array(maxIndex);
@@ -59,6 +66,10 @@ 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)
 {
+    if(gameCanvas == undefined){
+        console.log("But the game hasn't started yet!");
+        return;
+    }
     var column = Math.floor(x/gameCanvas.blockSize);
     var row = Math.floor(y/gameCanvas.blockSize);
     if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
@@ -153,11 +164,18 @@ function victoryCheck()
     // Checks for game over
     if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1))) {
         gameDuration = new Date() - gameDuration;
+        if(nameInputDialog == null){
+            nameInputDialog = Qt.createQmlObject('import "."; import "samegame.js" as Logic; NameInputDialog{onAccepted: Logic.saveHighScore(name)}', gameCanvas, "highscoredialog.qml");
+        }
+        if(dialog == null){
+            dialog = Qt.createComponent("Dialog.qml").createObject(gameCanvas);
+        }
+        initHighScoreBar();
         if(gameCanvas.score > highScoreBar){
             nameInputDialog.show("You won! Please enter your name:                 ");
             nameInputDialog.initialWidth = nameInputDialog.text.width + 20;
             if (nameInputDialog.name == "")
-                nameInputDialog.width = nameInputDialog.initialWidth;
+               nameInputDialog.width = nameInputDialog.initialWidth;
             nameInputDialog.text.opacity = 0; // Just a spacer
         }else{
             dialog.show("You won!");
@@ -185,12 +203,13 @@ function createBlock(column,row)
     // 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.status == Component.Ready){
+    if(component.status == 1){
         var dynamicObject = component.createObject(gameCanvas,
                 {"type": Math.floor(Math.random() * 3),
                 "x": column*gameCanvas.blockSize,
                 "width": gameCanvas.blockSize,
-                "height": gameCanvas.blockSize});
+                "height": gameCanvas.blockSize,
+                "particleSystem": gameCanvas.ps});
         if(dynamicObject == null){
             console.log("error creating block");
             console.log(component.errorString());
@@ -210,8 +229,6 @@ function createBlock(column,row)
 
 function initHighScoreBar()
 {
-    if(scoresURL != "")
-        return true;//don't query remote scores
     var db = openDatabaseSync(
         "SameGameScores",
         "1.0",
@@ -270,19 +287,3 @@ function saveHighScore(name)
         }
     );
 }
-
-function sendHighScore(name)
-{
-    var postman = new XMLHttpRequest()
-    var postData = "name=" + name + "&score=" + gameCanvas.score
-        + "&gridSize=" + maxColumn + "x" + maxRow
-        + "&time=" + Math.floor(gameDuration / 1000);
-    postman.open("POST", scoresURL, true);
-    postman.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-    postman.onreadystatechange = function() {
-        if (postman.readyState == postman.DONE) {
-            dialog.show("Your score has been uploaded.");
-        }
-    }
-    postman.send(postData);
-}
diff --git a/examples/declarative/samegame/highscores/README b/examples/declarative/samegame/highscores/README
deleted file mode 100644 (file)
index eaa00fa..0000000
+++ /dev/null
@@ -1 +0,0 @@
-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/samegame/highscores/score_data.xml b/examples/declarative/samegame/highscores/score_data.xml
deleted file mode 100755 (executable)
index c3fd90d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<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/samegame/highscores/score_style.xsl b/examples/declarative/samegame/highscores/score_style.xsl
deleted file mode 100755 (executable)
index 670354c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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/samegame/highscores/scores.php b/examples/declarative/samegame/highscores/scores.php
deleted file mode 100755 (executable)
index 3cceb2d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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>";
-?>
index 887cfe1..baf5b8e 100644 (file)
@@ -46,143 +46,38 @@ import "SamegameCore/samegame.js" as Logic
 
 Rectangle {
     id: screen
-    width: 360; height: 640
-    property bool inAnotherDemo: false //Samegame often is just plonked straight into other examples
+    width: 480; height: 640
 
     SystemPalette { id: activePalette }
 
-    Item {
+    GameArea {
+        id: gameCanvas
         width: parent.width
         anchors { top: parent.top; bottom: toolBar.top }
-
-        Image {
-            id: background
-            anchors.fill: parent
-            source: "SamegameCore/pics/background.png"
-            fillMode: Image.PreserveAspectCrop
-        }
-
-        Item {
-            id: gameCanvas
-            property int score: 0
-            property int blockSize: 40
-
-            z: 20; anchors.centerIn: parent
-            width: parent.width - (parent.width % blockSize);
-            height: parent.height - (parent.height % blockSize);
-
-            MouseArea {
-                anchors.fill: parent; onClicked: Logic.handleClick(mouse.x,mouse.y);
-            }
-        }
-        Item{
-            ParticleSystem{ id: particleSystem; }
-            ImageParticle {
-                system: particleSystem
-                particles: ["red"]
-                color: Qt.darker("red");//Actually want desaturated...
-                source: "SamegameCore/pics/particle.png"
-                colorVariation: 0.4
-                alpha: 0.1
-            }
-            ImageParticle {
-                system: particleSystem
-                particles: ["green"]
-                color: Qt.darker("green");//Actually want desaturated...
-                source: "SamegameCore/pics/particle.png"
-                colorVariation: 0.4
-                alpha: 0.1
-            }
-            ImageParticle {
-                system: particleSystem
-                particles: ["blue"]
-                color: Qt.darker("blue");//Actually want desaturated...
-                source: "SamegameCore/pics/particle.png"
-                colorVariation: 0.4
-                alpha: 0.1
-            }
-            id: aboveGameCanvas
-            anchors.fill: gameCanvas
-            z: gameCanvas.z + 1
-        }
-    }
-
-    Dialog { id: dialog; anchors.centerIn: parent; z: 21 }
-
-    Dialog {
-        id: nameInputDialog
-
-        property int initialWidth: 0
-        property alias name: nameInputText.text
-
-        anchors.centerIn: parent
-        z: 22;
-
-        Behavior on width {
-            NumberAnimation {} 
-            enabled: nameInputDialog.initialWidth != 0
-        }
-
-        onClosed: {
-            if (nameInputText.text != "")
-                Logic.saveHighScore(nameInputText.text);
-        }
-        Text {
-            id: dialogText
-            anchors { left: nameInputDialog.left; leftMargin: 20; verticalCenter: parent.verticalCenter }
-            text: "You won! Please enter your name: "
-        }
-        MouseArea {
-            anchors.fill: parent
-            onClicked: {
-                if (nameInputText.text == "")
-                    nameInputText.openSoftwareInputPanel();
-                else
-                    nameInputDialog.forceClose();
-            }
-        }
-
-        TextInput {
-            id: nameInputText
-            anchors { verticalCenter: parent.verticalCenter; left: dialogText.right }
-            focus: visible
-            autoScroll: false
-            maximumLength: 24
-            onTextChanged: {
-                var newWidth = nameInputText.width + dialogText.width + 40;
-                if ( (newWidth > nameInputDialog.width && newWidth < screen.width) 
-                        || (nameInputDialog.width > nameInputDialog.initialWidth) )
-                    nameInputDialog.width = newWidth;
-            }
-            onAccepted: {
-                nameInputDialog.forceClose();
-            }
-        }
     }
 
     Rectangle {
         id: toolBar
-        width: parent.width; height: 58
+        width: parent.width; height: 80
         color: activePalette.window
         anchors.bottom: screen.bottom
 
         Button {
             id: newGameButton
-            anchors { left: parent.left; leftMargin: 3; verticalCenter: parent.verticalCenter }
+            anchors { left: parent.left; leftMargin: 12; verticalCenter: parent.verticalCenter }
             text: "New Game" 
-            onClicked: Logic.startNewGame()
+            onClicked: Logic.startNewGame(gameCanvas)
         }
 
         Button {
-            visible: !inAnotherDemo
             text: "Quit"
-            anchors { left: newGameButton.right; leftMargin: 3; verticalCenter: parent.verticalCenter }
+            anchors { left: newGameButton.right; leftMargin: 12; verticalCenter: parent.verticalCenter }
             onClicked: Qt.quit();
         }
 
         Text {
             id: score
-            anchors { right: parent.right; rightMargin: 3; verticalCenter: parent.verticalCenter }
+            anchors { right: parent.right; rightMargin: 12; verticalCenter: parent.verticalCenter }
             text: "Score: " + gameCanvas.score
             font.bold: true
             font.pixelSize: 24