class Car(): def __init__(self,world,space,pos): #variables self.world=world self.world.setContactSurfaceLayer(0.01) self.space=space self.turn=False self.turnspeed=0.0 self.turnangle=0.0 self.carOrientation=1 self.acceleration=False self.maxSpeed=0 self.accForce=0 #Body of the our car - similar the boxes self.box = loader.loadModel("car") self.box.setPos(pos) self.box.setColor(1,0.5,0.5) self.box.reparentTo(render) self.body=OdeBody(self.world) M = OdeMass() M.setBox(4, 1.8, 4, 0.5) self.body.setMass(M) self.body.setPosition(self.box.getPos(render)) self.bodyGeom = OdeBoxGeom(self.space, 1,3,1) self.bodyGeom.setBody(self.body) self.joints=[] #suspensions self.wheelsbody=[] #wheels body self.wheelsgeom=[] #wheels geometry self.wheels=[] #wheels visualisation for i in range(4): #set physic of the wheel self.wheelsbody.append(OdeBody(self.world)) M = OdeMass() M.setCylinder(2,2,1, 0.4) self.wheelsbody[i].setMass(M) self.wheelsbody[i].setQuaternion(Quat(0.7,0,0.7,0)) self.wheelsbody[i].setFiniteRotationMode(1) #self.wheelsgeom.append(OdeCylinderGeom(self.space, 1,0.4)) self.wheelsgeom.append(OdeSphereGeom(self.space, 1)) self.wheelsgeom[i].setBody(self.wheelsbody[i]) self.wheelsgeom[i].setCategoryBits(BitMask32(0x00000002)) #add hinge2 joint, wich simulate suspension self.joints.append(OdeHinge2Joint(self.world)) self.joints[i].attachBodies(self.body,self.wheelsbody[i]) #min/max angle for the wheel. Set min=max for stable turn self.joints[i].setParamHiStop(0, 0.0) self.joints[i].setParamLoStop(0, 0.0) #Error reduction parameter of suspension self.joints[i].setParamSuspensionERP(0, 0.9) #Blending of forces - in this case influences rigidity of a suspension self.joints[i].setParamSuspensionCFM(0, 0.001) #self.joints[i].setParamFudgeFactor(0,0.1) #axis of joint: set one - vertical, and one - horisontal self.joints[i].setAxis1(0,0,1) self.joints[i].setAxis2(1,0,0) #visual mesh of wheel self.wheels.append(loader.loadModelCopy("wheel")) self.wheels[i].setColor(1,0.5,0.5) self.wheels[i].setScale(1,1,2) self.wheels[i].reparentTo(render) wheelDistance = 3.1 #1.8 bodyDistance = 5.2 # 1.1 #bodyHeight = 2.5 bodyHeight= -1.5#car add #set wheels to start position self.wheelsbody[0].setPosition(pos.getX()-wheelDistance,pos.getY()+bodyDistance,pos.getZ()+bodyHeight) self.wheelsbody[1].setPosition(pos.getX()-wheelDistance,pos.getY()-bodyDistance,pos.getZ()+bodyHeight) self.wheelsbody[2].setPosition(pos.getX()+wheelDistance,pos.getY()+bodyDistance,pos.getZ()+bodyHeight) self.wheelsbody[3].setPosition(pos.getX()+wheelDistance,pos.getY()-bodyDistance,pos.getZ()+bodyHeight) #set joints to start position self.joints[0].setAnchor(Vec3(pos.getX()-(wheelDistance-0.2),pos.getY()+bodyDistance,pos.getZ()+bodyHeight)) self.joints[1].setAnchor(Vec3(pos.getX()-(wheelDistance-0.2),pos.getY()-bodyDistance,pos.getZ()+bodyHeight)) self.joints[2].setAnchor(Vec3(pos.getX()+(wheelDistance-0.2),pos.getY()+bodyDistance,pos.getZ()+bodyHeight)) self.joints[3].setAnchor(Vec3(pos.getX()+(wheelDistance-0.2),pos.getY()-bodyDistance,pos.getZ()+bodyHeight)) #Set surface types for the wheels self.space.setSurfaceType(self.wheelsgeom[0],1) self.space.setSurfaceType(self.wheelsgeom[2],1) self.space.setSurfaceType(self.wheelsgeom[1],2) self.space.setSurfaceType(self.wheelsgeom[3],2) self.maxVelocity = 65 self.maxSpeed=50 self.accForce=500 # register actions and tasks axis=[1,3] axis2=[1,3,0,2] base.accept('w', self.Accel,[self.maxVelocity, 40,axis]) base.accept('w-up', self.Accel,[0, 15,axis2]) base.accept('s', self.Accel,[-25, 40,axis]) base.accept('s-up', self.Accel,[0, 15,axis2]) base.accept('space', self.Accel, [0, 200,axis2]) base.accept('space-up', self.Accel, [0, 15,axis2]) base.accept('shift', self.Accel, [0, 50,axis2]) base.accept('shift-up', self.Accel, [0, 15,axis2]) base.accept('d', self.Turn,[True,0.01]) base.accept('a', self.Turn,[True,-0.01]) base.accept('d-up', self.Turn,[False,0.01]) base.accept('a-up', self.Turn,[False,-0.01]) taskMgr.add(self.TurnTask,"Rule Car") taskMgr.add(self.JetTask,"Jet Task") taskMgr.doMethodLater(0.5,self.checkRotation, "checkRotation") #Setup the camera basis self.camPosNode = self.box.attachNewNode('camPosNode') self.camPosNode.setPos(0,6,-2) self.camLookatNode = self.box.attachNewNode('camLookatNode') self.camLookatNode.setPos(0,0,2) base.camLens.setFar(10000) #spedometer spdm = OnscreenImage(image = 'spdm.png', scale=0.25, pos = (1, 0, -0.6)) spdm.setTransparency(TransparencyAttrib.MAlpha) self.pointer = OnscreenImage(image = 'spdm_pointer.png', scale=0.25, pos = (1, 0, -0.6)) self.pointer.setTransparency(TransparencyAttrib.MAlpha) self.lastPos = Vec3(0,0,0) def addCamdist(self, v): self.camDistance += v print "new camdistance:", self.camDistance #acceleration function def Accel(self, aspect, force, axis): for i in [1,3,0,2]: self.joints[i].setParamFMax(1, 0) #We use two different methods for move forward and backward #Forward - "jet engine" - add force to the body of the car #Backward - angular engine - add angular speed to the wheels if aspect>0: self.acceleration=True else: self.acceleration=False for i in axis: #set angular engine speed self.joints[i].setParamVel(1,aspect*self.carOrientation) #and force to it self.joints[i].setParamFMax(1, force) #check car orientation, and change control according to it def checkRotation(self,task): oldO=self.carOrientation if abs(int(self.box.getR()))<90: self.carOrientation=1 else: self.carOrientation=-1 if oldO<>self.carOrientation: self.camPosNode.setZ(-self.camPosNode.getZ()) for i in [1,3,0,2]: self.joints[i].setParamVel(1,-self.joints[i].getParamVel(1)) return task.again #turn wheels - set variables def Turn(self,enabled,aspect): self.turn=enabled self.turnspeed=aspect #immediately, turn wheels here def TurnTask(self,task): #calculate angle if not self.turn: if self.turnangle>0: self.turnspeed=-0.01*self.carOrientation if self.turnangle<0: self.turnspeed=0.01*self.carOrientation if -0.01<self.turnangle<0.01: self.turnangle=0; self.turnangle=self.turnangle+self.turnspeed*self.carOrientation if self.turnangle>0.3: self.turnangle=0.3 if self.turnangle<-0.3: self.turnangle=-0.3 # and set angle to the front wheels self.joints[0].setParamHiStop(0, self.turnangle) self.joints[0].setParamLoStop(0, self.turnangle) self.joints[2].setParamHiStop(0, self.turnangle) self.joints[2].setParamLoStop(0, self.turnangle) # will fix wheel position a bit better for i in xrange(4): self.wheelsbody[i].setFiniteRotationAxis(self.joints[i].getAxis2()) return task.cont #task for jet engeene def JetTask(self,task): if self.acceleration<>0: if self.maxSpeed>self.body.getLinearVel().length(): self.body.addRelForce(0,self.accForce,0) return task.cont #sync our visible geometry with them physic bodyes def Sync(self): self.box.setPos(render, self.body.getPosition()) self.box.setQuat(render,Quat(self.body.getQuaternion())) for i in range(4): self.wheels[i].setPos(render, self.wheelsbody[i].getPosition()) self.wheels[i].setQuat(render,Quat(self.wheelsbody[i].getQuaternion())) # update the camera camVec = self.camPosNode.getPos(render) - self.body.getPosition() camDistance = Vec2(-5, 3) targetCamPos = self.body.getPosition() + camVec * camDistance.getX() + Vec3(0,0,camDistance.getY()) camLookat = self.camLookatNode.getPos(render) dPos = targetCamPos - base.camera.getPos(render) dt = globalClock.getDt() base.camera.setPos(base.camera.getPos(render) + dPos * dt / .5) base.camera.lookAt(camLookat) # the speedometer pointer curPos = self.box.getPos(render) vel = (self.lastPos - curPos).length() * 6000 / self.maxVelocity self.lastPos = curPos dr=vel-self.pointer.getR() if dr>30: dr=30 dr=dr*0.1 self.pointer.setR(self.pointer.getR()+dr)