text: from panda3d.core import CollisionNode, CollisionBox, CollisionSphere, CollisionPolygon
  from panda3d.core import NodePath
  from ursina.vec3 import Vec3
  
  
  class Collider(NodePath):
      def __init__(self):
          super().__init__('box_collider')
  
      def show(self):
          self.visible = True
  
      def hide(self):
          self.visible = False
  
      def remove(self):
          self.node_path.removeNode()
  
      @property
      def visible(self):
          return self._visible
  
      @visible.setter
      def visible(self, value):
          if value:
              self.node_path.show()
          else:
              self.node_path.hide()
              pass
  
  
  class BoxCollider(Collider):
      def __init__(self, entity, center=(0,0,0), size=(1,1,1)):
          super().__init__()
          size = [e/2 for e in size]
          size = [max(0.001, e) for e in size] # collider needs to have thickness
          self.shape = CollisionBox(Vec3(center[0], center[1], center[2]), size[0], size[1], size[2])
          # self.remove()
          self.collision_node = CollisionNode('CollisionNode')
          self.node_path = entity.attachNewNode(self.collision_node)
          self.node_path.node().addSolid(self.shape)
          self.visible = False
          # self.node_path.show()
          # for some reason self.node_path gets removed after this and can't be shown.
  
  class SphereCollider(Collider):
      def __init__(self, entity, center=(0,0,0), radius=.5):
          super().__init__()
          self.shape = CollisionSphere(center[0], center[1], center[2], radius)
          self.node_path = entity.attachNewNode(CollisionNode('CollisionNode'))
          self.node_path.node().addSolid(self.shape)
          self.visible = False
  
  
  class MeshCollider(Collider):
      def __init__(self, entity, mesh=None, center=(0,0,0)):
          super().__init__()
          center = Vec3(center)
          if mesh == None and entity.model:
              print('auto gen mesh colider from entity mesh')
              mesh = entity.model
  
          self.node_path = entity.attachNewNode(CollisionNode('CollisionNode'))
          node = self.node_path.node()
  
          if mesh.triangles:
              for tri in mesh.triangles:
                  if len(tri) == 3:
                      shape = CollisionPolygon(
                          Vec3(mesh.vertices[tri[0]]) + center,
                          Vec3(mesh.vertices[tri[1]]) + center,
                          Vec3(mesh.vertices[tri[2]]) + center)
                      node.addSolid(shape)
                  elif len(tri) == 4:
                      shape = CollisionPolygon(
                          Vec3(mesh.vertices[tri[0]]) + center,
                          Vec3(mesh.vertices[tri[1]]) + center,
                          Vec3(mesh.vertices[tri[2]]) + center)
                      node.addSolid(shape)
                      shape = CollisionPolygon(
                          Vec3(mesh.vertices[tri[2]]) + center,
                          Vec3(mesh.vertices[tri[3]]) + center,
                          Vec3(mesh.vertices[tri[0]]) + center)
                      node.addSolid(shape)
  
          elif mesh.mode == 'triangle':
              for i in range(0, len(mesh.vertices), 3):
                  shape = CollisionPolygon(
                      Vec3(mesh.vertices[i]) + center,
                      Vec3(mesh.vertices[i+1]) + center,
                      Vec3(mesh.vertices[i+2]) + center
                      )
                  node.addSolid(shape)
  
          else:
              print('error: mesh collider does not support', mesh.mode, 'mode')
  
  
          self.visible = False
  
  
  
  
  if __name__ == '__main__':
      from ursina import *
      app = Ursina()
  
      e = Entity(model='sphere', x=2)
      e.collider = 'box'      # add BoxCollider based on entity's bounds.
      e.collider = 'sphere'   # add SphereCollider based on entity's bounds.
      e.collider = 'mesh'     # add MeshCollider based on entity's bounds.
  
      e.collider = BoxCollider(e, center=Vec3(0,0,0), size=Vec3(1,1,1))   # add BoxCollider at custom positions and size.
      e.collider = SphereCollider(e, center=Vec3(0,0,0), radius=.75)      # add SphereCollider at custom positions and size.
      e.collider = MeshCollider(e, mesh=e.model, center=Vec3(0,0,0))      # add MeshCollider with custom shape and center.
  
      m = Prismatoid(base_shape=Circle(6), thicknesses=(1, .5))
      e = Button(parent=scene, model=m, collider='mesh', color=color.red, highlight_color=color.yellow)
  
      EditorCamera()
      app.run()
  