1
votes

I'm using this example: QML Flipable Example. I created rectangles with GridLayout. I just added my new state the example:

states: [
      State {
        name: 'back'
        PropertyChanges { target: rotation; angle: 180 }
        when: flipable.flipped
      },
      State {
        name: 'remove'
        PropertyChanges {
          target: card
          visible: false
        }
      }
    ]

I wanted when I click the rectangles, check rectangles, they open and if they are same or not. My algorithm for this job:

property int card1: -1
property int card2: -1
property int remaining: 20

function cardClicked(index) {
  var card = repeater.itemAt(index); // Selected card
  if (!card.flipped) { // If selected card is not opened
    card.flipped = true; // Open card
    if (card1 === -1) {  // If card is first selected card
      card1 = index; // Set first selected card
    } else { // If selected card is not first card, I mean that is second card because first card is already selected
      card2 = index; // Set second card
      area.enabled = false; // Disabled GridLayout (area)
      delayTimer.start(); // Start `Timer` QML component
    }
  } else { // If card is opened so, close that card, because that card is opened and player clicked its
      card.flipped = false; // Close that card
      card1 = -1; // first card is not selected
  }
}

function validateCards() {
  var state = ''; // Default state: Close cards
  if (imageIndexes[card1] === imageIndexes[card2]) { // If first card and second card are equal, you found same cards :)
    state = 'remove'; // You found cards so, remove cards
    --remaining; // If this equals 0, you found all cards
  }
  // If cards are not same, close cards but if they are same remove them
  repeater.itemAt(card1).state = state; 
  repeater.itemAt(card2).state = state;
  card1 = -1; // first card is not selected
  card2 = -1; // second card is not selected
  area.enabled = true; // Enabled area (GridLayout)
  if (remaining === 0) { // If you found all cards, game over
    console.log('Game Over!');
  }
}

I added MouseArea into Rectangles:

MouseArea {
  anchors.fill: parent
  onClicked: cardClicked(index) // This index belongs to my `Repeater`.
}

I put a Timer for animation to work correctly and check cards:

  Timer {
    id: delayTimer
    interval: 1000
    onTriggered: validateCards()
  }

This example and animations are running nice but sometimes they aren't running correctly: qml_flip_animation_bug.gif
How can I solve this animation bug?

UPDATE!
You can find all source code on here.

1
Please provide mcve describes the issue. Currently there is nothing to do with this code if someone wants to test it. Now it looks like a logic problem. - folibis
what is card? - eyllanesc
@folibis I added source code. - İbrahim
@eyllanesc card is currently selected rectangle. I'm handling currently selected card (or Rectangle). This is a memory game. - İbrahim

1 Answers

1
votes

I think you are complicating the application by using the timer since you do not know if the item finished changing its position, it would be appropriate to execute that task when it finishes turning the letter over.

Another error that I see in your code is that you are assigning a state = "".

I have modified in the following parts:

GameArea.qml

GridLayout {
    [...]
    property variant imageIndexes: GameUtils.generateCardIndexes(
                                       imageCount, repeatCount)

    property int lastIndex : -1


    Repeater {
        id: repeater
        model: 40
        Card {
            id: card
            backImageSource: 'qrc:/images/img_' + area.imageIndexes[index] + '.jpg'
            onFinished: verify(index)
        }
    }

    function verify(index){
        if(lastIndex == -1){
            lastIndex = index
            return
        }
        area.enabled = false
        var lastItem = repeater.itemAt(lastIndex)
        var currentItem = repeater.itemAt(index)

        if(lastItem.backImageSource === currentItem.backImageSource){
            lastItem.state = "remove"
            currentItem.state = "remove"
        }
        else{
            lastItem.flipped = false
            currentItem.flipped = false
        }
        if(repeater.model === 0){
            console.log("Winning")
        }
        lastIndex = -1
        area.enabled = true
    }
}

Card.qml

Item {
    [...]        
    property alias state: flipable.state
    signal finished()

    Flipable {
        [...]
        transitions: Transition {
            NumberAnimation { target: rotation; property: 'angle'; duration: 400 }
            onRunningChanged: {
                if ((state == "back") && (!running))
                    finished()
            }
        }

        MouseArea {
            anchors.fill: parent
            onClicked: card.flipped = true
        }
    }
}

The complete code can be found at the following link