SameGame refactor

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>
This commit is contained in:
Alan Alpert 2011-08-10 13:24:37 +10:00 committed by Qt by Nokia
parent b631e1e4f2
commit 4796c4d955
11 changed files with 220 additions and 206 deletions

View 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;

View File

@ -43,6 +43,7 @@ import QtQuick 2.0
Rectangle {
id: page
anchors.centerIn: parent
property Item text: dialogText
property bool open: false

View File

@ -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
}
}

View File

@ -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();
}
}
}

View File

@ -1,3 +0,0 @@
BoomBlock BoomBlock.qml
Button Button.qml
Dialog Dialog.qml

View File

@ -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);
}

View File

@ -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.

View File

@ -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>

View File

@ -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>

View File

@ -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>";
?>

View 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