def MouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) """ if self.mouseJoint != None: return # Create a mouse joint on the selected body (assuming it's dynamic) # Make a small box. aabb = box2d.b2AABB() d = box2d.b2Vec2(0.001, 0.001) aabb.lowerBound = p - d aabb.upperBound = p + d # Query the world for overlapping shapes. body = None k_maxCount = 10 # maximum amount of shapes to return (count, shapes) = self.world.Query(aabb, k_maxCount) for shape in shapes: shapeBody = shape.GetBody() if shapeBody.IsStatic() == False and shapeBody.GetMass() > 0.0: if shape.TestPoint(shapeBody.GetXForm(), p): # is it inside? body = shapeBody break if body: md = box2d.b2MouseJointDef() md.body1 = self.world.GetGroundBody() md.body2 = body md.target = p md.maxForce= 1000.0 * body.GetMass() self.mouseJoint = self.world.CreateJoint(md).getAsType() body.WakeUp()
def update_shapes(world): for body in get_bodies(world): v = body.GetLinearVelocity() if body.IsSleeping() or v.LengthSquared() < 0.2: i = body.GetWorldVector(box2d.b2Vec2(box2d.b2Random(-200, 200), box2d.b2Random(-200, 200))) p = body.GetWorldPoint(box2d.b2Vec2(0.0, 0.0)) body.ApplyImpulse(i, p)
def __init__(self): # Pygame Initialization pygame.init() caption= "Python Box2D Testbed - " + self.name pygame.display.set_caption(caption) self.screen = pygame.display.set_mode( (640,480) ) self.screenSize = box2d.b2Vec2(*self.screen.get_size()) self.font = pygame.font.Font(None, 15) # GUI Initialization self.gui_app = gui.App() self.gui_table=fwGUI(self.settings) container = gui.Container(align=1,valign=-1) container.add(self.gui_table,0,0) self.gui_app.init(container) # Box2D Initialization self.worldAABB.lowerBound.Set(-200.0, -100.0) self.worldAABB.upperBound.Set( 200.0, 200.0) gravity = box2d.b2Vec2(0.0, -10.0) doSleep = True self.world = box2d.b2World(self.worldAABB, gravity, doSleep) self.destructionListener = fwDestructionListener() self.boundaryListener = fwBoundaryListener() self.contactListener = fwContactListener() self.debugDraw = fwDebugDraw() self.debugDraw.surface = self.screen self.destructionListener.test = self self.boundaryListener.test = self self.contactListener.test = self self.world.SetDestructionListener(self.destructionListener) self.world.SetBoundaryListener(self.boundaryListener) self.world.SetContactListener(self.contactListener) self.world.SetDebugDraw(self.debugDraw) self.updateCenter()
def LaunchBomb(self): """ Create a new bomb and launch it at the testbed. A bomb is a simple circle which has a random position and velocity. """ if self.bomb: self.world.DestroyBody(self.bomb) self.bomb = None bd = box2d.b2BodyDef() bd.allowSleep = True bd.position.Set(box2d.b2Random(-15.0, 15.0), 30.0) bd.isBullet = True self.bomb = self.world.CreateBody(bd) self.bomb.SetLinearVelocity(-5.0 * bd.position) sd = box2d.b2CircleDef() sd.radius = 0.3 sd.density = 20.0 sd.restitution = 0.1 self.bomb.CreateShape(sd) self.bomb.SetMassFromShapes()
def checkEvents(self): """ Check for pygame events (mainly keyboard/mouse events). Passes the events onto the GUI also. """ for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): return False elif event.type == KEYDOWN: self._Keyboard_Event(event.key) elif event.type == MOUSEBUTTONDOWN: p = self.ConvertScreenToWorld(*event.pos) if event.button == 1: # left self.MouseDown( p ) elif event.button == 2: #middle pass elif event.button == 3: #right self.rMouseDown = True elif event.button ==4: self.viewZoom *= 1.1 self.updateCenter() elif event.button == 5: self.viewZoom /= 1.1 self.updateCenter() elif event.type == MOUSEBUTTONUP: if event.button == 3: #right self.rMouseDown = False else: self.MouseUp() elif event.type == MOUSEMOTION: p = self.ConvertScreenToWorld(*event.pos) self.MouseMove(p) if self.rMouseDown: self.viewCenter -= box2d.b2Vec2(event.rel[0], -event.rel[1]) self.updateCenter() self.gui_app.event(event) #Pass the event to the GUI return True
def ConvertScreenToWorld(self, x, y): """ Return a b2Vec2 in world coordinates of the passed in screen coordinates x, y """ return box2d.b2Vec2((x + self.viewOffset.x) / self.viewZoom, ((self.screenSize.y - y + self.viewOffset.y) / self.viewZoom))
def Step(self, settings): """ The main physics step. Takes care of physics drawing (callbacks are executed after the world.Step() ) and drawing additional information. """ # Update the settings based on the GUI self.gui_table.updateSettings(settings) # Don't do anything if the setting's Hz are <= 0 if settings.hz > 0.0: timeStep = 1.0 / settings.hz else: timeStep = 0.0 # If paused, display so if settings.pause: if settings.singleStep: settings.singleStep=False else: timeStep = 0.0 self.DrawString(5, self.textLine, "****PAUSED****") self.textLine += 15 # Set the flags based on what the settings show (uses a bitwise or mask) flags = 0 if settings.drawShapes: flags |= box2d.b2DebugDraw.e_shapeBit if settings.drawJoints: flags |= box2d.b2DebugDraw.e_jointBit if settings.drawCoreShapes: flags |= box2d.b2DebugDraw.e_coreShapeBit if settings.drawAABBs: flags |= box2d.b2DebugDraw.e_aabbBit if settings.drawOBBs: flags |= box2d.b2DebugDraw.e_obbBit if settings.drawPairs: flags |= box2d.b2DebugDraw.e_pairBit if settings.drawCOMs: flags |= box2d.b2DebugDraw.e_centerOfMassBit self.debugDraw.SetFlags(flags) # Set the other settings that aren't contained in the flags self.world.SetWarmStarting(settings.enableWarmStarting) self.world.SetPositionCorrection(settings.enablePositionCorrection) self.world.SetContinuousPhysics(settings.enableTOI) # Reset the collision points self.points = [] # Tell Box2D to step self.world.Step(timeStep, settings.iterationCount) self.world.Validate() # If the bomb is frozen, get rid of it. if self.bomb and self.bomb.IsFrozen(): self.world.DestroyBody(self.bomb) self.bomb = None if settings.drawStats: self.DrawString(5, self.textLine, "proxies(max) = %d(%d), pairs(max) = %d(%d)" % ( self.world.GetProxyCount(), box2d.b2_maxProxies, self.world.GetPairCount(), box2d.b2_maxPairs) ) self.textLine += 15 self.DrawString(5, self.textLine, "bodies/contacts/joints = %d/%d/%d" % (self.world.GetBodyCount(), self.world.GetContactCount(), self.world.GetJointCount())) self.textLine += 15 self.DrawString(5, self.textLine, "hz %d iterations %d" % (settings.hz, settings.iterationCount)) self.textLine += 15 #self.DrawString(5, self.textLine, "heap bytes = %d" % box2d.b2_byteCount) # not wrapped? #self.textLine += 15 if settings.drawFPS: #python version only self.DrawString(5, self.textLine, "FPS %d" % self.fps) self.textLine += 15 # If there's a mouse joint, draw the connection between the object and the current pointer position. if self.mouseJoint: body = self.mouseJoint.GetBody2() p1 = body.GetWorldPoint(self.mouseJoint.m_localAnchor) p2 = self.mouseJoint.m_target self.debugDraw.DrawPoint(p1, settings.pointSize, box2d.b2Color(0,1.0,0)) self.debugDraw.DrawPoint(p2, settings.pointSize, box2d.b2Color(0,1.0,0)) self.debugDraw.DrawSegment(p1, p2, box2d.b2Color(0.8,0.8,0.8)) # Draw each of the contact points in different colors. if self.settings.drawContactPoints: #k_impulseScale = 0.1 k_axisScale = 0.3 for point in self.points: if point.state == fwContactTypes.contactAdded: self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.3, 0.95, 0.3)) elif point.state == fwContactTypes.contactPersisted: self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.3, 0.3, 0.95)) else: #elif point.state == fwContactTypes.contactRemoved: self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.95, 0.3, 0.3)) if settings.drawContactNormals: p1 = point.position p2 = p1 + k_axisScale * point.normal self.debugDraw.DrawSegment(p1, p2, box2d.b2Color(0.4, 0.9, 0.4))
def main(): # gui initialization screen = pygame.display.set_mode((width, height)) caption = "Python Box2D Testbed Demos" pygame.display.set_caption(caption) theme = gui.Theme("default") app = gui.Desktop(theme=theme) app.connect(gui.QUIT, app.quit, None) main = gui.Container(width=width, height=height) main.add(gui.Label("Box2D Testbed Demos", cls="h1"), 20, 20) list_size = (width / 2, height / 2) list_pos = (width / 2 - list_size[0] / 2, height / 2 - list_size[1] / 2) demolist = gui.List(width=list_size[0], height=list_size[1]) main.add(demolist, list_pos[0], list_pos[1]) add_demos(demolist) buttonw = list_size[0] / 2 - 20 bottom = list_pos[1] + list_size[1] + 20 b = gui.Button("Run", width=buttonw) main.add(b, list_pos[0], bottom) b.connect(gui.CLICK, run_demo, demolist) b = gui.Button("Quit", width=buttonw) main.add(b, list_pos[0] + buttonw + 30, bottom) b.connect(gui.CLICK, lambda x: pygame.event.post(pygame.event.Event(pygame.QUIT)), None) # box2d initialization z = 10 # scale renderer = fwDebugDraw() renderer.surface = screen renderer.viewZoom = z renderer.viewCenter = box2d.b2Vec2(0, 0) renderer.width, renderer.height = width, height renderer.viewOffset = renderer.viewCenter - box2d.b2Vec2(width, height) / 2 renderer.SetFlags(box2d.b2DebugDraw.e_shapeBit) renderer.DrawSolidPolygon = lambda a, b, c: 0 renderer.DrawPolygon = lambda a, b, c: 0 worldAABB = box2d.b2AABB() worldAABB.lowerBound.Set(-100.0, -100.0) worldAABB.upperBound.Set(100.0, 100.0) gravity = box2d.b2Vec2(0.0, -10.0) world = box2d.b2World(worldAABB, gravity, True) world.SetDebugDraw(renderer) bd = box2d.b2BodyDef() bd.position.Set(0.0, 0.0) ground = world.CreateBody(bd) # the borders and the world shapes for the file listing, etc. sd = box2d.b2PolygonDef() sd.SetAsBox(1, height / z, box2d.b2Vec2(-width / (2 * z) - 1, 0), 0) ground.CreateShape(sd) sd.SetAsBox(1, height / z, box2d.b2Vec2(width / (2 * z) + 1, 0), 0) ground.CreateShape(sd) sd.SetAsBox(width / z, 1, box2d.b2Vec2(0, -height / (2 * z) - 1), 0) ground.CreateShape(sd) sd.SetAsBox(width / z, 1, box2d.b2Vec2(0, height / (2 * z) + 1), 0) ground.CreateShape(sd) sd.SetAsBox(list_size[0] / (2 * z), list_size[1] / (2 * z)) ground.CreateShape(sd) for i in range(10): bd = box2d.b2BodyDef() bd.allowSleep = True bd.position.Set( box2d.b2Random(-width / (2 * z), width / (2 * z)), box2d.b2Random(-height / (2 * z), height / (2 * z)) ) bd.isBullet = True bomb = world.CreateBody(bd) bomb.SetLinearVelocity(-5.0 * bd.position) sd = box2d.b2CircleDef() sd.radius = 1 sd.density = 1.0 sd.restitution = 0.7 bomb.CreateShape(sd) bomb.SetMassFromShapes() app.init(main) main_loop(world, screen, demolist, app)