diff --git a/src/activities/programmingMaze/ProgrammingMaze.qml b/src/activities/programmingMaze/ProgrammingMaze.qml index 89d064ca4..0903ad327 100644 --- a/src/activities/programmingMaze/ProgrammingMaze.qml +++ b/src/activities/programmingMaze/ProgrammingMaze.qml @@ -1,491 +1,505 @@ /* GCompris - programmingMaze.qml * * Copyright (C) 2014 Siddhesh Suthar * * Authors: * Siddhesh Suthar (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.2 import GCompris 1.0 import "../../core" import "qrc:/gcompris/src/core/core.js" as Core import "programmingMaze.js" as Activity import QtQuick.Controls 1.0 import QtQuick.Layouts 1.0 ActivityBase { id: activity onStart: focus = true onStop: {} property int oldWidth: width onWidthChanged: { // Reposition planets and asteroids, same for height Activity.repositionObjectsOnWidthChanged(width / oldWidth) oldWidth = width } property int oldHeight: height onHeightChanged: { // Reposition planets and asteroids, same for height Activity.repositionObjectsOnHeightChanged(height / oldHeight) oldHeight = height } pageComponent: Rectangle { id: background anchors.fill: parent color: "#8C8984" property bool keyNavigation: false 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 GCAudio audioEffects: activity.audioEffects property alias mazeModel: mazeModel property alias instructionModel: instructionModel property alias answerModel: answerModel property alias player: player property alias fish: fish } onStart: { Activity.start(items) keyNavigation = false } onStop: { Activity.stop() } Keys.onRightPressed: { keyNavigation = true instruction.incrementCurrentIndex() } Keys.onLeftPressed: { keyNavigation = true instruction.decrementCurrentIndex() } Keys.onDownPressed: { keyNavigation = true instruction.incrementCurrentIndex() } Keys.onUpPressed: { keyNavigation = true instruction.decrementCurrentIndex() } Keys.onSpacePressed: { keyNavigation = true instruction.currentItem.children[3].clicked() } Keys.onEnterPressed: { keyNavigation = true instruction.currentItem.children[3].clicked() } Keys.onReturnPressed: { keyNavigation = true instruction.currentItem.children[3].clicked() } ListModel { id: instructionModel ListElement { name: "Move Forward" } ListElement { name: "Turn Left" } ListElement { name: "Turn Right" } } ListModel { id: answerModel } Repeater { id: mazeModel model: Activity.mazeBlocks[0] anchors.left: parent.left anchors.top: parent.top anchors.bottom: instruction.top Image { x: modelData[0] * background.width / 8 y: modelData[1] * (background.height - background.height/8) / 8 width: background.width / 8 height: background.height / 8 source: Activity.reverseCountUrl + "iceblock.svg" } } Image { id: player source: "qrc:/gcompris/src/activities/maze/resource/" + "tux_top_south.svg" sourceSize.width: background.width / 10 x: 0; y: 0; z: 11 - property int duration: 2000 + property int duration: 0 signal init onInit: { - player.rotation = -90 -// Activity.runCode() + player.rotation = -90 + // Activity.runCode() } Behavior on x { - SmoothedAnimation { -// reversingMode: SmoothedAnimation.Immediate -// onRunningChanged: Activity.playerRunningChanged() + NumberAnimation { duration: player.duration } } -// Behavior on y { -// SmoothedAnimation { -// reversingMode: SmoothedAnimation.Immediate -// onRunningChanged: Activity.playerRunningChanged() -// duration: player.duration -// } -// } + + Behavior on y { + NumberAnimation { + duration: player.duration + } + } + + // Behavior on x { + // SmoothedAnimation { + // reversingMode: SmoothedAnimation.Immediate + // onRunningChanged: Activity.playerRunningChanged() + // duration: player.duration + // } + // } + // Behavior on y { + // SmoothedAnimation { + // reversingMode: SmoothedAnimation.Immediate + // onRunningChanged: Activity.playerRunningChanged() + // duration: player.duration + // } + // } + Behavior on rotation { RotationAnimation { duration: player.duration / 2 direction: RotationAnimation.Shortest } } } Image { id: fish source: Activity.reverseCountUrl + "blue-fish.svg" sourceSize.width: background.width / 10 -// anchors.leftMargin: 20 * ApplicationInfo.ratio + // anchors.leftMargin: 20 * ApplicationInfo.ratio x: 0; y: 0; z: 5 } ListView { id: instruction width: parent.width * 0.625 height: parent.height * 0.375 - bar.height / 2 anchors.left: parent.left anchors.bottom: bar.top anchors.margins: 10 * ApplicationInfo.ratio anchors.bottomMargin: bar.height / 2 orientation: Qt.Vertical verticalLayoutDirection: ListView.TopToBottom spacing: 5 * ApplicationInfo.ratio interactive: false model: instructionModel header: instructionHeaderComponent highlight: Rectangle { width: instruction.width height: instruction.buttonHeight color: "lightsteelblue" border.width: 3 border.color: "black" visible: background.keyNavigation y: instruction.currentItem.y Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } } } highlightFollowsCurrentItem: false focus: true keyNavigationWraps: true property int buttonHeight: instruction.height / instructionModel.count - instruction.spacing delegate: Item { width: instruction.width - instruction.spacing height: instruction.buttonHeight Rectangle { id: rect anchors.fill: parent gradient: Gradient { GradientStop { position: 0.0; color: "#0191C8" } GradientStop { position: 1.0; color: "#005B9A" } } opacity: 0.5 } Image { source: "qrc:/gcompris/src/core/resource/button.svg" sourceSize { height: parent.height; width: parent.width } width: sourceSize.width height: sourceSize.height smooth: false } GCText { id: instructionText anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignHCenter width: instruction.width fontSizeMode: Text.Fit minimumPointSize: 7 fontSize: regularSize wrapMode: Text.WordWrap color: "white" text: name } MouseArea { id: mouseArea anchors.fill: parent signal clicked onClicked: { clickedAnim.start() answerModel.append({"name": instructionText.text, "selected": false}) } onPressed: { clickedAnim.start() answerModel.append({"name": instructionText.text, "selected": false}) } } SequentialAnimation { id: clickedAnim PropertyAnimation { target: rect property: "opacity" to: "1" duration: 300 } PropertyAnimation { target: rect property: "opacity" to: "0.5" duration: 300 } } } } // insert data upon clicking the list items into this answerData // and then process it to run the code ListView { id: answerSheet width: parent.width * 0.350 height: parent.height * 0.80 - bar.height anchors.right: parent.right anchors.top: parent.top anchors.margins: 10 * ApplicationInfo.ratio orientation: Qt.Vertical verticalLayoutDirection: ListView.TopToBottom spacing: 5 * ApplicationInfo.ratio interactive: false model: answerModel header: answerHeaderComponent footer: answerFooterComponent delegate: Item { width: answerSheet.width - answerSheet.spacing height: answerSheet.height / answerModel.count - answerSheet.spacing Rectangle { id: answerRect anchors.fill: parent color: "#005B9A" opacity: 1 } Image { source: "qrc:/gcompris/src/core/resource/button.svg" sourceSize { height: parent.height; width: parent.width } width: sourceSize.width height: sourceSize.height smooth: false } GCText { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignHCenter width: parent.width fontSizeMode: Text.Fit minimumPointSize: 7 fontSize: regularSize wrapMode: Text.WordWrap color: "white" text: name } Image { source: "qrc:/gcompris/src/core/resource/bar_exit.svg" sourceSize { height: parent.height ; width: parent.width } width: sourceSize.width / 8 height: sourceSize.height / 3 smooth: false anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter anchors.rightMargin: 10 * ApplicationInfo.ratio MouseArea { id: answerRemove anchors.fill: parent onPressed: { answerModel.remove(model.index) } } } } } Component { id: answerFooterComponent Image { id: runCode source:"qrc:/gcompris/src/core/resource/bar_ok.svg" width: background.width / 8 height: background.height / 8 fillMode: Image.PreserveAspectFit MouseArea { id: runCodeMouseArea anchors.fill: parent hoverEnabled: true onEntered: runCode.scale = 1.1 onClicked: { Activity.runCode() } onExited: runCode.scale = 1 } } } Component { id: instructionHeaderComponent Rectangle { id: headerRect width: ListView.view.width height: 40 * ApplicationInfo.ratio color: "#005B9A" opacity: 1 Image { source: "qrc:/gcompris/src/core/resource/button.svg" sourceSize { height: parent.height; width: parent.width } width: sourceSize.width height: sourceSize.height smooth: false } GCText { id: headerText anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignHCenter width: parent.width fontSizeMode: Font.DemiBold minimumPointSize: 7 fontSize: mediumSize wrapMode: Text.WordWrap color: "white" text: qsTr("Choose the instructions") } } } Component { id: answerHeaderComponent Rectangle { id: answerHeaderRect width: ListView.view.width height: 40 * ApplicationInfo.ratio color: "#005B9A" opacity: 1 Image { source: "qrc:/gcompris/src/core/resource/button.svg" sourceSize { height: parent.height; width: parent.width } width: sourceSize.width height: sourceSize.height smooth: false } GCText { id: answerHeaderText anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignHCenter width: parent.width fontSizeMode: Font.DemiBold minimumPointSize: 7 fontSize: mediumSize wrapMode: Text.WordWrap color: "white" text: qsTr("Your Code") } } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level | reload } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.initLevel() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/activities/programmingMaze/programmingMaze.js b/src/activities/programmingMaze/programmingMaze.js index b80e95400..a80a19e62 100644 --- a/src/activities/programmingMaze/programmingMaze.js +++ b/src/activities/programmingMaze/programmingMaze.js @@ -1,183 +1,224 @@ /* GCompris - programmingMaze.js * * Copyright (C) 2014 * * Authors: * "Siddhesh Suthar" (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 var currentLevel = 0 var numberOfLevel = 4 var items var reverseCountUrl = "qrc:/gcompris/src/activities/reversecount/resource/" var mazeBlocks = [ - [[1,2],[2,2],[3,2]], - [[1,3],[2,3],[2,2],[2,1],[3,1]], - [[1,1],[2,1],[3,1],[3,2],[3,3],[2,3],[1,3]], - [[0,3],[1,3],[1,2],[2,2],[2,1],[3,1]] + [[1,2],[2,2],[3,2]], + [[1,3],[2,3],[2,2],[2,1],[3,1]], + [[1,1],[2,1],[3,1],[3,2],[3,3],[2,3],[1,3]], + [[0,3],[1,3],[1,2],[2,2],[2,1],[3,1]] ] var countOfMazeBlocks var initialX var initialY var stepX var stepY var playerCode = [] var currentInstruction var tuxIceBlockNumber var currentBlock var nextBlock var currentX var currentY var nextX var nextY var changedX var changedY +var currentRotation var changedRotation +var flag = 0 +var tuxIsMoving = false function start(items_) { items = items_ currentLevel = 0 initLevel() } function stop() { } function initLevel() { items.bar.level = currentLevel + 1 items.mazeModel.model = mazeBlocks[currentLevel] items.answerModel.clear() countOfMazeBlocks = mazeBlocks[currentLevel].length stepX = items.background.width / 8 stepY = (items.background.height - items.background.height/8) / 8 initialX = mazeBlocks[currentLevel][0][0] * stepX initialY = mazeBlocks[currentLevel][0][1] * stepY items.player.x = initialX items.player.y = initialY items.fish.x = mazeBlocks[currentLevel][countOfMazeBlocks -1][0] * stepX items.fish.y = mazeBlocks[currentLevel][countOfMazeBlocks -1][1] * stepY tuxIceBlockNumber = 0 + currentRotation = -90 changedRotation = -90 + flag = 0 + tuxIsMoving = false items.player.init() } +/* 0= SOUTH +* 90= WEST +* 180 = NORTH +* 270 =EAST +*/ +function getPlayerRotation() { + // return ((items.player.rotation % 360) + 360) % 360 + return ((changedRotation % 360) + 360) % 360 + +} + function runCode() { //initiallize back to starting position and code playerCode = [] -// items.player.x = initialX -// items.player.y = initialY for(var i = 0; i < items.answerModel.count; i++) { playerCode.push(items.answerModel.get([i]).name) } for( var j = 0; j < playerCode.length; j++) { currentInstruction = playerCode[j] - + tuxIsMoving = false changedX = items.player.x changedY = items.player.y - changedRotation = items.player.rotation + currentRotation = getPlayerRotation() - if(tuxIceBlockNumber > mazeBlocks[currentLevel].length) { - console.log("can't solve, breaking out of loop") - break; - } + // see how to end it nextX nextY won't be accesible after it + // if(tuxIceBlockNumber > mazeBlocks[currentLevel].length) { + // console.log("can't solve, breaking out of loop") + // break; + // } currentBlock = tuxIceBlockNumber nextBlock = tuxIceBlockNumber + 1 currentX = mazeBlocks[currentLevel][currentBlock][0] currentY = mazeBlocks[currentLevel][currentBlock][1] nextX = mazeBlocks[currentLevel][nextBlock][0] nextY = mazeBlocks[currentLevel][nextBlock][1] - if ( currentInstruction == "Move Forward") { - - if (nextX - currentX > 0) { - changedX = currentX * stepX + stepX -// console.log("have to go left "+items.player.x + "changed X "+ changedY) - } - else if(nextX - currentX < 0){ - changedX = currentX * stepX - stepX -// console.log("have to go right "+items.player.x + "changed X "+ changedY) - } - - else if (nextY - currentY < 0) { - changedY = currentY * stepY - stepY -// console.log("have to go up "+items.player.y + "changed Y "+ changedY) - } - else if (nextY - currentY > 0 ) { - changedY = currentY * stepY + stepY -// console.log("have to go down "+items.player.y + "changed Y "+changedY) - } - else { - // add an animation to indicate that its not possible -// console.log("dead end") - } - - ++tuxIceBlockNumber; + if(flag == 1) { + tuxIsMoving = false + break } - if ( currentInstruction == "Turn Left") { - changedRotation = -90 - items.player.rotation = items.player.rotation + changedRotation -// items.player.rotation -= 90 - } - if ( currentInstruction == "Turn Right") { - changedRotation = +90 - items.player.rotation = items.player.rotation + changedRotation - } + // tuxIsMoving = false + executeNextInstruction() + + checkSuccess() + } -// console.log("changed rotation "+changedRotation) - items.player.x = changedX - items.player.y = changedY +} + +function playerRunningChanged() { - if(changedX === items.fish.x && changedY === items.fish.y){ - items.bonus.good("smiley") + //TODO: if its moving keep moving don't go to next instruction + // if(tuxIsMoving) { + // executeNextInstruction() + // } +} + +function executeNextInstruction() { + + if ( currentInstruction == "Move Forward") { + if (nextX - currentX > 0 && currentRotation == 270) { //EAST 270 + // console.log("moving forward") + changedX = currentX * stepX + stepX + items.player.x = changedX + items.player.y = changedY + } + else if(nextX - currentX < 0 && currentRotation == 90){ //WEST 90 + changedX = currentX * stepX - stepX + items.player.x = changedX + items.player.y = changedY + } + else if (nextY - currentY < 0 && currentRotation == 180) { //NORTH 0 + // console.log("moving up") + changedY = currentY * stepY - stepY + items.player.x = changedX + items.player.y = changedY + } + else if (nextY - currentY > 0 && currentRotation == 0) { //SOUTH 180 + changedY = currentY * stepY + stepY + items.player.x = changedX + items.player.y = changedY + } + else { + // add an animation to indicate that its not possible + flag = 1 + items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/brick.wav") + console.log("dead end") } + ++tuxIceBlockNumber; } + else if ( currentInstruction == "Turn Left") { + changedRotation = (currentRotation - 90) % 360 + // console.log("turning left") + items.player.rotation = changedRotation + } + else if ( currentInstruction == "Turn Right") { + changedRotation = (currentRotation + 90) % 360 + items.player.rotation = changedRotation + } +} + +function checkSuccess() { + if(changedX === items.fish.x && changedY === items.fish.y){ + tuxIsMoving = false + items.bonus.good("smiley") + } } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); } function repositionObjectsOnWidthChanged(factor) { if(items) initLevel() } function repositionObjectsOnHeightChanged(factor) { if(items) initLevel() }