from direct.distributed import DistributedObject from direct.directnotify import DirectNotifyGlobal from toontown.toonbase import ToontownGlobals from panda3d.core import * from panda3d.ode import OdeWorld, OdeSimpleSpace, OdeJointGroup, OdePlaneGeom, OdeBody, OdeMass, OdeSphereGeom, OdeBoxGeom, OdeSliderJoint, OdeTriMeshData, OdeTriMeshGeom, OdeHingeJoint from math import * import math from direct.fsm.FSM import FSM from toontown.minigame import ArrowKeys from direct.showbase import PythonUtil from direct.task import Task from direct.distributed.ClockDelta import * from . import BuildGeometry from toontown.golf import GolfGlobals import random, time def scalp(vec, scal): vec0 = vec[0] * scal vec1 = vec[1] * scal vec2 = vec[2] * scal vec = Vec3(vec0, vec1, vec2) def length(vec): return sqrt(vec[0] ** 2 + vec[1] ** 2 + vec[2] ** 2) class PhysicsWorldBase: notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPhysicsWorld') def __init__(self, canRender = 0): self.canRender = canRender self.world = OdeWorld() self.space = OdeSimpleSpace() self.contactgroup = OdeJointGroup() self.bodyList = [] self.geomList = [] self.massList = [] self.rayList = [] self.showContacts = 0 self.jointMarkers = [] self.jointMarkerCount = 64 self.meshDataList = [] self.geomDataList = [] self.commonObjectInfoDict = {} self.maxColCount = 0 if self.canRender: self.odePandaRelationList = self.bodyList self.root = render.attachNewNode('physics root node') else: self.root = NodePath('physics root node') self.placerNode = self.root.attachNewNode('Placer') self.subPlacerNode = self.placerNode.attachNewNode('Placer Sub Node') self.commonObjectDict = {} self.commonId = 0 self.worldAttach = self.root.attachNewNode('physics geom attach point') self.timingCycleLength = 10.0 self.timingCycleOffset = 0.0 self.timingSimTime = 0.0 self.FPS = 90.0 self.refFPS = 60.0 self.DTAStep = 1.0 / self.FPS self.refCon = 1.2 self.collisionEventName = 'ode-collision-%s' % id(self) self.space.setCollisionEvent(self.collisionEventName) self.accept(self.collisionEventName, self.__handleCollision) def delete(self): self.notify.debug('Max Collision Count was %s' % self.maxColCount) self.stopSim() self.commonObjectDict = None if self.canRender: for pair in self.odePandaRelationList: pair[0].removeNode() pair[1].destroy() self.odePandaRelationList = None else: for body in self.bodyList: body[1].destroy() self.bodyList = None for mass in self.massList: mass = None for geom in self.geomList: geom.destroy() geom = None for ray in self.rayList: ray.destroy() ray = None self.placerNode.removeNode() self.root.removeNode() for marker in self.jointMarkers: marker.removeNode() self.jointMarkers = None for data in self.geomDataList: data.destroy() for data in self.meshDataList: data.destroy() self.floor.destroy() self.floor = None self.contactgroup.empty() self.world.destroy() self.space.destroy() self.world = None self.space = None self.ignore(self.collisionEventName) return def setupSimulation(self): self.world.setAutoDisableFlag(0) self.world.setAutoDisableLinearThreshold(0.15) self.world.setAutoDisableAngularThreshold(0.15) self.world.setAutoDisableSteps(2) self.world.setGravity(0, 0, -25) self.world.setErp(0.8) self.world.setCfm(1e-05) self.world.initSurfaceTable(5) self.world.setSurfaceEntry(0, 0, 150, 0.05, 0.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(1, 1, 1500, 0.05, 0.1, 0.9, 1e-05, 0.0, 0.001 / self.refCon) self.world.setSurfaceEntry(2, 2, 150, 0.05, 0.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(0, 2, 150, 0.05, 0.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(0, 3, 150, 0.0, 0.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(1, 3, 150, 0.0, 99.1, 0.9, 1e-05, 0.0, 1.0 / self.refCon) self.world.setSurfaceEntry(2, 3, 150, 0.0, 9.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(3, 3, 150, 0.0, 9.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(4, 4, 150, 0.0, 9.1, 0.9, 1e-05, 0.0, 0.4 / self.refCon) self.world.setSurfaceEntry(1, 4, 150, 0.0, 99.1, 0.9, 1e-05, 0.0, 0.001 / self.refCon) self.world.setSurfaceEntry(pos1=0, pos2=1, mu=80, bounce=0.15, bounce_vel=0.1, soft_erp=0.9, soft_cfm=1e-05, slip=0.0, dampen=0.35 / self.refCon) self.world.setSurfaceEntry(pos1=2, pos2=1, mu=1500, bounce=0.9, bounce_vel=0.01, soft_erp=0.9, soft_cfm=1e-05, slip=0.0, dampen=0.001 / self.refCon) self.floor = OdePlaneGeom(self.space, Vec4(0.0, 0.0, 1.0, -20.0)) self.floor.setCollideBits(BitMask32(0)) self.floor.setCategoryBits(BitMask32(3840)) self.space.setAutoCollideWorld(self.world) self.space.setAutoCollideJointGroup(self.contactgroup) self.world.setQuickStepNumIterations(8) self.DTA = 0.0 self.frameCounter = 0 if self.canRender: for count in range(self.jointMarkerCount): testMarker = render.attachNewNode('Joint Marker') ballmodel = loader.loadModel('phase_3/models/misc/sphere') ballmodel.reparentTo(testMarker) ballmodel.setScale(0.1) testMarker.setPos(0.0, 0.0, -100.0) self.jointMarkers.append(testMarker) def setTimingCycleLength(self, time): self.timingCycleLength = time def getTimingCycleLength(self): return self.timingCycleLength def getCycleTime(self, doprint = 0): cycleTime = (globalClock.getRealTime() + self.timingCycleOffset) % self.timingCycleLength if doprint: print('Get Cycle Time %s' % cycleTime) return cycleTime def setTimeIntoCycle(self, time, doprint = 0): trueCycleTime = globalClock.getRealTime() % self.timingCycleLength self.timingCycleOffset = time - trueCycleTime if doprint: self.notify.debug('Set Cycle Time %s' % self.timingCycleOffset) self.notify.debug('SET cycle time %s' % ((globalClock.getRealTime() + self.timingCycleOffset) % self.timingCycleLength)) def getSimCycleTime(self): return return self.timingSimTime % self.timingCycleLength def startSim(self): taskMgr.add(self.__simulationTask, 'simulation task') def stopSim(self): taskMgr.remove('simulation task') def __simulationTask(self, task): self.DTA += globalClock.getDt() self.frameCounter += 1 if self.frameCounter >= 10: self.frameCounter = 0 startTime = globalClock.getRealTime() colCount = 0 while self.DTA >= self.DTAStep: self.DTA -= self.DTAStep self.preStep() self.simulate() self.postStep() if self.canRender: self.placeBodies() if self.frameCounter == 0: endTime = globalClock.getRealTime() - startTime return task.cont def __handleCollision(self, entry): self.colEntries.append(entry) def simulate(self): self.colEntries = [] self.space.autoCollide() eventMgr.doEvents() self.colCount = len(self.colEntries) if self.maxColCount < self.colCount: self.maxColCount = self.colCount self.notify.debug('New Max Collision Count %s' % self.maxColCount) self.world.quickStep(self.DTAStep) for bodyPair in self.bodyList: self.world.applyDampening(self.DTAStep, bodyPair[1]) self.contactgroup.empty() self.commonObjectControl() self.timingSimTime = self.timingSimTime + self.DTAStep def placeBodies(self): for pair in self.odePandaRelationList: pandaNodePathGeom = pair[0] odeBody = pair[1] if pandaNodePathGeom: pandaNodePathGeom.setPos(odeBody.getPosition()) rotation = odeBody.getRotation() * (180.0 / math.pi) pandaNodePathGeom.setQuat(Quat(odeBody.getQuaternion()[0], odeBody.getQuaternion()[1], odeBody.getQuaternion()[2], odeBody.getQuaternion()[3])) def preStep(self): pass def postStep(self): if self.showContacts and self.canRender: for count in range(self.jointMarkerCount): pandaNodePathGeom = self.jointMarkers[count] if count < self.colCount: pandaNodePathGeom.setPos(self.space.getContactData(count * 3 + 0), self.space.getContactData(count * 3 + 1), self.space.getContactData(count * 3 + 2)) else: pandaNodePathGeom.setPos(0.0, 0.0, -100.0) def commonObjectControl(self): time = self.getCycleTime() for key in self.commonObjectDict: if key not in self.commonObjectInfoDict: self.commonObjectInfoDict[key] = None entry = self.commonObjectDict[key] if entry[1] in [2, 4]: type = entry[1] body = entry[2] motor = entry[3] timeData = entry[4] forceData = entry[5] eventData = entry[6] model = entry[7] force = 0.0 for index in range(len(timeData)): if index == len(timeData) - 1 and timeData[index] < time or timeData[index] < time and timeData[index + 1] > time: force = forceData[index] event = eventData[index] if event != self.commonObjectInfoDict[key]: self.commonObjectEvent(key, model, type, force, event) self.commonObjectInfoDict[key] = event motor.setParamVel(force) return def commonObjectEvent(self, key, model, type, force, event): self.notify.debug('commonObjectForceEvent %s %s %s %s %s' % (key, model, type, force, event)) def getCommonObjectData(self): objectStream = [(0, 0, self.getCycleTime(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)] for key in self.commonObjectDict: objectPair = self.commonObjectDict[key] object = objectPair[2] pos3 = object.getPosition() quat4 = object.getQuaternion() anV3 = object.getAngularVel() lnV3 = object.getLinearVel() data = (objectPair[0], objectPair[1], pos3[0], pos3[1], pos3[2], quat4[0], quat4[1], quat4[2], quat4[3], anV3[0], anV3[1], anV3[2], lnV3[0], lnV3[1], lnV3[2]) objectStream.append(data) if len(objectStream) <= 1: data = (0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) objectStream.append(data) return objectStream def useCommonObjectData(self, objectData, enable = 1): if not objectData: return if objectData[1][1] == 99: return time = objectData[0] self.setTimeIntoCycle(time[2]) if time[2] > self.timingCycleLength: pass for dataIndex in range(1, len(objectData)): data = objectData[dataIndex] commonObject = self.commonObjectDict[data[0]] commonObject[2].setPosition(data[2], data[3], data[4]) commonObject[2].setQuaternion(Quat(data[5], data[6], data[7], data[8])) commonObject[2].setAngularVel(data[9], data[10], data[11]) commonObject[2].setLinearVel(data[12], data[13], data[14]) if enable: commonObject[2].enable() else: commonObject[2].disable() def createCommonObject(self, type, commonId, pos, hpr, sizeX = 0, sizeY = 0, moveDistance = 0): if commonId == None: commonId = self.commonId self.commonId += 1 vPos = Point3(float(pos[0]), float(pos[1]), float(pos[2])) vHpr = Vec3(float(hpr[0]), float(hpr[1]), float(hpr[2])) rHpr = Vec3(float(hpr[0]), float(hpr[1]), float(hpr[2])) self.placerNode.setHpr(vHpr) self.placerNode.setPos(vPos) if type == 0: model, box = self.createBox(self.world, self.space, 10.0, 5.0, 5.0, 5.0) box.setPosition(vPos) self.placerNode.setHpr(vHpr) box.setQuaternion(self.placerNode.getQuat()) self.commonObjectDict[commonId] = (commonId, type, box) elif type == 1: model, cross = self.createCross(self.world, self.space, 1.0, 3.0, 12.0, 2.0, 2) motor = OdeHingeJoint(self.world) cross.setPosition(vPos) cross.setQuaternion(self.placerNode.getQuat()) ourAxis = render.getRelativeVector(self.placerNode, Vec3(0, 0, 1)) motor.setParamVel(1.5) motor.setParamFMax(500000000.0) boxsize = Vec3(1.0, 1.0, 1.0) motor.attachBody(cross, 0) motor.setAnchor(vPos) motor.setAxis(ourAxis) self.cross = cross cross.enable() self.commonObjectDict[commonId] = (commonId, type, cross) elif type == 2: ourAxis = render.getRelativeVector(self.placerNode, Vec3(0, 0, 1)) model, box = self.createBox(self.world, self.space, 10.0, 5.0, 5.0, 5.0, 2) box.setPosition(vPos) box.setQuaternion(self.placerNode.getQuat()) motor = OdeSliderJoint(self.world) motor.attachBody(box, 0) motor.setAxis(ourAxis) motor.setParamVel(3.0) motor.setParamFMax(5000000.0) motor.setParamHiStop(10.0) motor.setParamLoStop(-10.0) timeData = (0.0, 5.0) forceData = (3.0, -3.0) eventData = (1, 2) self.commonObjectDict[commonId] = (commonId, type, box, motor, timeData, forceData, eventData, model) elif type == 3: vPos = Point3(float(pos[0]), float(pos[1]), float(pos[2])) vHpr = Vec3(float(hpr[0]), float(hpr[1]), float(hpr[2])) self.placerNode.setHpr(vHpr) self.placerNode.setPos(vPos) self.subPlacerNode.setPos(0, 0, 0) if self.canRender: myModel = loader.loadModel('phase_6/models/golf/golf_windmill_b') else: myModel = loader.loadModel('phase_6/models/golf/golf_windmill_b.bam') myModel.reparentTo(self.root) myModel.setPos(vPos) myModel.setHpr(vHpr) millFan = myModel.find('**/windmillFan0') millBase = myModel.find('**/arm') rod = myModel.find('**/rod') rod.wrtReparentTo(millBase) self.windmillFanNodePath = millFan self.windmillBaseNodePath = millBase millData = OdeTriMeshData(millBase) millGeom = OdeTriMeshGeom(self.space, millData) self.meshDataList.append(millData) millGeom.setPosition(self.subPlacerNode.getPos(self.root)) millGeom.setQuaternion(self.subPlacerNode.getQuat()) millGeom.setCollideBits(BitMask32(251658240)) millGeom.setCategoryBits(BitMask32(8388608)) self.space.setCollideId(millGeom, 8) vPos = Point3(float(pos[0]), float(pos[1]), float(pos[2]) + 5) vHpr = Vec3(float(hpr[0]), float(hpr[1] + 90), float(hpr[2]) - 90) self.placerNode.setHpr(vHpr) self.placerNode.setPos(vPos) self.subPlacerNode.setPos(-1, 0, 0.0) model, cross = self.createPinWheel(self.world, self.space, 10.0, 1.6, 4.0, 0.6, 5, 3.7, 1.2, 1, millFan, (0, 0, 90), (-4.6, -0.5, -0.25), 20) self.placerNode.setHpr(vHpr) self.placerNode.setPos(vPos) self.subPlacerNode.setPos(-1, 0, 0.0) motor = OdeHingeJoint(self.world) cross.setPosition(self.subPlacerNode.getPos(self.root)) cross.setQuaternion(self.placerNode.getQuat()) ourAxis = self.root.getRelativeVector(self.subPlacerNode, Vec3(0, 0, 1)) motor.setParamVel(1.0) motor.setParamFMax(50000.0) boxsize = Vec3(1.0, 1.0, 1.0) motor.attachBody(cross, 0) motor.setAnchor(self.subPlacerNode.getPos(self.root)) motor.setAxis(ourAxis) self.cross = cross cross.enable() self.commonObjectDict[commonId] = (commonId, type, cross) elif type == 4: ourAxis = self.root.getRelativeVector(self.placerNode, Vec3(0, 1, 0)) model, box = self.createBox(self.world, self.space, 50.0, sizeX, sizeY, 1.0, 2) box.setPosition(vPos) box.setQuaternion(self.placerNode.getQuat()) motor = OdeSliderJoint(self.world) motor.attachBody(box, 0) motor.setAxis(ourAxis) motor.setParamVel(moveDistance / 4.0) motor.setParamFMax(25000.0) motor.setParamHiStop(moveDistance) motor.setParamLoStop(0) timeData = (0.0, 1.0, 5.0, 6.0) forceData = (-moveDistance / 4.0, moveDistance / 4.0, moveDistance / 4.0, -moveDistance / 4.0) eventData = (-1, 1, -2, 2) radius = moveDistance + sizeY * 0.5 self.commonObjectDict[commonId] = (commonId, type, box, motor, timeData, forceData, eventData, model, radius) return [type, commonId, (pos[0], pos[1], pos[2]), (hpr[0], hpr[1], hpr[2]), sizeX, sizeY, moveDistance] def createSphere(self, world, space, density, radius, ballIndex = None): self.notify.debug('create sphere index %s' % ballIndex) body = OdeBody(world) M = OdeMass() M.setSphere(density, radius) body.setMass(M) body.setPosition(0, 0, -100) geom = OdeSphereGeom(space, radius) self.space.setSurfaceType(geom, 1) self.notify.debug('collide ID is %s' % self.space.setCollideId(geom, 42)) self.massList.append(M) self.geomList.append(geom) if ballIndex == 1: self.notify.debug('1') geom.setCollideBits(BitMask32(16777215)) geom.setCategoryBits(BitMask32(4278190080)) elif ballIndex == 2: self.notify.debug('2') geom.setCollideBits(BitMask32(16777215)) geom.setCategoryBits(BitMask32(4278190080)) elif ballIndex == 3: self.notify.debug('3') geom.setCollideBits(BitMask32(16777215)) geom.setCategoryBits(BitMask32(4278190080)) elif ballIndex == 4: self.notify.debug('4') geom.setCollideBits(BitMask32(16777215)) geom.setCategoryBits(BitMask32(4278190080)) else: geom.setCollideBits(BitMask32(4294967295)) geom.setCategoryBits(BitMask32(4294967295)) geom.setBody(body) if self.notify.getDebug(): self.notify.debug('golf ball geom id') geom.write() self.notify.debug(' -') self.notify.debug('Collide Bits %s' % geom.getCollideBits()) if self.canRender: testball = render.attachNewNode('Ball Holder') ballmodel = loader.loadModel('phase_6/models/golf/golf_ball') ballmodel.reparentTo(testball) ballmodel.setColor(*GolfGlobals.PlayerColors[ballIndex - 1]) testball.setPos(0, 0, -100) self.odePandaRelationList.append((testball, body)) else: testball = None self.bodyList.append((None, body)) return (testball, body, geom) def createBox(self, world, space, density, lx, ly, lz, colOnlyBall = 0): body = OdeBody(self.world) M = OdeMass() M.setSphere(density, 0.3 * (lx + ly + lz)) body.setMass(M) boxsize = Vec3(lx, ly, lz) geom = OdeBoxGeom(space, boxsize) geom.setBody(body) self.space.setSurfaceType(geom, 0) self.space.setCollideId(geom, 7) self.massList.append(M) self.geomList.append(geom) if colOnlyBall: geom.setCollideBits(BitMask32(251658240)) geom.setCategoryBits(BitMask32(0)) elif colOnlyBall == 2: geom.setCollideBits(BitMask32(0)) geom.setCategoryBits(BitMask32(0)) if self.canRender: color = random.choice([Vec4(1.0, 0.0, 0.5, 1.0), Vec4(0.5, 0.5, 1.0, 1.0), Vec4(0.5, 1.0, 0.5, 1.0)]) boxsize = Vec3(lx, ly, lz) boxNodePathGeom, t1, t2 = BuildGeometry.addBoxGeom(self.worldAttach, lx, ly, lz, color, 1) boxNodePathGeom.setPos(0, 0, -100) self.odePandaRelationList.append((boxNodePathGeom, body)) else: boxNodePathGeom = None self.bodyList.append((None, body)) return (boxNodePathGeom, body) def createCross(self, world, space, density, lx, ly, lz, colOnlyBall = 0, attachedGeo = None, aHPR = None, aPos = None): body = OdeBody(self.world) M = OdeMass() M.setBox(density, lx, ly, lz) body.setMass(M) body.setFiniteRotationMode(1) boxsize = Vec3(lx, ly, lz) boxsize2 = Vec3(ly, lx, lz) geom = OdeBoxGeom(space, boxsize) geom.setBody(body) self.space.setSurfaceType(geom, 0) self.space.setCollideId(geom, 13) geom2 = OdeBoxGeom(space, boxsize2) geom2.setBody(body) self.space.setSurfaceType(geom2, 0) self.space.setCollideId(geom2, 26) self.massList.append(M) self.geomList.append(geom) self.geomList.append(geom2) self.odePandaRelationList.append((boxNodePathGeom, body)) if colOnlyBall == 1: geom.setCollideBits(BitMask32(251658240)) geom.setCategoryBits(BitMask32(0)) geom2.setCollideBits(BitMask32(251658240)) geom2.setCategoryBits(BitMask32(0)) elif colOnlyBall == 2: geom.setCollideBits(BitMask32(0)) geom.setCategoryBits(BitMask32(0)) geom2.setCollideBits(BitMask32(0)) geom2.setCategoryBits(BitMask32(0)) if self.canRender: boxNodePathGeom, t1, t2 = BuildGeometry.addBoxGeom(self.worldAttach, lx, ly, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom.setPos(0, 0, -100) boxNodePathGeom2, t1, t2 = BuildGeometry.addBoxGeom(boxNodePathGeom, ly, lx, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom2.setPos(0, 0, 0) if attachedGeo: attachedGeo.reparentTo(boxNodePathGeom) attachedGeo.setHpr(0, 0, 90) attachedGeo.setPos(-4.8, 0, -2.0) self.odePandaRelationList.append((boxNodePathGeom, body)) else: boxNodePathGeom = None self.bodyList.append((None, body)) return (boxNodePathGeom, body) def createCross2(self, world, space, density, lx, ly, lz, latSlide, colOnlyBall = 0, attachedGeo = None, aHPR = None, aPos = None): body = OdeBody(self.world) M = OdeMass() M.setBox(density, lx, ly, lz) body.setMass(M) body.setFiniteRotationMode(1) boxsize = Vec3(lx, ly * 0.5, lz) boxsize2 = Vec3(ly * 0.5, lx, lz) geom = OdeBoxGeom(space, boxsize) geom.setBody(body) geom.setOffsetPosition(-latSlide, ly * 0.25, 0) self.space.setSurfaceType(geom, 0) self.space.setCollideId(geom, 13) geom2 = OdeBoxGeom(space, boxsize2) geom2.setBody(body) geom2.setOffsetPosition(ly * 0.25, latSlide, 0) self.space.setSurfaceType(geom2, 0) self.space.setCollideId(geom2, 13) geom3 = OdeBoxGeom(space, boxsize) geom3.setBody(body) geom3.setOffsetPosition(latSlide, -ly * 0.25, 0) self.space.setSurfaceType(geom3, 0) self.space.setCollideId(geom3, 13) geom4 = OdeBoxGeom(space, boxsize2) geom4.setBody(body) geom4.setOffsetPosition(-ly * 0.25, -latSlide, 0) self.space.setSurfaceType(geom4, 0) self.space.setCollideId(geom4, 13) self.massList.append(M) self.geomList.append(geom) self.geomList.append(geom2) self.geomList.append(geom3) self.geomList.append(geom4) if colOnlyBall == 1: geom.setCollideBits(BitMask32(251658240)) geom.setCategoryBits(BitMask32(0)) geom2.setCollideBits(BitMask32(251658240)) geom2.setCategoryBits(BitMask32(0)) geom3.setCollideBits(BitMask32(251658240)) geom3.setCategoryBits(BitMask32(0)) geom4.setCollideBits(BitMask32(251658240)) geom4.setCategoryBits(BitMask32(0)) elif colOnlyBall == 2: geom.setCollideBits(BitMask32(0)) geom.setCategoryBits(BitMask32(0)) geom2.setCollideBits(BitMask32(0)) geom2.setCategoryBits(BitMask32(0)) geom3.setCollideBits(BitMask32(0)) geom3.setCategoryBits(BitMask32(0)) geom4.setCollideBits(BitMask32(0)) geom4.setCategoryBits(BitMask32(0)) if self.canRender: someNodePathGeom = render.attachNewNode('pinwheel') if attachedGeo: attachedGeo.reparentTo(someNodePathGeom) attachedGeo.setHpr(aHPR[0], aHPR[1], aHPR[2]) attachedGeo.setPos(aPos[0], aPos[1], aPos[2]) boxNodePathGeom, t1, t2 = BuildGeometry.addBoxGeom(someNodePathGeom, lx, ly * 0.5, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom.setPos(-latSlide, ly * 0.25, 0) boxNodePathGeom2, t1, t2 = BuildGeometry.addBoxGeom(someNodePathGeom, ly * 0.5, lx, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom2.setPos(ly * 0.25, latSlide, 0) boxNodePathGeom3, t1, t2 = BuildGeometry.addBoxGeom(someNodePathGeom, lx, ly * 0.5, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom3.setPos(latSlide, -ly * 0.25, 0) boxNodePathGeom4, t1, t2 = BuildGeometry.addBoxGeom(someNodePathGeom, ly * 0.5, lx, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom4.setPos(-ly * 0.25, -latSlide, 0) self.odePandaRelationList.append((someNodePathGeom, body)) else: someNodePathGeom = None self.bodyList.append((None, body)) return (someNodePathGeom, body) def createPinWheel(self, world, space, density, lx, ly, lz, numBoxes, disV, disH, colOnlyBall = 0, attachedGeo = None, aHPR = None, aPos = None, offRot = 0): body = OdeBody(self.world) M = OdeMass() M.setBox(density, lx, ly, lz) body.setMass(M) body.setFiniteRotationMode(1) boxsize = Vec3(lx, ly * 0.5, lz) boxsize2 = Vec3(ly * 0.5, lx, lz) self.massList.append(M) self.placerNode.setPos(0, 0, 0) self.placerNode.setHpr(0, 0, 0) self.subPlacerNode.setHpr(0, 0, 0) self.subPlacerNode.setPos(disH, disV, 0) if self.canRender: someNodePathGeom = render.attachNewNode('pinwheel') else: someNodePathGeom = self.root.attachNewNode('pinwheel') for num in range(numBoxes): spin = 360.0 * float(num) / float(numBoxes) + float(offRot) self.placerNode.setH(spin) geom = OdeBoxGeom(space, boxsize) geom.setBody(body) geom.setOffsetPosition(self.subPlacerNode.getPos(self.root)) geom.setOffsetQuaternion(self.subPlacerNode.getQuat(self.root)) self.geomList.append(geom) self.space.setSurfaceType(geom, 0) self.space.setCollideId(geom, 13) if colOnlyBall == 1: geom.setCollideBits(BitMask32(251658240)) geom.setCategoryBits(BitMask32(0)) elif colOnlyBall == 2: geom.setCollideBits(BitMask32(0)) geom.setCategoryBits(BitMask32(0)) if not attachedGeo: boxNodePathGeom, t1, t2 = BuildGeometry.addBoxGeom(someNodePathGeom, lx, ly * 0.5, lz, Vec4(1.0, 1.0, 1.0, 1.0), 1) boxNodePathGeom.setPos(self.subPlacerNode.getPos(self.root)) boxNodePathGeom.setHpr(self.subPlacerNode.getHpr(self.root)) if attachedGeo and self.canRender: attachedGeo.reparentTo(someNodePathGeom) attachedGeo.setHpr(aHPR[0], aHPR[1], aHPR[2]) attachedGeo.setPos(aPos[0], aPos[1], aPos[2]) if self.canRender: self.odePandaRelationList.append((someNodePathGeom, body)) else: someNodePathGeom = None self.bodyList.append((None, body)) return (someNodePathGeom, body) def attachMarker(self, body): if self.canRender: testMarker = render.attachNewNode('Joint Marker') ballmodel = loader.loadModel('models/misc/sphere') ballmodel.reparentTo(testMarker) ballmodel.setScale(0.25) testMarker.setPos(0.0, 0.0, -100.0) self.odePandaRelationList.append((testMarker, body))