This post participates in the competition " Smart phones for smart posts " Even despite the fact that many programmers at the moment are not in a hurry to put the development of their applications and games on Qt Quick, the infrastructure around the technology itself is growing and developing every day.
So it came to the simulation of physics in two-dimensional space. Or rather, before the appearance of the QML-plugin. which allows, with the inherent Qt Quick, to easily integrate the physics engine Box2D into its applications. That's about it today and talk. Or rather, let's look at the example of the implementation of a simple arkanoid, how quickly you can create a simple game, never before working with physics engines and almost neznaya terminology.
Link QML and Box2d
First of all, we need to get the source of the plugin. To do this, click on the link gitorious.org/qml-box2d/qml-box2d/trees/master and on the right click on the “Download master as tar.gz” button. Postpone until the archive aside and go to Qt Creator.
Here, we create a new project, such as "Qt Qucik Application". In the wizard, enter the name, location in the file system, select the Qt profile, then, further, complete. ')
And now one of the most important parts begins. And usually one of the most difficult in OTHER languages ​​and technologies. You must actually connect the plugin to the newly created application. To do this, unpack the resulting archive into the root directory of the application and rename the resulting directory qml-box2d-qml-box2d to qml-box2d. B we add one new line to the .pro file of our application:
register in the application the types of Qt / Box2D, which will be available and necessary for us in the future in QML. That's all. This is enough to connect the plugin as a statically linked library. Of course, a plugin can be assembled as an independent unit and put in a general directory of all QML plug-ins in the system. But for our goal and the first option. The appearance of the resulting project is approximately as follows:
If we try to compile the application now, we will see the standard Hello World, which is the default project template in Qt Quick. But it is not interesting. We are interested in using physics.
We formalize the description of the game
So, we have decided what we will do arkanoid. We list what we need in the toy of this plan:
The default 360x640 window is for easier porting to mobile devices in the future. And of course fixing it in landscape mode.
The background of the application is a simple picture, against which it will be convenient to play.
4 walls bordering our world at the edges of the window.
Bulb flying within the world.
Platform at the bottom of the window, to beat the ball.
Several bricks in the upper part of the window, which must be knocked down with our ball.
Time counter on the screen.
Starting and finishing screens of the game.
Implement the task
It is for this simple TZ that we will work further. As shown above, in main.cpp, we have already instructed our application to run in landscape mode. It means more need to edit C ++ - we have no code. Open the main.qml file and bring it to the form:
What have we done? We created a window with the size of 640x360, set its background and added one child element of the World type, which in the future should be the ancestor for all physical objects. As it is easy to guess, the World object describes the entire game world and sets its basic parameters, namely:
gravity — X and Y gravity. For our application, gravity is not needed.
And a few parameters, with the correct translation of which, unfortunately, I have problems: timeStep, velocityIterations, positionIterations, frameTime
Their description can be peeped in the box2dworld.h header file.
An empty three-line physical world is cool. But let's dilute it with statics. Or walls, as you like. Create a new QML file, let's call it Wall.qml. add next to the application and fill in the following contents:
The wall, like all objects on the scene (and the Wold object is essentially a scene), are objects of type Body. Therefore, Body is the base class for all physical elements. It has the following properties:
active - enable / disable physics on the element
linearVelocity - linear acceleration
fixtures - the boundaries of the body, which will be determined by collisions
bodyType - body type, static, dynamic or kinematic
fixedRotation - disable rotation
sleepingAllowed - allow physics to automatically turn off to save resources
linearDamping, angularDamping, bullet - not clear at first glance
The body, as such, cannot handle collisions with other objects. In order to teach the body this, you must set the fixtures property. Values ​​for this property can be Circle, Box and Polygon. All of them are descendants of the base class Fixture, which is responsible for interacting with other objects. Independently, of course, it is not available from QML, but only after three of its descendants. We list the properties available for clarity. Fixture class:
density
friction - friction force
restitution - resilience / recoil
groupIndex - the index in the group (presumably the group is one Body object)
collidesWith - list of objects. with which the current object is in contact at the moment
sensor, categories - advanced parameters
Each of the descendants slightly extends this class with its own properties:
The Box class does not add new properties, but uses standard widths and heights to define the boundaries of the rectangle.
The Circle class introduces the radius property, which oddly enough is the radius of a circular object, such as a wheel.
The Polygon class adds a verticles property containing a list of object vertices for more accurate physical simulation.
Back to practice
From theory it becomes clear that the wall is a physical body (Body) of the rectangle type (Box) and is graphically represented as a filled picture. And now, having one wall, we can create as many walls as we like, we also need them 4. Open the main.qml and inside the World object, after gravity.y: 0, add a description of our walls:
We save everything and run our application, on the screen we will see a background image and 4 walls framing the world at the edges. Further, according to the plan we have a ball that can fly within our world and hit the walls. To describe the ball, create the Ball.qml file and fill it with the following contents:
The same as with the wall, but instead of Box we have Circle. Add our ball to the world we created, after describing the last wall in the World object, we add the ball description:
We start, we see the ball in the center of the screen, which does not move anywhere due to the lack of gravity and linear acceleration. From clever what ... The next step is a platform representing the only player control with which we will beat the ball. According to the previous scheme, the new Platform.qml file, in it:
This physical object differs from the others in that we allow the user to lead them around the screen with the mouse / finger cursor in the horizontal direction. After the Ball description, we add a description of the platform to main.qml:
Platform { id: platform }
At the moment, I advise you to remember our walls. For good, we know that they work, but since we are limited by the screen size, we can hide our walls off the screen. so as not to hurt the eyes and do not interfere. To do this, in turn, we will add one of the following properties to each of the Wall objects inside the World: left leftMargin: -width, right rightMargin: -width, top topMargin: -height, and bottom bottomMargin: -height. After that, we re-launch and look at what we get:
The next item of our plan. Bricks that must be knocked down with a ball. But! We must not forget that we will not have enough space on the screen. Therefore, we will try to implement this part of the game differently. Namely - at the top of the screen there will be several bricks of green color, on which it is constantly necessary to hit the ball, preventing them from turning red. If the brick becomes red finally - peel on it already to no purpose. And in the game, we introduce a timer that counts the amount of time until all the bricks turn red. The animation of the transition from green to red will be equal to for example 20 seconds. After the brick turns red, it disappears. If we have time to get on the brick, then the 20-second timer is reset and the brick begins to redden again. Let's start with the description of the brick in the Brick.qml file:
As you can see, there is also nothing complicated here: a description of the body, a description of its display, two states with smooth animation of the transition between them, a timer counting down 20 seconds with a restart after each collision with the ball and the auxiliary function show (). In the main.qml file, after the platform announcement, we add the advertisements of our bricks:
By the way, don’t ask me why I didn’t use the Row and Repeat elements - using them to automatically create the Body type, the application crashes. At the very beginning of the file we will add the declaration of a new variable, after determining the height and width:
propertyint bricksCount: 5
According to it, we will count the number of remaining bricks, when it reaches the example of two - we end the game. That is, the logic of user interaction with the game will be simple - it is necessary that at least three bricks remain on the screen as much as possible. We describe the seconds counter at the very bottom of the World object:
What do we have left? It remains to add the start and finish screens, well, a bit to correct the logic of the game. Actually it is the little things that you can omit in the article. I’ll just give you a complete final listing of the main.qml file:
Here is a demo application. Now I propose to look at what happened in the end, and then read a couple of concluding lines and write my impressions of the work done by the developers of the plugin. We look:
In my opinion it turned out well. In fact, the development of the application itself and the writing of this article took only two evenings (yesterday and today). First of all, it speaks of the simplicity and very low threshold for entering development using QML, and secondly, of the quality of the code that developers over and over again manage to achieve both the Qt framework and third-party developers writing similar plug-ins for it.
A plus. Of course, I want to note that Box2D itself is not tied to any OS and is platform independent, therefore, the created application will work equally well on desktop as well as on mobile platforms. Well, even in this example, you can see screenshots from under Windows and videos from under Linux.
Of course. This article does not cover all the functionality of Box2D, which was transferred to QML, there are still at least Joint s. On the other hand, I believe that this material is quite enough for understanding the essence of things. And already having an idea about the QML / Box2D bundle, you can easily rivet toys using physics. It can also be labyrinths using the phone’s accelerometer and falling cubes that are fun to blow from each other, cars and cars like X-Moto, and much more. In this case, do not forget. that QML is only a wrapper on C ++ classes and the application itself will work as if originally written in C ++.