diff --git a/src/activities/programmingMaze/ActivityInfo.qml b/src/activities/programmingMaze/ActivityInfo.qml index c7e58c034..d2bdbd520 100644 --- a/src/activities/programmingMaze/ActivityInfo.qml +++ b/src/activities/programmingMaze/ActivityInfo.qml @@ -1,53 +1,59 @@ /* GCompris - ActivityInfo.qml * * Copyright (C) 2015 Siddhesh Suthar * Copyright (C) 2018 Aman Kumar Gupta * * 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 GCompris 1.0 ActivityInfo { name: "programmingMaze/ProgrammingMaze.qml" difficulty: 3 icon: "programmingMaze/programmingMaze.svg" - author: "Siddhesh Suthar <siddhesh.it@gmail.com>" + author: "Aman Kumar Gupta <gupta2140@gmail.com>" demo: false + //: Activity title title: qsTr("Programming Maze") + //: Help title description: qsTr("This activity teaches the kid to program the Tux to its goal using simple instructions like move forward, turn left etc") + // intro: "Arrange the instructions and traverse the correct path to reach the fish." + //: Help goal goal: qsTr("Tux is hungry. Help him find fish by programming him to the correct ice spot.") + //: Help prerequisite prerequisite: qsTr("Can read instructions. Thinking of the path logically") + //: Help manual manual: qsTr("Choose the instructions from given menu. Arrange the instruction in an order so that they can make the tux reach to its goal.

") + qsTr("Keyboard Controls:

") + qsTr("1. To navigate through instructions in the current code area having keyboard focus:") + qsTr("
  • Arrow keys

") + qsTr("2. To append an instruction from instruction area to the main/procedure code area:") + qsTr("
  • Select an instruction from the instruction area by pressing SPACE.
  • ") + qsTr("
  • Navigate to the code areas by pressing TAB, then press SPACE to append the instruction.

") + qsTr("3. To add an instruction at any particular position in the main/procedure code area:") + qsTr("
  • Navigate to the instruction at that position and press SPACE to add the selected instruction from the instruction area.

") + qsTr("4. To delete the current navigated instruction in the main/procedure code area:") + qsTr("
  • DELETE.

") + qsTr("5. To edit an instruction in the main/procedure code area:") + qsTr("
  • Navigate to the instruction to edit using Arrow keys.
  • ") + qsTr("
  • Press SPACE to select it.
  • ") + qsTr("
  • Then navigate to the instruction area using TAB and select the new instruction by pressing SPACE.

") + qsTr("6. To run the code or reset Tux when it fails to reach the fish:") + qsTr("
  • ENTER or RETURN.
") credit: "" section: "fun" createdInVersion: 9500 } diff --git a/src/activities/programmingMaze/CMakeLists.txt b/src/activities/programmingMaze/CMakeLists.txt index 4d9a1dad5..6ab9f7d21 100644 --- a/src/activities/programmingMaze/CMakeLists.txt +++ b/src/activities/programmingMaze/CMakeLists.txt @@ -1 +1 @@ -GCOMPRIS_ADD_RCC(activities/programmingMaze *.qml *.svg *.js resource/* instructions/*) +GCOMPRIS_ADD_RCC(activities/programmingMaze *.qml *.svg *.js resource/*) diff --git a/src/activities/programmingMaze/ProgrammingMaze.qml b/src/activities/programmingMaze/ProgrammingMaze.qml index 0e80f3293..0c401e2c7 100644 --- a/src/activities/programmingMaze/ProgrammingMaze.qml +++ b/src/activities/programmingMaze/ProgrammingMaze.qml @@ -1,410 +1,410 @@ /* GCompris - ProgrammingMaze.qml * * Copyright (C) 2015 Siddhesh Suthar * Copyright (C) 2018 Aman Kumar Gupta * * Authors: * Siddhesh Suthar * Aman Kumar Gupta * * 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.6 import GCompris 1.0 import "../../core" import "programmingMaze.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} property int oldWidth: width onWidthChanged: { Activity.repositionObjectsOnWidthChanged(width / oldWidth) oldWidth = width } property int oldHeight: height onHeightChanged: { Activity.repositionObjectsOnHeightChanged(height / oldHeight) oldHeight = height } property bool keyboardNavigationVisible: false property string mode: "basic" property string datasetUrl: "qrc:/gcompris/src/activities/programmingMaze/Dataset.qml" pageComponent: Image { id: background source: "qrc:/gcompris/src/activities/programmingMaze/resource/background.svg" fillMode: Image.PreserveAspectCrop sourceSize.width: parent.width signal start signal stop property bool insertIntoMain: true property alias items: items property int buttonWidth: background.width / 10 property int buttonHeight: background.height / 15.3 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 mainFunctionModel: mainFunctionModel property alias mainFunctionCodeArea: mainFunctionCodeArea property alias procedureModel: procedureModel property alias procedureCodeArea: procedureCodeArea property alias instructionArea: instructionArea property alias player: player property alias constraintInstruction: constraintInstruction property alias tutorialImage: tutorialImage property alias fish: fish property alias dataset: dataset property bool isRunCodeEnabled: true property bool isTuxMouseAreaEnabled: false property bool currentLevelContainsProcedure property int maxNumberOfInstructionsAllowed property int numberOfInstructionsAdded } // This function catches the signal emitted after completion of movement of Tux after executing each instruction. function checkSuccessAndExecuteNextInstruction() { Activity.checkSuccessAndExecuteNextInstruction() } // This function catches the signal emitted after finding a dead-end in any of the executing instruction. function deadEnd() { Activity.deadEnd() } Loader { id: dataset } onStart: { Activity.start(items, mode, datasetUrl) } onStop: { Activity.stop() } property var areaWithKeyboardInput: instructionArea onAreaWithKeyboardInputChanged: activeCodeAreaIndicator.changeActiveCodeAreaIndicator(areaWithKeyboardInput) Keys.enabled: items.isTuxMouseAreaEnabled || items.isRunCodeEnabled Keys.onPressed: { activity.keyboardNavigationVisible = true if(event.key === Qt.Key_Left) areaWithKeyboardInput.moveCurrentIndexLeft() if(event.key === Qt.Key_Right) areaWithKeyboardInput.moveCurrentIndexRight() if(event.key === Qt.Key_Up) areaWithKeyboardInput.moveCurrentIndexUp() if(event.key === Qt.Key_Down) areaWithKeyboardInput.moveCurrentIndexDown() if(event.key === Qt.Key_Space) areaWithKeyboardInput.spaceKeyPressed() if(event.key === Qt.Key_Enter || event.key === Qt.Key_Return) runCodeOrResetTux() if(event.key === Qt.Key_Tab) areaWithKeyboardInput.tabKeyPressed() if(event.key === Qt.Key_Delete && activeCodeAreaIndicator.top != instructionArea.top) { areaWithKeyboardInput.deleteKeyPressed() } } function runCodeOrResetTux() { if(!Activity.deadEndPoint) runCodeMouseArea.executeCode() else Activity.initLevel() } ListModel { id: instructionModel } ListModel { id: mainFunctionModel } ListModel { id: procedureModel } Rectangle { id: constraintInstruction anchors.left: parent.left anchors.bottom: runCode.top width: parent.width / 2.3 height: parent.height / 8.9 radius: 10 z: 3 color: "#E8E8E8" //paper white border.width: 3 * ApplicationInfo.ratio border.color: "#87A6DD" //light blue Behavior on opacity { PropertyAnimation { duration: 200 } } function changeConstraintInstructionOpacity() { if(opacity) constraintInstruction.hide() else constraintInstruction.show() } function show() { if(instructionText.text) opacity = 0.8 } function hide() { opacity = 0 } GCText { id: instructionText anchors.fill: parent anchors.margins: parent.border.width horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter fontSizeMode: Text.Fit wrapMode: Text.WordWrap readonly property string resetTuxInstructionText: qsTr("Click on Tux or press Enter key to reset it or RELOAD button to reload the level.") - readonly property string constraintInstructionText: qsTr("Reach the fish in less than %1 instructions.").arg(items.maxNumberOfInstructionsAllowed) + readonly property string constraintInstructionText: qsTr("Reach the fish in less than %1 instructions.").arg(items.maxNumberOfInstructionsAllowed + 1) text: items.isTuxMouseAreaEnabled ? resetTuxInstructionText : constraintInstructionText } } MouseArea { anchors.fill: parent onClicked: constraintInstruction.changeConstraintInstructionOpacity() } Repeater { id: mazeModel anchors.left: parent.left anchors.top: parent.top Image { x: modelData.x * width y: modelData.y * height width: background.width / 10 height: (background.height - background.height / 10) / 10 source: Activity.reverseCountUrl + "iceblock.svg" } } Image { id: fish sourceSize.width: background.width / 12 source: Activity.reverseCountUrl + "blue-fish.svg" } Image { id: player source: "qrc:/gcompris/src/activities/maze/resource/tux_top_south.svg" sourceSize.width: background.width / 12 z: 1 property int duration: 1000 readonly property real playerCenterX: x + width / 2 readonly property real playerCenterY: y + height / 2 MouseArea { id: tuxMouseArea anchors.fill: parent enabled: items.isTuxMouseAreaEnabled onClicked: { Activity.initLevel() } } } Rectangle { id: activeCodeAreaIndicator opacity: 0.5 visible: activity.keyboardNavigationVisible function changeActiveCodeAreaIndicator(activeArea) { anchors.top = activeArea.top anchors.fill = activeArea } } InstructionArea { id: instructionArea } HeaderArea { id: mainFunctionHeader headerText: qsTr("Main") headerOpacity: background.insertIntoMain ? 1 : 0.5 onClicked: background.insertIntoMain = true anchors.top: parent.top anchors.right: parent.right } CodeArea { id: mainFunctionCodeArea currentModel: mainFunctionModel anchors.right: parent.right anchors.top: mainFunctionHeader.bottom onTabKeyPressed: { mainFunctionCodeArea.currentIndex = -1 if(!items.currentLevelContainsProcedure) { background.areaWithKeyboardInput = instructionArea instructionArea.currentIndex = 0 } else { background.areaWithKeyboardInput = procedureCodeArea background.insertIntoMain = false } } } HeaderArea { id: procedureHeader headerText: qsTr("Procedure") headerOpacity: !background.insertIntoMain ? 1 : 0.5 visible: procedureCodeArea.visible onClicked: background.insertIntoMain = false anchors.top: mainFunctionCodeArea.bottom anchors.right: parent.right } CodeArea { id: procedureCodeArea currentModel: procedureModel anchors.right: parent.right anchors.top: procedureHeader.bottom visible: items.currentLevelContainsProcedure property alias procedureIterator: procedureCodeArea.currentIndex onTabKeyPressed: { procedureCodeArea.currentIndex = -1 background.areaWithKeyboardInput = instructionArea instructionArea.currentIndex = 0 background.insertIntoMain = true } } Image { id: runCode width: background.width / 10 height: background.height / 10 anchors.right: instructionArea.right anchors.bottom: bar.top anchors.margins: 10 * ApplicationInfo.ratio source:"qrc:/gcompris/src/core/resource/bar_ok.svg" fillMode: Image.PreserveAspectFit MouseArea { id: runCodeMouseArea anchors.fill: parent hoverEnabled: ApplicationInfo.isMobile ? false : (!items.isRunCodeEnabled ? false : true) enabled: items.isRunCodeEnabled signal executeCode onEntered: runCode.scale = 1.1 onExecuteCode: { if(mainFunctionModel.count) startCodeExecution() } onClicked: executeCode() onExited: runCode.scale = 1 function startCodeExecution() { runCodeClickAnimation.start() Activity.resetCodeAreasIndices() if(constraintInstruction.opacity) constraintInstruction.hide() Activity.runCode() } } SequentialAnimation { id: runCodeClickAnimation NumberAnimation { target: runCode; property: "scale"; to: 0.8; duration: 100 } NumberAnimation { target: runCode; property: "scale"; to: 1.0; duration: 100 } } } Image { id: tutorialImage source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg" anchors.fill: parent z: 5 visible: true property bool shownProcedureTutorialInstructions: false Tutorial { id:tutorialSection tutorialDetails: bar.level <= 2 ? Activity.mainTutorialInstructions : Activity.procedureTutorialInstructions onSkipPressed: { Activity.initLevel() tutorialImage.visible = false tutorialNumber = 0 } } onVisibleChanged: { if(tutorialImage.visible && tutorialImage.shownProcedureTutorialInstructions) tutorialSection.visible = true } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: tutorialImage.visible ? help | home : help | home | level | reload } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.reloadLevel() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/activities/programmingMaze/programmingMaze.js b/src/activities/programmingMaze/programmingMaze.js index 7bc6a9cae..3bd69fec4 100644 --- a/src/activities/programmingMaze/programmingMaze.js +++ b/src/activities/programmingMaze/programmingMaze.js @@ -1,358 +1,358 @@ /* GCompris - programmingMaze.js * * Copyright (C) 2015 Siddhesh Suthar * Copyright (C) 2018 Aman Kumar Gupta * * Authors: * Siddhesh Suthar * Aman Kumar Gupta * * 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.6 as Quick .import GCompris 1.0 as GCompris //for ApplicationInfo // possible instructions var MOVE_FORWARD = "move-forward" var TURN_LEFT = "turn-left" var TURN_RIGHT = "turn-right" var CALL_PROCEDURE = "call-procedure" var mazeBlocks // Length of 1 step along x-axis var stepX // Length of 1 step along y-axis var stepY /** * Lookup tables of instruction objects for main and procedure areas which will be stored here on creation and can be * accessed when required to execute. */ var mainInstructionObjects = [] var procedureInstructionObjects = [] // New rotation of Tux on turning. var changedRotation // Indicates if there is a dead-end var deadEndPoint = false // Stores the index of mainInstructionObjects[] which is going to be processed var codeIterator = 0 /** * Stores if the reset is done only when Tux is clicked. * * If resetTux is true, initLevel() is called and the instruction areas are not cleared. * * Else, it means that initLevel() is called to reset the entire level and the instruction areas are cleared as well. */ var resetTux = false // Duration of movement of highlight in the execution area. var moveAnimDuration //Stores the currrent instruction which is going to be processed var currentInstruction var url = "qrc:/gcompris/src/activities/programmingMaze/resource/" var reverseCountUrl = "qrc:/gcompris/src/activities/reversecount/resource/" var currentLevel = 0 var numberOfLevel var items var NORTH = 0 var WEST = 90 var SOUTH = 180 var EAST = 270 /** * Stores the qml file components of all the instructions used in the activity. * * To add a new instruction, add its component here and add the instruction name in "instructionList" inside createInstructionObjects() along with the other instructions. */ var instructionComponents = { - "move-forward": Qt.createComponent("qrc:/gcompris/src/activities/programmingMaze/instructions/MoveForward.qml"), - "turn-left": Qt.createComponent("qrc:/gcompris/src/activities/programmingMaze/instructions/TurnLeftOrRight.qml"), - "turn-right": Qt.createComponent("qrc:/gcompris/src/activities/programmingMaze/instructions/TurnLeftOrRight.qml"), - "call-procedure": Qt.createComponent("qrc:/gcompris/src/activities/programmingMaze/instructions/Procedure.qml") + "move-forward": Qt.createComponent(url + "instructions/MoveForward.qml"), + "turn-left": Qt.createComponent(url + "instructions/TurnLeftOrRight.qml"), + "turn-right": Qt.createComponent(url + "instructions/TurnLeftOrRight.qml"), + "call-procedure": Qt.createComponent(url + "instructions/Procedure.qml") } var mainTutorialInstructions = [ { "instruction": qsTr("Instruction Area:" + "There are 3 instructions which you have to use to code and make Tux reach the fish:" + "
  • 1. Move forward: Moves Tux one step forward in the direction it is facing.
  • " + "
  • 2. Turn left: Turns Tux in the left direction from where it is facing.
  • " + "
  • 3. Turn right: Turns Tux in the right direction from where it is facing.
  • "), "instructionImage": "qrc:/gcompris/src/activities/programmingMaze/resource/tutorial1.png" }, { "instruction": qsTr("Main Function:" + "
  • -The execution of code starts here on running.
  • " + "
  • -Click on any instruction in the instruction area to add them to the Main Function
  • " + "
  • -The instructions will execute in order until there's none left, dead-end or Tux reaches the fish.
  • "), "instructionImage": "qrc:/gcompris/src/activities/programmingMaze/resource/tutorial2.png" }, ] var procedureTutorialInstructions = [ { "instruction": qsTr("Procedure:" + "
  • -Procedure is a reusable set of instructions which can be used in a code by calling it where needed.
  • " + "
  • -To switch between the Procedure area and Main Function area to add your code, click on the label Procedure or Main Function.
  • "), "instructionImage": "qrc:/gcompris/src/activities/programmingMaze/resource/tutorial3.png" }, ] // Mode of the activity: basic or loop var activityMode function start(items_, mode_, datasetUrl_) { items = items_ items.dataset.source = datasetUrl_ activityMode = mode_ currentLevel = 0 mazeBlocks = items.dataset.item.levels numberOfLevel = mazeBlocks.length resetTux = false initLevel() } function stop() { destroyInstructionObjects() } /** * This function creates and populate instruction objects for main as well as procedure area. * * These are stored in the lookup table, provided in the parameter as "instructionObjects". * The instructions are then connected to the slots of their code area (main or procedure), provided as "instructionCodeArea" in the parameter. * * The instructions can now be obtained from the look-up tables and executed when called. * * This saves the process of re-creating all the instruction objets, connecting them to their parent's slot and destroying * them everytime for each instruction call which will be very redundant and quite memory consuming on devices with * less RAM, weak processing power and slow performance specially for "loops" mode. * * Hence these look-up table objects will be created and destroyed only once in each level (depending on the need) and can be accessed when needed. */ function createInstructionObjects(instructionObjects, instructionCodeArea) { var instructionList = [MOVE_FORWARD, TURN_LEFT, TURN_RIGHT] for(var i = 0; i < instructionList.length; i++) createInstruction(instructionObjects, instructionList[i], instructionCodeArea) } function createInstruction(instructionObjects, instructionName, instructionCodeArea) { if(instructionName == TURN_LEFT || instructionName == TURN_RIGHT) instructionObjects[instructionName] = instructionComponents[instructionName].createObject(instructionCodeArea, { "turnDirection": instructionName }) else instructionObjects[instructionName] = instructionComponents[instructionName].createObject(instructionCodeArea) instructionObjects[instructionName].foundDeadEnd.connect(instructionCodeArea.deadEnd) instructionObjects[instructionName].executionComplete.connect(instructionCodeArea.checkSuccessAndExecuteNextInstruction) } // Destroy instruction objects from the look-up tables function destroyInstructionObjects() { var instructionList = Object.keys(mainInstructionObjects) for(var i = 0; i < instructionList.length; i++) mainInstructionObjects[instructionList[i]].destroy() instructionList = Object.keys(procedureInstructionObjects) for(var i = 0; i < instructionList.length; i++) procedureInstructionObjects[instructionList[i]].destroy() mainInstructionObjects = [] procedureInstructionObjects = [] } function initLevel() { if(!items || !items.bar) return items.bar.level = currentLevel + 1 destroyInstructionObjects() var levelInstructions = mazeBlocks[currentLevel].instructions if(levelInstructions.indexOf(CALL_PROCEDURE) != -1) items.currentLevelContainsProcedure = true else items.currentLevelContainsProcedure = false // Create, populate and connect signals of instructions for main function code area and store them in mainInstructionObjects. createInstructionObjects(mainInstructionObjects, items.background) if(items.currentLevelContainsProcedure) { if(!items.tutorialImage.shownProcedureTutorialInstructions) { items.tutorialImage.shownProcedureTutorialInstructions = true items.tutorialImage.visible = true } // Create procedure object in the main look-up table ,if the level has procedure/loop, to execute it for procedure/loop calls from the main code area. createInstruction(mainInstructionObjects, CALL_PROCEDURE, items.background) // Create, populate and connect signals of instructions for procedure code area if the level has procedure/loop. createInstructionObjects(procedureInstructionObjects, mainInstructionObjects[CALL_PROCEDURE]) } // Stores the co-ordinates of the tile blocks in the current level var currentLevelBlocksCoordinates = mazeBlocks[currentLevel].map items.mazeModel.model = currentLevelBlocksCoordinates if(!resetTux) { items.mainFunctionModel.clear() items.procedureModel.clear() items.numberOfInstructionsAdded = 0 } stepX = items.mazeModel.itemAt(0).width stepY = items.mazeModel.itemAt(0).height items.instructionModel.clear() for (var i = 0; i < levelInstructions.length; i++) items.instructionModel.append({"name":levelInstructions[i]}) // Center Tux in its first case items.player.x = currentLevelBlocksCoordinates[0].x * stepX + (stepX - items.player.width) / 2 items.player.y = currentLevelBlocksCoordinates[0].y * stepY + (stepY - items.player.height) / 2 items.player.rotation = EAST // Center fish at it's co-ordinate items.fish.x = mazeBlocks[currentLevel].fish.x * stepX + (stepX - items.fish.width) / 2 items.fish.y = mazeBlocks[currentLevel].fish.y * stepY + (stepY - items.fish.height) / 2 changedRotation = EAST deadEndPoint = false moveAnimDuration = 1000 items.background.insertIntoMain = true items.mainFunctionCodeArea.highlightMoveDuration = moveAnimDuration / 2 items.procedureCodeArea.highlightMoveDuration = moveAnimDuration / 2 items.isTuxMouseAreaEnabled = false items.isRunCodeEnabled = true items.maxNumberOfInstructionsAllowed = mazeBlocks[currentLevel].maxNumberOfInstructions items.constraintInstruction.show() items.mainFunctionCodeArea.resetEditingValues() items.procedureCodeArea.resetEditingValues() items.background.areaWithKeyboardInput = items.instructionArea resetCodeAreasIndices() resetTux = false codeIterator = 0 } function resetCodeAreasIndices() { items.instructionArea.currentIndex = -1 items.mainFunctionCodeArea.currentIndex = -1 items.procedureCodeArea.currentIndex = -1 items.instructionArea.instructionToInsert = '' } function getPlayerRotation() { return ((changedRotation % 360) + 360) % 360 } function runCode() { items.mainFunctionCodeArea.resetEditingValues() items.procedureCodeArea.resetEditingValues() var instructionName // Append all the procedure instructions to the procedure area object. for(var j = 0; j < items.procedureModel.count; j++) { instructionName = items.procedureModel.get(j).name mainInstructionObjects[CALL_PROCEDURE].procedureCode.append({ "name" : instructionName }) } items.isRunCodeEnabled = false if(items.mainFunctionModel.count > 0) executeNextInstruction() else deadEnd() } function executeNextInstruction() { if((codeIterator < items.mainFunctionModel.count) && !deadEndPoint) { items.mainFunctionCodeArea.currentIndex += 1 var instructionToExecute = items.mainFunctionModel.get(codeIterator).name mainInstructionObjects[instructionToExecute].checkAndExecuteMovement() } } function deadEnd() { deadEndPoint = true resetTux = true items.isTuxMouseAreaEnabled = true items.constraintInstruction.show() items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/brick.wav") items.bonus.bad("tux") } function checkSuccessAndExecuteNextInstruction() { var fishX = mazeBlocks[currentLevel].fish.x var fishY = mazeBlocks[currentLevel].fish.y var tuxX = Math.floor(items.player.playerCenterX / stepX) var tuxY = Math.floor(items.player.playerCenterY / stepY) if(tuxX === fishX && tuxY === fishY) { codeIterator = 0 items.bonus.good("tux") } else if(codeIterator === (items.mainFunctionModel.count - 1)) { deadEnd() } else { codeIterator++ executeNextInstruction() } } function nextLevel() { resetTux = false if(numberOfLevel <= ++currentLevel) { currentLevel = 0 } initLevel(); } function previousLevel() { resetTux = false if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); } function repositionObjectsOnWidthChanged(factor) { resetTux = true if(items) initLevel() } function repositionObjectsOnHeightChanged(factor) { resetTux = true if(items) initLevel() } function reloadLevel() { resetTux = false initLevel() } diff --git a/src/activities/programmingMaze/instructions/Instruction.qml b/src/activities/programmingMaze/resource/instructions/Instruction.qml similarity index 97% rename from src/activities/programmingMaze/instructions/Instruction.qml rename to src/activities/programmingMaze/resource/instructions/Instruction.qml index b1167345d..16063a07e 100644 --- a/src/activities/programmingMaze/instructions/Instruction.qml +++ b/src/activities/programmingMaze/resource/instructions/Instruction.qml @@ -1,51 +1,51 @@ /* GCompris - Instruction.qml * * Copyright (C) 2018 Aman Kumar Gupta * * Author: * Aman Kumar Gupta * * 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.6 import GCompris 1.0 -import "../programmingMaze.js" as Activity +import "../../programmingMaze.js" as Activity Item { id: instruction //stores the movement animation duration of Tux when an instruction is executed. property real movementAnimationDuration /** * This signal is emitted after the execution of current instruction is complete. * * The signal will be caught by ProgrammingMaze.qml/Procedure.qml depending on with whom the connection is made, * and it will check if Tux has reached the fish(level is complete) or will execute the next instruction. */ signal executionComplete /** * This signal is emitted if Tux cannot move according to the current executed instruction. * * It will be caught by deadEnd() in its parent file. */ signal foundDeadEnd function setCodeAreaHighlightMoveDuration() { Activity.items.mainFunctionCodeArea.highlightMoveDuration = movementAnimationDuration Activity.items.procedureCodeArea.highlightMoveDuration = movementAnimationDuration } } diff --git a/src/activities/programmingMaze/instructions/MoveForward.qml b/src/activities/programmingMaze/resource/instructions/MoveForward.qml similarity index 98% rename from src/activities/programmingMaze/instructions/MoveForward.qml rename to src/activities/programmingMaze/resource/instructions/MoveForward.qml index 4cd166aa9..4c797ebe4 100644 --- a/src/activities/programmingMaze/instructions/MoveForward.qml +++ b/src/activities/programmingMaze/resource/instructions/MoveForward.qml @@ -1,104 +1,104 @@ /* GCompris - MoveForward.qml * * Copyright (C) 2018 Aman Kumar Gupta * * Author: * Aman Kumar Gupta * * 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.6 import GCompris 1.0 -import "../programmingMaze.js" as Activity +import "../../programmingMaze.js" as Activity Instruction { id: moveForward movementAnimationDuration: 1000 property double playerXCoordinate: 0 property double playerYCoordinate: 0 //If there has been an x-axis movement, x co-ordinate will be animated without any effect on y-axis movement and same vice-versa. ParallelAnimation { id: movementAnimation SmoothedAnimation { target: Activity.items.player property: 'x' to: playerXCoordinate duration: moveForward.movementAnimationDuration reversingMode: SmoothedAnimation.Immediate } SmoothedAnimation { target: Activity.items.player property: 'y' to: playerYCoordinate duration: moveForward.movementAnimationDuration reversingMode: SmoothedAnimation.Immediate } onStopped: executionComplete() } function nextPositionExists(playerCenterX, playerCenterY) { var playerNextPositionX = Math.floor(playerCenterX / Activity.stepX) var playerNextPositionY = Math.floor(playerCenterY / Activity.stepY) var currentLevelCoordinates = Activity.mazeBlocks[Activity.currentLevel].map for(var i = 0; i < currentLevelCoordinates.length; i++) { if(currentLevelCoordinates[i].x == playerNextPositionX && currentLevelCoordinates[i].y == playerNextPositionY) return true } return false } //Function to check if the current movement is possible or not and then process the instruction accordingly function checkAndExecuteMovement() { var currentRotation = Activity.getPlayerRotation() var playerCenterX = Activity.items.player.playerCenterX var playerCenterY = Activity.items.player.playerCenterY var nextTileExists = false moveForward.playerXCoordinate = Activity.items.player.x moveForward.playerYCoordinate = Activity.items.player.y if(currentRotation === Activity.EAST) { playerCenterX += Activity.stepX moveForward.playerXCoordinate += Activity.stepX } else if(currentRotation === Activity.WEST) { playerCenterX -= Activity.stepX moveForward.playerXCoordinate -= Activity.stepX } else if(currentRotation === Activity.SOUTH) { playerCenterY -= Activity.stepY moveForward.playerYCoordinate -= Activity.stepY } else if(currentRotation === Activity.NORTH) { playerCenterY += Activity.stepY moveForward.playerYCoordinate += Activity.stepY } nextTileExists = nextPositionExists(playerCenterX, playerCenterY) setCodeAreaHighlightMoveDuration() if(nextTileExists) { movementAnimation.start() } else foundDeadEnd() } } diff --git a/src/activities/programmingMaze/instructions/Procedure.qml b/src/activities/programmingMaze/resource/instructions/Procedure.qml similarity index 98% rename from src/activities/programmingMaze/instructions/Procedure.qml rename to src/activities/programmingMaze/resource/instructions/Procedure.qml index db891c272..faad00019 100644 --- a/src/activities/programmingMaze/instructions/Procedure.qml +++ b/src/activities/programmingMaze/resource/instructions/Procedure.qml @@ -1,67 +1,67 @@ /* GCompris - Procedure.qml * * Copyright (C) 2018 Aman Kumar Gupta * * Author: * Aman Kumar Gupta * * 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.6 import GCompris 1.0 -import "../programmingMaze.js" as Activity +import "../../programmingMaze.js" as Activity Instruction { id: callProcedure property alias procedureCode: procedureCode //Stores the list of instructions to be executed in procedure code area ListModel { id: procedureCode } function checkAndExecuteMovement() { if(!Activity.deadEndPoint && parent.items.procedureCodeArea.procedureIterator < callProcedure.procedureCode.count - 1) { parent.items.procedureCodeArea.procedureIterator++ var currentInstruction = procedureCode.get(parent.items.procedureCodeArea.procedureIterator).name Activity.procedureInstructionObjects[currentInstruction].checkAndExecuteMovement() } else { parent.items.procedureCodeArea.procedureIterator = -1 executionComplete() } } function deadEnd() { foundDeadEnd() } function checkSuccessAndExecuteNextInstruction() { var fishX = Activity.mazeBlocks[Activity.currentLevel].fish.x var fishY = Activity.mazeBlocks[Activity.currentLevel].fish.y var tuxX = Math.floor(Activity.items.player.playerCenterX / Activity.stepX) var tuxY = Math.floor(Activity.items.player.playerCenterY / Activity.stepY) if(tuxX === fishX && tuxY === fishY) { Activity.codeIterator = 0 parent.items.bonus.good("tux") } else { checkAndExecuteMovement() } } } diff --git a/src/activities/programmingMaze/instructions/TurnLeftOrRight.qml b/src/activities/programmingMaze/resource/instructions/TurnLeftOrRight.qml similarity index 97% rename from src/activities/programmingMaze/instructions/TurnLeftOrRight.qml rename to src/activities/programmingMaze/resource/instructions/TurnLeftOrRight.qml index 2e8d2ba7f..781d26fe0 100644 --- a/src/activities/programmingMaze/instructions/TurnLeftOrRight.qml +++ b/src/activities/programmingMaze/resource/instructions/TurnLeftOrRight.qml @@ -1,55 +1,55 @@ /* GCompris - TurnLeftOrRight.qml * * Copyright (C) 2018 Aman Kumar Gupta * * Author: * Aman Kumar Gupta * * 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.6 import GCompris 1.0 -import "../programmingMaze.js" as Activity +import "../../programmingMaze.js" as Activity Instruction { id: turnLeftOrRight movementAnimationDuration: 500 property real finalRotation: 0 property string turnDirection RotationAnimation { id: movementAnimation target: Activity.items.player to: finalRotation duration: turnLeftOrRight.movementAnimationDuration direction: RotationAnimation.Shortest onStopped: executionComplete() } function checkAndExecuteMovement() { var currentRotation = Activity.getPlayerRotation() if(turnLeftOrRight.turnDirection === "turn-left") Activity.changedRotation = (currentRotation - 90) % 360 else Activity.changedRotation = (currentRotation + 90) % 360 setCodeAreaHighlightMoveDuration() turnLeftOrRight.finalRotation = Activity.changedRotation movementAnimation.start() } }