2

Well, there may be many QML programs in which if two components collide with each other the programmer defines an action based on that. In such programs as the one below, we want to concentrate on that collision and try to know how to define a function that tells us whether such a collision is done or not.

The code below is part of a bigger program. I tried to use a function called collision for that, in the code. The issue up to now is that it's not working well. I wanted to know if there is a built-in function in QML "or" if there is a good code you've used for that purpose.

The racket has three faces that may collide with the ball: a long one at the front, an upper and a lower one. The issue specifically is that the ball goes inside the racket when it collides with it from the upper or lower face!
The problem that I want to solve is that. I want that when the ball hits the racket from any faces, it reflects.

main.qml:

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    visible: true
    width: 720
    height: 620
    title: qsTr("Collision Test")

    Rectangle {
        id: table
        anchors.fill: parent
        color: "gray"

        Rectangle {
            id: ball
            property double xincrement: Math.random() + 0.5
            property double yincrement: Math.random() + 0.5
            width: 15
            height: width
            radius: width / 2
            color: "white"
            x: 300; y: 300
        }

        Racket {
            id: myRacket
            x: table.width - 50
            y: table.height/3
            color: "blue"
        }

        Timer {
            interval: 5; repeat: true; running: true

            function collision() {
                if((ball.x + ball.width >= myRacket.x  &&
                    ball.x < myRacket.x + myRacket.width) &&
                   (ball.y + ball.height >= myRacket.y &&
                    ball.y <= myRacket.y + myRacket.height))
                    return true
                return false
            }

            onTriggered: {
                if(ball.x + ball.width >= table.width)
                    running = false

                else if(ball.x <= 0)
                    ball.xincrement *= -1

                else if (collision())
                    ball.xincrement *= -1

                ball.x = ball.x + (ball.xincrement * 1.5);
                ball.y = ball.y + (ball.yincrement * 1.5);

                if(ball.y <= 0 || ball.y + ball.height >= table.height)
                    ball.yincrement *= -1
            }
        }
    }
}

Racket.qml:

import QtQuick 2.9

Rectangle {
    id: root
    width: 15; height: 50

    MouseArea {
        anchors.fill: parent
        drag.target: root
        drag.axis: Drag.YAxis
        drag.minimumY: table.y
        drag.maximumY: table.y + table.height - 50
    }
}
Franky
  • 1,181
  • 2
  • 11
  • 33
  • Unfortunately there's nothing for collisions (unlike in `QGraphicsScene`) in Qt Quick. I'd recommend the QML Box2D plugin: https://github.com/qml-box2d/qml-box2d – Mitch Dec 22 '17 at 11:39
  • Thank you for your recommendation, but it includes many files not only many many lines of code! What I need is just some better code than that 4 lines of code inside `collision`. :) – Franky Dec 22 '17 at 11:43
  • You cannot do `collision` in 2 lines of code. That is physics and lots of calculation. So for what you should reinvent existing thing. Use `qml-box2d` as @Mitch said. QML Box2D is a plugin, you just have to include *.pro into your project and you immediately have all the 2D power - collisions, bounce, forces etc. – folibis Dec 22 '17 at 16:16
  • QtQuick2 per se is no game engine, so many functions that are common to those, might be lacking. What Mitch recommended is a plugin that enables you (to some degree?) physics in QML. Of course a library are many files with many lines of code. But at least you don't need to write it your self. – derM - not here for BOT dreams Dec 22 '17 at 16:18
  • @folibis, Do you mean that I should copy the contents of [this .pro](https://github.com/qml-box2d/qml-box2d/blob/master/box2d.pro) file into my projects' `.pro` file? I've not used this way as yet. – Franky Dec 22 '17 at 18:32
  • 1
    You need to copy the whole thing, not just the pro-file. – derM - not here for BOT dreams Dec 22 '17 at 19:09
  • (+1) Please look, there are 4 lines in the function (`collision()`) that does the work but not perfectly. So does it make sense to use thousands of lines of code instead of that?! That whole code is probably very great but it can be used in some other program with the same purpose. My program is really not that important and is small (the whole code contains about 300 lines of code). So, what would you do please? Wouldn't you work on that function to make it a little better? – Franky Dec 22 '17 at 19:45

1 Answers1

3

For simple checks, whether a point is within a Item or not, you can use contains(point p).

This function needs a point in local coordinates, (relative to the Items origin), so you should use mapFromItem(...) or mapToItem(...) to get the right position.

  • Thanks. I go for using them in a code for that program. +1 – Franky Dec 22 '17 at 21:29
  • I tried to make an edition in the code but whatever I did I got [this message](https://s9.postimg.org/pinrumiyn/image.png). I tired to edit the code [this way](https://s9.postimg.org/bcd2w66lr/Capture.png) but I got errors! :( – Franky Dec 23 '17 at 09:35
  • those lines `var ...` are outside a function, so you can't use JS there. Move those to into the function. – derM - not here for BOT dreams Dec 23 '17 at 12:09
  • No, by *Qt 5.10* I'm using a *Qt Quick Application - Empty* project. I moved those lines inside the function and [it was](https://s9.postimg.org/tn2zbtn67/Capture.png) the result! – Franky Dec 23 '17 at 12:22
  • `Qt.point(x, y)` does not take a `point` as argument. But since you already have a `point`, e.g. in uL, you don't need to construct an new one. Replace those lines like `myRacket.contains(Qt.point(<...>))` by `myRacket.contains(<...>)` – derM - not here for BOT dreams Dec 23 '17 at 13:17
  • Well, I used that way this time: *myRacket.contains(uL)*, but the ball passes through the racket as if there weren't any racket! – Franky Dec 23 '17 at 14:34