samegame.qml Example File
demos/samegame/samegame.qml
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.0
import QtQuick.Particles 2.0
import "content/samegame.js" as Logic
import "content"
Rectangle {
id : root
width : Settings .screenWidth ; height : Settings .screenHeight
property int acc : 0
function loadPuzzle () {
if (gameCanvas .mode != "" )
Logic .cleanUp ();
Logic .startNewGame (gameCanvas ,"puzzle" ,"levels/level" + acc + ".qml" )
}
function nextPuzzle () {
acc = (acc + 1 ) % 10 ;
loadPuzzle ();
}
Timer {
id : gameOverTimer
interval : 1500
running : gameCanvas .gameOver && gameCanvas .mode == "puzzle" //mode will be reset by cleanUp();
repeat : false
onTriggered : {
Logic .cleanUp ();
nextPuzzle ();
}
}
Image {
source : "content/gfx/background.png"
anchors .fill: parent
}
GameArea {
id : gameCanvas
z : 1
y : Settings .headerHeight
width : parent .width
height : parent .height - Settings .headerHeight - Settings .footerHeight
backgroundVisible : root .state == "in-game"
onModeChanged : if (gameCanvas .mode != "puzzle" ) puzzleWon = false ; //UI has stricter constraints on this variable than the game does
Age {
groups : ["redspots" , "greenspots" , "bluespots" , "yellowspots" ]
enabled : root .state == ""
system : gameCanvas .ps
}
onPuzzleLost : acc--;//So that nextPuzzle() reloads the current one
}
Item {
id : menu
z : 2
width : parent .width ;
anchors .top: parent .top
anchors .bottom: bottomBar .top
LogoAnimation {
x : 64
y : Settings .headerHeight
particleSystem : gameCanvas .ps
running : root .state == ""
}
Row {
x : 112
y : 20
Image { source : "content/gfx/logo-a.png" }
Image { source : "content/gfx/logo-m.png" }
Image { source : "content/gfx/logo-e.png" }
}
Column {
y : 100 + 40
spacing : Settings .menuButtonSpacing
width : parent .width
height : parent .height - (140 + Settings .footerHeight )
Button {
width : root .width
rotatedButton : true
imgSrc : "content/gfx/but-game-1.png"
onClicked : {
if (root .state == "in-game" )
return //Prevent double clicking
root .state = "in-game"
gameCanvas .blockFile = "Block.qml"
gameCanvas .background = "gfx/background.png"
arcadeTimer .start ();
}
//Emitted particles don't fade out, because ImageParticle is on the GameArea
system : gameCanvas .ps
group : "green"
Timer {
id : arcadeTimer
interval : Settings .menuDelay
running : false
repeat : false
onTriggered : Logic .startNewGame (gameCanvas )
}
}
Button {
width : root .width
rotatedButton : true
imgSrc : "content/gfx/but-game-2.png"
onClicked : {
if (root .state == "in-game" )
return
root .state = "in-game"
gameCanvas .blockFile = "Block.qml"
gameCanvas .background = "gfx/background.png"
twopTimer .start ();
}
system : gameCanvas .ps
group : "green"
Timer {
id : twopTimer
interval : Settings .menuDelay
running : false
repeat : false
onTriggered : Logic .startNewGame (gameCanvas , "multiplayer" )
}
}
Button {
width : root .width
rotatedButton : true
imgSrc : "content/gfx/but-game-3.png"
onClicked : {
if (root .state == "in-game" )
return
root .state = "in-game"
gameCanvas .blockFile = "SimpleBlock.qml"
gameCanvas .background = "gfx/background.png"
endlessTimer .start ();
}
system : gameCanvas .ps
group : "blue"
Timer {
id : endlessTimer
interval : Settings .menuDelay
running : false
repeat : false
onTriggered : Logic .startNewGame (gameCanvas , "endless" )
}
}
Button {
width : root .width
rotatedButton : true
imgSrc : "content/gfx/but-game-4.png"
group : "yellow"
onClicked : {
if (root .state == "in-game" )
return
root .state = "in-game"
gameCanvas .blockFile = "PuzzleBlock.qml"
gameCanvas .background = "gfx/background.png"
puzzleTimer .start ();
}
Timer {
id : puzzleTimer
interval : Settings .menuDelay
running : false
repeat : false
onTriggered : loadPuzzle ();
}
system : gameCanvas .ps
}
}
}
Image {
id : scoreBar
source : "content/gfx/bar.png"
width : parent .width
z : 6
y : -Settings .headerHeight
height : Settings .headerHeight
Behavior on opacity { NumberAnimation {} }
SamegameText {
id : arcadeScore
anchors { right : parent .right ; topMargin : 3 ; rightMargin : 11 ; top : parent .top }
text : '<font color="#f7d303">P1:</font> ' + gameCanvas .score
font .pixelSize: Settings .fontPixelSize
textFormat : Text .StyledText
color : "white"
opacity : gameCanvas .mode == "arcade" ? 1 : 0
Behavior on opacity { NumberAnimation {} }
}
SamegameText {
id : arcadeHighScore
anchors { left : parent .left ; topMargin : 3 ; leftMargin : 11 ; top : parent .top }
text : '<font color="#f7d303">Highscore:</font> ' + gameCanvas .highScore
opacity : gameCanvas .mode == "arcade" ? 1 : 0
}
SamegameText {
id : p1Score
anchors { right : parent .right ; topMargin : 3 ; rightMargin : 11 ; top : parent .top }
text : '<font color="#f7d303">P1:</font> ' + gameCanvas .score
opacity : gameCanvas .mode == "multiplayer" ? 1 : 0
}
SamegameText {
id : p2Score
anchors { left : parent .left ; topMargin : 3 ; leftMargin : 11 ; top : parent .top }
text : '<font color="#f7d303">P2:</font> ' + gameCanvas .score2
opacity : gameCanvas .mode == "multiplayer" ? 1 : 0
rotation : 180
}
SamegameText {
id : puzzleMoves
anchors { left : parent .left ; topMargin : 3 ; leftMargin : 11 ; top : parent .top }
text : '<font color="#f7d303">Moves:</font> ' + gameCanvas .moves
opacity : gameCanvas .mode == "puzzle" ? 1 : 0
}
SamegameText {
Image {
source : "content/gfx/icon-time.png"
x : -20
}
id : puzzleTime
anchors { topMargin : 3 ; top : parent .top ; horizontalCenter : parent .horizontalCenter ; horizontalCenterOffset : 20 }
text : "00:00"
opacity : gameCanvas .mode == "puzzle" ? 1 : 0
Timer {
interval : 1000
repeat : true
running : gameCanvas .mode == "puzzle" && !gameCanvas .gameOver
onTriggered : {
var elapsed = Math .floor ((new Date () - Logic .gameDuration )/ 1000.0 );
var mins = Math .floor (elapsed / 60.0 );
var secs = (elapsed % 60 );
puzzleTime .text = (mins < 10 ? "0" : "" ) + mins + ":" + (secs < 10 ? "0" : "" ) + secs ;
}
}
}
SamegameText {
id : puzzleScore
anchors { right : parent .right ; topMargin : 3 ; rightMargin : 11 ; top : parent .top }
text : '<font color="#f7d303">Score:</font> ' + gameCanvas .score
opacity : gameCanvas .mode == "puzzle" ? 1 : 0
}
}
Image {
id : bottomBar
width : parent .width
height : Settings .footerHeight
source : "content/gfx/bar.png"
y : parent .height - Settings .footerHeight ;
z : 2
Button {
id : quitButton
height : Settings .toolButtonHeight
imgSrc : "content/gfx/but-quit.png"
onClicked : {Qt .quit (); }
anchors { left : parent .left ; verticalCenter : parent .verticalCenter ; leftMargin : 11 }
}
Button {
id : menuButton
height : Settings .toolButtonHeight
imgSrc : "content/gfx/but-menu.png"
visible : (root .state == "in-game" );
onClicked : {root .state = "" ; Logic .cleanUp (); gameCanvas .mode = "" }
anchors { left : quitButton .right ; verticalCenter : parent .verticalCenter ; leftMargin : 0 }
}
Button {
id : againButton
height : Settings .toolButtonHeight
imgSrc : "content/gfx/but-game-new.png"
visible : (root .state == "in-game" );
opacity : gameCanvas .gameOver && (gameCanvas .mode == "arcade" || gameCanvas .mode == "multiplayer" )
Behavior on opacity { NumberAnimation {} }
onClicked : {if (gameCanvas .gameOver ) { Logic .startNewGame (gameCanvas , gameCanvas .mode );}}
anchors { right : parent .right ; verticalCenter : parent .verticalCenter ; rightMargin : 11 }
}
Button {
id : nextButton
height : Settings .toolButtonHeight
imgSrc : "content/gfx/but-puzzle-next.png"
visible : (root .state == "in-game" ) && gameCanvas .mode == "puzzle" && gameCanvas .puzzleWon
opacity : gameCanvas .puzzleWon ? 1 : 0
Behavior on opacity { NumberAnimation {} }
onClicked : {if (gameCanvas .puzzleWon ) nextPuzzle ();}
anchors { right : parent .right ; verticalCenter : parent .verticalCenter ; rightMargin : 11 }
}
}
Connections {
target : root
onStateChanged : stateChangeAnim .running = true
}
SequentialAnimation {
id : stateChangeAnim
ParallelAnimation {
NumberAnimation { target : bottomBar ; property : "y" ; to : root .height ; duration : Settings .menuDelay / 2 ; easing .type: Easing .OutQuad }
NumberAnimation { target : scoreBar ; property : "y" ; to : -Settings .headerHeight ; duration : Settings .menuDelay / 2 ; easing .type: Easing .OutQuad }
}
ParallelAnimation {
NumberAnimation { target : bottomBar ; property : "y" ; to : root .height - Settings .footerHeight ; duration : Settings .menuDelay / 2 ; easing .type: Easing .OutBounce }
NumberAnimation { target : scoreBar ; property : "y" ; to : root .state == "" ? -Settings .headerHeight : 0 ; duration : Settings .menuDelay / 2 ; easing .type: Easing .OutBounce }
}
}
states : [
State {
name : "in-game"
PropertyChanges {
target : menu
opacity : 0
visible : false
}
}
]
transitions : [
Transition {
NumberAnimation {properties : "x,y,opacity" }
}
]
//"Debug mode"
focus : true
Keys .onAsteriskPressed: Logic .nuke ();
Keys .onSpacePressed: gameCanvas .puzzleWon = true ;
}