Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Game Development
  4. How to use the Box2D's b2Draw class in PyQt6 with OpenGL3? DrawSegment is not called
Forum Updated to NodeBB v4.3 + New Features

How to use the Box2D's b2Draw class in PyQt6 with OpenGL3? DrawSegment is not called

Scheduled Pinned Locked Moved Solved Game Development
11 Posts 2 Posters 1.2k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • 8 Offline
    8 Offline
    8Observer8
    wrote on 13 Aug 2022, 21:28 last edited by 8Observer8 1 Oct 2023, 14:04
    #1

    I am trying to draw colliders of Box2D. Now I have only physics in this example without graphics for simplicity. The DrawSegment() method must be called to print hello. I inherited the DebugDrawer class from the b2Draw class:

    debug_drawer.py

    from Box2D import b2Draw
    
    
    class DebugDrawer(b2Draw):
    
        def DrawSegment(self, p1, p2, color):
            print("hello")
    
        def DrawSolidPolygon(self, vertices, color):
            pass
        def DrawPoint(self, p, size, color):
            pass
        def DrawPolygon(self, vertices, color):
            pass
        def DrawCircle(self, center, radius, color, drawwidth=1):
            pass
        def DrawSolidCircle(self, center, radius, axis, color):
            pass
        def DrawTransform(self, xf):
            pass
    

    I created one object with the box shape. I have the animationLoop() method that I call with timer. Inside of the animationLoop() method I the self.world.Step() method and I call the paintGL() method by calling the self.update() method. Inside of the paintGL() method I call the self.world.DrawDebugData() method. I expect that the DrawSegment() will be called but it does not happen.

    widget.py

    
    from Box2D import (b2_staticBody, b2Body, b2BodyDef, b2FixtureDef,
                       b2PolygonShape, b2Vec2, b2World)
    from OpenGL import GL as gl
    from PyQt6.QtCore import QElapsedTimer, QSize, QTimer
    from PyQt6.QtOpenGLWidgets import QOpenGLWidget
    
    from debug_drawer import DebugDrawer
    
    
    class Widget(QOpenGLWidget):
    
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Box2D, OpenGL3, PyQt6")
            self.setFixedSize(QSize(500, 500))
            self.deltaTime = 0
    
            self.WORLD_SCALE = 30.0
            self.world = b2World(gravity=b2Vec2(0.0, 9.8))
    
        def initializeGL(self):
            gl.glClearColor(0.2, 0.2, 0.2, 1.0)
            gl.glEnable(gl.GL_DEPTH_TEST)
    
            self.debugDrawer = DebugDrawer()
            self.world.renderer = self.debugDrawer
    
            self.debugDrawer.flags = { 'drawShapes': True,
                'drawJoints': True, 'drawAABBs': True, 'drawPairs': True }
            # print(self.debugDrawer.flags)
    
            shape = b2PolygonShape()
            shape.SetAsBox(50.0 / self.WORLD_SCALE, 50.0 / self.WORLD_SCALE)
    
            bodyDef = b2BodyDef()
            bodyDef.type = b2_staticBody
    
            self.body: b2Body = self.world.CreateBody(bodyDef)
            fixtureDef = b2FixtureDef()
            fixtureDef.shape = shape
            fixtureDef.density = 2
            self.body.CreateFixture(fixtureDef)
    
            self.timer = QTimer()
            self.timer.timeout.connect(self.animationLoop)
            self.elapsedTimer = QElapsedTimer()
            self.elapsedTimer.start()
            self.timer.start(1000//60)
        
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.world.DrawDebugData()
        
        def resizeGL(self, w: int, h: int):
            gl.glViewport(0, 0, w, h)
    
        def animationLoop(self):
            self.deltaTime = self.elapsedTimer.elapsed() / 1000.0
            self.elapsedTimer.restart()
            self.world.Step(self.deltaTime, 8, 3)
            self.update()
    

    main.py

    import sys
    
    from PyQt6.QtCore import Qt
    from PyQt6.QtGui import QSurfaceFormat
    from PyQt6.QtWidgets import QApplication
    
    from widget import Widget
    
    
    def main():
        QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
        app = QApplication(sys.argv)
    
        format = QSurfaceFormat()
        format.setSamples(8)
        
        w = Widget()
        w.setFormat(format)
        w.show()
        sys.exit(app.exec())
    
    if __name__ == "__main__":
        main()
    

    Plan:

    • Add restart button
    1 Reply Last reply
    0
    • 8 Offline
      8 Offline
      8Observer8
      wrote on 15 Aug 2022, 12:13 last edited by 8Observer8
      #8

      I have to use DrawPolygon to draw collider segments when I use blocks to draw borders around gameobjects. DrawSegment() will be called when b2EdgeShape is instantiated:

              edgeShape = b2EdgeShape()
              edgeShape.vertices = [(0.0, 0.0), (1.0, 0.0)]
              self.edgeBody: b2Body = self.world.CreateBody(bodyDef)
              edgeFixtureDef = b2FixtureDef()
              edgeFixtureDef.shape = edgeShape
              edgeFixtureDef.density = 2
              self.edgeBody.CreateFixture(edgeFixtureDef)
      
      1 Reply Last reply
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 13 Aug 2022, 21:59 last edited by
        #2

        Hi,

        From a quick look at the repo, and if I understood correctly your question, it seems you would need to call SetDebugDraw from the b2World class to make use of your class.

        However there's a bug opened about that method so it's not really clear if it's possible.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        8 1 Reply Last reply 14 Aug 2022, 09:06
        0
        • S SGaist
          13 Aug 2022, 21:59

          Hi,

          From a quick look at the repo, and if I understood correctly your question, it seems you would need to call SetDebugDraw from the b2World class to make use of your class.

          However there's a bug opened about that method so it's not really clear if it's possible.

          8 Offline
          8 Offline
          8Observer8
          wrote on 14 Aug 2022, 09:06 last edited by 8Observer8
          #3

          @SGaist said in How to use the Box2D's b2Draw class in PyQt6 with OpenGL3? DrawSegment is not called:

          However there's a bug opened about that method so it's not really clear if it's possible.

          This issue was opened by me. There is self.world.renderer = self.debugDrawer instead of self.world.SetDebugDraw(self.debugDrawer).

          1 Reply Last reply
          0
          • S Offline
            S Offline
            SGaist
            Lifetime Qt Champion
            wrote on 14 Aug 2022, 18:29 last edited by
            #4

            These are python bindings, so setting render like that might not work unless there is explicit support for that through the bindings.

            You can add new attributes to python objects but that does not mean it will translate to the underlying C++ object.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • 8 Offline
              8 Offline
              8Observer8
              wrote on 14 Aug 2022, 20:48 last edited by 8Observer8
              #5

              This property exists in IntelliSense:

              93d5b8ff-7d60-4034-8f15-321f324e188d-image.png

              At first I found it in the documentation: https://github.com/pybox2d/pybox2d/wiki/manual#drawing

              You can see there this example of usage:

              draw = MyDraw()
              world = b2World()
              world.renderer = draw
              

              DrawPolygon() works in my example. It prints hello:

              from Box2D import b2Draw
              
              
              class DebugDrawer(b2Draw):
              
                  def DrawSegment(self, p1, p2, color):
                      print("hello")
              
                  def DrawPolygon(self, vertices, color):
                      print("hello")
              
                  def DrawSolidPolygon(self, vertices, color):
                      pass
                  def DrawPoint(self, p, size, color):
                      pass
                  def DrawCircle(self, center, radius, color, drawwidth=1):
                      pass
                  def DrawSolidCircle(self, center, radius, axis, color):
                      pass
                  def DrawTransform(self, xf):
                      pass
              

              But DrawSegment does not work and I do not understand why.

              1 Reply Last reply
              0
              • 8 Offline
                8 Offline
                8Observer8
                wrote on 14 Aug 2022, 20:58 last edited by 8Observer8
                #6

                I can print polygons like this:

                class DebugDrawer(b2Draw):
                
                    def DrawSegment(self, p1, p2, color):
                        print("hello")
                
                    def DrawPolygon(self, vertices, color):
                        print("Polygon. Begin")
                        print(vertices[0][0] * 30, vertices[0][1] * 30)
                        print(vertices[1][0] * 30, vertices[1][1] * 30)
                        print(vertices[2][0] * 30, vertices[2][1] * 30)
                        print(vertices[3][0] * 30, vertices[3][1] * 30)
                        print("Polygon. End")
                

                Output:

                Polygon. Begin
                -53.29999923706055 -53.29999923706055
                53.29999923706055 -53.29999923706055
                53.29999923706055 53.29999923706055
                -53.29999923706055 53.29999923706055
                Polygon. End
                

                But I need segments. Why DrawSegment does not work?

                1 Reply Last reply
                0
                • 8 Offline
                  8 Offline
                  8Observer8
                  wrote on 14 Aug 2022, 21:05 last edited by
                  #7

                  Temporary I can get segments from polygon.

                  1 Reply Last reply
                  0
                  • 8 Offline
                    8 Offline
                    8Observer8
                    wrote on 15 Aug 2022, 12:13 last edited by 8Observer8
                    #8

                    I have to use DrawPolygon to draw collider segments when I use blocks to draw borders around gameobjects. DrawSegment() will be called when b2EdgeShape is instantiated:

                            edgeShape = b2EdgeShape()
                            edgeShape.vertices = [(0.0, 0.0), (1.0, 0.0)]
                            self.edgeBody: b2Body = self.world.CreateBody(bodyDef)
                            edgeFixtureDef = b2FixtureDef()
                            edgeFixtureDef.shape = edgeShape
                            edgeFixtureDef.density = 2
                            self.edgeBody.CreateFixture(edgeFixtureDef)
                    
                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on 15 Aug 2022, 19:01 last edited by
                      #9

                      Glad you found out and thanks for sharing !

                      It would be nice a have a complete example that shows how to use a debug drawer provided by Box2D. Did you consider submitting one ?

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      8 1 Reply Last reply 8 Jan 2023, 16:27
                      1
                      • S SGaist
                        15 Aug 2022, 19:01

                        Glad you found out and thanks for sharing !

                        It would be nice a have a complete example that shows how to use a debug drawer provided by Box2D. Did you consider submitting one ?

                        8 Offline
                        8 Offline
                        8Observer8
                        wrote on 8 Jan 2023, 16:27 last edited by 8Observer8 1 Aug 2023, 17:15
                        #10

                        @SGaist said in How to use the Box2D's b2Draw class in PyQt6 with OpenGL3? DrawSegment is not called:

                        It would be nice a have a complete example that shows how to use a debug drawer provided by Box2D. Did you consider submitting one ?

                        I wrote this simple example using OpenGL version 1 for simplicity:

                        debug-drawer-opengl1-pyqt6.gif

                        PyBox2D currently works at most with Python version 3.8, as written on GitHub:

                        Recent builds should be available for Windows, Linux, and OS X, with Python 3.6, 3.7, and 3.8.

                        You must have PyQt6, PyOpenGL, and PyBox2D installed to run this example:

                        pip install PyQt6 PyOpenGL Box2D

                        main.py

                        import sys
                        
                        from PyQt6.QtCore import Qt
                        from PyQt6.QtGui import QSurfaceFormat
                        from PyQt6.QtWidgets import QApplication
                        
                        from opengl_widget import OpenGLWidget
                        
                        
                        def main():
                            QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
                            app = QApplication(sys.argv)
                        
                            format = QSurfaceFormat()
                            format.setSamples(8)
                        
                            w = OpenGLWidget()
                            w.setFormat(format)
                            w.show()
                            sys.exit(app.exec())
                        
                        if __name__ == "__main__":
                            main()
                        

                        opengl_widget.py

                        import math
                        
                        from Box2D import (b2_dynamicBody, b2_staticBody, b2Body, b2BodyDef,
                                           b2FixtureDef, b2PolygonShape, b2Vec2, b2World)
                        from OpenGL.GL import *
                        from PyQt6.QtCore import QElapsedTimer, QSize, QTimer
                        from PyQt6.QtOpenGLWidgets import QOpenGLWidget
                        
                        from debug_drawer import DebugDrawer
                        
                        
                        class OpenGLWidget(QOpenGLWidget):
                        
                            def __init__(self):
                                super().__init__()
                                self.setWindowTitle("Box2D, OpenGL1, PyQt6")
                                self.setFixedSize(QSize(400, 400))
                                self.deltaTime = 0
                        
                                self.WORLD_SCALE = 30.0
                                self.world = b2World(gravity=b2Vec2(0.0, -9.8))
                        
                            def initializeGL(self):
                                glClearColor(0.2, 0.2, 0.2, 1.0)
                        
                                self.debugDrawer = DebugDrawer()
                                self.world.renderer = self.debugDrawer
                        
                                self.debugDrawer.flags = { 'drawShapes': True,
                                    'drawJoints': True, 'drawAABBs': True, 'drawPairs': True }
                                # print(self.debugDrawer.flags)
                        
                                boxShape = b2PolygonShape()
                                boxShape.SetAsBox(10 / self.WORLD_SCALE, 10 / self.WORLD_SCALE)
                                boxBodyDef = b2BodyDef()
                                boxBodyDef.type = b2_dynamicBody
                                self.boxBody = self.world.CreateBody(boxBodyDef)
                                boxFixtureDef = b2FixtureDef()
                                boxFixtureDef.shape = boxShape
                                boxFixtureDef.density = 2
                                self.boxBody.CreateFixture(boxFixtureDef)
                                self.boxBody.position = b2Vec2(100 / self.WORLD_SCALE, 100 / self.WORLD_SCALE)
                        
                                groundShape = b2PolygonShape()
                                groundShape.SetAsBox(100 / self.WORLD_SCALE, 10 / self.WORLD_SCALE)
                                groundBodyDef = b2BodyDef()
                                groundBodyDef.type = b2_staticBody
                                groundBody = self.world.CreateBody(groundBodyDef)
                                groundFixtureDef = b2FixtureDef()
                                groundFixtureDef.shape = groundShape
                                groundFixtureDef.density = 2
                                groundBody.CreateFixture(groundFixtureDef)
                                groundBody.position = b2Vec2(100 / self.WORLD_SCALE, 0 / self.WORLD_SCALE)
                        
                                platformShape = b2PolygonShape()
                                platformShape.SetAsBox(30 / self.WORLD_SCALE, 5 / self.WORLD_SCALE)
                                platformBodyDef = b2BodyDef()
                                platformBodyDef.type = b2_staticBody
                                platformBody = self.world.CreateBody(platformBodyDef)
                                platformFixtureDef = b2FixtureDef()
                                platformFixtureDef.shape = platformShape
                                boxFixtureDef.density = 2
                                platformBody.CreateFixture(platformFixtureDef)
                                platformBody.position = b2Vec2(100 / self.WORLD_SCALE, 50 / self.WORLD_SCALE)
                                platformBody.angle = math.radians(-10)
                        
                                self.timer = QTimer()
                                self.timer.timeout.connect(self.animationLoop)
                                self.elapsedTimer = QElapsedTimer()
                                self.elapsedTimer.start()
                                self.timer.start(1000//60)
                        
                            def paintGL(self):
                                glClear(GL_COLOR_BUFFER_BIT)
                                self.world.DrawDebugData()
                        
                            def resizeGL(self, w, h):
                                glViewport(0, 0, w, h)
                                glMatrixMode(GL_PROJECTION)
                                glLoadIdentity()
                                glOrtho(0, 200, 0, 200, -10, 10)
                        
                            def animationLoop(self):
                                self.deltaTime = self.elapsedTimer.elapsed() / 1000.0
                                self.elapsedTimer.restart()
                                self.world.Step(self.deltaTime, 8, 3)
                                self.update()
                        

                        debug_drawer.py

                        from Box2D import b2Draw
                        from OpenGL.GL import *
                        
                        
                        class DebugDrawer(b2Draw):
                        
                            def DrawSolidPolygon(self, vertexes, color):
                                # print("Polygon. Begin")
                                # print(vertexes[0][0] * 30, vertexes[0][1] * 30)
                                # print(vertexes[1][0] * 30, vertexes[1][1] * 30)
                                # print(vertexes[2][0] * 30, vertexes[2][1] * 30)
                                # print(vertexes[3][0] * 30, vertexes[3][1] * 30)
                                # print("Polygon. End")
                        
                                glLineWidth(3)
                        
                                glBegin(GL_LINES)
                                glColor3f(color.r, color.g, color.b)
                        
                                glVertex2f(vertexes[0][0] * 30, vertexes[0][1] * 30)
                                glVertex2f(vertexes[1][0] * 30, vertexes[1][1] * 30)
                        
                                glVertex2f(vertexes[1][0] * 30, vertexes[1][1] * 30)
                                glVertex2f(vertexes[2][0] * 30, vertexes[2][1] * 30)
                        
                                glVertex2f(vertexes[2][0] * 30, vertexes[2][1] * 30)
                                glVertex2f(vertexes[3][0] * 30, vertexes[3][1] * 30)
                                
                                glVertex2f(vertexes[3][0] * 30, vertexes[3][1] * 30)
                                glVertex2f(vertexes[0][0] * 30, vertexes[0][1] * 30)
                                glEnd()
                        
                            def DrawPolygon(self, vertexes, color):
                                pass
                            def DrawSegment(self, p1, p2, color):
                                pass
                            def DrawPoint(self, p, size, color):
                                pass
                            def DrawCircle(self, center, radius, color, drawwidth=1):
                                pass
                            def DrawSolidCircle(self, center, radius, axis, color):
                                pass
                            def DrawTransform(self, xf):
                                pass
                        
                        1 Reply Last reply
                        1
                        • 8 Offline
                          8 Offline
                          8Observer8
                          wrote on 11 Jan 2023, 03:48 last edited by
                          #11

                          Added restart button:

                          edit-gravity-debug-drawer-opengl1-pyqt6.gif

                          Source code: https://github.com/8Observer8/edit-gravity-debug-drawer-opengl1-pyqt6

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved