diff --git a/src/activities/tangram/Tangram.qml b/src/activities/tangram/Tangram.qml index 1eff9b5fc..d3b92d8ed 100644 --- a/src/activities/tangram/Tangram.qml +++ b/src/activities/tangram/Tangram.qml @@ -1,198 +1,302 @@ /* GCompris - tangram.qml * * Copyright (C) 2015 Bruno Coudoin * * Authors: * Yves Combe / Philippe Banwarth (GTK+ version) * Bruno Coudoin (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 QtGraphicalEffects 1.0 import GCompris 1.0 import "../../core" import "tangram.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Image { id: background anchors.fill: parent signal start signal stop fillMode: Image.PreserveAspectCrop source: Activity.url + "background.svg" sourceSize.width: parent.width Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } onWidthChanged: { - for(var i=0; i < itemList.model; i++) { - itemList.itemAt(i).positionMe() + for(var i=0; i < modelList.model; i++) { + modelList.itemAt(i).positionMe() } } onHeightChanged: { - for(var i=0; i < itemList.model; i++) { - itemList.itemAt(i).positionMe() + for(var i=0; i < modelList.model; i++) { + modelList.itemAt(i).positionMe() } } // 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 itemListModel: itemList.model + property alias modelListModel: modelList.model + property alias userList: userList + property alias userListModel: userList.model property Item selected } onStart: { Activity.start(items) } onStop: { Activity.stop() } MouseArea { id: rotateArea anchors.fill: parent enabled: items.selected property double prevRotation: 0 onPositionChanged: { // Calc the angle touch / object center var rotation = Activity.getAngleOfLineBetweenTwoPoints( items.selected.x + items.selected.width / 2, items.selected.y + items.selected.height / 2, mouseX, mouseY) * (180 / Math.PI) if(prevRotation) { items.selected.rotation += rotation - prevRotation } prevRotation = rotation } onReleased: { prevRotation = 0 - // Force a modulo 5 rotation - items.selected.rotation = items.selected.rotation + (items.selected.rotation + 2.5) % 5 + // Force a modulo 45 rotation + items.selected.rotation = Math.floor((items.selected.rotation + 45 / 2) / 45) * 45 } } DropArea { id: dropableArea anchors.left: background.left anchors.bottom: background.bottom width: background.width height: background.height } Repeater { - id: itemList + id: modelList + Image { + id: tansModel + // Let the items comes from random side of the screen + x: Math.random() > 0.5 ? - width : background.width + y: Math.random() > 0.5 ? - height : background.height + mirror: modelData[1] + rotation: modelData[4] + source: Activity.url + modelData[0] + '.svg' + z: 0 + + property real xRatio: modelData[2] + property real yRatio: modelData[3] + property bool selected: false + + Component.onCompleted: { + positionMe() + } + + function positionMe() { + x = background.width * xRatio / 7 + y = background.height * yRatio / 8 + } + + Colorize { + anchors.fill: parent + source: parent + hue: 0.5 + lightness: -0.2 + saturation: 0 + } + Behavior on x { + PropertyAnimation { + duration: 2000 + easing.type: Easing.InOutQuad + } + } + Behavior on y { + PropertyAnimation { + duration: 2000 + easing.type: Easing.InOutQuad + } + } + } + } + + + GCText { + id: text + x: 100 + y: bar.y - 50 + } + + Repeater { + id: userList Image { id: tans // Let the items comes from random side of the screen x: Math.random() > 0.5 ? - width : background.width y: Math.random() > 0.5 ? - height : background.height mirror: modelData[1] - rotation: -modelData[4] + rotation: modelData[4] source: Activity.url + modelData[0] + '.svg' z: 0 property real xRatio: modelData[2] property real yRatio: modelData[3] property bool selected: false + property int animDuration: 3000 Component.onCompleted: { positionMe() } function positionMe() { x = background.width * xRatio / 7 - y = (background.height - bar.height) * yRatio / 8 + y = background.height * yRatio / 8 + } + + function positionToTans() { + return [ + x / (background.width / 7), + y / (background.height / 8) + ] + } + + function rotationToTans() { + var mod = 360 + if(modelData[0] == 'p2') + mod = 90 + else if(modelData[0] == 'p3') + mod = 180 + return rotation >= 0 ? rotation % mod : (360 + rotation) % mod + } + + function asTans() { + console.log("asTans", rotation, rotation >= 0 ? rotation : 360 + rotation) + return [modelData[0], mirror, positionToTans()[0], positionToTans()[1], + rotationToTans()] } Drag.active: dragArea.drag.active Drag.hotSpot.x : width / 2 Drag.hotSpot.y : height / 2 MouseArea { id: dragArea anchors.fill: parent drag.target: parent onPressed: { parent.z = ++Activity.globalZ if(items.selected) items.selected.selected = false items.selected = tans parent.selected = true + var win = Activity.check() + if(win) + text.text = "win" + else + text.text = "loose" + } + onDoubleClicked: parent.mirror = !parent.mirror + onReleased: { + tans.animDuration = 30 + parent.Drag.drop() + var closest = Activity.getClosest(positionToTans()) + if(closest) { + console.log('closest found', closest[0], closest[1]) + tans.xRatio = closest[0] + tans.yRatio = closest[1] + tans.positionMe() + } } - onReleased: parent.Drag.drop() } Colorize { id: color anchors.fill: parent source: parent hue: 0.6 lightness: -0.2 saturation: 0.5 opacity: parent.selected ? 1 : 0 } Behavior on x { PropertyAnimation { - duration: 2000 + duration: tans.animDuration easing.type: Easing.InOutQuad } } Behavior on y { PropertyAnimation { - duration: 2000 + duration: tans.animDuration easing.type: Easing.InOutQuad } } } + + // Return the tans model of all the user tans + function asTans() { + var tans = [] + for(var i = 0; i < userList.count; i++) { + tans.push(userList.itemAt(i).asTans()) + } + return tans + } } 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) } } } diff --git a/src/activities/tangram/tangram.js b/src/activities/tangram/tangram.js index 4be30a28f..2437b90a4 100644 --- a/src/activities/tangram/tangram.js +++ b/src/activities/tangram/tangram.js @@ -1,98 +1,171 @@ /* GCompris - tangram.js * * Copyright (C) 2015 YOUR NAME * * Authors: * (GTK+ version) * "YOUR NAME" (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 url = "qrc:/gcompris/src/activities/tangram/resource/" var dataset = [ [ - ['p3', 1, 1.555033, 3.667909, 225], + ['p2', 0, 1.0, 1.0, 0], + ['p4', 0, 2.0, 1.0, 0], + ['p1', 0, 3.0, 1.0, 0], + ['p3', 0, 4.0, 1.0, 0], + ['p4', 0, 1.0, 2.0, 0], + ['p0', 0, 2.0, 2.0, 0], + ['p0', 0, 3.0, 2.0, 0] + ], + [ + ['p3', 1, 1.555033, 3.667909, 45], ['p2', 0, 3.055033, 4.667909, 0], ['p4', 0, 2.221700, 4.501242, 270], ['p4', 0, 3.888367, 4.834575, 90], ['p0', 0, 3.083629, 2.753695, 45], ['p0', 0, 1.221700, 5.834575, 0], ['p1', 0, 5.221700, 5.167909, 45] ], [ ['p2', 0, 3.450292, 1.017544, 45], - ['p4', 0, 3.450292, 2.196055, 315], - ['p1', 0, 3.450292, 3.098424, 315], + ['p4', 0, 3.450292, 2.196055, 45], + ['p1', 0, 3.450292, 3.098424, 45], ['p3', 0, 3.096739, 5.199524, 90], - ['p4', 0, 4.157399, 5.081673, 135], - ['p0', 0, 3.450292, 6.495887, 315], - ['p0', 0, 3.450292, 4.374566, 315] + ['p4', 0, 4.157399, 5.081673, 45], + ['p0', 0, 3.450292, 6.495887, 45], + ['p0', 0, 3.450292, 4.374566, 45] ] ] +var defaultTan = [ + ['p2', 0, 1.0, 1.0, 0], + ['p4', 0, 2.0, 1.0, 0], + ['p1', 0, 3.0, 1.0, 0], + ['p3', 0, 4.0, 1.0, 0], + ['p4', 0, 1.0, 2.0, 0], + ['p0', 0, 2.0, 2.0, 0], + ['p0', 0, 3.0, 2.0, 0] + ] + +var tan // The current user tangran positions var currentLevel = 0 var numberOfLevel = dataset.length var items // We keep a globalZ across all items. It is increased on each // item selection to put it on top var globalZ = 0 function start(items_) { items = items_ currentLevel = 0 initLevel() } function stop() { } function initLevel() { globalZ = 0 items.bar.level = currentLevel + 1 - items.itemListModel = dataset[items.bar.level - 1] + items.modelListModel = dataset[items.bar.level - 1] + items.userListModel = [] + items.userListModel = defaultTan.slice(); } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } // Determines the angle of a straight line drawn between point one and two. // The number returned, which is a float in radian, // tells us how much we have to rotate a horizontal line clockwise // for it to match the line between the two points. function getAngleOfLineBetweenTwoPoints(x1, y1, x2, y2) { var xDiff = x2 - x1; var yDiff = y2 - y1; return Math.atan2(yDiff, xDiff); } + +function getDistance(ix, iy, jx, jy) { + return Math.sqrt(Math.pow((ix - jx), 2) + Math.pow((iy - jy), 2)) +} + +function dumpTans(tans) { + for(var i = 0; i < tans.length; i++) { + console.log(tans[i][0], tans[i][1], tans[i][2], tans[i][3], tans[i][4]) + } +} + +function getClosest(point) { + console.log("getClosest", point) + var nbpiece = dataset[items.bar.level - 1].length + for(var i = 0; i < nbpiece; i++) { + var p1 = dataset[items.bar.level - 1][i] + if(getDistance(p1[2], p1[3], point[0], point[1]) < 0.2) + return [p1[2], p1[3]] + } + return +} + +function check() { + console.log(("===== check ======")) + var nbpiece = dataset[items.bar.level - 1].length + var userTans = items.userList.asTans() + dumpTans(userTans) + for(var i = 0; i < nbpiece; i++) { + var p1 = dataset[items.bar.level - 1][i] + var ok = false + for(var j = 0; j < nbpiece; j++) { + var p2 = userTans[j] + // Check type distance and rotation are close enough + if(p1[0] === p2[0]) + if(p1[0] === p2[0] && // Type + p1[1] == p2[1] && // Flipping + getDistance(p1[2], p1[3], p2[2], p2[3]) < 0.2 && // X, Y + p1[4] === p2[4] /* Rotation */ ) { + ok = true + } + if(p1[0] === p2[0]) + if(ok) + console.log("distance ", p1[0], getDistance(p1[2], p1[3], p2[2], p2[3]), "OK") + else + console.log("distance ", p1[0], getDistance(p1[2], p1[3], p2[2], p2[3]), "NOK") + } + if(!ok) + return false + } + return true +}