Exemplo n.º 1
0
class Vehicle(object):
    '''
    '''
    def __init__(self, ode_world, ode_space, name="standard"):
        '''
        '''
        self._notify = DirectNotify().newCategory("Vehicle")
        self._notify.info("New Vehicle-Object created: %s" % (self))
        self._ode_world = ode_world
        self._ode_space = ode_space
        self._model = None
        self._physics_model = None
        self._physics_mass = None
        self._collision_model = None
        self._speed = 0.0  # the actual speed of the vehicle (forward direction)
        self._direction = Vec3(0, 0, 0)  # the direction the car is heading
        self._boost_direction = Vec3(0, 0, 0)
        self._boost_strength = 10.0  # the boost propertys of the vehicle
        self._control_strength = 1.5  # impact on the steering behaviour
        self._grip_strength = 0.5  # impact on the steering behaviour
        self._track_grip = 0.8  # impact on the steering behaviour
        self._energy = 100.0
        self._armor = 100.0
        self._max_energy = 100.0
        self._max_armor = 100.0
        self._weight = 10.0
        self._description = "The best vehicle ever"
        self._name = "The flying egg"
        self._brake_strength = 10.0
        self._hit_ground = True
        self._model_loading = False
        self._blowout = []
        self._blowout_on = False
        self._streetnormal = Vec3(0, 0, 1)

        # set up the propertys of the vehicle that schould be loaded
        # the methods get called because the data is immutable and
        # wouldnt get updated when calling the objects directly
        # the last entry is the function to convert the string
        self._tags = [["name", self.setName, str],
                      ["description", self.setDescription, str],
                      ["control_strength", self.setControlStrength, float],
                      ["grip_strength", self.setGripStrength, float],
                      ["track_grip", self.setTrackGrip, float],
                      ["max_energy", self.setMaxEnergy, float],
                      ["max_armor", self.setMaxArmor, float],
                      ["weight", self.setWeight, float],
                      ["brake_strength", self.setBrakeStrength, float],
                      ["boost_strength", self.setBoostStrength, float]]

    # ---------------------------------------------------------

    def setVehicle(self, model):
        '''
        Choose what vehicle the player has chosen. This method initializes all data of this vehicle
        '''
        self.cleanResources()

        self._notify.debug("Set new vehicle: %s" % model)

        # Load the attributes of the vehicle
        attributes = model.find("**/Attributes")
        if attributes.isEmpty():
            self._notify.warning("No Attribute-Node found")
        for tag in self._tags:
            value = attributes.getNetTag(tag[0])
            if value:
                self._notify.debug("%s: %s" % (tag[0], value))
                # translate the value if its a string
                if type(tag[2](value)) == str:
                    tag[1](_(tag[2](value)))
                else:
                    tag[1](tag[2](value))
            else:
                self._notify.warning("No value defined for tag: %s" % (tag[0]))

        self._weight = 10  # for testing purposes

        blowout = model.find("**/Blowout")
        if not blowout.isEmpty():
            self._notify.debug("Loading Blowout-Particles")
            for node in blowout.getChildren():
                particle = ParticleEffect()
                self._blowout.append(particle)
                particle.loadConfig('./data/particles/blowout_test.ptf')

                try:  # try to read out the particle scale
                    scale = float(node.getTag("scale"))
                except Exception:  # default is 0.5
                    scale = .5

                renderer = particle.getParticlesList()[0].getRenderer()
                renderer.setInitialXScale(scale)
                renderer.setInitialYScale(scale)

                particle.setLightOff()
                particle.start(node)
                particle.softStop()
        else:
            self._notify.warning("No Blowout-Node found")

        if self._model is not None:
            heading = self._model.getH()
            self._model.removeNode()
        else:
            heading = 160

        # display the attributes
        text = model.getParent().find("AttributeNode")
        if not text.isEmpty():
            node = text.find("name")
            if not node.isEmpty():
                node = node.node()
                node.setText(self._name)
                node.update()
                text.show()

            node = text.find("description")
            if not node.isEmpty():
                node = node.node()
                node.setText(self._name)
                node.update()
                text.show()

        self._model = model
        self._model.setPos(0, 0, 2)
        self._model.setHpr(heading, 0, 0)

        #        #Test
        #        plightCenter = NodePath( 'plightCenter' )
        #        plightCenter.reparentTo( render )
        #        self.interval = plightCenter.hprInterval(12, Vec3(360, 0, 0))
        #        self.interval.loop()
        #
        #        plight = PointLight('plight')
        #        plight.setColor(VBase4(0.8, 0.8, 0.8, 1))
        #        plight.setAttenuation(Vec3(1,0,0))
        #        plnp = plightCenter.attachNewNode(plight)
        #        plnp.setPos(5, 5, 10)
        #        render.setLight(plnp)
        #
        #        alight = AmbientLight('alight')
        #        alight.setColor(VBase4(0,0,0, 1))
        #        alnp = render.attachNewNode(alight)
        #        render.setLight(alnp)

        #        GlowTextur
        #        self.glowSize=10
        #        self.filters = CommonFilters(base.win, self._model)
        #        self.filters.setBloom(blend=(0,self.glowSize,0,0) ,desat=1, intensity=1, size='medium')
        #        tex = loader.loadTexture( 'data/textures/glowmap.png' )
        #        ts = TextureStage('ts')
        #        ts.setMode(TextureStage.MGlow)
        #        self._model.setTexture(ts, tex)

        # Initialize the physics-simulation for the vehicle
        self._physics_model = OdeBody(self._ode_world)
        self._physics_model.setPosition(self._model.getPos(render))
        self._physics_model.setQuaternion(self._model.getQuat(render))

        # Initialize the mass of the vehicle
        physics_mass = OdeMass()
        physics_mass.setBoxTotal(self._weight, 1, 1, 1)
        self._physics_model.setMass(physics_mass)

        # Initialize the collision-model of the vehicle
        # for use with blender models
        # try:
        # col_model = loader.loadModel("data/models/vehicles/%s.collision" %(self._model.getName()))
        # self.collision_model = OdeTriMeshGeom(self._ode_space, OdeTriMeshData(col_model, True))
        # self._notify.info("Loading collision-file: %s" %("data/models/vehicles/%s.collision" %(self._model.getName())))
        # for fast collisions
        # except:
        # self._notify.warning("Could not load collision-file. Using standard collision-box")
        # self.collision_model = OdeTriMeshGeom(self._ode_space, OdeTriMeshData(model, False))
        # self._collision_model = OdeBoxGeom(self._ode_space, 3,3,2)
        self._collision_model = OdeBoxGeom(self._ode_space, 3, 3, 2)
        self._collision_model.setBody(self._physics_model)
        self._collision_model.setCollideBits(7)
        self._collision_model.setCategoryBits(2)

        # Add collision-rays for the floating effect
        self._ray = CollisionRay(Vec3(5, 0, 0),
                                 Vec3(0, 0, -1),
                                 self._ode_space,
                                 parent=self._collision_model,
                                 collide_bits=0,
                                 length=20.0)
        # This one is used for the floating effect but also for slipstream
        self._frontray = CollisionRay(Vec3(0, 0, 0),
                                      Vec3(1, 0, 0),
                                      self._ode_space,
                                      parent=self._collision_model,
                                      collide_bits=0,
                                      length=15.0)
        # Overwrite variables for testing purposes
        self._grip_strength = 0.9
        self._track_grip = 0.2
        self._boost_strength = 1400
        self._control_strength = 2.5

        # Loading finished
        self._model_loading = False

    def toggleGlow(self):
        self.glowSize += .1
        print((self.glowSize))
        if (self.glowSize == 4):
            self.glowSize = 0
        self.filters.setBloom(blend=(0, self.glowSize, 0, 0),
                              desat=-2,
                              intensity=3,
                              size='medium')

    def boggleGlow(self):
        self.glowSize -= .1
        print((self.glowSize))
        if (self.glowSize == 4):
            self.glowSize = 0
        self.filters.setBloom(blend=(0, self.glowSize, 0, 0),
                              desat=-2,
                              intensity=3.0,
                              size='medium')

    # ---------------------------------------------------------

    def setPos(self, x, y, z):
        '''
        '''
        self._model.setPos(x, y, z)

    def getPos(self):
        '''
        '''
        return self._model.getPos()

    position = property(fget=getPos, fset=setPos)

    # ---------------------------------------------------------

    def startBlowout(self):
        '''
        '''
        if not self._blowout_on:
            self._blowout_on = True
            for particle in self._blowout:
                particle.softStart()

    def stopBlowout(self):
        '''
        '''
        if self._blowout_on:
            self._blowout_on = False
            for particle in self._blowout:
                particle.softStop()

    # ---------------------------------------------------------

    def setModel(self, model):
        '''
        '''
        self._model = model

    def getModel(self):
        '''
        '''
        return self._model

    model = property(fget=getModel, fset=setModel)

    # ---------------------------------------------------------

    def setCollisionModel(self, model):
        '''
        '''
        self._collision_model = model

    def getCollisionModel(self):
        '''
        '''
        return self._collision_model

    collision_model = property(fget=getCollisionModel, fset=setCollisionModel)

    # ---------------------------------------------------------

    def setPhysicsModel(self, model):
        '''
        '''
        self._physics_model = model

    def getPhysicsModel(self):
        '''
        '''
        return self._physics_model

    physics_model = property(fget=getPhysicsModel, fset=setPhysicsModel)

    # ---------------------------------------------------------
    def setBoost(self, strength=1):
        '''
        Boosts the vehicle by indicated strength
        '''
        self.startBlowout()
        if self._hit_ground:
            direction = self._streetnormal.cross(
                self._collision_model.getQuaternion().xform(Vec3(1, 0, 0)))
            self._physics_model.addForce(
                direction *
                ((self._boost_strength *
                  self.physics_model.getMass().getMagnitude() * strength)))
            self._hit_ground = False
            self._collision_model.setCollideBits(7)
        else:
            direction = self._streetnormal.cross(
                self._collision_model.getQuaternion().xform(Vec3(1, 0, 0)))
            self._physics_model.addForce(
                direction * self._boost_strength * 0.5 *
                self.physics_model.getMass().getMagnitude() * strength)

    # ---------------------------------------------------------

    def setDirection(self, dir):
        '''
        Steers the vehicle into the target-direction
        '''
        rel_direction = self._collision_model.getQuaternion().xform(
            Vec3(dir[1], 0, dir[0]))
        # rel_position = self._collision_model.getQuaternion().xform(Vec3(5,0,0))
        # force = Vec3(rel_direction[0]*self.direction[0]*self._control_strength*self.speed,rel_direction[1]*self.direction[1]*self._control_strength*self.speed,rel_direction[2]*self.direction[2]*self._control_strength*self.speed)
        self._physics_model.addTorque(
            -rel_direction * self._control_strength *
            self.physics_model.getMass().getMagnitude())

    def getDirection(self):
        return self._direction

    direction = property(fget=getDirection, fset=setDirection)

    # ---------------------------------------------------------

    def getBoostDirection(self):
        return self._boost_direction

    boost_direction = property(fget=getBoostDirection)

    # ---------------------------------------------------------

    def getSpeed(self):
        return self._speed

    speed = property(fget=getSpeed)

    # ---------------------------------------------------------

    def setEnergy(self, energy):
        '''
        Boosts the vehicle by indicated strength
        '''
        self._energy = energy

    def getEnergy(self):
        return self._energy

    energy = property(fget=getEnergy, fset=setEnergy)

    # ---------------------------------------------------------
    def setModelLoading(self, bool):
        '''
        '''
        self._model_loading = bool

    def getModelLoading(self):
        return self._model_loading

    model_loading = property(fget=getModelLoading, fset=setModelLoading)

    # ---------------------------------------------------------

    def doStep(self):
        '''
        Needs to get executed every Ode-Step
        '''
        # refresh variables
        linear_velocity = self._physics_model.getLinearVel()
        direction = self._streetnormal.cross(
            self._collision_model.getQuaternion().xform(Vec3(1, 0, 0)))
        self._boost_direction[0], self._boost_direction[
            1], self._boost_direction[2] = self.physics_model.getLinearVel(
            )[0], self.physics_model.getLinearVel(
            )[1], self.physics_model.getLinearVel()[2]

        # This needs to be done, so we dont create a new object but only change the existing one. else the camera wont update
        self._direction[0], self._direction[1], self._direction[2] = direction[
            0], direction[1], direction[2]

        xy_direction = self.collision_model.getQuaternion().xform(Vec3(
            1, 1, 0))
        self._speed = Vec3(linear_velocity[0] * xy_direction[0],
                           linear_velocity[1] * xy_direction[1],
                           linear_velocity[2] * xy_direction[2]).length()

        # calculate air resistance
        self._physics_model.addForce(
            -linear_velocity * linear_velocity.length() /
            10)  # *((self._speed/2)*(self._speed/2)))#+linear_velocity)

        # calculate delayed velocity changes
        linear_velocity.normalize()
        self._direction.normalize()
        self._physics_model.addForce(
            self._direction *
            (self._speed * self._grip_strength *
             self.physics_model.getMass().getMagnitude()))  # +linear_velocity)
        self._physics_model.addForce(
            -linear_velocity *
            (self._speed * self._grip_strength *
             self.physics_model.getMass().getMagnitude()))  # +linear_velocity)

        # calculate the grip
        self._physics_model.addTorque(
            self._physics_model.getAngularVel() * -self._track_grip *
            self.physics_model.getMass().getMagnitude())

        # refresh the positions of the collisionrays
        self._ray.doStep()
        self._frontray.doStep()
        self._physics_model.setGravityMode(1)

    # ---------------------------------------------------------

    def getRay(self):
        return self._ray

    ray = property(fget=getRay)

    # ---------------------------------------------------------

    def getFrontRay(self):
        return self._frontray

    frontray = property(fget=getFrontRay)

    # -----------------------------------------------------------------

    def getHitGround(self):
        return self._hit_ground

    def setHitGround(self, value):
        if type(value) != bool:
            raise TypeError("Type should be %s not %s" % (bool, type(value)))
        self._hit_ground = value

    hit_ground = property(fget=getHitGround, fset=setHitGround)

    # -----------------------------------------------------------------

    def getControlStrength(self):
        return self._control_strength

    def setControlStrength(self, value):
        self._control_strength = value

    control_strength = property(fget=getControlStrength,
                                fset=setControlStrength)

    # -----------------------------------------------------------------

    def getBoostStrength(self):
        return self._boost_strength

    def setBoostStrength(self, value):
        self._boost_strength = value

    boost_strength = property(fget=getBoostStrength, fset=setBoostStrength)

    # -----------------------------------------------------------------

    def getGripStrength(self):
        return self._grip_strength

    def setGripStrength(self, value):
        self._grip_strength = value

    grip_strength = property(fget=getGripStrength, fset=setGripStrength)

    # -----------------------------------------------------------------

    def getTrackGrip(self):
        return self._track_grip

    def setTrackGrip(self, value):
        self._track_grip = value

    track_grip = property(fget=getTrackGrip, fset=setTrackGrip)

    # -----------------------------------------------------------------

    def getMaxEnergy(self):
        return self._max_energy

    def setMaxEnergy(self, value):
        self._max_energy = value

    max_energy = property(fget=getMaxEnergy, fset=setMaxEnergy)

    # -----------------------------------------------------------------

    def getMaxArmor(self):
        return self._max_armor

    def setMaxArmor(self, value):
        self._max_armor = value

    max_armor = property(fget=getMaxArmor, fset=setMaxArmor)

    # -----------------------------------------------------------------

    def getWeight(self):
        return self._weight

    def setWeight(self, value):
        self._weight = value

    weight = property(fget=getWeight, fset=setWeight)

    # -----------------------------------------------------------------

    def getDescription(self):
        return self._description

    def setDescription(self, value):
        self._description = value

    description = property(fget=getDescription, fset=setDescription)

    # -----------------------------------------------------------------

    def getBrakeStrength(self):
        return self._brake_strength

    def setBrakeStrength(self, value):
        self._brake_strength = value

    brake_strength = property(fget=getBrakeStrength, fset=setBrakeStrength)

    # -----------------------------------------------------------------

    def getName(self):
        return self._name

    def setName(self, value):
        self._name = value

    name = property(fget=getName, fset=setName)

    # -----------------------------------------------------------------

    def getStreetNormal(self):
        return self._streetnormal

    def setStreetNormal(self, value):
        self._streetnormal = value

    streetnormal = property(fget=getStreetNormal, fset=setStreetNormal)

    # -----------------------------------------------------------------

    def cleanResources(self):
        '''
        Removes old nodes, gets called when a new vehcile loads
        '''
        for node in self._blowout:
            node.removeNode()
            self._blowout = []

        if self._model is not None:
            for node in self._model.getChildren():
                node.removeNode()
            self._model.removeNode()
            self._model = None
            # self._physics_model.destroy()
            # self._collision_model.destroy()
            # temporary fix because destroy() doesnt work
            self._physics_model.disable()
            self._collision_model.disable()

        self._notify.info("Vehicle-Object cleaned: %s" % (self))

    def __del__(self):
        '''
        Destroy unused nodes
        '''
        for node in self._blowout:
            node.removeNode()

        if self._model is not None:
            for node in self._model.getChildren():
                node.removeNode()
            self._model.removeNode()
            self._model = None
            self._physics_model.destroy()
            self._collision_model.destroy()
            # temporary fix because destroy() doesnt work
            self._physics_model.disable()
            self._collision_model.disable()

        self._notify.info("Vehicle-Object deleted: %s" % (self))