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:
parent
b631e1e4f2
commit
4796c4d955
|
@ -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;
|
||||
|
|
|
@ -43,6 +43,7 @@ import QtQuick 2.0
|
|||
|
||||
Rectangle {
|
||||
id: page
|
||||
anchors.centerIn: parent
|
||||
|
||||
property Item text: dialogText
|
||||
property bool open: false
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
BoomBlock BoomBlock.qml
|
||||
Button Button.qml
|
||||
Dialog Dialog.qml
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>";
|
||||
?>
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue