summaryrefslogtreecommitdiffstats
path: root/demos/declarative/samegame
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2009-07-15 05:58:48 (GMT)
committerAlan Alpert <alan.alpert@nokia.com>2009-07-15 05:58:48 (GMT)
commitdc0a731659f2ed2f53ffe18bb98615d956c51ae4 (patch)
treec37009af37bd1644f58e5afdc5ea9a39032e07ee /demos/declarative/samegame
parent023fdd3116aa0cba5687c66eda9d3f17e1a731ba (diff)
downloadQt-dc0a731659f2ed2f53ffe18bb98615d956c51ae4.zip
Qt-dc0a731659f2ed2f53ffe18bb98615d956c51ae4.tar.gz
Qt-dc0a731659f2ed2f53ffe18bb98615d956c51ae4.tar.bz2
Initial commit of the Same Game demo. Compare to KSame if on KDE.
This demo primarily demonstrates use of JS and dynamic creation with QML, by creating a functional and animated game entirely with QML & JS
Diffstat (limited to 'demos/declarative/samegame')
-rw-r--r--demos/declarative/samegame/README10
-rw-r--r--demos/declarative/samegame/SameGame.qml36
-rw-r--r--demos/declarative/samegame/TODO5
-rw-r--r--demos/declarative/samegame/content/BoomBlock.qml48
-rw-r--r--demos/declarative/samegame/content/FastBlock.qml41
-rw-r--r--demos/declarative/samegame/content/MediaButton.qml39
-rw-r--r--demos/declarative/samegame/content/SameDialog.qml17
-rw-r--r--demos/declarative/samegame/content/pics/background.pngbin0 -> 153328 bytes
-rw-r--r--demos/declarative/samegame/content/pics/blueStone.pngbin0 -> 4823 bytes
-rw-r--r--demos/declarative/samegame/content/pics/button-pressed.pngbin0 -> 571 bytes
-rw-r--r--demos/declarative/samegame/content/pics/button.pngbin0 -> 564 bytes
-rw-r--r--demos/declarative/samegame/content/pics/greenStone.pngbin0 -> 4724 bytes
-rw-r--r--demos/declarative/samegame/content/pics/qtlogo.pngbin0 -> 2738 bytes
-rw-r--r--demos/declarative/samegame/content/pics/redStone.pngbin0 -> 4585 bytes
-rw-r--r--demos/declarative/samegame/content/pics/star.pngbin0 -> 262 bytes
-rw-r--r--demos/declarative/samegame/content/pics/yellowStone.pngbin0 -> 4818 bytes
-rw-r--r--demos/declarative/samegame/content/samegame.js163
17 files changed, 359 insertions, 0 deletions
diff --git a/demos/declarative/samegame/README b/demos/declarative/samegame/README
new file mode 100644
index 0000000..244b205
--- /dev/null
+++ b/demos/declarative/samegame/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/demos/declarative/samegame/SameGame.qml b/demos/declarative/samegame/SameGame.qml
new file mode 100644
index 0000000..0e5bb0f
--- /dev/null
+++ b/demos/declarative/samegame/SameGame.qml
@@ -0,0 +1,36 @@
+import "content"
+
+Rect {
+ width: 400
+ height: 700
+ color: "white"
+ Script { source: "content/samegame.js" }
+ Rect{
+ property int score: 0
+ x:20; y:20; width:360; height:600; id: gameCanvas;
+ color: "white"
+ pen.width: 1
+ Image { id:background;
+ source: "content/pics/qtlogo.png"
+ anchors.fill: parent
+ }
+
+ MouseRegion { id: gameMR; anchors.fill: parent;
+ onClicked: handleClick(mouseX, mouseY);
+ }
+ }
+ HorizontalLayout {
+ anchors.top: gameCanvas.bottom
+ anchors.topMargin: 10
+ anchors.horizontalCenter: parent.horizontalCenter
+ MediaButton { id: btnA; text: "New Game"; onClicked: {initBoard();} }
+ MediaButton { id: btnB; text: "Swap Theme"; onClicked: {swapTileSrc(); dialog.opacity = 1;}
+ }
+ Text{ text: "Score: " + gameCanvas.score; width:100 }
+ }
+ SameDialog {
+ id: dialog
+ anchors.centeredIn: parent
+ text: "Takes effect next game."
+ }
+}
diff --git a/demos/declarative/samegame/TODO b/demos/declarative/samegame/TODO
new file mode 100644
index 0000000..b02ce54
--- /dev/null
+++ b/demos/declarative/samegame/TODO
@@ -0,0 +1,5 @@
+Still to do before initial release
+-Garbage collect on click
+-Particles with count 0->50 should work properly
+-Particles are too slow to start
+-Everything is too slow, we should have four times the number of tiles there
diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml
new file mode 100644
index 0000000..5eaaade
--- /dev/null
+++ b/demos/declarative/samegame/content/BoomBlock.qml
@@ -0,0 +1,48 @@
+Item { id:block
+ property bool dying: false
+ property bool spawning: false
+ property int type: 0
+ property int targetX: 0
+ property int targetY: 0
+
+ x: targetX
+ y: Follow { source: targetY; spring: 1.2; damping: 0.1 }
+ //y: Behavior { NumberAnimation { properties:"y"; duration: 200 } }
+
+ 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.centeredIn: parent; opacity: 0
+ lifeSpan: 100000; source: "pics/star.png"; count:1; streamIn: false
+ angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30
+ }
+ states: [
+
+ State{ name: "SpawnState"; when: spawning == true && dying == false
+ SetProperties { target: img; opacity: 1 }
+ },
+ State{ name: "DeathState"; when: dying == true
+ SetProperties { target: particles; count: 50 }
+ SetProperties { target: particles; opacity: 1 }
+ SetProperties { target: img; opacity: 0 }
+ }
+ ]
+// transitions: [
+// Transition {
+// fromState: "SpawnState"
+// NumberAnimation { properties: "opacity"; duration: 200 }
+// },
+// Transition {
+// toState: "DeathState"
+// SequentialAnimation {
+// NumberAnimation { properties: "opacity"; duration: 200 }
+// //TODO: Warning about following line, if it works
+// //RunScriptAction { script: page.destroy() }
+// }
+// }
+// ]
+}
diff --git a/demos/declarative/samegame/content/FastBlock.qml b/demos/declarative/samegame/content/FastBlock.qml
new file mode 100644
index 0000000..3d14959
--- /dev/null
+++ b/demos/declarative/samegame/content/FastBlock.qml
@@ -0,0 +1,41 @@
+Rect { id:block
+ //Note: These properties are the interface used to control the blocks
+ property bool dying: false
+ property bool spawning: false
+ property int type: 0
+ property int targetY: 0
+ property int targetX: 0
+
+ color: {if(type==0){"red";}else if(type==1){"blue";}else{"green";}}
+ pen.width: 1
+ pen.color: "black"
+ opacity: 0
+ y: targetY
+ x: targetX
+ y: Behavior { NumberAnimation { properties:"y"; duration: 200 } }
+ opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } }
+
+ states: [
+
+ State{ name: "SpawnState"; when: spawning == true && dying == false
+ SetProperties { target: block; opacity: 1 }
+ },
+ State{ name: "DeathState"; when: dying == true
+ SetProperties { target: block; opacity: 0 }
+ }
+ ]
+// transitions: [
+// Transition {
+// fromState: "SpawnState"
+// NumberAnimation { properties: "opacity"; duration: 200 }
+// },
+// Transition {
+// toState: "DeathState"
+// SequentialAnimation {
+// NumberAnimation { properties: "opacity"; duration: 200 }
+// //TODO: Warning about following line, if it works
+// //RunScriptAction { script: page.destroy() }
+// }
+// }
+// ]
+}
diff --git a/demos/declarative/samegame/content/MediaButton.qml b/demos/declarative/samegame/content/MediaButton.qml
new file mode 100644
index 0000000..49922f0
--- /dev/null
+++ b/demos/declarative/samegame/content/MediaButton.qml
@@ -0,0 +1,39 @@
+Item {
+ id: Container
+
+ signal clicked
+
+ property string text
+
+ Image {
+ id: Image
+ source: "pics/button.png"
+ }
+ Image {
+ id: Pressed
+ source: "pics/button-pressed.png"
+ opacity: 0
+ }
+ MouseRegion {
+ id: MouseRegion
+ anchors.fill: Image
+ onClicked: { Container.clicked(); }
+ }
+ Text {
+ font.bold: true
+ color: "white"
+ anchors.centeredIn: Image
+ text: Container.text
+ }
+ width: Image.width
+ states: [
+ State {
+ name: "Pressed"
+ when: MouseRegion.pressed == true
+ SetProperties {
+ target: Pressed
+ opacity: 1
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/samegame/content/SameDialog.qml b/demos/declarative/samegame/content/SameDialog.qml
new file mode 100644
index 0000000..eed52f0
--- /dev/null
+++ b/demos/declarative/samegame/content/SameDialog.qml
@@ -0,0 +1,17 @@
+Rect {
+ property string text: "Hello World!"
+ property int show: 0
+ id: page
+ opacity: 0
+ opacity: Behavior {
+ SequentialAnimation {
+ NumberAnimation {property: "opacity"; duration: 1000 }
+ NumberAnimation {property: "opacity"; to: 0; duration: 1000 }
+ }
+ }
+ color: "white"
+ pen.width: 1
+ width: 200
+ height: 60
+ Text { anchors.centeredIn: parent; text: parent.text }
+}
diff --git a/demos/declarative/samegame/content/pics/background.png b/demos/declarative/samegame/content/pics/background.png
new file mode 100644
index 0000000..25e885f
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/background.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/blueStone.png b/demos/declarative/samegame/content/pics/blueStone.png
new file mode 100644
index 0000000..673f1ce
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/blueStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/button-pressed.png b/demos/declarative/samegame/content/pics/button-pressed.png
new file mode 100644
index 0000000..e434d32
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/button-pressed.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/button.png b/demos/declarative/samegame/content/pics/button.png
new file mode 100644
index 0000000..56a63ce
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/button.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/greenStone.png b/demos/declarative/samegame/content/pics/greenStone.png
new file mode 100644
index 0000000..0c087d0
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/greenStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/qtlogo.png b/demos/declarative/samegame/content/pics/qtlogo.png
new file mode 100644
index 0000000..399bd0b
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/qtlogo.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/redStone.png b/demos/declarative/samegame/content/pics/redStone.png
new file mode 100644
index 0000000..80c2e2e
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/redStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/star.png b/demos/declarative/samegame/content/pics/star.png
new file mode 100644
index 0000000..defbde5
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/star.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/yellowStone.png b/demos/declarative/samegame/content/pics/yellowStone.png
new file mode 100644
index 0000000..5349eff
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/yellowStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js
new file mode 100644
index 0000000..f3bb5b6
--- /dev/null
+++ b/demos/declarative/samegame/content/samegame.js
@@ -0,0 +1,163 @@
+/* This script file handles the game logic */
+
+var maxIdx = 18/2;//Nums are for tileSize 20 (desired tile size but too slow)
+var maxY = 30/2;
+var tileSize = 40;
+var maxIndex = maxIdx*maxY;
+var board = new Array(maxIndex);
+var tileSrc = "content/FastBlock.qml";
+var backSrc = "content/pics/background.png";
+var swapped = false;
+
+var compSrc;
+var component;
+
+function swapTileSrc(){
+ if(swapped)
+ return;
+ if(tileSrc == "content/FastBlock.qml"){
+ tileSrc = "content/BoomBlock.qml";
+ backSrc = "content/pics/background.png";
+ }else{
+ backSrc = "content/pics/qtlogo.png";
+ tileSrc = "content/FastBlock.qml";
+ }
+ swapped = true;
+}
+
+function index(xIdx,yIdx){
+ return xIdx + (yIdx * maxIdx);
+}
+
+function initBoard()
+{
+ background.source = backSrc;
+ swapped = false;
+ gameCanvas.score = 0;
+ for(xIdx=0; xIdx<maxIdx; xIdx++){
+ for(yIdx=0; yIdx<maxY; yIdx++){
+ if(board[index(xIdx,yIdx)] != null){
+ //Delete old blocks
+ board[index(xIdx,yIdx)].destroy();
+ }
+ board[index(xIdx,yIdx)] = null;
+ startCreatingBlock(xIdx,yIdx);
+ }
+ }
+ //TODO: a flag that handleMouse uses to ignore clicks when we're loading
+}
+
+var removed;
+function handleClick(x,y)
+{
+ //NOTE: Be careful with vars named x,y - they can set to the calling object?
+ xIdx = Math.floor(x/tileSize);
+ yIdx = Math.floor(y/tileSize);
+ if(xIdx >= maxIdx || xIdx < 0 || yIdx >= maxY || yIdx < 0)
+ return;
+ if(board[index(xIdx, yIdx)] == null)
+ return;
+ removed = 0;
+ floodKill(xIdx,yIdx, -1);
+ gameCanvas.score += removed * removed;
+ shuffleDown();
+}
+
+function floodKill(xIdx,yIdx,type)
+{
+ if(xIdx >= maxIdx || xIdx < 0 || yIdx >= maxY || yIdx < 0)
+ return;
+ if(board[index(xIdx, yIdx)] == null)
+ return;
+ if(type == -1){
+ type = board[index(xIdx,yIdx)].type;
+ }else{
+ if(type != board[index(xIdx,yIdx)].type)
+ return;
+ }
+ board[index(xIdx,yIdx)].dying = true;
+ board[index(xIdx,yIdx)] = null;//They'll have to destroy themselves(can we do that?)
+ removed += 1;
+ floodKill(xIdx+1,yIdx,type);
+ floodKill(xIdx-1,yIdx,type);
+ floodKill(xIdx,yIdx+1,type);
+ floodKill(xIdx,yIdx-1,type);
+}
+
+function shuffleDown()
+{
+ for(xIdx=0; xIdx<maxIdx; 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;
+ }
+ }
+ }
+ }
+}
+
+//Need a simpler method of doing this?
+var waitStack = new Array(maxIndex);
+var waitTop = -1;
+
+function finishCreatingBlock(xIdx,yIdx){
+ //TODO: Doc that the 'xIdx', 'yIdx' here are hidden properties from the calling QFxItem
+ if(component.isReady()){
+ if(xIdx == undefined){
+ //Called without arguments, create a previously stored (xIdx,yIdx)
+ if(waitTop == -1)
+ return;//Don't have a previously stored (xIdx,yIdx)
+ xIdx = waitStack[waitTop] % maxIdx;
+ yIdx = Math.floor(waitStack[waitTop] / maxIdx);
+ waitTop -= 1;
+ }
+ 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.targetX = xIdx*tileSize;
+ dynamicObject.targetY = yIdx*tileSize;
+ dynamicObject.width = tileSize;
+ dynamicObject.height = tileSize;
+ dynamicObject.spawning = true;
+ board[index(xIdx,yIdx)] = dynamicObject;
+ return true;
+ }else if(component.isError()){
+ print("error creating block");
+ print(component.errorsString());
+ }else{
+ //It isn't ready, but we'll be called again when it is.
+ //So store the requested (xIdx,yIdx) for later use
+ waitTop += 1;
+ waitStack[waitTop] = index(xIdx,yIdx);
+ }
+ return false;
+}
+
+function startCreatingBlock(xIdx,yIdx){
+ if(component!=null && compSrc == tileSrc){
+ finishCreatingBlock(xIdx,yIdx);
+ return;
+ }
+
+ if(component!=null){//Changed source
+ //delete component; //Does the engine handle this?
+ compSrc = tileSrc;
+ }
+ component = createComponent(tileSrc);
+ if(finishCreatingBlock(xIdx,yIdx))
+ return;
+ component.statusChanged.connect(finishCreatingBlock());
+ return;
+}