Forums

OverviewV-Play 2 Support (Qt 5)Camera movement and zoom › Reply To: Camera movement and zoom

OverviewV-Play 2 Support (Qt 5)Camera movement and zoom › Reply To: Camera movement and zoom
#10487

Alex
V-Play Team

Hi,

well that one’s a little tricky, I came up with one quick solution, might not be the best but it kind of works, I’m sure it can be improved further.

I introduced a new Camera component that handles the focusing and zooming. There is still a minor “problem”, if the focused object is moving while the smooth focusing is running, I added comments for that to the code.

Main.qml

import QtQuick 2.0
import VPlay 2.0

GameWindow{
  id: window

  // this will be our game scene
  Scene {
    id: scene

    EntityManager {
      id: entityManager
      entityContainer: container // the entityContainer is now our container that will be moving
    }

    // instead of changing the scene position we rather introduce a container that holds the entities, and adepts its position accordingly to the player position to keep the player centered in the screen. Also we are sing a property binding to update the position every frame instead of a timer, this is more reliable to keep in in sync.
    Item {
      id: container
      transformOrigin: Item.Center

      Camera {
        id: camera
        scene: scene
        objectContainer: container
        focusedObject: entityBase
      }

      // put the physicsworld inside the entitycontainer to have correct debug draw
      PhysicsWorld {
        id: physicsWorld
        gravity: Qt.point(0,0)
      }

      // background
      Grid {
        id: grid
        x: scene.width/2
        y: scene.height/2
        width: 2 * window.width
        height: 2 * window.height
        columns: 8
        rows: columns * window.height / window.width    // make each grid a square
        Repeater {
          model: parent.columns * parent.rows
          Rectangle{
            property int rectangleNumber: index
            width: parent.width / parent.columns
            height: width
            color: "transparent"
            border.color: "black"
            border.width: 3
            Text {
              anchors.centerIn: parent
              text: parent.rectangleNumber + 1
              font.pointSize: parent.height / 3
            }
          }
        }
      }

      // the player
      EntityBase {
        id: entityBase
        x: scene.width / 2
        y: scene.height / 2

        Rectangle {
          id: player
          x: -width / 2
          y: -height / 2
          width: 80
          height: width
          radius: width / 2
          color: "blue"

          // start player moving when clicked, and start the timer to update the camera's position
          MouseArea {
            anchors.fill: parent
            onClicked: {
              //cameraTimer.start()
              collider.linearVelocity = Qt.point(100, 75)
              colliderObstacle.linearVelocity = Qt.point(-100,75)
            }
          }
          Text {
            anchors.centerIn: parent
            font.pixelSize: 15
            text: "click me"
            color: "white"
          }
        }
        CircleCollider {
          id: collider
          radius: player.width / 2
          anchors.centerIn: player
          bodyType: Body.Dynamic
          linearVelocity: Qt.point(0, 0)
          categories: Box.Category1
          collidesWith: Box.Category2
          fixture.onBeginContact: player.opacity = 0.5
        }
      }

      // an obstacle
      EntityBase {
        id: entityBase2
        x: scene.width / 2 + 2*window.width
        y: scene.height / 2

        Rectangle {
          id: obstacle
          x: -width / 2
          y: -height / 2
          width: 80
          height: width
          color: "red"
          Text {
            anchors.centerIn: parent
            font.pixelSize: 15
            text: "obstacle"
            color: "white"
          }
        }
        BoxCollider {
          id: colliderObstacle
          width: player.width
          height: width
          anchors.centerIn: obstacle
          bodyType: Body.Dynamic
          sensor: true
          linearVelocity: Qt.point(0, 0)
          categories: Box.Category2
          collidesWith: Box.Category1
        }
      }
    }
  }

  // to avoid having to recalculate the size and position of the HUD elements, we just introduce a 2nd scene that we put on top of the game scene, to hold the hud elements, this one will stay untouched when we zoom into the game sceen
  Scene {
    id: hudScene
    // button to toggle zoom in
    Rectangle {
      id: zoomButton
      x: 10
      y: 10
      width: 100
      height: 40
      radius: 3
      color: "black"
      opacity: 0.2
      Text {
        anchors.centerIn: parent
        font.pixelSize: 30
        text: "zoom"
      }
      MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onEntered: parent.opacity = 0.3
        onExited: parent.opacity = 0.2
        onClicked: {
          if(camera.zoom == 1){
            camera.zoom = 1.2
          }
          else{
            camera.zoom = 1
          }
        }
      }
    }

    // button to toggle centered object
    Rectangle {
      id: focusButton
      x: 120
      y: 10
      width: 100
      height: 40
      radius: 3
      color: "black"
      opacity: 0.2
      Text {
        anchors.centerIn: parent
        font.pixelSize: 30
        text: "focus"
      }
      MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onEntered: parent.opacity = 0.3
        onExited: parent.opacity = 0.2
        onClicked: {
          if(camera.focusedObject === entityBase){
            camera.focusedObject = entityBase2
          }
          else{
            camera.focusedObject = entityBase
          }
        }
      }
    }
  }
}

Camera.qml

import QtQuick 2.0
import VPlay 2.0

Item {
  id: camera
  property Scene scene
  property Item objectContainer
  property Item focusedObject

  property int focusEasing: Easing.InOutQuad
  property int zoomEasing: Easing.InOutQuad
  property int focusDuration: 200
  property int zoomDuration: 200

  property real zoom: 1
  Behavior on zoom{NumberAnimation{duration: zoomDuration; easing.type: zoomEasing}}

  Component.onCompleted: {
    objectContainer.x = Qt.binding(function() { return scene.width/2 - focusedObject.x })
    objectContainer.y = Qt.binding(function() { return scene.height/2 - focusedObject.y })
  }

  onFocusedObjectChanged: {
    // the problem is that we are taking the position of the object to focus and set it as target for the animation, then the animationr runs for e.g. 200ms, but in the meantime also the object moved by some pixels, so the animation ends up at the position where the object was 200ms ago, and then jumps the the actual position. So to improve this you would need to calculate the camera movement during the focus change yourself every frame (with a Timer) instead of using a simple animation.
    objectContainer.x = objectContainer.x
    objectContainer.y = objectContainer.y
    smoothX.from = objectContainer.x
    smoothX.to = scene.width/2 - focusedObject.x
    smoothY.from = objectContainer.y
    smoothY.to = scene.height/2 - focusedObject.y
    smoothFocus.start()
  }

  onZoomChanged: {
    scene.scale = zoom
  }

  ParallelAnimation {
    id: smoothFocus
    NumberAnimation {
      id: smoothX
      target: objectContainer
      property: "x"
      duration: camera.focusDuration
      easing.type: camera.focusEasing
    }
    NumberAnimation {
      id: smoothY
      target: objectContainer
      property: "y"
      duration: camera.focusDuration
      easing.type: camera.focusEasing
    }
    onStopped: {
      objectContainer.x = Qt.binding(function() { return scene.width/2 - focusedObject.x })
      objectContainer.y = Qt.binding(function() { return scene.height/2 - focusedObject.y })
    }
  }
}

Cheers,
Alex

  • This reply was modified 2 years, 11 months ago by  Alex.

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