diff --git a/src/activities/crane/Crane.qml b/src/activities/crane/Crane.qml index 5bd99aa66..5cddf3b03 100644 --- a/src/activities/crane/Crane.qml +++ b/src/activities/crane/Crane.qml @@ -1,472 +1,469 @@ /* GCompris - Crane.qml * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (Qt Quick port) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.1 import "../../core" import "crane.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent color: "#ffeecc" signal start signal stop Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property alias bar: bar property alias bonus: bonus property alias board: board property alias grid: grid property alias repeater: repeater property alias modelRepeater: modelRepeater property alias gridRepeater: gridRepeater property alias showGrid1: showGrid1 property int selected property int columns property int rows property bool ok: true property int sensivity: 80 property bool gameFinished: false } onStart: { Activity.start(items) } onStop: { Activity.stop() } property bool portrait: height > width ? true : false + property bool inLine: true Keys.onPressed: { if (event.key === Qt.Key_Left) Activity.move("left") else if (event.key === Qt.Key_Right) Activity.move("right") else if (event.key === Qt.Key_Up) Activity.move("up") else if (event.key === Qt.Key_Down) Activity.move("down") else if (event.key === Qt.Key_Space || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Return) Activity.move("next") } //implementation of Swipe effect MouseArea { anchors.fill: parent property int startX; property int startY; onPressed: { startX = mouse.x; startY = mouse.y; } onReleased: Activity.gesture(mouse.x - startX, mouse.y - startY) } Rectangle { id: board color: "lightblue" radius: width * 0.02 z: 1 anchors { verticalCenter: crane_vertical.verticalCenter right: crane_vertical.left margins: 15 } width: background.portrait ? parent.width * 0.65 : ((parent.width - anchors.margins * 3 - crane_vertical.width) / 2 ) * 0.9 height: background.portrait ? (parent.height - bar.height * 1.45 - crane_top.height - crane_body.height ) / 2 : (parent.height - bar.height * 1.45 - crane_top.height - crane_body.height) * 0.9 } Grid { id: showGrid1 columns: items.columns rows: items.rows z: 1 anchors.fill: board Repeater { id: gridRepeater Rectangle { width: board.width/items.columns height: board.height/items.rows color: "transparent" border.width: 2 border.color: "grey" } } } Rectangle { id: coverEgdes1 color: "transparent" width: board.width height: board.height border.color: board.color border.width: 10 opacity: showGrid1.opacity anchors.centerIn: board z: 3 } - Grid { id: grid columns: items.columns rows: items.rows z: 4 anchors.fill: board Repeater { id: repeater Image { id: figure sourceSize.height: board.height/3 sourceSize.width: board.width/3 width: board.width/items.columns height: board.height/items.rows property int initialIndex: -1 property bool showSelected: false property alias selected: selected property alias anim: anim property alias opac: selected.opacity property int distance property int indexChange property int startPoint property string animationProperty property int _index: index // make current index accessible from outside SequentialAnimation { id: anim PropertyAction { target: items; property: "ok"; value: "false"} NumberAnimation { target: figure; property: figure.animationProperty; from: figure.startPoint; to: figure.startPoint + distance; duration: 200 } PropertyAction { target: figure; property: "opacity"; value: 0 } PropertyAction { target: selected; property: "opacity"; value: 0 } NumberAnimation { target: figure; property: figure.animationProperty; from: figure.startPoint + distance; to: figure.startPoint; duration: 0; } PropertyAction { target: figure; property: "opacity"; value: 1 } PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "source"; value: figure.source } PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "opac"; value: 1 } - PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "initialIndex"; value: figure.initialIndex } PropertyAction { target: figure; property: "initialIndex"; value: -1 } - PropertyAction { target: figure; property: "source"; value: "" } PropertyAction { target: items; property: "ok"; value: "true"} ScriptAction { script: Activity.checkAnswer() } } MouseArea { anchors.fill: parent // Swipe effect property int startX; property int startY; onPressed: { startX = mouse.x; startY = mouse.y; - print("print: ",Activity.showGrid[Activity.currentLevel]=="true" ) } onReleased: Activity.gesture(mouse.x - startX, mouse.y - startY) // Select a figure with mouse/touch onClicked: { if (source != "") { items.repeater.itemAt(items.selected).opac = 0 items.selected = index items.repeater.itemAt(items.selected).opac = 1 } } - } // selected marker Image { id: selected source: "resource/selected.png" width: parent.width height: parent.height opacity: 0 } } } } Rectangle { id: modelBoard color: "pink" radius: width * 0.02 z: 1 anchors { left: background.portrait ? board.left : crane_vertical.right - top: background.portrait ? crane_body.bottom : parent.top - topMargin: background.portrait ? board.anchors.margins : crane_top.height * 1.5 + top: background.portrait ? crane_body.bottom : background.inLine ? board.top : parent.top + topMargin: background.portrait ? board.anchors.margins : background.inLine ? 0 : crane_top.height * 1.5 + leftMargin: background.portrait ? 0 : board.anchors.margins * 1.2 margins: board.anchors.margins } width: board.width height: board.height } Grid { id: modelGrid columns: items.columns rows: items.rows anchors.fill: modelBoard z: 4 Repeater { id: modelRepeater Image { id: modelFigure sourceSize.height: board.height/items.rows sourceSize.width: board.width/items.columns width: board.width/items.columns height: board.height/items.rows } } } Grid { id: showGrid2 columns: items.columns rows: items.rows z: 1 opacity: showGrid1.opacity anchors.fill: modelBoard Repeater { id: gridRepeater2 model: gridRepeater.model Rectangle { width: modelBoard.width/items.columns height: modelBoard.height/items.rows color: "transparent" border.width: 2 - border.color: Activity.showGrid[Activity.currentLevel] ? "grey" : "transparent" + border.color: showGrid1.opacity == 1 ? "grey" : "transparent" } } } Rectangle { id: coverEgdes2 color: "transparent" width: modelBoard.width height: modelBoard.height - border.color: Activity.showGrid[Activity.currentLevel] ? modelBoard.color : "transparent" + border.color: showGrid1.opacity == 1 ? modelBoard.color : "transparent" border.width: 10 anchors.centerIn: modelBoard opacity: showGrid1.opacity z: 3 } Image { id: crane_top source: "resource/crane_up.svg" sourceSize.width: background.portrait ? background.width * 0.8 : background.width * 0.5 sourceSize.height: background.portrait ? background.height * 0.03 : background.height * 0.06 width: background.portrait ? background.width * 0.8 : background.width * 0.5 height: background.portrait ? background.height * 0.03 : background.height * 0.06 z: 4 anchors { top: parent.top right: crane_vertical.right rightMargin: 0 margins: board.anchors.margins } } Image { id: crane_vertical source: "resource/crane_vertical.svg" sourceSize.width: background.width * 0.04 sourceSize.height: background.height * 0.73 width: background.width * 0.05 height: background.portrait ? background.height * 0.45 : background.height * 0.73 anchors { top: crane_top.top right: background.portrait ? parent.right : parent.horizontalCenter rightMargin: background.portrait ? width / 2 : - width / 2 topMargin: board.anchors.margins } } Image { id: crane_body source: "resource/crane_only.svg" z: 2 sourceSize.width: parent.width / 5 sourceSize.height: parent.height/ 3.6 mirror: background.portrait ? true : false anchors { top: crane_vertical.bottom topMargin: - (height / 1.8) right: crane_vertical.right rightMargin: background.portrait ? board.anchors.margins : - crane_body.width + crane_vertical.width margins: board.anchors.margins } } Image { id: crane_wire source: "resource/crane-wire.svg" z: 1 sourceSize.width: parent.width / 22 sourceSize.height: parent.width / 17 anchors { right: crane_body.left bottom: crane_command.verticalCenter rightMargin: -10 bottomMargin: -10 } } Image { id: crane_command source: "resource/command.svg" sourceSize.width: parent.width / 4 sourceSize.height: parent.height/ 3.5 mirror: true anchors { top: crane_body.top bottom: crane_body.bottom right: crane_wire.left rightMargin: 0 topMargin: background.portrait ? board.anchors.margins : 50 margins: board.anchors.margins } Controls { id: up source: "resource/arrow_up.svg" anchors { left: parent.left leftMargin: parent.width / 10 } command: "up" } Controls { id: down source: "resource/arrow_down.svg" anchors { left: up.right leftMargin: parent.width / 20 } command: "down" } Controls { id: left source: "resource/arrow_left.svg" anchors { right: right.left rightMargin: parent.width / 20 } command: "left" } Controls { id: right source: "resource/arrow_right.svg" anchors { right: parent.right rightMargin: parent.width / 10 } command: "right" } } Rectangle { id: cable color: "black" width: 5 height: convert.y - crane_top.y x: convert.x + board.width / items.columns / 2 z: 3 anchors.top: crane_top.top anchors.topMargin: 10 property var convert: items.selected == 0 ? grid : items.repeater.mapToItem(background,items.repeater.itemAt(items.selected).x, items.repeater.itemAt(items.selected).y) Behavior on x { NumberAnimation { duration: 200 } } Behavior on height { NumberAnimation { duration: 200 } } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } -} \ No newline at end of file +} diff --git a/src/activities/crane/crane.js b/src/activities/crane/crane.js index 114042fbf..f19a49646 100644 --- a/src/activities/crane/crane.js +++ b/src/activities/crane/crane.js @@ -1,317 +1,357 @@ /* GCompris - crane.js * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (Qt Quick port) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ .pragma library .import QtQuick 2.0 as Quick .import "qrc:/gcompris/src/core/core.js" as Core - var currentLevel = 0 -var numberOfLevel = 10 +var numberLevelsWords = 2 +var maxWordLevels = 3 * numberLevelsWords +var maxImageLevels = 10 +var numberOfLevel = maxWordLevels + maxImageLevels var items var url = "qrc:/gcompris/src/activities/crane/resource/" -var showGrid = [1,1,1,0,0,1,1,0,0,0] -var howManyFigures = [3,3,3,4,5,5,6,7,8,9,10,11,12,13] +var levels = [{showGrid: 1, noOfItems: 2, inLine: 1, columns: 4, rows: 3 }, + {showGrid: 1, noOfItems: 3, inLine: 1, columns: 5, rows: 4 }, + {showGrid: 1, noOfItems: 4, inLine: 1, columns: 6, rows: 5 }, + {showGrid: 0, noOfItems: 5, inLine: 0, columns: 7, rows: 6 }, + {showGrid: 0, noOfItems: 6, inLine: 0, columns: 7, rows: 6 }, + {showGrid: 1, noOfItems: 7, inLine: 1, columns: 7, rows: 6 }, + {showGrid: 1, noOfItems: 8, inLine: 1, columns: 7, rows: 6 }, + {showGrid: 0, noOfItems: 9, inLine: 0, columns: 7, rows: 6 }, + {showGrid: 0, noOfItems: 10, inLine: 0, columns: 7, rows: 6 }, + {showGrid: 0, noOfItems: 11, inLine: 0, columns: 7, rows: 6 }] + var allNames = ["bulb.svg","letter-a.svg","letter-b.svg", "rectangle1.svg","rectangle2.svg","square1.svg", "square2.svg","triangle1.svg","triangle2.svg", "tux.svg","water_drop1.svg","water_drop2.svg", "water_spot1.svg","water_spot2.svg"] -var words = ["cat","dog","win","good","happy"] + + +var words3Letters = ["cat","dog","win","red","yes","big","box","air","arm", + "car","bus","fun","day","eat","hat","leg","ice","old","egg"] +var words4Letters = ["blue","best","good","area","bell","coat","easy","farm", + "food","else","girl","give","hero","help","hour","sand","song"] +var words5Letters = ["happy","child","white","apple","brown","truth","fresh", + "green","horse","hotel","house","paper","shape","shirt","study"] + var names = [] var names2 = [] var good = [] function start(items_) { items = items_ currentLevel = 0 + Core.shuffle(words3Letters) + Core.shuffle(words4Letters) + Core.shuffle(words5Letters) initLevel() } function stop() { } function initLevel() { items.bar.level = currentLevel + 1 - init() } function init() { - items.columns = 7 - items.rows = 6 - items.gameFinished = false + // set models for repaters + if (currentLevel >= maxWordLevels) + setRandomModelImage() + else setRandomModelWord() - setRandomModel() + items.gameFinished = false + // set "initialIndex" to the position in the repeater for(var i = 0; i < names.length; i++) { if (items.repeater.itemAt(i).source != "") { items.repeater.itemAt(i).initialIndex = i good[i] = i } else { + // set the initialIndex to -1 if there is no item inside (no source) items.repeater.itemAt(i).initialIndex = -1 good[i] = -1 } } - //select the first item in the grid - for(var i = 0; i < items.repeater.count; i++) { + // select the first item in the grid + for(i = 0; i < items.repeater.count; i++) { if (items.repeater.itemAt(i).source != "") { items.selected = i break } } - //set opacity for first item's "selection frame" + // set opacity for first item's "selection frame" items.repeater.itemAt(items.selected).selected.opacity = 1 - - //show or hide the grid - if (showGrid[currentLevel]) - items.showGrid1.opacity = 1 - else items.showGrid1.opacity = 0 } -function setRandomModel(){ +// levels with words as items +function setRandomModelWord(){ + // reset the arrays + names = [] + names2 = [] + var numbers = [] + var i + var wordsUsed = [] + + if (currentLevel < numberLevelsWords) { + wordsUsed = words3Letters + // set the number of columns and rows from "levels" + items.columns = 4 + items.rows = 3 + // show or hide the grid + items.showGrid1.opacity = 1 + // set the two boards in line or not + items.background.inLine = true + } else if (currentLevel < numberLevelsWords * 2) { + wordsUsed = words4Letters + // set the number of columns and rows from "levels" + items.columns = 5 + items.rows = 4 + // show or hide the grid + items.showGrid1.opacity = 1 + // set the two boards in line or not + items.background.inLine = false + } else { + wordsUsed = words5Letters + // set the number of columns and rows from "levels" + items.columns = 6 + items.rows = 5 + // show or hide the grid + items.showGrid1.opacity = 0 + // set the two boards in line or not + items.background.inLine = false + } - for (var i = 0; i < items.columns * items.rows; i++){ - names[i] = "" // reset the board + for (i = 0; i < items.columns * items.rows; i++) { + names[i] = "" names2[i] = "" numbers[i] = i; // generate columns*rows numbers } - if (currentLevel >= words.length) { - // randomize the names - Core.shuffle(allNames) - - //get "howManyFigures[currentLevel]" random numbers - Core.shuffle(numbers) - - for (i = 0; i < howManyFigures[currentLevel]; i++) - names[numbers[i]] = url + allNames[i] - - Core.shuffle(numbers) - - for (i = 0; i < howManyFigures[currentLevel]; i++) - names2[numbers[i]] = url + allNames[i] - - } else { + var currentIndex = currentLevel % numberLevelsWords - var model = setModel() + // place the word at a random position in the grid + var randomRow = Math.floor(Math.random() * items.rows) + var randomCol = Math.floor(Math.random() * items.columns) - for (i = 0; i < model.length; i++) { - if (model[i] != "") { - names[i] = model[i] - names2[i] = model[i] - } - } + // check if the word goes out of the frame and replace to left it if needed + if (items.columns - randomCol - wordsUsed[currentIndex].length < 0) + randomCol = randomCol - Math.abs(items.columns - randomCol - wordsUsed[currentIndex].length) - Core.shuffle(names) + // set full path (url) to the letter image + for (i = 0; i < wordsUsed[currentIndex].length; i++) { + names[randomRow * items.columns + randomCol + i] = url + "letters/" + wordsUsed[currentIndex].charAt(i) + ".svg" + names2[randomRow * items.columns + randomCol + i] = names[randomRow * items.columns + randomCol + i] } + Core.shuffle(names) + + // set model for repeaters items.repeater.model = names.length items.modelRepeater.model = names2.length items.gridRepeater.model = names.length + // set the source of items inside repeaters to names and names2 for (i = 0; i < names.length; i++) { items.repeater.itemAt(i).source = names[i] items.repeater.itemAt(i).opac = 0 items.modelRepeater.itemAt(i).source = names2[i] } } -function setModel() { - var model = [] - for (var i = 0; i < items.columns * items.rows; i++){ - model[i] = "" +// levels with images as items +function setRandomModelImage(){ + // reset the arrays + names = [] + names2 = [] + + var numbers = [] + var i + + // set the number of columns and rows from "levels" + items.columns = levels[currentLevel - maxWordLevels].columns + items.rows = levels[currentLevel - maxWordLevels].rows + + for (i = 0; i < items.columns * items.rows; i++) { + names[i] = "" + names2[i] = "" + numbers[i] = i; // generate columns*rows numbers } - var randomRow = Math.floor(Math.random() * items.rows) - var randomCol = Math.floor(Math.random() * items.columns) + // randomize the names + Core.shuffle(allNames) + + //get "levels[currentLevel].noOfItems" random numbers + Core.shuffle(numbers) - if (items.columns - randomCol - words[currentLevel].length < 0) - randomCol = randomCol - Math.abs(items.columns - randomCol - words[currentLevel].length) + for (i = 0; i < levels[currentLevel - maxWordLevels].noOfItems; i++) + names[numbers[i]] = url + allNames[i] - for (i=0; i items.repeater.itemAt(i).initialIndex) { + // update min and index min = items.repeater.itemAt(i).initialIndex - indexx = i + biggerIndex = i } } - if (items.repeater.itemAt(i).initialIndex >= 0 && realMin > items.repeater.itemAt(i).initialIndex) { - realMin = items.repeater.itemAt(i).initialIndex - realMinIndex = i + // in case current index is the biggest, search the smalles index from start + if (items.repeater.itemAt(i).initialIndex >= 0 && min2 > items.repeater.itemAt(i).initialIndex) { + min2 = items.repeater.itemAt(i).initialIndex + smallestIndex = i } } - if (indexx != -1) { - return indexx - } + // if a bigger index was found, return it + if (biggerIndex != -1) + return biggerIndex - return realMinIndex + // this is the biggest index; the next one is the smallest in the array + return smallestIndex } -//function getNextIndex (index) { -// var i -// var min = 100 -// var indexx = -1 - -// for (i = 0; i < good.length; i++) { -// if (good[i] > good[index] && min > good[i]) { -// min = good[i] -// indexx = i -// } -// } -// if (min!=100) { -// print("found after index") -// return indexx -// } - -// for (i = 0; i < good.length; i++) { -// if (good[i] > 0 && min > good[i]) { -// min = good[i] -// indexx = i -// } -// } - -// print("found before index") -// return indexx -//} - //touchscreen gestures function gesture(deltax, deltay) { - if (Math.abs(deltax) > 40 || Math.abs(deltay) > 40) { - if (deltax > 30 && Math.abs(deltay) < items.sensivity) { + if (Math.abs(deltax) > 40 || Math.abs(deltay) > 40) + if (deltax > 30 && Math.abs(deltay) < items.sensivity) move("right") - } else if (deltax < -30 && Math.abs(deltay) < items.sensivity) { + else if (deltax < -30 && Math.abs(deltay) < items.sensivity) move("left") - } else if (Math.abs(deltax) < items.sensivity && deltay > 30) { + else if (Math.abs(deltax) < items.sensivity && deltay > 30) move("down") - } else if (Math.abs(deltax) < items.sensivity && deltay < 30) { + else if (Math.abs(deltax) < items.sensivity && deltay < 30) move("up") - } - } } //depeding on the command, make a move to left/right/up/down or select next item function move(command) { if (items.ok == true && items.gameFinished == false) { var item = items.repeater.itemAt(items.selected) if (command === "left") { - if (items.selected % items.columns != 0) { -// var aux = good[items.selected-1] -// good[items.selected-1] = good[items.selected] -// good[items.selected] = aux + if (items.selected % items.columns != 0) makeMove(item,-item.width,item.x,-1,"x") - } } else if (command === "right") { - if ((items.selected+1) % items.columns != 0) { -// aux = good[items.selected+1] -// good[items.selected+1] = good[items.selected] -// good[items.selected] = aux + if ((items.selected+1) % items.columns != 0) makeMove(item,item.width,item.x,1,"x") - } } else if (command === "up") { - if (items.selected > items.columns-1) { -// aux = good[items.selected-items.columns] -// good[items.selected-items.columns] = good[items.selected] -// good[items.selected] = aux + if (items.selected > items.columns-1) makeMove(item,-item.height,item.y,-items.columns,"y") - } } else if (command === "down") { - if (items.selected < (items.repeater.count-items.columns)) { -// aux = good[items.selected+items.columns] -// good[items.selected+items.columns] = good[items.selected] -// good[items.selected] = aux + if (items.selected < (items.repeater.count-items.columns)) makeMove(item,item.height,item.y,items.columns,"y") - } } else if (command === "next") { items.repeater.itemAt(items.selected).selected.opacity = 0 -// items.selected = getNextIndex(items.selected) - items.selected = newFunction() + items.selected = getNextIndex() items.repeater.itemAt(items.selected).selected.opacity = 1 } } } //set the environment for making a move and start the animation function makeMove(item,distance,startPoint,add,animationProperty) { if (items.repeater.itemAt(items.selected+add).source == "") { //setup the animation item.distance = distance item.indexChange = add item.startPoint = startPoint item.animationProperty = animationProperty //start the animation item.anim.start() //update the selected item items.selected += add; } } //check the answer; advance to next level if the answer is good function checkAnswer() { var count = 0 for (var i = 0; i < items.repeater.count; i++) { if (items.repeater.itemAt(i).source != items.modelRepeater.itemAt(i).source){ count = -1 } } if (count == 0) { items.bonus.good("flower") items.gameFinished = true } } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); -} \ No newline at end of file +}