def _add_side_walk2bullet(self, lane_start, lane_end, middle, radius=0.0, direction=0): length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1]) body_node = BulletRigidBodyNode(BodyName.Side_walk) body_node.setActive(False) body_node.setKinematic(False) body_node.setStatic(True) side_np = self.side_walk_node_path.attachNewNode(body_node) shape = BulletBoxShape(Vec3(1 / 2, 1 / 2, 1 / 2)) body_node.addShape(shape) body_node.setIntoCollideMask(BitMask32.bit(Block.LANE_LINE_COLLISION_MASK)) self.dynamic_nodes.append(body_node) if radius == 0: factor = 1 else: if direction == 1: factor = (1 - self.SIDE_WALK_LINE_DIST / radius) else: factor = (1 + self.SIDE_WALK_WIDTH / radius) * (1 + self.SIDE_WALK_LINE_DIST / radius) direction_v = lane_end - lane_start vertical_v = (-direction_v[1], direction_v[0]) / numpy.linalg.norm(direction_v) middle += vertical_v * (self.SIDE_WALK_WIDTH / 2 + self.SIDE_WALK_LINE_DIST) side_np.setPos(panda_position(middle, 0)) theta = -numpy.arctan2(direction_v[1], direction_v[0]) side_np.setQuat(LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2))) side_np.setScale( length * factor, self.SIDE_WALK_WIDTH, self.SIDE_WALK_THICKNESS * (1 + 0.1 * numpy.random.rand()) ) if self.render: side_np.setTexture(self.ts_color, self.side_texture) self.side_walk.instanceTo(side_np)
def setupPhysics(self, radius=None, height=None): if not radius: radius = self.getWidth() if not height: height = self.getHeight() self.notify.debug("setupPhysics(r{0}, h{1}) hitboxData: {2}".format( radius, height, self.hitboxData)) # When the height is passed into BulletCapsuleShape, it's # talking about the height only of the cylinder part. # But what we want is the height of the entire capsule. #height -= (radius * 2) # The middle of the capsule is the origin by default. Push the capsule shape up # so the very bottom of the capsule is the origin. zOfs = (height / 2.0) + radius capsule = BulletCapsuleShape(radius, height) bodyNode = BulletRigidBodyNode('avatarBodyNode') bodyNode.addShape(capsule, TransformState.makePos(Point3(0, 0, zOfs))) bodyNode.setKinematic(True) bodyNode.setPythonTag("avatar", self) BasePhysicsObject.setupPhysics(self, bodyNode, True) self.stopWaterCheck()
def makeVPPhysics(multipart=False): from panda3d.core import TransformState from panda3d.bullet import BulletBoxShape, BulletRigidBodyNode carriage = BulletBoxShape((4.40625, 7.125, 2.75)) tread = BulletBoxShape((1.9, 10.34, 2.75)) legs = BulletBoxShape((3.375, 3.375, 2.1875)) gear = BulletBoxShape((6.72, 6.72, 1.1)) torso = BulletBoxShape((4.44, 3.625, 4.125)) head = BulletBoxShape((2, 2, 2.22)) torsoTrans = TransformState.makePos((0, 0, 13.93)) headTrans = TransformState.makePos((0, 0, 20.28)) bodyNode = BulletRigidBodyNode("VPPhysics") bodyNode.addShape(carriage, TransformState.makePos((0, 0, 2.75))) bodyNode.addShape(tread, TransformState.makePos((6.3, 0, 2.75))) bodyNode.addShape(tread, TransformState.makePos((-6.3, 0, 2.75))) bodyNode.addShape(legs, TransformState.makePos((0, 0, 7.75))) bodyNode.addShape(gear, TransformState.makePos((0, 0, 10.94))) if not multipart: bodyNode.addShape(torso, torsoTrans) bodyNode.addShape(head, headTrans) bodyNode.setKinematic(True) bodyNode.setMass(0.0) if multipart: upperNode = BulletRigidBodyNode("VPPhysics-upper") upperNode.addShape(torso, torsoTrans) upperNode.addShape(head, headTrans) upperNode.setKinematic(True) upperNode.setMass(0.0) if multipart: return [bodyNode, upperNode] return bodyNode
def getPhysBody(self): shape = BulletCylinderShape(0.3925, 1.4, ZUp) body = BulletRigidBodyNode('tntBody') body.addShape(shape) body.setKinematic(True) body.setCcdMotionThreshold(1e-7) body.setCcdSweptSphereRadius(0.3925) return body
def makeBulletBoxColl(node, extents): shape = BulletBoxShape(extents) rbnode = BulletRigidBodyNode(node.getName() + "_bulletBoxColl") rbnode.addShape(shape) rbnode.setKinematic(True) rbnodeNp = node.attachNewNode(rbnode) rbnodeNp.setCollideMask(WallGroup) base.physicsWorld.attachRigidBody(rbnode)
def getPhysBody(self): shape = BulletCylinderShape(0.3925, 1.4, ZUp) body = BulletRigidBodyNode('tntBody') body.addShape(shape) body.setCcdMotionThreshold(1e-7) body.setCcdSweptSphereRadius(0.3925) body.setKinematic(False) body.setMass(5.0) body.setAngularDamping(0.3) body.setLinearDamping(0.8) return body
def load(self): SafeZoneLoader.SafeZoneLoader.load(self, False) self.geom.find('**/ground_center').setBin('ground', 18) self.geom.find('**/ground_sidewalk').setBin('ground', 18) self.geom.find('**/ground').setBin('ground', 18) self.geom.find('**/ground_center_coll').setCollideMask( CIGlobals.FloorGroup) self.geom.find('**/ground_sidewalk_coll').setCollideMask( CIGlobals.FloorGroup) self.geom.find('**/ground_coll').setCollideMask(CIGlobals.FloorGroup) for tree in self.geom.findAllMatches('**/prop_green_tree_*_DNARoot'): tree.wrtReparentTo(hidden) # Make corrected collisions tree.find("**/+BulletRigidBodyNode").removeNode() capsule = BulletCapsuleShape(2.0, 6.0, ZUp) bnode = BulletRigidBodyNode("tree_collision") bnode.addShape(capsule, TransformState.makePos((0, 0, 3.0))) bnode.setKinematic(True) bnode.setIntoCollideMask(CIGlobals.WallGroup) tree.attachNewNode(bnode) self.trees.append(tree) newShadow = loader.loadModel( "phase_3/models/props/drop_shadow.bam") newShadow.reparentTo(tree) newShadow.setScale(1.5) newShadow.setBillboardAxis(2) newShadow.setColor(0, 0, 0, 0.5, 1) #tree.clearModelNodes() #tree.flattenStrong() # Fix bank door trigger bank = self.geom.find('**/*toon_landmark_TT_bank_DNARoot') doorTrigger = bank.find('**/door_trigger*') doorTrigger.setY(doorTrigger.getY() - 1.0) #self.telescope = Actor(self.geom.find('**/*animated_prop_HQTelescopeAnimatedProp*'), copy = 0) #{'chan': 'phase_3.5/models/props/HQ_telescope-chan.bam'}, copy=0) #self.telescope.reparentTo(self.geom.find('**/tb20:toon_landmark_hqTT_DNARoot')) #self.telescope.setPos(1, 0.46, 0) #self.geom.setMaterialOff() water = self.geom.find("**/pond_water") water.removeNode() self.doFlatten()
def getPhysBody(self): bsph = BulletSphereShape(0.6) bcy = BulletCylinderShape(0.25, 0.35, ZUp) body = BulletRigidBodyNode('tntBody') body.addShape( bsph, TransformState.makePosHpr((0.05, 0, 0.43), (86.597, 24.5539, 98.1435))) body.addShape( bcy, TransformState.makePosHpr((0.05, 0.655, 0.35), (86.597, 24.5539, 98.1435))) body.setKinematic(True) body.setCcdMotionThreshold(1e-7) body.setCcdSweptSphereRadius(0.6) return body
def _add_lane_line2bullet( self, lane_start, lane_end, middle, parent_np: NodePath, color: Vec4, line_type: LineType, straight_stripe=False ): length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1]) if length <= 0: return if LineType.prohibit(line_type): node_name = BodyName.Continuous_line else: node_name = BodyName.Stripped_line # add bullet body for it if straight_stripe: body_np = parent_np.attachNewNode(node_name) else: scale = 2 if line_type == LineType.STRIPED else 1 body_node = BulletRigidBodyNode(node_name) body_node.setActive(False) body_node.setKinematic(False) body_node.setStatic(True) body_np = parent_np.attachNewNode(body_node) shape = BulletBoxShape(Vec3(scale / 2, Block.LANE_LINE_WIDTH / 2, Block.LANE_LINE_THICKNESS)) body_np.node().addShape(shape) body_np.node().setIntoCollideMask(BitMask32.bit(Block.LANE_LINE_COLLISION_MASK)) self.dynamic_nodes.append(body_np.node()) # position and heading body_np.setPos(panda_position(middle, 0)) direction_v = lane_end - lane_start theta = -numpy.arctan2(direction_v[1], direction_v[0]) body_np.setQuat(LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2))) if self.render: # For visualization lane_line = self.loader.loadModel(AssetLoader.file_path("models", "box.bam")) lane_line.getChildren().reparentTo(body_np) body_np.setScale(length, Block.LANE_LINE_WIDTH, Block.LANE_LINE_THICKNESS) body_np.set_color(color)
def setupPhysics(self): if not self.NeedsPhysics: return bodyNode = BulletRigidBodyNode(self.uniqueName('avatarBodyNode')) radius = self.getWidth() height = self.getHeight() # - (radius * 2) zOfs = (height / 2.0) + radius capsule = BulletCapsuleShape(radius, height) bodyNode.addShape(capsule, TransformState.makePos(Point3(0, 0, zOfs))) bodyNode.setKinematic(True) bodyNode.setMass(0.0) self.notify.debug("setupPhysics(r{0}, h{1}) hitboxData: {2}".format( radius, height, self.hitboxData)) BasePhysicsObjectAI.setupPhysics(self, bodyNode, True)
def _add_box_body(self, lane_start, lane_end, middle, parent_np: NodePath, line_type): length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1]) if LineType.prohibit(line_type): node_name = BodyName.Continuous_line else: node_name = BodyName.Stripped_line body_node = BulletRigidBodyNode(node_name) body_node.setActive(False) body_node.setKinematic(False) body_node.setStatic(True) body_np = parent_np.attachNewNode(body_node) shape = BulletBoxShape(Vec3(length / 2, Block.LANE_LINE_WIDTH / 2, Block.LANE_LINE_THICKNESS)) body_np.node().addShape(shape) body_np.node().setIntoCollideMask(BitMask32.bit(Block.LANE_LINE_COLLISION_MASK)) self.dynamic_nodes.append(body_np.node()) body_np.setPos(panda_position(middle, 0)) direction_v = lane_end - lane_start theta = -numpy.arctan2(direction_v[1], direction_v[0]) body_np.setQuat(LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2)))
def makeBulletBoundingBoxColl(node): """ Creates and attaches a BulletRigidBodyNode underneath `node` which contains a BulletBoxShape that covers the tight bounds of `node`. Useful for quick prop collisions and such. """ mins = Point3(0) maxs = Point3(0) node.calcTightBounds(mins, maxs) extents = extentsFromMinMax(mins, maxs) tsCenter = TransformState.makePos(centerFromMinMax(mins, maxs)) shape = BulletBoxShape(extents) rbnode = BulletRigidBodyNode(node.getName() + "_bulletBoundingBoxColl") rbnode.addShape(shape, tsCenter) rbnode.setKinematic(True) rbnodeNp = render.attachNewNode(rbnode) rbnodeNp.wrtReparentTo(node) rbnodeNp.setCollideMask(WallGroup) base.physicsWorld.attachRigidBody(rbnode)
class DistributedRestockBarrel(DistributedEntity, DistributedNode): notify = directNotify.newCategory('DistributedRestockBarrel') def __init__(self, cr): DistributedEntity.__init__(self, cr) DistributedNode.__init__(self, cr) NodePath.__init__(self, 'restock_barrel') self.grabSfx = None self.rejectSfx = None self.grabSoundPath = 'phase_4/audio/sfx/SZ_DD_treasure.ogg' self.rejectSoundPath = 'phase_4/audio/sfx/ring_miss.ogg' self.animTrack = None self.barrelScale = 0.5 self.radius = 1.5 self.height = 4.275 self.playSoundForRemoteToons = 1 self.barrel = None self.gagNode = None self.gagModel = None # Collision nodes self.collSphere = None self.collNode = None self.collNodePath = None def load(self): DistributedEntity.load(self) self.setPos(self.cEntity.getOrigin()) self.setHpr(self.cEntity.getAngles()) def announceGenerate(self): DistributedEntity.announceGenerate(self) DistributedNode.announceGenerate(self) self.build() # Build collisions self.collSphere = BulletCylinderShape(self.radius, self.height, ZUp) self.collNode = BulletRigidBodyNode(self.uniqueName('barrelSphere')) self.collNode.setKinematic(True) self.collNode.addShape(self.collSphere, TransformState.makePos(Point3(0, 0, self.height / 2))) self.collNode.setIntoCollideMask(WallGroup) self.collNodePath = self.attachNewNode(self.collNode) base.physicsWorld.attach(self.collNodePath.node()) self.accept('enter' + self.collNodePath.getName(), self.__handleCollision) self.reparentTo(render) def disable(self): DistributedEntity.disable(self) DistributedNode.disable(self) self.ignoreAll() if self.animTrack: self.animTrack.pause() self.animTrack = None return def delete(self): self.gagNode.removeNode() self.barrel.removeNode() base.physicsWorld.remove(self.collNode) self.collNodePath.removeNode() del self.barrel del self.gagNode del self.grabSfx del self.rejectSfx del self.grabSoundPath del self.rejectSoundPath del self.animTrack del self.barrelScale del self.radius del self.height del self.playSoundForRemoteToons del self.gagModel del self.collNode del self.collNodePath del self.collSphere DistributedNode.delete(self) DistributedEntity.delete(self) def setLabel(self, labelId): if labelId == 0: self.gagModel = loader.loadModel('phase_4/models/props/icecream.bam') self.gagModel.reparentTo(self.gagNode) self.gagModel.find('**/p1_2').clearBillboard() self.gagModel.setScale(0.6) self.gagModel.setPos(0, -0.1, -0.1 - 0.6) elif labelId == 1: purchaseModels = loader.loadModel('phase_4/models/gui/purchase_gui.bam') self.gagModel = purchaseModels.find('**/Jar') self.gagModel.reparentTo(self.gagNode) self.gagModel.setScale(3.0) self.gagModel.setPos(0, -0.1, 0) purchaseModels.removeNode() elif labelId < 1000: gagId = labelId - 2 iconName = GagGlobals.InventoryIconByName.get(self.cr.attackMgr.getAttackName(gagId)) invModel = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam').find('**/%s' % iconName) if invModel: self.gagModel = invModel self.gagModel.reparentTo(self.gagNode) self.gagModel.setScale(13.0) self.gagModel.setPos(0, -0.1, 0) else: self.notify.warning('Failed to find gag label %s.' % (str(labelId))) else: # Provided a hood id, the restock barrel will select the model of the # treasure for that playground and use it as the label. hoodName = ZoneUtil.ZoneId2Hood.get(labelId) modelPath = 'phase_4/models/props/icecream.bam' if hoodName is ZoneUtil.DonaldsDreamland: modelPath = 'phase_8/models/props/zzz_treasure.bam' elif hoodName is ZoneUtil.TheBrrrgh: modelPath = 'phase_8/models/props/snowflake_treasure.bam' elif hoodName is ZoneUtil.MinniesMelodyland: modelPath = 'phase_6/models/props/music_treasure.bam' elif hoodName is ZoneUtil.DaisyGardens: modelPath = 'phase_8/models/props/flower_treasure.bam' elif hoodName is ZoneUtil.DonaldsDock: modelPath = 'phase_6/models/props/starfish_treasure.bam' self.gagModel = loader.loadModel(modelPath) self.gagModel.reparentTo(self.gagNode) self.gagModel.find('**/p1_2').clearBillboard() self.gagModel.setScale(0.6) self.gagModel.setPos(0, -0.1, -0.7) def __handleCollision(self, _ = None): self.sendUpdate('requestGrab', []) def setGrab(self, avId): local = (avId == base.localAvatar.getDoId()) if local: self.ignore(self.uniqueName('enterbarrelSphere')) self.barrel.setColorScale(0.5, 0.5, 0.5, 1) if self.playSoundForRemoteToons or local: base.playSfx(self.grabSfx) if self.animTrack: self.animTrack.finish() self.animTrack = None self.animTrack = Sequence( LerpScaleInterval(self.barrel, 0.2, 1.1 * self.barrelScale, blendType='easeInOut'), LerpScaleInterval(self.barrel, 0.2, self.barrelScale, blendType='easeInOut'), Func(self.reset), name=self.uniqueName('animTrack')) self.animTrack.start() def setReject(self): base.playSfx(self.rejectSfx) self.notify.warning('Pickup rejected.') def build(self): self.grabSfx = base.audio3d.loadSfx(self.grabSoundPath) self.rejectSfx = base.audio3d.loadSfx(self.rejectSoundPath) base.audio3d.attachSoundToObject(self.grabSfx, self) base.audio3d.attachSoundToObject(self.rejectSfx, self) self.barrel = loader.loadModel('phase_4/models/cogHQ/gagTank.bam') self.barrel.setScale(self.barrelScale) self.barrel.reparentTo(self) self.barrel.setH(180) # Set the label background color. lblBg = self.barrel.find('**/gagLabelDCS') lblBg.setColor(0.15, 0.15, 0.1) self.gagNode = self.barrel.attachNewNode('gagNode') self.gagNode.setPosHpr(0.0, -2.62, 4.0, 0, 0, 0) self.gagNode.setColorScale(0.7, 0.7, 0.6, 1) def reset(self): self.barrel.setScale(self.barrelScale) self.accept(self.uniqueName('enterbarrelSphere'), self.__handleCollision)
def makeBulletCollFromGeoms(rootNode, exclusions=[], enableNow=True, world=None): """ Creates and attaches bullet triangle mesh nodes underneath each GeomNode of `rootNode`, which contains the same mesh as the Geoms. This can be expensive if the geometry contains lots of triangles or GeomNodes. """ if not world: world = base.physicsWorld # BulletRigidBodyNode -> triangle index -> surfaceprop # (it's so we know which surface we are walking on) result = {} for faceNp in rootNode.findAllMatches("**"): if faceNp.getName() in exclusions: continue if faceNp.node().getType() != GeomNode.getClassType(): continue # Create a separate list of geoms for each possible face type # ( a wall or floor ) type2geoms = {} for i in xrange(faceNp.node().getNumGeoms()): geom = faceNp.node().getGeom(i) state = faceNp.node().getGeomState(i) if not geom.getPrimitive(0).isIndexed(): continue if state.hasAttrib(BSPFaceAttrib.getClassSlot()): bca = state.getAttrib(BSPFaceAttrib.getClassSlot()) facetype = bca.getFaceType() else: facetype = BSPFaceAttrib.FACETYPE_WALL if not type2geoms.has_key(facetype): type2geoms[facetype] = [(geom, state)] else: type2geoms[facetype].append((geom, state)) # Now create a separate body node to group each face type, # and assign the correct bit for facetype, geoms in type2geoms.items(): data = {} numGeoms = 0 mesh = BulletTriangleMesh() for i in xrange(len(geoms)): geom, state = geoms[i] mesh.addGeom(geom, True) surfaceprop = "default" if state.hasAttrib(BSPMaterialAttrib.getClassSlot()): mat = state.getAttrib( BSPMaterialAttrib.getClassSlot()).getMaterial() if mat: surfaceprop = mat.getSurfaceProp() for j in xrange(geom.getNumPrimitives()): prim = geom.getPrimitive(j) prim = prim.decompose() tris = prim.getNumVertices() / 3 for tidx in xrange(tris): data[numGeoms] = surfaceprop numGeoms += 1 shape = BulletTriangleMeshShape(mesh, False) rbnode = BulletRigidBodyNode(faceNp.getName() + "_bullet_type" + str(facetype)) rbnode.setKinematic(True) rbnode.addShape(shape) rbnodeNp = NodePath(rbnode) rbnodeNp.reparentTo(faceNp) if facetype == BSPFaceAttrib.FACETYPE_WALL: rbnodeNp.setCollideMask(CIGlobals.WallGroup) elif facetype == BSPFaceAttrib.FACETYPE_FLOOR: rbnodeNp.setCollideMask(CIGlobals.FloorGroup) if enableNow: world.attachRigidBody(rbnode) result[rbnode] = data return result