Would you ever build a 3D Endless Runner Mobile Game with Qt? and if no why?
-
The best solution will be to use Godot, Unity, Unreal Engine and so on. It depends what language do you like. Godot uses GDScript (it is similar to Python) and C#. Unity uses C# only. Unread Engine uses C++ and Blueprints (visual scripting without programming). These engines are the most popular. They have unofficial scripting languages, for example, you can use JavaScript for Unreal Engine: https://github.com/ncsoft/Unreal.js or Python, Lua and so on. If you don't like C++, you like JavaScript and you want to make web games you can use Three.js. Three.js game can be build to mobile and desktop using Cordova.
But I like to study Qt, OpenGL ES 2.0, Box2D and Bullet Physics for game programming as hobby. It is very bad choice. I don't recommend it for commercial games. Because you will not find a job for game development in Qt. I study game development as hobby to study C++, Qt, computer graphics programming, WebSockets (client/server programming for games).
I have some progress with Qt in 3D. I know how to build Bullet Physics for Android and WebAssembly. I know how to play 3D sounds for Android using OpenAL and how to play 3D sounds with WebAssembly using Web Audio API. The most important thing for 3D games is a physics engine because it allows to move your player, detect collisions, avoid obstacles, collect items (like coins). Bullet Physics has the btIDebugDraw class. This class has the drawLine method. My next example uses that class and method to draw the collider edges by OpenGL. I made a movement of character using Bullet Physics with OpenGL ES 2.0, Qt6, C++ for WebAssembly, Desktop, and Android. The desktop demo requires 27.8 MB. It is not so big like Cordova/Electron that requires more than 100 MB.
Use WASD to move:
- WebAssembly demo: https://65d4f11321dc4f162266ec50--astounding-pika-5d00ff.netlify.app/
- Demo for Windows 10, 64-bit: mario-3d-simple-movement-qt6-cpp-win10x64-exe.zip - 11.6 MB
- APK for Android 7-14: mario-3d-simple-movement-qt6-cpp-android-7-14-apk.zip - 9.06 MB
I already know how to import a skeleton animation from Blender using the DAE COLLADA format. But I have made the next my demo using pure WebGL 1.0, OimoPhysics, glMatrix, Web Audio API, and WebSockets. I want to remake it to Qt and OpenGL ES 2.0 to make a Android/Desktop/Web client in Qt C++: https://8observer8.github.io/webgl10-js/room-webgl-js/
-
@Michele-Rossi Thank you @SGaist for your input. Do you mean that if we create a tailored documentation, examples and tutorial to cover those items in one course should be already a good start? Would not have Godot the same learning curve? Or maybe the question is: why do you think Godot has a lower barrier of entry to build such use case than using Qt? thx!
-
@Michele-Rossi You can also use FELGO which is Qt based and more oriented for games.If you want to do a course it could be a great start
-
@Ronel_qtmaster thank you, would you use Felgo as well for a 3D Endless Runner, or you see value in Felgo mainly for a 2D Endless Runner use case? thx!
-
@SGaist said in Would you ever build a 3D Endless Runner Mobile Game with Qt? and if no why?:
How QtQuick3D works
You don't really need this. You could learn it if you choose to use it, but it is commercial/GPL, while
Qt3D
is more permissive. The latter is still rather lacking in documentation quality, though. -
Popular game engines have many ready-made free and paid game assets in Asset Stores. This can save a lot of time. There are many experts on game engines and companies. Game engines make it easier for you to form a team or find a job. Very few people and companies use Qt for game development. Of course, this doesn't concern you if you program games alone. But Qt requires much more time to develop games and much more knowledge needs to be mastered. You will have to study physics engines and write those assets yourself that you could quickly download from Asset Stores and master using ready-made popular game engines. Maybe you've come across the following book: Game Programming using Qt 5 Beginner's Guide: Create amazing games with Qt 5, C++, and Qt Quick, 2nd Edition I haven't read it, but maybe it will be useful to you.
-
Neither of those are reasons why you wouldn't develop a game with Qt. Qt3D already can import ready assets and as far as I recall you can wire the skeleton animations.
The most significant reason is actually the lack of tooling for the job.You don't have a tool on hand to wire shaders, build materials, modify a render graph, etc.
(I'm excluding Qt Design Studio as it's a commercial product as far as I know, and I have not used it at all) -
Personally, I chose Qt for game development because I like to understand how skeletal animation works, computer graphics on shaders, how linear algebra works, physics engines, COLLADA parsing, low-level audio on OpenAL. Qt allows you to create small executables for desktop and Android. Creating WebGL applications using Emscripten and Android is very easy. Compared to other 3D engines in C++, I like Qt much more based on the indicators that I listed above. I see great potential for the future in him. I like that Qt is not popular in games because in the future I can create Qt tutorials in English and become more famous than if I made Unity tutorials. But first I need to make a lot of small games in Qt and learn spoken English at a good level.
I see the following problems for beginners who want to make 3D games in Qt. Few tutorials. There are probably no companies where beginners can become an intern and gain experience developing games in Qt. For example, I worked as an intern for several companies on Unity, and this helped me learn a little about game development. Lack of store assets. For example, go to https://assetstore.unity.com/ and enter “3D Endless Runner” in the search bar. You will find out how many ready-made assets are available to you to start developing 3D Endless Runner:
-
Hello @8Observer8 , such valuable discussion here.
I would like to point out couple things. The 3D has taken major advances with Qt and it's not just Qt 3D engine but also the the Quick3D engine which is 100% controlled by QML and backed up with tooling from Qt Design Studio. Both are also available thru the Qt installer and at the time of writing Qt is at level 6.6. and Qt DS is 4.5.
The way it works is that all QML items are atomic components, so for instance we don't currently ship ready-packaged items that have collision detection, but you need to build it from the existing pieces. Thing is there are lot of things you can do out of the box but they require some hand-holding and that's what we are now looking into. The Quick3D has 3D particle system, supports FBX, GLTF2 etc, has skeletal animation framework, can do mesh morphing, has support for LOD and resource management not to mention awesome rendering quality (in Qt 6.5) and we also have 3D physics. But it does not have level controls or game-related logic off the bat. This is where things like Tiled come into play but still you need the assets, right? You can get a lot of free stuff from Sketchfab or Turbosquid and with your credit card even hi-res versions. You pull them into the Qt Design Studio and then it's not just FBX but we create a proper QML components out from those assets, you get your animations, materials, lights etc as part of the process and you can then fine-tune or even replace parts of the imported components.
Already in the Qt Academy there are bunch of free courses on the topic to get started so go ahead.
-
@kshegunov thank you for your input! Would you be so kind to share your thought on which kind of "tooling for the job" Qt would be missing today? Would you be able to point concrete examples? thx!
-
In my perspective, I appreciated Qt3D in many ways.
A bonus is the simple adding of entities, transformations and components, for example materials.The overall performance of my 3D scenes were good (in release mode).
Unfortunately, I was not able to apply shinings and shadows in my 3D view.
This would be a game changer for me and any new applications. -
@Michele-Rossi Both cases can be used with yocto, check this https://felgo.com/doc/felgo-examples/
-
I don't understand why Felgo was suggested several times. I carefully looked through the website of this framework and did not find any information that it supports the development of 3D games.
-
-
@Ronel_qtmaster said in Would you ever build a 3D Endless Runner Mobile Game with Qt? and if no why?:
check this https://blog.felgo.com/updates/qt-3d-game-engine-with-qt-5-5-and-felgo-game-engine
Developers of Felgo should add make these things on their website:
- The car example should be ported from Qt 5 to Qt 6
- Box2D in the car example should be replaced with Bullet Physics or PhysX for 3D games
- Shadow mapping should be added to the car example and to the documentation
- Documentation for 3D API should be added to the official web site of Felgo
- Getting started tutorials for 3D games should be added
- Official examples in 3D with 3D physics should be added
Now all the examples, documentation and getting started examples on the official website are for 2D games with the Box2D physics engine. But perhaps Box2D can be used for 3D Endless Runner. Or the Bullet Physics engine can be integrated by Felgo user. I think shadow mapping was not integrated into Felgo because it was not integrated into Qt3D.
I like using pure Qt with OpenGL because I can implement shadow rendering myself. This is my example in pure WebGL 1.0 (the camera can be rotated by holding the left or middle mouse button) https://8observer8.github.io/webgl10-js/door-with-ortho-shadow-map-webgl-js/
Personally, I don't like Felgo because it also doesn't allow you to build WebGL for free. For this you need to pay 79 euros per month: https://felgo.com/pricing.
-
I am using Qt and Quick3D for game developing and it is a beauty. Godot is becoming very popular, but I am some what lazy and lack the time to learn new stuff, so I just go along with javascript to develop my own algorithms. In the end of the day, the final user does not care what you use to develop the game. Third party libraries may be good for complex games, but thats depends of the type of game you are trying to develop. A endless runner game does not seem a complex task to me, and I thing it is perfectly fine to use only Qt / quick3D for that.
Here is a 3D game I am developing using only qt / quick3D (quick3D makes it very easy to load 3D assets and animated characters using the balsam tool) https://bitbucket.org/joaodeusmorgado/davidgalacticadventures/src/master/https://www.youtube.com/watch?v=DJKYHq_x9VY
I have also developed a 2D game using only Qt / qml:
https://bitbucket.org/joaodeusmorgado/superepicmegahero/src/master/https://www.youtube.com/watch?v=U3Hx4uospF8
Hope this helps.
-
@johngod looks amazing.Do you have any tutorial on QtQuick3D?
-
@Ronel_qtmaster @Ronel_qtmaster I dont, I have learn it using the docs and demos.
The assets that I have used make all the difference in visual of the game.
Here is my take on 3D game development, one has to know 3d game development, them the tools you use are a bonus.
For example I have used OpenGL before, but it is very low level, the API is not user friendly, you have to do a lot of coding for basic stuff, like loading textures. To me learning OpenGL was a very good school, but in the end it was a bit overkill to what I wanted to achieve.
Why did I choose Quick3D? Compared with Q3D, I liked quick3D API better, with more documentation and examples, and at the time I believed that a lot more resources would be put in quick3D development from the Qt company than in the Q3D. Why I do not use Godot, Unity, or other? Because I am not a game developer, I am a hobbyist developer in my free time, and I really like Qt, so I just went with my gut feeling and jumped in the quick3D wagon and I did the right thing. For sure there could be better tools or tools that I would like better if I know them, but time is limited and I can’t learn every stuff out there. I can reuse the knowledge that I am gaining with quick3D, because I developed other 3D apps than games, not sure I could use unity, godot, for other stuff than games.
What I like in Quick3D? It has a nice API, supports loading textures easily, loading animated assets from blender, Maya, and others, you have to use balsam utility, but once you get used to it, it works fine. Skyboxes are a beauty, they just work easily, I could never manage to put OpenGL skybox working correctly. The way you compose a scene using Nodes in the Viwe3D are more powerful and versatile than I thought at first. It has built in cameras, but in this it falls short, it lacks a proper camera for FPS games. I had to develop my own FPS cameras for my game. If you guys from Qt company are listen, adding a good FPS camera should not be that hard, also the Qt rockstars devs always surprise for how good API’s they make. There are several types of lights, they just work out of the box. The recent addition of physics is very good, I still haven explore these, but I think it will bring games to the next level. Quick3D performance seems to be good, I get 120 frames with a gaming monitor.
At the end of the day, you can build a great game and still be a failure. It is a like a lottery, were the tools you use are least important, being the assets and the marking huge deals. Then some guy comes and builds a flappy bird with crappy graphs, and it gets huge success :) -
@johngod said in Would you ever build a 3D Endless Runner Mobile Game with Qt? and if no why?:
you have to do a lot of coding for basic stuff, like loading textures
Loading textures is a bad example because it doesn't require much code:
m_texture.create(); m_texture.setData(QImage(texturePath).mirrored()); m_texture.setMinMagFilters(QOpenGLTexture::Filter::Linear, QOpenGLTexture::Filter::Linear); m_texture.setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge);
But if you need to load materials using a specular map, a normal map, or you need to implement glass, water, fire, smoke and so on - yes, in this case you will have to learn a lot and write a lot of code. I haven't tried to implement this in OpenGL. I especially believe that it is very difficult to implement PBR materials using OpenGL, as was implemented using Qt3D: PBR Materials QML Example These materials were also implemented in Qt Quick 3D: https://doc.qt.io/qt-6/quick3d-pbr.html But some people need PBR, and some don’t.
I spend a lot of time implementing BMFont (text rendering), skeletal animation, and sprite animation with pure WebGL (I haven't rewritten it in Qt OpenGL yet), but once you've implemented this stuff once, you can copy it from project to project.
I want to rewrite the following example in Qt OpenGL ES from OpenGL1/SDL2/Python. I created a C++ version of this example to create an EXE file because PyInstaller creates a very large EXE file. Perhaps this will be useful for those who want to use OpenGL, since text is very important for games. I can help to rewrite it to Qt, OpenGL ES 2.0
- Source in Python, PySDL2: font-opengl1-sdl2-py.zip - 63.5 KB
- EXE in C++, SDL2: font-opengl1-sdl2-cpp-win64bit-exe.zip - 1.41 MB
Here is 244 lines of code in one file:
import ctypes import sys from dataclasses import dataclass import numpy as np from OpenGL.GL import * from PIL import Image from sdl2 import * maxFPS = 60.0 window: SDL_Window = None def fatalError(message): print(message) if window: SDL_DestroyWindow(window) SDL_Quit() exit(-1) @dataclass class CharData: id: int = 0 x: int = 0 y: int = 0 w: int = 0 h: int = 0 xOffset: int = 0 yOffset: int = 0 xAdvance: int = 0 class Font: def __init__(self, fontContentPath, texture): self.charMap = {} self.charIndices = {} self.texture = texture self.parse(fontContentPath) self.vertPositions = [] for i in range(len(self.charMap)): # vertex 0 self.vertPositions.append(0.0) self.vertPositions.append(0.0) self.vertPositions.append(0.0) # vertex 1 self.vertPositions.append(0.0) self.vertPositions.append(1.0) self.vertPositions.append(0.0) # vertex 2 self.vertPositions.append(1.0) self.vertPositions.append(0.0) self.vertPositions.append(0.0) # vertex 3 self.vertPositions.append(1.0) self.vertPositions.append(1.0) self.vertPositions.append(0.0) drawIndex = 0 self.texCoords = [] for i in self.charMap: cd = self.charMap[i] self.charIndices[i] = drawIndex drawIndex += 4 x = cd.x / 512.0 y = cd.y / 512.0 w = cd.w / 512.0 h = cd.h / 512.0 # vertex 0 self.texCoords.append(x) self.texCoords.append(y) # vertex 1 self.texCoords.append(x) self.texCoords.append(y + h) # vertex 2 self.texCoords.append(x + w) self.texCoords.append(y) # vertex 3 self.texCoords.append(x + w) self.texCoords.append(y + h) def parse(self, filePath): f = open(filePath, "r") # Skip three lines for i in range(3): f.readline() # Get the count count = int(f.readline().split("=")[1]) # Get char info for i in range(count): charData = CharData() tokens = f.readline().split() charData.id = int(tokens[1].split("=")[1]) charData.x = int(tokens[2].split("=")[1]) charData.y = int(tokens[3].split("=")[1]) charData.w = int(tokens[4].split("=")[1]) charData.h = int(tokens[5].split("=")[1]) charData.xOffset = int(tokens[6].split("=")[1]) charData.yOffset = int(tokens[7].split("=")[1]) charData.xAdvance = int(tokens[8].split("=")[1]) self.charMap[chr(charData.id)] = charData f.close() class Text: def __init__(self, font: Font, x: float, y: float, scale: float, text: str): self.font = font self.text = text self.x = x self.y = y self.scale = scale def draw(self): glBindTexture(GL_TEXTURE_2D, self.font.texture) glVertexPointer(3, GL_FLOAT, 0, self.font.vertPositions) glTexCoordPointer(2, GL_FLOAT, 0, self.font.texCoords) cursorX = 0 for i in range(len(self.text)): cd: CharData = self.font.charMap[self.text[i]] glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(self.x + cursorX + cd.xOffset * self.scale, self.y + cd.yOffset * self.scale, 0) glScalef(cd.w * self.scale, cd.h * self.scale, 1) glDrawArrays(GL_TRIANGLE_STRIP, self.font.charIndices[chr(cd.id)], 4) cursorX += cd.xAdvance * self.scale def setText(self, text: str): self.text = text def createTexture(path): image = Image.open(path) data = image.convert("RGBA").tobytes() glEnable(GL_TEXTURE_2D) texture = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data) glBindTexture(GL_TEXTURE_2D, 0) return texture def main(): if SDL_Init(SDL_INIT_VIDEO) < 0: fatalError(SDL_GetError()) winW = 350 winH = 350 window = SDL_CreateWindow( b"OpenGL1, SDL2, Python", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, winW, winH, SDL_WINDOW_OPENGL) if not window: fatalError(SDL_GetError()) context = SDL_GL_CreateContext(window) if not context: fatalError("Failed to create the SDL_GL context") glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) glClearColor(0.2, 0.2, 0.2, 1.0) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0, winW, winH, 0, -100, 100) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY) vertPositions = np.array([ -0.5, -0.5, 0, -0.5, 0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0 ], dtype=np.float32) texCoords = np.array([ 0, 0, 0, 1, 1, 0, 1, 1 ], dtype=np.float32) marioFontTexture = createTexture("assets/fonts/super-plumber-brothers-y00v.png") marioFont = Font("assets/fonts/super-plumber-brothers-y00v.fnt", marioFontTexture) title = Text(marioFont, 40, 50, 0.5, "Hello, Super Mario!") comicFontTexture = createTexture("assets/fonts/comic71.png") comicFont = Font("assets/fonts/comic71.fnt", comicFontTexture) secondsText = Text(comicFont, 40, 200, 0.5, "seconds = 0") marioIconTexture = createTexture("assets/sprites/mario-icon.png") lastTime = SDL_GetTicks() seconds = 0.0 event = SDL_Event() running = True while running: while SDL_PollEvent(ctypes.byref(event)) != 0: if event.type == SDL_QUIT: running = False startTicks = SDL_GetTicks() glClear(GL_COLOR_BUFFER_BIT) title.draw() currentTime = SDL_GetTicks() deltaTime = (currentTime - lastTime) / 1000.0 lastTime = currentTime seconds += deltaTime secondsText.setText("seconds = " + str(seconds)) secondsText.draw() glBindTexture(GL_TEXTURE_2D, marioIconTexture) glVertexPointer(3, GL_FLOAT, 0, vertPositions) glTexCoordPointer(2, GL_FLOAT, 0, texCoords) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(175, 150, 0) glScalef(100, 100, 1) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) SDL_GL_SwapWindow(window) # Limit the FPS to the max FPS frameTicks = SDL_GetTicks() - startTicks if 1000.0 / maxFPS > frameTicks: SDL_Delay(int(1000.0 / maxFPS - frameTicks)) SDL_GL_DeleteContext(context) SDL_DestroyWindow(window) SDL_Quit() return 0 if __name__ == "__main__": sys.exit(main())
-
@Michele-Rossi said in Would you ever build a 3D Endless Runner Mobile Game with Qt? and if no why?:
Would you be so kind to share your thought on which kind of "tooling for the job" Qt would be missing today? Would you be able to point concrete examples?
I did:
You don't have a tool on hand to wire shaders, build materials, modify a render graph, etc.
... but I have the creeping suspicion that we are talking about different things. I was specifically talking about Qt3D, which is a module that was developed by KDAB. Whereas I imagine you're soliciting opinions on Qt Quick3D (and by extension Qt DS), which were developed by the TQtC.
As mentioned I have no opinion on the latter, as I have not used them, and probably I never will.