Forums

OverviewV-Play 2 Support (Qt 5) › Help with a bouncing ball

Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • #12862

    Kool

    Hi all,

    I’m hoping to get some help the correct settings (physics world gravity, linear impulse on the ball) for a bouncing ball. I want to have a circle shape that bounces in the middle of the screen once every second and there is no ‘floor’ for the ball. My difficulty is that I’m unsure of the units of measurements for the PhysicsWorld gravity and the applyLinearImpulse() function for a collider body. This could be similar to the FlappyBird example, however the difference is that I have a measurement to follow (e.g. the ball must return to it’s starting position in exactly 1 second (or thereabouts), and bounce again). There’s also the constraint that it starts bouncing after the user has clicked a button. This is a simple example, however I’ve noted that setting the restitution(bounce)/friction for a body isn’t suitable to what I actually want to achieve, so I need to get this effect through gravity and applying a linear impulse.

    Here’s an example:

    import VPlay 2.0
    import QtQuick 2.0
    
    GameWindow {
        id: gameWindow
        activeScene: scene
    
        screenWidth: 960
        screenHeight: 640
    
        EntityManager {
            id: entityManager
            entityContainer: scene
        }
    
        Scene {
            id: scene
    
            width: 480
            height: 320
    
            Timer {
                id: timer
                interval: 1000; repeat: false; running: false
                onTriggered: ball.bounce()
            }
    
            Rectangle {
                id: background
                anchors.fill: parent
                color: "black"
            }
    
            StyledButton {
                id: startButtonn
                text: physicsWorld.running ? "Stop" : "Start"
                anchors {top: parent.top; right: parent.right}
                onClicked: physicsWorld.running = ! physicsWorld.running
            }
    
            EntityBase {
                id: ball
                height: 10
                width: 10
                x: parent.width / 2
                y: parent.height / 2
                anchors.centerIn: parent
    
                Rectangle {
                    id: shape
                    anchors.fill: parent
                    color: "white"
                    radius: 10
                }
    
                CircleCollider {
                    id: collider
                    radius:  shape.radius
                    bodyType: Body.Dynamic
                    anchors.centerIn: parent
                }
    
                function bounce() {
                    // reset linear velocity
                    collider.body.linearVelocity = Qt.point(0,0);
    
                    // create the impulse vector and apply it
                    var localForwardVector = collider.body.toWorldVector(Qt.point(0, -50));
                    collider.body.applyLinearImpulse(localForwardVector, collider.body.getWorldCenter());
                }
            }
    
            PhysicsWorld {
                id: physicsWorld
                gravity.y: 5
                running: false
                onRunningChanged: {
                    if (running)
                        timer.restart()
                    else
                        timer.stop();
                }
            }
        }
    }
    

    You can see the collider doing something, however the shape of the ball doesn’t move at all. Could someone please point out the what I might be missing here? Thanks a bunch!

     

    • This topic was modified 2 years, 7 months ago.
    #12864

    Alex
    V-Play Team

    Hi Kool,

    you got a classic case of your QML positioning of your Entity working against the positioning derived from the physics system. The physics system will update the x and y position of the EntityBase every frame, but you are using

    anchors.centerIn: parent

    on the EntityBase, which creates a conflict, as QML will always try to keep the EntityBase centered in the screen and also update the x and y values accordingly.

    Long story short, remove the anchors of the EntityBase and physics will work fine.

    Regards,
    Alex

    #12865

    Kool

    Thanks Alex.

    I’ve updated the code and set the timer to repeat (as well as bounce as soon as the physics is set to running):

     

    import VPlay 2.0
    import QtQuick 2.0
    
    GameWindow {
        id: gameWindow
        activeScene: scene
    
        screenWidth: 960
        screenHeight: 640
    
        EntityManager {
            id: entityManager
            entityContainer: scene
        }
    
        Scene {
            id: scene
    
            width: 480
            height: 320
    
            Timer {
                id: timer
                interval: 1000; repeat: true; running: false
                onTriggered: ball.bounce()
            }
    
            Rectangle {
                id: background
                anchors.fill: parent
                color: "black"
            }
    
            StyledButton {
                id: startButtonn
                text: physicsWorld.running ? "Stop" : "Start"
                anchors {top: parent.top; right: parent.right}
                onClicked: physicsWorld.running = !physicsWorld.running
            }
    
            EntityBase {
                id: ball
                height: 10
                width: 10
                x: parent.width / 2
                y: parent.height / 2
    
                Rectangle {
                    id: shape
                    anchors.fill: parent
                    color: "white"
                    radius: 10
                }
    
                CircleCollider {
                    id: collider
                    radius:  shape.radius
                    bodyType: Body.Dynamic
                    anchors.centerIn: parent
                }
    
                function bounce() {
                    console.debug("Bouncing");
    
                    // reset linear velocity
                    collider.body.linearVelocity = Qt.point(0,0);
    
                    // create the impulse vector and apply it
                    var localForwardVector = collider.body.toWorldVector(Qt.point(0, -100));
                    collider.body.applyLinearImpulse(localForwardVector, collider.body.getWorldCenter());
                }
            }
    
            PhysicsWorld {
                id: physicsWorld
                gravity.y: 5
                running: false
                onRunningChanged: {
                    if (running)
                    {
                        ball.bounce();
                        timer.restart();
                    }
                    else
                    {
                        timer.stop();
                    }
                }
            }
        }
    }
    

    The ball does bounce however it will bounce upwards of the screen (I’m assuming that gravity is not as high as it needs to be). I need it to return to the same spot it started at.

    Does anyone know the units of measurements for PhysicsWorld gravity and applyLinearImpulse()?

    #12866

    Alex
    V-Play Team

    Hi again,

    you can also set the triggeredOnStart property of the timer to true a bounce on start.

    Regarding the units, you can find them in the documentation. The gravity is in m/s². applyLinearImpuls() takes a vector in world coordinates. The pixelsPerMeter property of the PhysicsWorld (inherited by the World class) defaults to 32. So 32 world pixels are 1 meter. Now taking the equation of a vertical throw we get the following:

    y = v0*t – (g/2)*t²

    assuming we have a gravity of 10, we get the following equation for reaching the origin (y=0) of our throw after t=1 second:

    0 = v0*1 – (10/2)*1

    v0 = -5 m/s –> multiply by pixelsPerMeter to get world coordinates –> v0 = -5 * 32 = -160 pixels/s

    So this means our vector would be Qt.point(0, -160).

    The problem you will face next is that Timers are not 100% accurate in terms of triggering at the exact millisecond and therefore the new bounce might get triggered a frame (which takes about 17ms with 60fps) too late, so the ball is slowly moving down after all. I’d recommend placing a sensor entity below the ball and bounce every time they collide. Use collisionTestingOnlyMode for this entity so it is not moved by any forces like gravity or collisions.

    This would look like this:

    import VPlay 2.0
    import QtQuick 2.0
    
    GameWindow {
        id: gameWindow
        activeScene: scene
    
        screenWidth: 960
        screenHeight: 640
    
        EntityManager {
            id: entityManager
            entityContainer: scene
        }
    
        Scene {
            id: scene
    
            width: 480
            height: 320
    
    //        Timer {
    //            id: timer
    //            interval: 1000; repeat: true; running: false; triggeredOnStart: true
    //            onTriggered: ball.bounce()
    //        }
    
            Rectangle {
                id: background
                anchors.fill: parent
                color: "black"
            }
    
            StyledButton {
                id: startButtonn
                text: physicsWorld.running ? "Stop" : "Start"
                anchors {top: parent.top; right: parent.right}
                onClicked: physicsWorld.running = !physicsWorld.running
            }
    
            EntityBase {
                id: ball
                height: 10
                width: 10
                x: parent.width / 2
                y: parent.height / 2
    
                Rectangle {
                    id: shape
                    anchors.fill: parent
                    color: "white"
                    radius: 5
                }
    
                CircleCollider {
                    id: collider
                    radius:  shape.radius
                    bodyType: Body.Dynamic
                    anchors.centerIn: parent
                }
    
                function bounce() {
                    console.debug("Bouncing");
    
                    // reset linear velocity
                    collider.body.linearVelocity = Qt.point(0,0);
    
                    // create the impulse vector and apply it
                    var localForwardVector = collider.body.toWorldVector(Qt.point(0, -160));
                    collider.body.applyLinearImpulse(localForwardVector, collider.body.getWorldCenter());
                }
            }
    
            EntityBase {
              id: sensor
              width: 10
              height: 1
              x: parent.width / 2
              y: parent.height / 2 + ball.height
    
              BoxCollider {
                anchors.fill: parent
                collisionTestingOnlyMode: true
                fixture.onBeginContact: ball.bounce()
              }
            }
    
            PhysicsWorld {
                id: physicsWorld
                gravity.y: 10
                running: false
                onRunningChanged: {
                    if (running)
                    {
                        ball.bounce()
                    }
                }
            }
        }
    }
    

    Regards,
    Alex

Viewing 4 posts - 1 through 4 (of 4 total)

RSS feed for this thread

You must be logged in to reply to this topic.

Voted #1 for:

  • Easiest to learn
  • Most time saving
  • Best support

Develop Cross-Platform Apps and Games 50% Faster!

  • Voted the best supported, most time-saving and easiest to learn cross-platform development tool
  • Based on the Qt framework, with native performance and appearance on all platforms including iOS and Android
  • Offers a variety of plugins to monetize, analyze and engage users
FREE!
create apps
create games
cross platform
native performance
3rd party services
game network
multiplayer
level editor
easiest to learn
biggest time saving
best support