Esempio n. 1
0
class XMLTruck(XMLVehicle):
	def __init__(self, xmlfile, datadir, spawnpos, world):
		super(XMLTruck, self).__init__(xmlfile, datadir, spawnpos, world)
		p = self.parser # For readability...
		self.hitchConstraint = None
		self.hitchedTrailer = None

		# ===== Sound =====
		self.sound = SoundController(p.getEngineRpmIdle(),
									p.getEngineRpmMax() * 1./4.,
									p.getEngineRpmMax() * 2./4.,
									p.getEngineRpmMax() * 3./4.)

		# ===== Steering =====
		self.physMaxAngle = p.getSteeringAngleMax()	# The absolute maximum angle possible
		self.maxAngle = self.physMaxAngle			# The maximum steering angle at the current speed (speed-sensitive)
		self.rate = p.getSteeringRate()
		self.curAngle = 0.0
		self._steerDir = 0	# -1, 0, 1: Sets the direction of steering

		# ===== Select a drivetrain =====
		if p.getDrivetrainType() == "automatic":
			#self.drivetrain = AutomaticDt(self.vehicle, self.parser)
			self.drivetrain = Drivetrain(self.vehicle, self.parser)
		else:
			print "[WRN] The selected drivetrain type is unknown, choosing automatic!"
			self.drivetrain = AutomaticDt(self.vehicle, self.parser)


	def setGas(self, gas):
		if gas <= 1. and gas >= 0.:
			self.drivetrain.setGas(gas)
		else:
			print "Truck.py:setGas(gas) out of range! (0 < x < 1)"

	def setBrake(self, brake):
		if brake <= 1. and brake >= 0.:
			self.drivetrain.setBrake(brake)
		else:
			print "Truck.py:setBrake(brake) out of range! (0 < x < 1)"

	def getGbState(self):
		return self.drivetrain.getGbState()

	def shiftDrive(self):
		self.drivetrain.shiftDrive()

	def shiftNeutral(self):
		self.drivetrain.shiftNeutral()

	def shiftReverse(self):
		self.drivetrain.shiftReverse()

	def shiftPark(self):
		self.drivetrain.shiftPark()

	def steer(self, direction):
		if direction >= -1 and direction <= 1:
			self._steerDir = direction
		else:
			print "[WRN] XMLTruck:steer(): Invalid direction parameter."

	def _steer(self):
		# We are speed sensitive
		speed = self.vehicle.getCurrentSpeedKmHour()
		if speed > 0 and speed < 90:
			self.maxAngle = (-.5) * speed + 45 # Graph this on WolframAlpha to make it obvious :)
		elif speed > 90:
			self.maxAngle = 1.0

		if self._steerDir == 1 and self.curAngle < self.maxAngle:
			if self.curAngle < 0:
				self.curAngle += 2.0 * self.rate
			else:
				self.curAngle += self.rate
		elif self._steerDir == -1 and self.curAngle > self.maxAngle * -1:
			if self.curAngle > 0:
				self.curAngle -= 2.0 * self.rate
			else:
				self.curAngle -= self.rate
		else: # self._steerDir == 0
			# steer straight
			if self.curAngle > self.rate:
				self.curAngle -= 2.0 * self.rate
			elif self.curAngle < self.rate * -1.0:
				self.curAngle += 2.0 * self.rate
			else:
				self.curAngle = 0.0

	def update(self, dt):
		super(XMLTruck, self).update(dt)
		self._steer()
		self.drivetrain.update(dt)
		self._applyAirDrag()
		self._makeSound()
		if not self.hitchedTrailer == None:
			self.hitchedTrailer.update(dt, self.curAngle)

		for axle in range(0, self.parser.getAxleCount()):
			if self.parser.isAxleSteerable(axle):
				self.vehicle.setSteeringValue(self.curAngle * self.parser.getAxleSteeringFactor(axle), 2 * axle)
				self.vehicle.setSteeringValue(self.curAngle * self.parser.getAxleSteeringFactor(axle), 2 * axle + 1)

	def _applyAirDrag(self):
		# air density 0.0012 g/cm3 (at sea level and 20 °C)
		# cw-Value: 0.8 for a "truck", 0.5 for a modern 40 ton "with aero-kit" (see wikipedia), choosing 0.4 for now.
		# force = (density * cw * A * vel) / 2
		force = 0.0012 * 0.4 \
				* (self.parser.getDimensions()[0] * self.parser.getDimensions()[1]) \
				* (self.getSpeed() / 3.6) \
				/ 2

		# Its a braking force, after all
		force *= -1.

		relFVector = self.components[0].getBodyNp().getRelativeVector(render, Point3(0, force, 0))
		self.components[0].getBodyNp().node().applyCentralForce(relFVector);

	def _makeSound(self):
		self.sound.playEngineSound(self.getRpm(), self.drivetrain.getGasPedal())

	def getRpm(self):
		return self.drivetrain.getRpm()

	def getGear(self):
		return self.drivetrain.getGear()

	def reset(self):
		for meshId in range(0, self.parser.getMeshCount()):
			self.components[meshId].setR(0)

			if meshId == 0:
				self.components[meshId].setPos(self.components[meshId].getPos() + Vec3(0, 0, 1.5))
			else:
				parentComp = self.components[self.parser.getMeshParent(meshId)]
				self.components[meshId].getBodyNp().setPos(self.components[meshId].getBodyNp().getPos()
															+ self.parser.getMeshOffset(meshId)
															+ Vec3(0, 0, 1.5))

		if not self.hitchedTrailer == None:
			self.hitchedTrailer.getChassis().setPos(self.hitchedTrailer.getChassis().getPos() + (0,0,1.5))
			self.hitchedTrailer.getChassis().setR(0)

	def control(self, conIndex, direction):
		if not direction in [-1, 0, 1]:
			raise ValueError("direction is none of [-1, 0, 1]")
		
		if conIndex == 0:
			if direction in [-1, 1]:
				self.constraints[conIndex].getConstraint().enableAngularMotor(True, .4 * direction, 10000000.)
			elif direction == 0:
				self.constraints[conIndex].getConstraint().enableAngularMotor(True, .0, 1000000.)
			else:
				print "[WRN] XMLTruck:control0(direction): Direction is none of [1., 0., -1.]"

	def couple(self, vehicles):
		""" Checks if another vehicle is within 1 unit (meter) range of our hitch. If yes, it will be connected to us. """
		if self.hitchConstraint == None:
			ourHitchAbsolute = Util.getAbsolutePos(self.getTrailerHitchPoint(), self.getChassis().getBodyNp())

			for vehicle in vehicles:
				otherHitchAbsolute = Util.getAbsolutePos(vehicle.getTrailerHitchPoint(), vehicle.getChassis().getBodyNp())

				if not self == vehicle and vehicle.getType() == "trailer" \
					and Util.getDistance(ourHitchAbsolute, otherHitchAbsolute) <= 1:
					self.hitchConstraint = self.createCouplingJoint(self.getTrailerHitchPoint(),
												vehicle.getTrailerHitchPoint(), vehicle.getChassis().getBodyNp().node())
					self.hitchedTrailer = vehicle
		else:
			self.world.removeConstraint(self.hitchConstraint)
			self.hitchConstraint = None
			self.hitchedTrailer = None

	def createCouplingJoint(self, ourHitch, otherHitch, otherChassisNode):
		#BulletConeTwistConstraint (BulletRigidBodyNode const node_a, BulletRigidBodyNode const node_b,
		#							TransformState const frame_a, TransformState const frame_b)
		ourFrame = TransformState.makePosHpr(ourHitch, Vec3(0,0,0))
		otherFrame = TransformState.makePosHpr(otherHitch, Vec3(0,0,0))
		hitchConstraint = BulletConeTwistConstraint(self.getChassis().getBodyNp().node(), otherChassisNode, ourFrame, otherFrame)
		hitchConstraint.setLimit(170, 40, 30)
		self.world.attachConstraint(hitchConstraint)
		return hitchConstraint