Example #1
0
class Obstacle:
    def __init__(self, x, y, z):

        self.model = loader.loadModel("models/cube")
        self.model.reparentTo(render)
        self.model.setPos(x, y, z)
        self.model.setHpr(0, 0, 0)
        self.model.setColor(0.9, 0.9, 0.9, 1)
        self.model.setTexture(loader.loadTexture("textures/texture.png"))

    def enable_physics(self, physics):

        self.body = OdeBody(physics.world)
        self.initial_position = self.model.getPos(render)
        self.initial_quaternion = self.model.getQuat(render)
        self.reset()

        mass = OdeMass()
        mass.setBox(0.2, 1, 1, 1)
        self.body.setMass(mass)

        self.geom = OdeBoxGeom(physics.space, 1, 1, 1)
        self.geom.setBody(self.body)

        physics.bodymodels[self.body] = self.model

    def reset(self):
        self.body.setPosition(self.initial_position)
        self.body.setQuaternion(self.initial_quaternion)
        self.body.setLinearVel(0, 0, 0)
        self.body.setAngularVel(0, 0, 0)
class Sphere(GameObject):
	def __init__(self, world, parent, color, pos, dir, radius, density, posParent=None):
		GameObject.__init__(self, world)

		self.node = parent.attachNewNode("")
		if posParent == None:
			self.node.setPos(*pos)
		else:
			self.node.setPos(posParent, *pos)
		self.node.setColor(*color)
		self.node.setScale(radius)
		self.node.lookAt(self.node, *dir)
		self.parent = parent

		self.color = color
		self.scale = radius

		self.model = loader.loadModel("models/smiley.egg")
		self.model.reparentTo(self.node)

		self.mass = OdeMass()
		self.mass.setSphere(density, radius)
		self.body = OdeBody(world.world)
		self.body.setMass(self.mass)
		self.body.setPosition(self.node.getPos())
		self.body.setQuaternion(self.node.getQuat())
		self.body.setData(self)
		self.geom = OdeSphereGeom(world.space, radius)
		self.geom.setBody(self.body)
		world.space.setSurfaceType(self.geom, world.surfaces["sphere"])

	def onCollision(self, otherBody, entry):
		if otherBody.isEmpty(): # Collision on a wall
			geom = entry.getContactGeom(0)
			Ripple(self.parent, self.color, geom.getPos(), geom.getNormal() * -1, self.scale * 2.5)
Example #3
0
 def createBallBody(self, modelNode, world):
     ballBody = OdeBody(world)
     M = OdeMass()
     M.setSphere(Ball.BALL_BODY_MASS_WEIGHT, Ball.BALL_BODY_MASS_RADIUS)
     ballBody.setMass(M)
     ballBody.setPosition(modelNode.getPos(render))
     ballBody.setQuaternion(modelNode.getQuat(render))
     return ballBody
Example #4
0
    def createTire(self, tireIndex):
        if tireIndex < 0 or tireIndex >= len(self.tireMasks):
            self.notify.error('invalid tireIndex %s' % tireIndex)

        self.notify.debug('create tireindex %s' % tireIndex)
        zOffset = 0
        body = OdeBody(self.world)
        mass = OdeMass()
        mass.setSphere(self.tireDensity, IceGameGlobals.TireRadius)
        body.setMass(mass)
        body.setPosition(IceGameGlobals.StartingPositions[tireIndex][0],
                         IceGameGlobals.StartingPositions[tireIndex][1],
                         IceGameGlobals.StartingPositions[tireIndex][2])
        body.setAutoDisableDefaults()
        geom = OdeSphereGeom(self.space, IceGameGlobals.TireRadius)
        self.space.setSurfaceType(geom, self.tireSurfaceType)
        self.space.setCollideId(geom, self.tireCollideIds[tireIndex])
        self.massList.append(mass)
        self.geomList.append(geom)
        geom.setCollideBits(self.allTiresMask | self.wallMask | self.floorMask
                            | self.obstacleMask)
        geom.setCategoryBits(self.tireMasks[tireIndex])
        geom.setBody(body)
        if self.notify.getDebug():
            self.notify.debug('tire geom id')
            geom.write()
            self.notify.debug(' -')

        if self.canRender:
            testTire = render.attachNewNode('tire holder %d' % tireIndex)
            smileyModel = NodePath()
            if not smileyModel.isEmpty():
                smileyModel.setScale(IceGameGlobals.TireRadius)
                smileyModel.reparentTo(testTire)
                smileyModel.setAlphaScale(0.5)
                smileyModel.setTransparency(1)

            testTire.setPos(IceGameGlobals.StartingPositions[tireIndex])
            tireModel = loader.loadModel(
                'phase_4/models/minigames/ice_game_tire')
            tireHeight = 1
            tireModel.setZ(-(IceGameGlobals.TireRadius) + 0.01)
            tireModel.reparentTo(testTire)
            self.odePandaRelationList.append((testTire, body))
        else:
            testTire = None
            self.bodyList.append((None, body))
        return (testTire, body, geom)
 def createTire(self, tireIndex):
     if tireIndex < 0 or tireIndex >= len(self.tireMasks):
         self.notify.error("invalid tireIndex %s" % tireIndex)
     self.notify.debug("create tireindex %s" % tireIndex)
     zOffset = 0
     body = OdeBody(self.world)
     mass = OdeMass()
     mass.setSphere(self.tireDensity, IceGameGlobals.TireRadius)
     body.setMass(mass)
     body.setPosition(
         IceGameGlobals.StartingPositions[tireIndex][0],
         IceGameGlobals.StartingPositions[tireIndex][1],
         IceGameGlobals.StartingPositions[tireIndex][2],
     )
     body.setAutoDisableDefaults()
     geom = OdeSphereGeom(self.space, IceGameGlobals.TireRadius)
     self.space.setSurfaceType(geom, self.tireSurfaceType)
     self.space.setCollideId(geom, self.tireCollideIds[tireIndex])
     self.massList.append(mass)
     self.geomList.append(geom)
     geom.setCollideBits(self.allTiresMask | self.wallMask | self.floorMask | self.obstacleMask)
     geom.setCategoryBits(self.tireMasks[tireIndex])
     geom.setBody(body)
     if self.notify.getDebug():
         self.notify.debug("tire geom id")
         geom.write()
         self.notify.debug(" -")
     if self.canRender:
         testTire = render.attachNewNode("tire holder %d" % tireIndex)
         smileyModel = NodePath()
         if not smileyModel.isEmpty():
             smileyModel.setScale(IceGameGlobals.TireRadius)
             smileyModel.reparentTo(testTire)
             smileyModel.setAlphaScale(0.5)
             smileyModel.setTransparency(1)
         testTire.setPos(IceGameGlobals.StartingPositions[tireIndex])
         tireModel = loader.loadModel("phase_4/models/minigames/ice_game_tire")
         tireHeight = 1
         tireModel.setZ(-IceGameGlobals.TireRadius + 0.01)
         tireModel.reparentTo(testTire)
         self.odePandaRelationList.append((testTire, body))
     else:
         testTire = None
         self.bodyList.append((None, body))
     return (testTire, body, geom)
class Sphere(GameObject):
    def __init__(self,
                 world,
                 parent,
                 color,
                 pos,
                 dir,
                 radius,
                 density,
                 posParent=None):
        GameObject.__init__(self, world)

        self.node = parent.attachNewNode("")
        if posParent == None:
            self.node.setPos(*pos)
        else:
            self.node.setPos(posParent, *pos)
        self.node.setColor(*color)
        self.node.setScale(radius)
        self.node.lookAt(self.node, *dir)
        self.parent = parent

        self.color = color
        self.scale = radius

        self.model = loader.loadModel("models/smiley.egg")
        self.model.reparentTo(self.node)

        self.mass = OdeMass()
        self.mass.setSphere(density, radius)
        self.body = OdeBody(world.world)
        self.body.setMass(self.mass)
        self.body.setPosition(self.node.getPos())
        self.body.setQuaternion(self.node.getQuat())
        self.body.setData(self)
        self.geom = OdeSphereGeom(world.space, radius)
        self.geom.setBody(self.body)
        world.space.setSurfaceType(self.geom, world.surfaces["sphere"])

    def onCollision(self, otherBody, entry):
        if otherBody.isEmpty():  # Collision on a wall
            geom = entry.getContactGeom(0)
            Ripple(self.parent, self.color, geom.getPos(),
                   geom.getNormal() * -1, self.scale * 2.5)
    def initPlanet(self, parent, tex, pos, radius, mass, lvel, avel):
        planet = loader.loadModel(self.main.modeld + "planet")
        planet.reparentTo(parent)
        planet_tex = loader.loadTexture(tex)
        planet.setTexture(planet_tex)
        planet.setPos(pos)
        planet.setScale(radius)

        body = OdeBody(self.main.physicsWorld)
        M = OdeMass()
        M.setSphereTotal(mass, radius)
        body.setMass(M)
        body.setPosition(planet.getPos(parent))
        body.setQuaternion(planet.getQuat(parent))
        body.setLinearVel(lvel)
        body.setAngularVel(avel)

        geom = OdeSphereGeom(self.main.space, radius)
        geom.setBody(body)

        self.main.getPlist().append(planet)
        self.main.getBlist().append(body)
        self.main.getGlist().append(geom)
Example #8
0
class Pallo(Collectible):
    
    
    def __init__(self, game, color):
        self.game = game
        
        
        self.visualNode = NodePath('Visual node')
        self.visualNode.reparentTo(render)
        model = loader.loadModel('testipalikka.egg')
        model.reparentTo(self.visualNode)

        plight = PointLight('plight')
        plight.setPoint( Point3(0.6, 0, 5) )
        plight.setColor( color )
        plight.setAttenuation( Vec3(0.5, 0.01, 0.01) )
        plightNodePath = model.attachNewNode(plight)
        model.setLight(plightNodePath)
        
        self.body = OdeBody(game.physicsWorld)
        self.mass = OdeMass()
        self.mass.setBox(10,1,1,1)
        self.body.setMass(self.mass)
        self.body.setGravityMode(False)
        #self.juttu = OdeUtil()
        
        self.collGeom = OdeSphereGeom( self.game.physicsSpace, 2)
        self.collGeom.setBody(self.body)
        self.collGeom.setCategoryBits( BitMask32(0xffffffff) )
        self.collGeom.setCollideBits( BitMask32(0xffffffff) )
    

    def PowerUpEffect(self, ship):
        ship.mass.add(self.mass)
        ship.addPower(-20)
        print ship.SHIP_TYPE + " lost 20 power!!"
class AeroplanePhysics(Physical):
    def __init__(self, node):

        Physical.__init__(self)

        self.node = node
        self.thrust = 0.0
        self.loadSpecs()

        # precalculated values for combinations of variables
        self.setCalculationConstants()

        # dynamic variables
        self.acceleration = Vec3(0.0,0.0,0.0)
        self.angle_of_attack = 0.0
        
        # state variables
        self.rudder = 0.0
        self.ailerons = 0.0
        self.elevator = 0.0
        
        
        self.ode_body = OdeBody(self.world)
        # positions and orientation are set relative to render
        self.ode_body.setPosition(self.node.getPos(render))
        self.ode_body.setQuaternion(self.node.getQuat(render))
        
        self.ode_mass = OdeMass()
        self.ode_mass.setBox(self.mass, 1, 1, 1)
        self.ode_body.setMass(self.ode_mass)
        
        self.accumulator = 0.0
        self.step_size = 0.02
        taskMgr.add(self.simulationTask,
                    "plane physics",
                    sort=-1,
                    taskChain="world")

    def loadSpecs(self):
        """Loads specifications for a plane. Force if already loaded."""

        # TODO (gjmm): these are specifications and should be moved to a file

        self.mass = 1000
        self.max_thrust = 5000.0

        self.wing_area = 48.0 # m^2
        self.wing_span = 24.0 # m

        self.drag_coef_x = 0.9
        self.drag_coef_y = 0.1
        self.drag_coef_z = 0.9
        self.drag_area_x = 30.0
        self.drag_area_y = 2.75
        self.drag_area_z = 50.0
        self.aspect_ratio = self.wing_span * self.wing_span /self.wing_area

        # What the hell is this?! I still don't get it... :-(
        # Does this need to be individual per plane?
        # -Nemesis13
        self.liftvsaoa = ListInterpolator([[radians(-10.0),-0.4],
                                           [radians(-8.0),-0.45],
                                           [radians(15.0),1.75],
                                           [radians(18.0),1.05]],
                                           0.0,0.0)
        self.dragvsaoa = ListInterpolator([[radians(-10.0),-0.010],
                                           [radians(0.0),0.006],
                                           [radians(4.0),0.005],
                                           [radians(8.0),0.0065],
                                           [radians(12.0),0.012],
                                           [radians(14.0),0.020],
                                           [radians(16.0),0.028]],
                                           0.03,0.1)

        self.yaw_damping = -100
        self.pitch_damping = -100
        self.roll_damping = -100
        
        self.terminal_yaw = 3
        self.terminal_pitch = 3
        self.terminal_roll = 3
        
        self.rudder_coefficient = 1.0
        self.elevator_coefficient = 4.5
        self.ailerons_coefficient = 5.5
        
        self.pitch_force_coefficient = 4.0
        self.heading_force_coefficient = 1.0
        self.pitch_torque_coefficient = 0.1
        self.heading_torque_coefficient = 12.0
    
    def move(self, movement):
        """Plane movement management."""
        if movement == "roll-left":
            self.ailerons = -1.0
        elif movement == "roll-right":
            self.ailerons = 1.0
        elif movement == "pitch-up":
            self.elevator = 1.0
        elif movement == "pitch-down":
            self.elevator = -1.0
        elif movement == "heading-left":
            self.rudder = 1.0
        elif movement == "heading-right":
            self.rudder = -1.0

    def chThrust(self, value):
        delta_time = global_clock.getDt()
        if value == "add" and self.thrust < 1.0:
            self.thrust += 0.01
        elif value == "subtract" and self.thrust > 0.0:
            self.thrust -= 0.01

    def setThrust(self, value):
        if value <= 0:
            self.thrust = 0
        elif value >= 1:
            self.thrust = 1
        else:
            self.thrust = value

    def getThrust(self):
        return self.thrust

    def setCalculationConstants(self):
        """pre-calculate some calculation constants from the
        flight parameters"""
        # density of air: rho = 1.2041 kg m-3
        half_rho = 0.602
        self.lift_factor = half_rho * self.wing_area

        # could modify lift_induced_drag by a factor of 1.05 to 1.15
        self.lift_induced_drag_factor = (-1.0) * self.lift_factor / \
                                        (pi*self.aspect_ratio)
        self.drag_factor_x = (-1.0) * half_rho * self.drag_area_x * \
                                                 self.drag_coef_x
        self.drag_factor_y = (-1.0) * half_rho * self.drag_area_y * \
                                                 self.drag_coef_y
        self.drag_factor_z = (-1.0) * half_rho * self.drag_area_z * \
                                                 self.drag_coef_z

        self.gravity = Vec3(0.0,0.0,-9.81) 
        self.gravityM = self.gravity * self.mass

    def _wingAngleOfAttack(self,v_norm,up):
        """ calculate the angle between the wing and the relative motion of the air """

        #projected_v = v_norm - right * v_norm.dot(right)
        #aoa = atan2(projected_v.dot(-up), projected_v.dot(forward))
        #return aoa

        # strangely enough, the above gets the same result as the below
        # for these vectors it must be calculating the angle in the plane where
        # right is the normal vector

        return v_norm.angleRad(up) - pi/2.0


    def _lift(self,v_norm,v_squared,right,aoa):
        """return the lift force vector generated by the wings"""
        # lift direction is always perpendicular to the airflow
        lift_vector = right.cross(v_norm)
        return lift_vector * v_squared * self.lift_factor * self.liftvsaoa[aoa]

    def _drag(self,v,v_squared,right,up,forward,aoa):
        """return the drag force"""

        # get the induced drag coefficient
        # Cdi = (Cl*Cl)/(pi*AR*e)

        lift_coef = self.liftvsaoa[aoa]
        ind_drag_coef = lift_coef * lift_coef / (pi * self.aspect_ratio * 1.10)

        # and calculate the drag induced by the creation of lift
        induced_drag =  -v * sqrt(v_squared) * self.lift_factor * ind_drag_coef
        #induced_drag = Vec3(0.0,0.0,0.0)
        profile_drag = self._simpleProfileDrag(v,right,up,forward)

        return induced_drag + profile_drag

    def _simpleProfileDrag(self,v,right,up,forward):
        """return the force vector due to the shape of the aircraft"""
        speed_x = right.dot(v)
        speed_y = forward.dot(v)
        speed_z = up.dot(v)

        drag_x = right*speed_x*abs(speed_x)*self.drag_factor_x
        drag_y = forward*speed_y*abs(speed_y)*self.drag_factor_y
        drag_z = up*speed_z*abs(speed_z)*self.drag_factor_z
        return drag_x + drag_y + drag_z

    def _thrust(self,thrust_vector):
        """return the force vector produced by the aircraft engines"""
        return thrust_vector * self.thrust * self.max_thrust

    def _force(self,p,v,right,up,forward):
        """calculate the forces due to the velocity and orientation of the aircraft"""
        v_squared = v.lengthSquared()
        v_norm = v + v.zero()
        v_norm.normalize()

        aoa = self._wingAngleOfAttack(v_norm,up)
        lift = self._lift(v_norm,v_squared,right,aoa)
        drag = self._drag(v,v_squared,right,up,forward,aoa)
        thrust = self._thrust(forward)
        self.angle_of_attack = aoa

        force = lift + drag + self.gravityM + thrust

        # if the plane is on the ground, the ground reacts to the downward force
        # TODO (gjmm): need to modify in order to consider reaction to objects
        #              at different altitudes.
        if p.getZ() == 0.0:
            if force[2] < 0.0:
                force.setZ(0.0)
        
        return force
    
    def angleOfAttack(self):
        return self.angle_of_attack
    def gForceTotal(self):
        acc = self.acceleration - self.gravity
        return acc.length()/9.81
    def gForce(self):
        up = self.node.getQuat().getUp()
        acc = self.acceleration - self.gravity
        gf = acc.dot(up) / 9.81
        return gf

    def lateralG(self):
        right = self.node.getQuat().getRight()
        acc = self.acceleration - self.gravity
        gf = acc.dot(right) / 9.81
        return gf

    def axialG(self):
        forward = self.node.getQuat().getForward()
        acc = self.acceleration - self.gravity
        gf = acc.dot(forward) / 9.81
        return gf

    def velocity(self):
        """ return the current velocity """
        #return self.physics_object.getVelocity()
        return Vec3(self.ode_body.getLinearVel())
    def setVelocity(self,v):
        self.ode_body.setLinearVel(v)
    
    def angVelVector(self):
        """ return the current angular velocity as a vector """
        return self.ode_body.getAngularVel()
    
    def angVelBodyHpr(self):
        """ return the heading, pitch and roll values about the body axis """
        angv = self.angVelVector()
        quat = self.quat()
        h = angv.dot(quat.getUp())
        p = angv.dot(quat.getRight())
        r = angv.dot(quat.getForward())
        return h,p,r
    
    def setAngularVelocity(self,v):
        self.ode_body.setAngularVel(v)
    
    def speed(self):
        """ returns the current velocity """
        return self.velocity().length()
        
    def position(self):
        """ return the current position """
        return self.ode_body.getPosition()
    def setPosition(self,p):
        self.ode_body.setPosition(p)
    
    def altitude(self):
        """ returns the current altitude """
        return self.position().getZ()
    
    def quat(self):
        """ return the current quaternion representation of the attitude """
        return Quat(self.ode_body.getQuaternion())
    
    def _controlRotForce(self,control,axis,coeff,speed,rspeed,max_rspeed):
        """ generic control rotation force
        control - positive or negative amount of elevator/rudder/ailerons
        axis - vector about which the torque is applied
        coeff - the conversion of the amount of the control to a rotational force
        speed - the speed of the plane
        rspeed - the current rotational speed about the axis
        max_rspeed - a cut-off for the rotational speed
        """
        if control * rspeed < max_rspeed:
            return axis * control * coeff * speed
        else:
            return Vec3(0.0,0.0,0.0)
    
    def _rotDamping(self,vector,rotv,damping_factor):
        """ generic damping """
        damp = damping_factor * rotv
        
        # rather than trusting that we have the sign right at any point
        # decide sign of the returned value based on the speed
        if rotv < 0.0:
            return vector * abs(damp)
        else:
            return vector * -abs(damp)
    
    def _forwardAndVelocityVectorForces(self,up,right,norm_v,speed):
        """ calculates torque and force resulting from deviation of the
        velocity vector from the forward vector """
        
        # could do with a better name for this method
        
        # get the projection of the normalised velocity onto the up and
        # right vectors to find relative pitch and heading angles
        p_angle = acos(up.dot(norm_v)) - pi/2
        h_angle = acos(right.dot(norm_v)) - pi/2
        
        torque_p = p_angle*self.pitch_torque_coefficient*speed
        torque_h = h_angle*self.heading_torque_coefficient*speed
        force_p = p_angle*self.pitch_force_coefficient*speed
        force_h = h_angle*self.heading_force_coefficient*speed
        
        return Vec3(-torque_p, 0.0, torque_h), Vec3(-force_p, 0.0, force_h)
    
    def simulationTask(self,task):
        """Update position and velocity based on aerodynamic forces."""
        delta_time = global_clock.getDt()
        self.accumulator += delta_time
        updated = False
        #print self.accumulator, delta_time
        while self.accumulator > self.step_size:
            self.accumulator -= self.step_size
            updated = True
            
            position = self.position()
            velocity = self.velocity()
            speed = velocity.length()
            norm_v = velocity + Vec3(0.0,0.0,0.0)
            norm_v.normalize()
            
            yawv,pitchv,rollv = self.angVelBodyHpr()
            
            quat = self.quat()
            forward = quat.getForward()
            up = quat.getUp()
            right = quat.getRight()
            
            linear_force = self._force(position,velocity,right,up,forward)
            
            self.ode_body.addForce(linear_force)

            # Control forces:
            elevator_af = self._controlRotForce(self.elevator,Vec3(1.0,0.0,0.0),
                                                self.elevator_coefficient,
                                                speed,pitchv,self.terminal_pitch)
            ailerons_af = self._controlRotForce(self.ailerons,Vec3(0.0,1.0,0.0),
                                                self.ailerons_coefficient,
                                                speed,rollv,self.terminal_roll)
            rudder_af = self._controlRotForce(self.rudder,Vec3(0.0,0.0,1.0),
                                                self.rudder_coefficient,
                                                speed,yawv,self.terminal_yaw)

            # Damping forces
            pitch_damping_avf = self._rotDamping(Vec3(1.0,0.0,0.0),pitchv,self.pitch_damping)
            roll_damping_avf = self._rotDamping(Vec3(0.0,1.0,0.0),rollv,self.roll_damping)
            yaw_damping_avf = self._rotDamping(Vec3(0.0,0.0,1.0),yawv,self.yaw_damping)

            self.ode_body.addRelTorque(elevator_af + ailerons_af + rudder_af +
                                     roll_damping_avf + pitch_damping_avf + yaw_damping_avf)

            # Forces to rotate the forward vector towards the velocity vector
            # and vice versa
            fvv_torque, fvv_force = self._forwardAndVelocityVectorForces(up,right,norm_v,speed)
            self.ode_body.addRelTorque(fvv_torque)
            self.ode_body.addForce(fvv_force)

            if position.getZ() < 0:
                position.setZ(0)
                velocity.setZ(0)
                self.setPosition(position)
                self.setVelocity(velocity)
            self.rudder = 0.0
            self.elevator = 0.0
            self.ailerons = 0.0
            self.world.quickStep(self.step_size)
        if updated:
            self.node.setPosQuat(render, self.position(), quat)
        return task.cont

    def destroy():
        """Call this while deactivating physics on a plane."""
        # TODO: clean up stuff
        pass
Example #10
0
class Pallo(Collectible):
    
 #   COLLECTIBLE_TYPE = 'PointBall'
 #   VALUE = 1
 #   DRAIN = 20

    
    def __init__(self, game, color, value = 1, drain = 20):
        self.game = game
        self.VALUE = value
        self.DRAIN = drain
        
        #self.idnumber = id
        self.visualNode = NodePath('Visual node')
        self.visualNode.reparentTo(render)
        model = loader.loadModel('Ball2.egg')
        model.setScale(2.5)
        model.reparentTo(self.visualNode)

        plight = PointLight('plight')
        plight.setPoint( Point3(0, 0, 3) )
        plight.setColor( color )
        plight.setAttenuation( Vec3(0.05, 0.01, 0.01) )
        self.plightNodePath = model.attachNewNode(plight)
        model.setLight(self.plightNodePath)

        self.body = OdeBody(game.physicsWorld)
        self.mass = OdeMass()
        self.mass.setBox(10,1,1,1)
        self.body.setMass(self.mass)

        self.body.setGravityMode(True)

        #self.body.setGravityMode(False)
        #self.juttu = OdeUtil()
        
        self.collGeom = OdeSphereGeom( self.game.physicsSpace, 3.5)
        self.collGeom.setBody(self.body)
        self.collGeom.setCategoryBits( BitMask32(0xffffffff) )
        self.collGeom.setCollideBits( BitMask32(0xffffffff) )
    
    def getValue(self):
        return self.VALUE
    
    def hitShips(self, shipList):
        
        for ship in shipList:
            if OdeUtil.areConnected(ship.body, self.body) and not ship.hasBall():
                self.PowerUpEffect(ship)

    def PowerUpEffect(self, ship):
     #   ship.mass.add(self.mass)
        ship.addPower(-(self.DRAIN))
        ship.gotBall(self)
        self.hideObject()
        ship.visualNode.setLight(self.plightNodePath)
        
        #print player
        print ship.SHIP_TYPE + " lost " + str(self.DRAIN) + " power!!"
        
    def Restore(self, ship):
      #  ship.mass.add(self.mass)
        ship.addPower(self.DRAIN)
        self.showObject()
        ship.visualNode.clearLight(self.plightNodePath)
        #self.setPos( Vec3(random.randrange(30), random.randrange(40), 0))
        #ship.dropBall()
        #print player
        print ship.getShipType() + " regained 20 power!!"
class Character(GameObject):
    def __init__(self, world):
        GameObject.__init__(self, world)

        # Set the speed parameters
        self.vel = Vec3(0, 0, 0)
        self.strafespeed = 20.0
        self.forwardspeed = 32.0
        self.backspeed = 24.0
        self.jumpspeed = 20
        self.wasJumping = False

        # Set character dimensions
        self.size = (4.0, 3.0, 10.0)
        self.eyeHeight = 9.0
        self.offset = Point3(0, 0, self.eyeHeight - (self.size[2] / 2))

        # Create character node
        self.node = base.render.attachNewNode("character")
        self.node.setPos(0, 0, self.eyeHeight)
        self.node.lookAt(0, 1, self.eyeHeight)

        # Create physics representation
        self.mass = OdeMass()
        self.mass.setBox(50, *self.size)
        self.body = OdeBody(world.world)
        self.body.setMass(self.mass)
        self.updatePhysicsFromPos()
        self.body.setData(self)
        self.geom = OdeBoxGeom(world.space, Vec3(*self.size))
        self.geom.setBody(self.body)
        world.space.setSurfaceType(self.geom, world.surfaces["box"])

        # Adjust collision bitmasks.
        self.geom.setCategoryBits(GameObject.bitmaskCharacter)
        self.geom.setCollideBits(GameObject.bitmaskAll & ~GameObject.bitmaskBullet)

        # Setup event handling
        self.keys = [0, 0, 0, 0, 0]
        self.setupKeys()
        base.taskMgr.add(self.moveTask, "character-move")

        # Create footsteps sound
        self.footstepsSound = base.loader.loadSfx("media/footsteps.wav")
        self.footstepsSound.setLoop(1)
        self.footsteps = SoundWrapper(self.footstepsSound)

        # Create other sounds.
        self.jumpSound = base.loader.loadSfx("media/jump_start.wav")
        self.landSound = base.loader.loadSfx("media/jump_fall.wav")

    def updatePosFromPhysics(self):
        self.node.setPos(render, self.body.getPosition() + self.offset)
        self.body.setAngularVel(0, 0, 0)

    def updatePhysicsFromPos(self):
        self.body.setPosition(self.node.getPos() - self.offset)
        self.body.setQuaternion(self.node.getQuat())

    def getDir(self):
        return base.render.getRelativeVector(self.node, (0, 1, 0))

    def moveTo(self, pos):
        self.node.setPos(pos)
        self.updatePhysicsFromPos()

    def recoil(self, mag):
        vel = self.body.getLinearVel()
        diff = self.getDir() * mag

        # Limit recoil
        if sign(vel[0]) != sign(diff[0]) and abs(vel[0]) > 15:
            diff[0] = 0
        if sign(vel[1]) != sign(diff[1]) and abs(vel[1]) > 15:
            diff[1] = 0
        diff[2] = 0

        self.body.setLinearVel(vel - diff)

    def jump(self):
        vel = self.body.getLinearVel()
        self.body.setLinearVel(vel[0], vel[1], vel[2] + self.jumpspeed)
        self.jumpSound.play()

    def isJumping(self):
        return abs(self.body.getLinearVel()[2]) > 0.05

    def setKey(self, button, value):
        self.keys[button] = value

    def setupKeys(self):
        base.accept("w", self.setKey, [0, 1])  # forward
        base.accept("s", self.setKey, [1, 1])  # back
        base.accept("a", self.setKey, [2, 1])  # strafe left
        base.accept("d", self.setKey, [3, 1])  # strafe right
        base.accept("space", self.setKey, [4, 1])  # jump
        base.accept("w-up", self.setKey, [0, 0])
        base.accept("s-up", self.setKey, [1, 0])
        base.accept("a-up", self.setKey, [2, 0])
        base.accept("d-up", self.setKey, [3, 0])
        base.accept("space-up", self.setKey, [4, 0])

    def moveTask(self, task):
        # Initialize variables
        elapsed = globalClock.getDt()
        x = 0.0
        y = 0.0
        jumping = self.isJumping()

        # Calculate movement vector.
        if self.keys[0] != 0:
            y = self.forwardspeed
        if self.keys[1] != 0:
            y = -self.backspeed
        if self.keys[2] != 0:
            x = -self.strafespeed
        if self.keys[3] != 0:
            x = self.strafespeed
        self.vel = Vec3(x, y, 0)
        self.vel *= elapsed

        # Move the character along the ground.
        hpr = self.node.getHpr()
        self.node.setP(0)
        self.node.setR(0)
        self.node.setPos(self.node, self.vel)
        self.updatePhysicsFromPos()
        self.node.setHpr(hpr)

        # Play landing sound (if applicable).
        if self.wasJumping and not jumping:
            pass  # Landing detection not working.
            # self.landSound.play()

            # Jump (if applicable).
        if self.keys[4] and not jumping:
            self.jump()
        self.wasJumping = jumping

        # Play footsteps if walking.
        if not jumping and (self.keys[0] != 0 or self.keys[1] != 0 or self.keys[2] != 0 or self.keys[3] != 0):
            self.footsteps.resume()
        else:
            self.footsteps.pause()

        return task.cont
class AeroplanePhysics(Physical):
    def __init__(self, node):

        Physical.__init__(self)

        self.node = node
        self.thrust = 0.0
        self.loadSpecs()

        # precalculated values for combinations of variables
        self.setCalculationConstants()

        # dynamic variables
        self.acceleration = Vec3(0.0, 0.0, 0.0)
        self.angle_of_attack = 0.0

        # state variables
        self.rudder = 0.0
        self.ailerons = 0.0
        self.elevator = 0.0

        self.ode_body = OdeBody(self.world)
        # positions and orientation are set relative to render
        self.ode_body.setPosition(self.node.getPos(render))
        self.ode_body.setQuaternion(self.node.getQuat(render))

        self.ode_mass = OdeMass()
        self.ode_mass.setBox(self.mass, 1, 1, 1)
        self.ode_body.setMass(self.ode_mass)

        self.accumulator = 0.0
        self.step_size = 0.02
        taskMgr.add(self.simulationTask,
                    "plane physics",
                    sort=-1,
                    taskChain="world")

    def loadSpecs(self):
        """Loads specifications for a plane. Force if already loaded."""

        # TODO (gjmm): these are specifications and should be moved to a file

        self.mass = 1000
        self.max_thrust = 5000.0

        self.wing_area = 48.0  # m^2
        self.wing_span = 24.0  # m

        self.drag_coef_x = 0.9
        self.drag_coef_y = 0.1
        self.drag_coef_z = 0.9
        self.drag_area_x = 30.0
        self.drag_area_y = 2.75
        self.drag_area_z = 50.0
        self.aspect_ratio = self.wing_span * self.wing_span / self.wing_area

        # What the hell is this?! I still don't get it... :-(
        # Does this need to be individual per plane?
        # -Nemesis13
        self.liftvsaoa = ListInterpolator(
            [[radians(-10.0), -0.4], [radians(-8.0), -0.45],
             [radians(15.0), 1.75], [radians(18.0), 1.05]], 0.0, 0.0)
        self.dragvsaoa = ListInterpolator(
            [[radians(-10.0), -0.010], [radians(0.0), 0.006],
             [radians(4.0), 0.005], [radians(8.0), 0.0065],
             [radians(12.0), 0.012], [radians(14.0), 0.020],
             [radians(16.0), 0.028]], 0.03, 0.1)

        self.yaw_damping = -100
        self.pitch_damping = -100
        self.roll_damping = -100

        self.terminal_yaw = 3
        self.terminal_pitch = 3
        self.terminal_roll = 3

        self.rudder_coefficient = 1.0
        self.elevator_coefficient = 4.5
        self.ailerons_coefficient = 5.5

        self.pitch_force_coefficient = 4.0
        self.heading_force_coefficient = 1.0
        self.pitch_torque_coefficient = 0.1
        self.heading_torque_coefficient = 12.0

    def move(self, movement):
        """Plane movement management."""
        if movement == "roll-left":
            self.ailerons = -1.0
        elif movement == "roll-right":
            self.ailerons = 1.0
        elif movement == "pitch-up":
            self.elevator = 1.0
        elif movement == "pitch-down":
            self.elevator = -1.0
        elif movement == "heading-left":
            self.rudder = 1.0
        elif movement == "heading-right":
            self.rudder = -1.0

    def chThrust(self, value):
        delta_time = global_clock.getDt()
        if value == "add" and self.thrust < 1.0:
            self.thrust += 0.01
        elif value == "subtract" and self.thrust > 0.0:
            self.thrust -= 0.01

    def setThrust(self, value):
        if value <= 0:
            self.thrust = 0
        elif value >= 1:
            self.thrust = 1
        else:
            self.thrust = value

    def getThrust(self):
        return self.thrust

    def setCalculationConstants(self):
        """pre-calculate some calculation constants from the
        flight parameters"""
        # density of air: rho = 1.2041 kg m-3
        half_rho = 0.602
        self.lift_factor = half_rho * self.wing_area

        # could modify lift_induced_drag by a factor of 1.05 to 1.15
        self.lift_induced_drag_factor = (-1.0) * self.lift_factor / \
                                        (pi*self.aspect_ratio)
        self.drag_factor_x = (-1.0) * half_rho * self.drag_area_x * \
                                                 self.drag_coef_x
        self.drag_factor_y = (-1.0) * half_rho * self.drag_area_y * \
                                                 self.drag_coef_y
        self.drag_factor_z = (-1.0) * half_rho * self.drag_area_z * \
                                                 self.drag_coef_z

        self.gravity = Vec3(0.0, 0.0, -9.81)
        self.gravityM = self.gravity * self.mass

    def _wingAngleOfAttack(self, v_norm, up):
        """ calculate the angle between the wing and the relative motion of the air """

        #projected_v = v_norm - right * v_norm.dot(right)
        #aoa = atan2(projected_v.dot(-up), projected_v.dot(forward))
        #return aoa

        # strangely enough, the above gets the same result as the below
        # for these vectors it must be calculating the angle in the plane where
        # right is the normal vector

        return v_norm.angleRad(up) - pi / 2.0

    def _lift(self, v_norm, v_squared, right, aoa):
        """return the lift force vector generated by the wings"""
        # lift direction is always perpendicular to the airflow
        lift_vector = right.cross(v_norm)
        return lift_vector * v_squared * self.lift_factor * self.liftvsaoa[aoa]

    def _drag(self, v, v_squared, right, up, forward, aoa):
        """return the drag force"""

        # get the induced drag coefficient
        # Cdi = (Cl*Cl)/(pi*AR*e)

        lift_coef = self.liftvsaoa[aoa]
        ind_drag_coef = lift_coef * lift_coef / (pi * self.aspect_ratio * 1.10)

        # and calculate the drag induced by the creation of lift
        induced_drag = -v * sqrt(v_squared) * self.lift_factor * ind_drag_coef
        #induced_drag = Vec3(0.0,0.0,0.0)
        profile_drag = self._simpleProfileDrag(v, right, up, forward)

        return induced_drag + profile_drag

    def _simpleProfileDrag(self, v, right, up, forward):
        """return the force vector due to the shape of the aircraft"""
        speed_x = right.dot(v)
        speed_y = forward.dot(v)
        speed_z = up.dot(v)

        drag_x = right * speed_x * abs(speed_x) * self.drag_factor_x
        drag_y = forward * speed_y * abs(speed_y) * self.drag_factor_y
        drag_z = up * speed_z * abs(speed_z) * self.drag_factor_z
        return drag_x + drag_y + drag_z

    def _thrust(self, thrust_vector):
        """return the force vector produced by the aircraft engines"""
        return thrust_vector * self.thrust * self.max_thrust

    def _force(self, p, v, right, up, forward):
        """calculate the forces due to the velocity and orientation of the aircraft"""
        v_squared = v.lengthSquared()
        v_norm = v + v.zero()
        v_norm.normalize()

        aoa = self._wingAngleOfAttack(v_norm, up)
        lift = self._lift(v_norm, v_squared, right, aoa)
        drag = self._drag(v, v_squared, right, up, forward, aoa)
        thrust = self._thrust(forward)
        self.angle_of_attack = aoa

        force = lift + drag + self.gravityM + thrust

        # if the plane is on the ground, the ground reacts to the downward force
        # TODO (gjmm): need to modify in order to consider reaction to objects
        #              at different altitudes.
        if p.getZ() == 0.0:
            if force[2] < 0.0:
                force.setZ(0.0)

        return force

    def angleOfAttack(self):
        return self.angle_of_attack

    def gForceTotal(self):
        acc = self.acceleration - self.gravity
        return acc.length() / 9.81

    def gForce(self):
        up = self.node.getQuat().getUp()
        acc = self.acceleration - self.gravity
        gf = acc.dot(up) / 9.81
        return gf

    def lateralG(self):
        right = self.node.getQuat().getRight()
        acc = self.acceleration - self.gravity
        gf = acc.dot(right) / 9.81
        return gf

    def axialG(self):
        forward = self.node.getQuat().getForward()
        acc = self.acceleration - self.gravity
        gf = acc.dot(forward) / 9.81
        return gf

    def velocity(self):
        """ return the current velocity """
        #return self.physics_object.getVelocity()
        return Vec3(self.ode_body.getLinearVel())

    def setVelocity(self, v):
        self.ode_body.setLinearVel(v)

    def angVelVector(self):
        """ return the current angular velocity as a vector """
        return self.ode_body.getAngularVel()

    def angVelBodyHpr(self):
        """ return the heading, pitch and roll values about the body axis """
        angv = self.angVelVector()
        quat = self.quat()
        h = angv.dot(quat.getUp())
        p = angv.dot(quat.getRight())
        r = angv.dot(quat.getForward())
        return h, p, r

    def setAngularVelocity(self, v):
        self.ode_body.setAngularVel(v)

    def speed(self):
        """ returns the current velocity """
        return self.velocity().length()

    def position(self):
        """ return the current position """
        return self.ode_body.getPosition()

    def setPosition(self, p):
        self.ode_body.setPosition(p)

    def altitude(self):
        """ returns the current altitude """
        return self.position().getZ()

    def quat(self):
        """ return the current quaternion representation of the attitude """
        return Quat(self.ode_body.getQuaternion())

    def _controlRotForce(self, control, axis, coeff, speed, rspeed,
                         max_rspeed):
        """ generic control rotation force
        control - positive or negative amount of elevator/rudder/ailerons
        axis - vector about which the torque is applied
        coeff - the conversion of the amount of the control to a rotational force
        speed - the speed of the plane
        rspeed - the current rotational speed about the axis
        max_rspeed - a cut-off for the rotational speed
        """
        if control * rspeed < max_rspeed:
            return axis * control * coeff * speed
        else:
            return Vec3(0.0, 0.0, 0.0)

    def _rotDamping(self, vector, rotv, damping_factor):
        """ generic damping """
        damp = damping_factor * rotv

        # rather than trusting that we have the sign right at any point
        # decide sign of the returned value based on the speed
        if rotv < 0.0:
            return vector * abs(damp)
        else:
            return vector * -abs(damp)

    def _forwardAndVelocityVectorForces(self, up, right, norm_v, speed):
        """ calculates torque and force resulting from deviation of the
        velocity vector from the forward vector """

        # could do with a better name for this method

        # get the projection of the normalised velocity onto the up and
        # right vectors to find relative pitch and heading angles
        p_angle = acos(up.dot(norm_v)) - pi / 2
        h_angle = acos(right.dot(norm_v)) - pi / 2

        torque_p = p_angle * self.pitch_torque_coefficient * speed
        torque_h = h_angle * self.heading_torque_coefficient * speed
        force_p = p_angle * self.pitch_force_coefficient * speed
        force_h = h_angle * self.heading_force_coefficient * speed

        return Vec3(-torque_p, 0.0, torque_h), Vec3(-force_p, 0.0, force_h)

    def simulationTask(self, task):
        """Update position and velocity based on aerodynamic forces."""
        delta_time = global_clock.getDt()
        self.accumulator += delta_time
        updated = False
        #print self.accumulator, delta_time
        while self.accumulator > self.step_size:
            self.accumulator -= self.step_size
            updated = True

            position = self.position()
            velocity = self.velocity()
            speed = velocity.length()
            norm_v = velocity + Vec3(0.0, 0.0, 0.0)
            norm_v.normalize()

            yawv, pitchv, rollv = self.angVelBodyHpr()

            quat = self.quat()
            forward = quat.getForward()
            up = quat.getUp()
            right = quat.getRight()

            linear_force = self._force(position, velocity, right, up, forward)

            self.ode_body.addForce(linear_force)

            # Control forces:
            elevator_af = self._controlRotForce(self.elevator,
                                                Vec3(1.0, 0.0, 0.0),
                                                self.elevator_coefficient,
                                                speed, pitchv,
                                                self.terminal_pitch)
            ailerons_af = self._controlRotForce(self.ailerons,
                                                Vec3(0.0, 1.0, 0.0),
                                                self.ailerons_coefficient,
                                                speed, rollv,
                                                self.terminal_roll)
            rudder_af = self._controlRotForce(self.rudder, Vec3(0.0, 0.0, 1.0),
                                              self.rudder_coefficient, speed,
                                              yawv, self.terminal_yaw)

            # Damping forces
            pitch_damping_avf = self._rotDamping(Vec3(1.0, 0.0, 0.0), pitchv,
                                                 self.pitch_damping)
            roll_damping_avf = self._rotDamping(Vec3(0.0, 1.0, 0.0), rollv,
                                                self.roll_damping)
            yaw_damping_avf = self._rotDamping(Vec3(0.0, 0.0, 1.0), yawv,
                                               self.yaw_damping)

            self.ode_body.addRelTorque(elevator_af + ailerons_af + rudder_af +
                                       roll_damping_avf + pitch_damping_avf +
                                       yaw_damping_avf)

            # Forces to rotate the forward vector towards the velocity vector
            # and vice versa
            fvv_torque, fvv_force = self._forwardAndVelocityVectorForces(
                up, right, norm_v, speed)
            self.ode_body.addRelTorque(fvv_torque)
            self.ode_body.addForce(fvv_force)

            if position.getZ() < 0:
                position.setZ(0)
                velocity.setZ(0)
                self.setPosition(position)
                self.setVelocity(velocity)
            self.rudder = 0.0
            self.elevator = 0.0
            self.ailerons = 0.0
            self.world.quickStep(self.step_size)
        if updated:
            self.node.setPosQuat(render, self.position(), quat)
        return task.cont

    def destroy():
        """Call this while deactivating physics on a plane."""
        # TODO: clean up stuff
        pass
Example #13
0
class Ship_1(Ship):
    
    POWER = 100
    SHIP_TYPE = "UFO"
    
    def __init__(self, game, color):
        #self.POWER = 100
        self.game = game
        
        self.thrust = False
        self.thrustLeft = False
        self.thrustRight = False
        self.thrustBack = False
        self.rotation = 0

        self.body = OdeBody(game.physicsWorld)
        self.mass = OdeMass()
        self.mass.setBox(10,1,1,1)
        self.body.setMass(self.mass)

        #odespheregeom(... , size of hitbox sphere)
        self.collGeom = OdeSphereGeom( self.game.physicsSpace, 5)
        self.collGeom.setBody(self.body)
        self.collGeom.setCategoryBits( BitMask32(0xffffffff) )
        self.collGeom.setCollideBits( BitMask32(0xffffffff) )
        
        self.visualNode = NodePath('Visual node')
        self.visualNode.reparentTo(render)
        model = loader.loadModel('lautanen2.egg')
        model.reparentTo(self.visualNode)
        
        plight = PointLight('plight')
        plight.setPoint( Point3(0.6, 0, 5) )
        plight.setColor( color )
        plight.setAttenuation( Vec3(0.5, 0.01, 0.01) )
        plightNodePath = model.attachNewNode(plight)
        model.setLight(plightNodePath)
        
 # setMoreKeys in ship class = BAD IDEA
    #def setMoreKeys(self):
     #   base.accept('arrow_down', self.thrustBackOn)
      #  base.accept('arrow_down-up', self.thrustBackOff) 
      

    def applyForces(self):
        if self.thrust:
            heading = self.getHeading()
            self.body.addForce(
              -math.sin( math.radians(heading) ) * self.POWER,
               math.cos( math.radians(heading) ) * self.POWER,
               0
            )
        if self.thrustLeft:
            heading = self.getHeading()
            self.body.addForce(
              -math.sin( math.radians(heading) + math.pi/2 ) * self.POWER,
               math.cos( math.radians(heading) + math.pi/2 ) * self.POWER,
               0
            )
        if self.thrustRight:
            heading = self.getHeading()
            self.body.addForce(
              -math.sin( math.radians(heading) - math.pi/2 ) * self.POWER,
               math.cos( math.radians(heading) - math.pi/2 ) * self.POWER,
               0
            )
        if self.thrustBack:
            heading = self.getHeading()
            self.body.addForce(
              -math.sin( math.radians(heading) + math.pi ) * self.POWER,
               math.cos( math.radians(heading) + math.pi ) * self.POWER,
               0
            )
Example #14
0
class Ship_2(Ship):
    
    ROTATING_SPEED = 1
    MAX_ROTATE_SPEED = 3.0
    SHIP_TYPE = "RAKETTI"
    
    def __init__(self, game, color):

        self.POWER = 100
        self.game = game
        
        self.thrust = False
        self.thrustLeft = False
        self.thrustRight = False
        self.thrustBack = False
        self.rotation = 0

        self.body = OdeBody(game.physicsWorld)
        self.mass = OdeMass()
        self.mass.setBox(10,1,1,1)
        self.body.setMass(self.mass)

        #odespheregeom(... , size of hitbox sphere)
        self.collGeom = OdeSphereGeom( self.game.physicsSpace, 2)
        self.collGeom.setBody(self.body)
        self.collGeom.setCategoryBits( BitMask32(0xffffffff) )
        self.collGeom.setCollideBits( BitMask32(0xffffffff) )
        
        self.visualNode = NodePath('Visual node')
        self.visualNode.reparentTo(render)
        model = loader.loadModel('testipalikka.egg')
        model.reparentTo(self.visualNode)
        
        plight = PointLight('plight')
        plight.setPoint( Point3(0.6, 0, 5) )
        plight.setColor( color )
        plight.setAttenuation( Vec3(0.5, 0.01, 0.01) )
        plightNodePath = model.attachNewNode(plight)
        model.setLight(plightNodePath)



    
    
    def rotating(self):
        if self.thrustLeft:
            self.setRotation(self.ROTATING_SPEED)
        if self.thrustRight:
            self.setRotation(-(self.ROTATING_SPEED))
        if not self.thrustRight and not self.thrustLeft:
            self.setRotation(0)


    def applyForces(self):
        if self.thrust:
            heading = self.getHeading()
            #addForce (x, y, z)
            self.body.addForce(
              -math.sin( math.radians(heading) ) * self.POWER,
               math.cos( math.radians(heading) ) * self.POWER,
              0
            )
# uncomment for backwards thrust (eli siis pakki)
#        if self.thrustBack:
#            heading = self.getHeading()
#            self.body.addForce(
#               math.sin( math.radians(heading) ) * self.POWER,
#              -math.cos( math.radians(heading) ) * self.POWER,
#              0
#            )
        self.rotating()
Example #15
0
class Box(GameObject):
	disableGracePeriod = 20
	
	def __init__(self, world, parent, color, pos, dir, size, density, unglueThreshold=None, shatterLimit=None, shatterThreshold=None):
		GameObject.__init__(self, world)

		if unglueThreshold == None: unglueThreshold = 20
		if shatterLimit == None: shatterLimit = 0
		if shatterThreshold == None: shatterThreshold = 30

		self.size = size
		self.density = density
		self.dir = dir
		self.parent = parent
		self.color = color = makeVec4Color(color)
		
		self.node = parent.attachNewNode("")
		self.node.setPos(*pos)
		self.node.setColorScale(color)
		self.node.setScale(*size)
		self.node.lookAt(self.node, *dir)

		self.model = loader.loadModel("models/box.egg")
		self.model.reparentTo(self.node)
		self.model.setScale(2.0)
		self.model.setPos(-1.0, -1.0, -1.0)

		self.applyTexture()

		self.mass = OdeMass()
		self.mass.setBox(density, Vec3(*size) * 2)
		self.body = OdeBody(world.world)
		self.body.setMass(self.mass)
		self.body.setPosition(self.node.getPos())
		self.body.setQuaternion(self.node.getQuat())
		self.body.setData(self)
		self.geom = OdeBoxGeom(world.space, Vec3(*size) * 2.0)
		self.geom.setBody(self.body)
		world.space.setSurfaceType(self.geom, world.surfaces["box"])

		# Adjust collision bitmasks.
		self.geom.setCategoryBits(GameObject.bitmaskBox)
		self.geom.setCollideBits(GameObject.bitmaskAll & ~GameObject.bitmaskTileGlued)

		# Tile, cement and shatter variables.
		self.tiles = []
		self.cements = []
		self.disableCount = 0
		self.unglueThreshold = unglueThreshold
		self.shatterLimit = shatterLimit
		self.shatterThreshold = shatterThreshold

	def applyTexture(self):
		self.texture = loader.loadTexture("media/brick_wall.tga")
		self.texture.setWrapU(Texture.WMRepeat)
		self.texture.setWrapV(Texture.WMRepeat)
		self.model.setTexture(self.texture, 1)
		self.model.setTexScale(TextureStage.getDefault(), max(self.size[0], self.size[1]), self.size[2])

	def addTile(self, tile):
		if tile not in self.tiles:
			self.tiles.append(tile)

	def removeTile(self, tile):
		if tile in self.tiles:
			self.tiles.remove(tile)

	def addCement(self, cement):
		if cement not in self.cements:
			self.cements.append(cement)

	def removeCement(self, cement):
		if cement in self.cements:
			self.cements.remove(cement)

	def destroy(self):
		for tile in self.tiles:
			tile.unglue()
		for cement in self.cements:
			cement.destroy()
		GameObject.destroy(self)

	def makeTiles(self, xNeg=False, xPos=False, yNeg=False, yPos=False, zNeg=False, zPos=False, thickness=0.1, unglueThreshold=None, shatterLimit=None, shatterThreshold=None):
		if xNeg: Tile(self, self.color, (-1,0,0), thickness, self.density, unglueThreshold, shatterLimit, shatterThreshold)
		if xPos: Tile(self, self.color, ( 1,0,0), thickness, self.density, unglueThreshold, shatterLimit, shatterThreshold)
		if yNeg: Tile(self, self.color, (0,-1,0), thickness, self.density, unglueThreshold, shatterLimit, shatterThreshold)
		if yPos: Tile(self, self.color, (0, 1,0), thickness, self.density, unglueThreshold, shatterLimit, shatterThreshold)
		if zNeg: Tile(self, self.color, (0,0,-1), thickness, self.density, unglueThreshold, shatterLimit, shatterThreshold)
		if zPos: Tile(self, self.color, (0,0, 1), thickness, self.density, unglueThreshold, shatterLimit, shatterThreshold)

	def onCollision(self, otherBody, entry):
		if otherBody.isEmpty():
			return
		self.disableCount = 0
		speed = otherBody.getData().body.getLinearVel()
		#if otherBody.getData().__class__ == Bullet: print speed.length(), self.shatterThreshold, self.shatterLimit #######
		if self.active and speed.length() >= self.shatterThreshold and self.shatterLimit > 0:
			adj = otherBody.getData().body.getMass().getMagnitude() / self.body.getMass().getMagnitude()
			speedMag = speed.length() * adj
			speedBase = ((speed * adj) + (self.body.getLinearVel() * 2) / 3)
			self.shatter(speedMag, speedBase)

	def shatter(self, speedMag, speedBase):
		#print 'box shatter' #########
		self.destroy()
		taskMgr.add(self.spawnTask, "box-spawn", extraArgs=[speedMag, speedBase])

		# Graphic (camera shake) and sound effects
		self.world.game.cameraHandler.shake((0,0,2), 0.1)
		sound = base.loader.loadSfx("media/shatter.wav")
		sound.setVolume(1.5)
		sound.play()

	def spawnTask(self, speedMag, speedBase):
		pos = self.node.getPos()
		size = Vec3(self.size) / 2
		w = 1
		for i in [-w, w]:
			for j in [-w, w]:
				for k in [-w, w]:
					box = Box(self.world, self.parent, self.color,
						(pos[0] + (i * size[0]), pos[1] + (j * size[1]), pos[2] + (k * size[2])),
						self.dir, size, self.density, self.unglueThreshold, self.shatterLimit - 1, self.shatterThreshold * 1)
					speed = (speedBase * (1.5 + random())) + (Vec3(i,j,k) * speedMag * (1 + random()))
					speed = speed / 2.0
					box.body.setLinearVel(speed)
					box.body.setAngularVel(speedMag * random(), speedMag * random(), speedMag * random())
					taskMgr.add(box.disableOnStopTask, "box-disableOnStop")

	def disableOnStopTask(self, task):
		if self.body.getLinearVel().length() > 0.1 or self.body.getAngularVel().length() > 0.1:
			self.disableCount = 0
			return task.cont
		elif self.disableCount < Box.disableGracePeriod:
			self.disableCount += 1
			return task.cont
		else:
			self.visibleAfterDestroy = True
			if DEBUG: self.node.setColorScale(1.0, 2.0, 1.0, 0.5)
			self.destroy()
			return task.done
Example #16
0
    def createTire(self, tireIndex):
        """Create one physics tire. Returns a (nodePath, OdeBody, OdeGeom) tuple"""
        if (tireIndex < 0) or (tireIndex >= len(self.tireMasks)):
            self.notify.error('invalid tireIndex %s' % tireIndex)
        self.notify.debug("create tireindex %s" % (tireIndex))
        zOffset = 0
        # for now the tires are spheres
        body = OdeBody(self.world)
        mass = OdeMass()
        mass.setSphere(self.tireDensity, IceGameGlobals.TireRadius)
        body.setMass(mass)
        body.setPosition(IceGameGlobals.StartingPositions[tireIndex][0],
                         IceGameGlobals.StartingPositions[tireIndex][1],
                         IceGameGlobals.StartingPositions[tireIndex][2])
        #body.setAutoDisableFlag(1)
        #body.setAutoDisableLinearThreshold(1.01 * MetersToFeet)
        # skipping AutoDisableAngularThreshold as that is radians per second
        #body.setAutoDisableAngularThreshold(0.1)
        body.setAutoDisableDefaults()

        geom = OdeSphereGeom(self.space, IceGameGlobals.TireRadius)
        self.space.setSurfaceType(geom, self.tireSurfaceType)
        self.space.setCollideId(geom, self.tireCollideIds[tireIndex])

        self.massList.append(mass)
        self.geomList.append(geom)

        # a tire collides against other tires, the wall and the floor
        geom.setCollideBits(self.allTiresMask | self.wallMask | self.floorMask
                            | self.obstacleMask)
        geom.setCategoryBits(self.tireMasks[tireIndex])
        geom.setBody(body)

        if self.notify.getDebug():
            self.notify.debug('tire geom id')
            geom.write()
            self.notify.debug(' -')

        if self.canRender:
            testTire = render.attachNewNode("tire holder %d" % tireIndex)
            smileyModel = NodePath(
            )  # loader.loadModel('models/misc/smiley') # smiley!
            if not smileyModel.isEmpty():
                smileyModel.setScale(IceGameGlobals.TireRadius)
                smileyModel.reparentTo(testTire)
                smileyModel.setAlphaScale(0.5)
                smileyModel.setTransparency(1)
            testTire.setPos(IceGameGlobals.StartingPositions[tireIndex])
            #debugAxis = loader.loadModel('models/misc/xyzAxis')
            if 0:  #not debugAxis.isEmpty():
                debugAxis.reparentTo(testTire)
                debugAxis.setScale(IceGameGlobals.TireRadius / 10.0)
                debugAxis2 = loader.loadModel('models/misc/xyzAxis')
                debugAxis2.reparentTo(testTire)
                debugAxis2.setScale(-IceGameGlobals.TireRadius / 10.0)
            # lets create a black tire
            #tireModel = loader.loadModel('phase_3/models/misc/sphere')
            tireModel = loader.loadModel(
                "phase_4/models/minigames/ice_game_tire")
            # assuming it has a radius of 1
            tireHeight = 1
            #tireModel.setScale(IceGameGlobals.TireRadius, IceGameGlobals.TireRadius, 1)
            #tireModel.setZ( 0 - IceGameGlobals.TireRadius + (tireHeight /2.0))
            #tireModel.setColor(0,0,0)
            tireModel.setZ(-IceGameGlobals.TireRadius + 0.01)
            tireModel.reparentTo(testTire)
            #tireModel.setAlphaScale(0.5)
            #tireModel.setTransparency(1)

            self.odePandaRelationList.append((testTire, body))
        else:
            testTire = None
            self.bodyList.append((None, body))
        return testTire, body, geom
Example #17
0
    def __init__(self, name, model_to_load=None, specs_to_load=None,
            soundfile=None,world=None):
        """arguments:
        name -- aircraft name
        model_to_load -- model to load on init. same as name if none given.
                         0 = don't load a model
        specs_to_load -- specifications to load on init. same as name if none
                         given. 0 = don't load specs
        soundfile -- engine sound file (not yet implemented)
        world -- the physics world to connect to

        examples:   # load a plane called "corsair1" with model and specs "corsair"
                    pirate1 = Aeroplane("corsair1", "corsair")
                    # load an empty craft instance (you'll have to load model
                    # and specs later in turn to see or fly it)
                    foo = Aeroplane("myname", 0, 0)
                    # for the node itself, use:
                    foo = Aeroplane("bar")
                    airplane = foo.node
                    # if you need access to the model itself, use:
                    foo = Aeroplane("bar")
                    model = foo.node.getChild(0)

        info:       invisible planes are for tracking only. you should assign them
                    at least models when they get into visible-range.

                    The idea behind the 'node' is pretty simple: working with
                    a virtual container prevents accidential replacement and
                    seperates things.
        """

        if Aeroplane.aircrafts is None:
            assert render
            Aeroplane.aircrafts = render.attachNewNode("aircrafts")
        self.id = Aeroplane._plane_count
        Aeroplane._plane_count += 1

        self.node = Aeroplane.aircrafts.attachNewNode(
                                     "aeroplane {0} {1}".format(self.id, name))

        self.name = name
        self.model = None
        self.hud = None  # later replaced

        self.thrust = 0.0

        #try:
        #    self.model = self.loadPlaneModel(model_to_load)
        #    self.model.reparentTo(Aeroplane.aircrafts)
        #except (ResourceHandleError, ResourceLoadError, IOError), e:
        #    handleError(e)
        if not model_to_load:
            model_to_load = name
        self.model, self.animcontrols = self.loadPlaneModel(model_to_load)
        self.model.reparentTo(self.node)

        if specs_to_load == 0:
            pass
        elif specs_to_load:
            self.loadSpecs(specs_to_load)
        else:
            self.loadSpecs(name)
        
        """
        if soundfile == 0:
            pass
        elif soundfile:
            self.assignSound(soundfile)
        else:
            self.assignSound(name)
        """

        # precalculated values for combinations of variables
        self.setCalculationConstants()

        # dynamic variables
        self.acceleration = Vec3(0.0,0.0,0.0)
        self.angle_of_attack = 0.0
        
        # state variables
        self.rudder = 0.0
        self.ailerons = 0.0
        self.elevator = 0.0
        
        # more parameters
        self.yaw_damping = -100
        self.pitch_damping = -100
        self.roll_damping = -100
        
        self.terminal_yaw = 3
        self.terminal_pitch = 3
        self.terminal_roll = 3
        
        self.rudder_coefficient = 1.0
        self.elevator_coefficient = 4.5
        self.ailerons_coefficient = 5.5
        
        self.pitch_force_coefficient = 4.0
        self.heading_force_coefficient = 1.0
        self.pitch_torque_coefficient = 0.1
        self.heading_torque_coefficient = 12.0
        
        # finally, complete initialisation of the physics for this plane
        if world is not None:
            # we are going to interact with the world :)
            body = OdeBody(world)
            # positions and orientation are set relative to render
            body.setPosition(self.node.getPos(render))
            body.setQuaternion(self.node.getQuat(render))
            
            mass = OdeMass()
            mass.setBox(self.mass, 1, 1, 1)
            body.setMass(mass)
            
            self.p_world = world
            self.p_body = body
            self.p_mass = mass
            
            self.accumulator = 0.0
            self.step_size = 0.02
            taskMgr.add(self.simulationTask, "plane physics", sort=-1)
            self.old_quat = self.quat()
        else:
            self.p_world = None
            self.p_body = None
            self.p_mass = None

        taskMgr.add(self._animations, "plane animations", sort=1)
        taskMgr.add(self._propellers, "propellers animations", sort=2)
Example #18
0
File: ode.py Project: gurgelff/Bast
ball.setTextureOff()

# Add a random amount of balls
balls = []
# This 'balls' list contains tuples of nodepaths with their ode geoms
for i in range(15):
  # Setup the geometry
  ballNP = ball.copyTo(render)
  ballNP.setPos(randint(-7, 7), randint(-7, 7), 10 + random() * 5.0)
  ballNP.setColor(random(), random(), random(), 1)
  ballNP.setHpr(randint(-45, 45), randint(-45, 45), randint(-45, 45))
  # Create the body and set the mass
  ballBody = OdeBody(world)
  M = OdeMass()
  M.setSphere(50, 1)
  ballBody.setMass(M)
  ballBody.setPosition(ballNP.getPos(render))
  ballBody.setQuaternion(ballNP.getQuat(render))
  # Create a ballGeom
  ballGeom = OdeSphereGeom(space, 1)
  ballGeom.setCollideBits(BitMask32(0x00000001))
  ballGeom.setCategoryBits(BitMask32(0x00000001))
  ballGeom.setBody(ballBody)
  # Create the sound
  ballSound = loader.loadSfx("audio/sfx/GUI_rollover.wav")
  balls.append((ballNP, ballGeom, ballSound))

# Add a plane to collide with
cm = CardMaker("ground")
cm.setFrame(-20, 20, -20, 20)
cm.setUvRange((0, 1), (1, 0))
Example #19
0
class Bullet(GameObject):
	lifetime = 120.0

	def __init__(self, world, parent, color, pos, dir, radius, density, posParent=None):
		GameObject.__init__(self, world)

		self.color = makeVec4Color(color)
		self.scale = radius
		self.collisionCount = 0

		diameter = 2 * radius
		length = 1.815 * diameter

		self.node = parent.attachNewNode("")
		if posParent == None:
			self.node.setPos(*pos)
		else:
			self.node.setPos(posParent, *pos)
		self.node.setColorScale(self.color)
		self.node.setTransparency(TransparencyAttrib.MAlpha)
		self.node.setScale(radius)
		self.node.lookAt(self.node, *dir)
		self.node.setHpr(self.node.getHpr() + Vec3(0, 270, 0))

		self.model = loader.loadModel("models/bullet.egg")
		self.model.reparentTo(self.node)
		self.model.setPos(-0.1, -0.1, 0.15)
		self.model.setScale(0.4)

		self.mass = OdeMass()
		self.mass.setCylinder(density, 3, radius, length)
		self.body = OdeBody(world.world)
		self.body.setMass(self.mass)
		self.body.setPosition(self.node.getPos())
		self.body.setQuaternion(self.node.getQuat())
		self.body.setData(self)
		self.body.setGravityMode(False)
		self.geom = OdeCylinderGeom(world.space, radius, length)
		self.geom.setBody(self.body)
		world.space.setSurfaceType(self.geom, world.surfaces["bullet"])

		# Adjust collision bitmasks.
		self.geom.setCategoryBits(GameObject.bitmaskBullet)
		self.geom.setCollideBits(GameObject.bitmaskAll & ~GameObject.bitmaskCharacter)

		# Keep the bullet hidden for a split second so it doesn't appear too close to the camera.
		self.node.hide()
		taskMgr.doMethodLater(0.1, self.showTask, 'show-bullet')

	def onCollision(self, otherBody, entry):
		self.body.setGravityMode(True)

		# Dissipate energy based on collision impact.
		factor = 1.0 - (min(entry.getContactGeom(0).getDepth(), 0.8) * 0.7)
		factor = min(factor, 0.98)
		base.taskMgr.doMethodLater(0.05, self.dissipateTask, "bullet-dissipate", extraArgs=[factor])
		
		# Reduce the lifespan.
		self.collisionCount += 1
		if self.collisionCount == 25:
			self.life = Bullet.lifetime
			taskMgr.add(self.fadeTask, "bullet-fade")
				
	def dissipateTask(self, factor):
		self.dissipate(factor)

	def fadeTask(self, task):
		if self.life > 0:
			self.life -= 1
			self.node.setAlphaScale(4.0 * self.life / Bullet.lifetime)
			return task.cont
		else:
			self.destroy()
			return task.done

	def showTask(self, task):
		if self.node != None:
			self.node.show()
Example #20
0
class Character(GameObject):	
	def __init__(self, world):
		GameObject.__init__(self, world)

		# Set the speed parameters
		self.vel = Vec3(0, 0, 0)
		self.strafespeed = 20.0
		self.forwardspeed = 32.0
		self.backspeed = 24.0
		self.jumpspeed = 20
		self.wasJumping = False

		# Set character dimensions
		self.size = (4.0, 3.0, 10.0)
		self.eyeHeight = 9.0
		self.offset = Point3(0, 0, self.eyeHeight - (self.size[2]/2))

		# Create character node
		self.node = base.render.attachNewNode("character")
		self.node.setPos(0, 0, self.eyeHeight)
		self.node.lookAt(0, 1, self.eyeHeight)

		# Create physics representation
		self.mass = OdeMass()
		self.mass.setBox(50, *self.size)
		self.body = OdeBody(world.world)
		self.body.setMass(self.mass)
		self.updatePhysicsFromPos()
		self.body.setData(self)
		self.geom = OdeBoxGeom(world.space, Vec3(*self.size))
		self.geom.setBody(self.body)
		world.space.setSurfaceType(self.geom, world.surfaces["box"])

		# Adjust collision bitmasks.
		self.geom.setCategoryBits(GameObject.bitmaskCharacter)
		self.geom.setCollideBits(GameObject.bitmaskAll & ~GameObject.bitmaskBullet)

		# Setup event handling
		self.keys = [0, 0, 0, 0, 0]
		self.setupKeys()
		base.taskMgr.add(self.moveTask, "character-move")

		# Create footsteps sound
		self.footstepsSound = base.loader.loadSfx("media/footsteps.wav")
		self.footstepsSound.setLoop(1)
		self.footsteps = SoundWrapper(self.footstepsSound)

		# Create other sounds.
		self.jumpSound = base.loader.loadSfx("media/jump_start.wav")
		self.landSound = base.loader.loadSfx("media/jump_fall.wav")

	def updatePosFromPhysics(self):
		self.node.setPos(render, self.body.getPosition() + self.offset)
		self.body.setAngularVel(0, 0, 0)

	def updatePhysicsFromPos(self):
		self.body.setPosition(self.node.getPos() - self.offset)
		self.body.setQuaternion(self.node.getQuat())

	def getDir(self):
		return base.render.getRelativeVector(self.node, (0, 1, 0))

	def moveTo(self, pos):
		self.node.setPos(pos)
		self.updatePhysicsFromPos()

	def recoil(self, mag):
		vel = self.body.getLinearVel()
		diff = self.getDir() * mag
		
		# Limit recoil
		if sign(vel[0]) != sign(diff[0]) and abs(vel[0]) > 15: diff[0] = 0
		if sign(vel[1]) != sign(diff[1]) and abs(vel[1]) > 15: diff[1] = 0
		diff[2] = 0

		self.body.setLinearVel(vel - diff)

	def jump(self):
		vel = self.body.getLinearVel()
		self.body.setLinearVel(vel[0], vel[1], vel[2] + self.jumpspeed)
		self.jumpSound.play()

	def isJumping(self):
		return abs(self.body.getLinearVel()[2]) > 0.05

	def setKey(self, button, value):
		self.keys[button] = value

	def setupKeys(self):
		base.accept("w", self.setKey, [0, 1]) #forward
		base.accept("s", self.setKey, [1, 1]) #back
		base.accept("a", self.setKey, [2, 1]) #strafe left
		base.accept("d", self.setKey, [3, 1]) #strafe right
		base.accept("space", self.setKey, [4, 1]) #jump
		base.accept("w-up", self.setKey, [0, 0])
		base.accept("s-up", self.setKey, [1, 0])
		base.accept("a-up", self.setKey, [2, 0])
		base.accept("d-up", self.setKey, [3, 0])
		base.accept("space-up", self.setKey, [4, 0])

	def moveTask(self, task):
		# Initialize variables
		elapsed = globalClock.getDt()
		x = 0.0
		y = 0.0
		jumping = self.isJumping()

		# Calculate movement vector.
		if self.keys[0] != 0:
			y = self.forwardspeed
		if self.keys[1] != 0:
			y = -self.backspeed
		if self.keys[2] != 0:
			x = -self.strafespeed
		if self.keys[3] != 0:
			x = self.strafespeed
		self.vel = Vec3(x, y, 0)
		self.vel *= elapsed

		# Move the character along the ground.
		hpr = self.node.getHpr()
		self.node.setP(0)
		self.node.setR(0)
		self.node.setPos(self.node, self.vel)
		self.updatePhysicsFromPos()
		self.node.setHpr(hpr)

		# Play landing sound (if applicable).
		if self.wasJumping and not jumping:
			pass #Landing detection not working.
			#self.landSound.play()

		# Jump (if applicable).
		if self.keys[4] and not jumping:
			self.jump()
		self.wasJumping = jumping

		# Play footsteps if walking.
		if not jumping and (self.keys[0] != 0 or self.keys[1] != 0 or self.keys[2] != 0 or self.keys[3] != 0):
			self.footsteps.resume()
		else:
			self.footsteps.pause()

		return task.cont
Example #21
0
class Player:

    def __init__(self, level):
        self._init_model()
        self._init_controls()
        self.level = level

    def _init_model(self):
        self.model = loader.loadModel("models/gyro")
        self.model.reparentTo(render)
        self.model.setPos(0, 0, 2)
        self.model.setHpr(0, 0, 0)
        self.model.setColor(0.1, 0.7, 0.7, 1)
        self.model.setTexture(loader.loadTexture('textures/texture.png'))

    def _init_controls(self):
        self.controls = Controls()

    def enable_physics(self, physics):
        self.body = OdeBody(physics.world)
        self.initial_position = self.model.getPos(render)
        self.initial_quaternion = self.model.getQuat(render)
        self.initial_spin_velocity = 50
        self.reset()

        mass = OdeMass()
        mass.setCylinder(10, 2, 1.2, 0.2)
        self.body.setMass(mass)

        modelTrimesh = OdeTriMeshData(loader.loadModel("models/gyro-low"), True)
        self.geom = OdeTriMeshGeom(physics.space, modelTrimesh)
        self.geom.setBody(self.body)

        physics.bodymodels[self.body] = self.model

        physics.actions.append(self._player_controls)
        self.exponent = 1000 * physics.step_size


    def _player_controls(self):

        avel = self.body.getAngularVel()

        on_plate = False
        accelerate = False

        for level_object in self.level.objects:
            collide = OdeUtil.collide(level_object.geom, self.geom)
            if collide:
                on_plate = True
                if avel.z < self.initial_spin_velocity and \
                   isinstance(level_object, Accelerator):
                    accelerate = level_object.player_interact(self)
                break

        if accelerate:
            avel.z += self.exponent / 200.0
            self.factor = 0

        self.calculate_factor(avel.z)

        if self.factor > 0.99:
            return

        f = self.factor**self.exponent

        if on_plate:
            if self.controls.jump:
                vel = self.body.getLinearVel()
                self.body.setLinearVel(vel.x, vel.y, vel.z + 5)
            force = 350
        else:
            force = 25

        self.controls.jump = False

        self.body.addForce(Mat3.rotateMat(self.controls.view_rotation).xform(
                           (self.controls.y*force,
                            -0.8*self.controls.x*force,
                            0)))

        hpr = self.model.getHpr()
        self.model.setHpr(hpr.x, f*hpr.y, f*hpr.z)
        self.body.setQuaternion(self.model.getQuat(render))

        self.body.setAngularVel(f*avel.x,
                                f*avel.y,
                                avel.z)

    def calculate_factor(self, spin_velocity):
        self.factor = max(self.factor, (1/(abs(spin_velocity/500.0)+1)))
        self.health = max(0, round((0.99-self.factor)*1000,1))

    def reset(self):
        self.body.setPosition(self.initial_position)
        self.body.setQuaternion(self.initial_quaternion)
        self.body.setLinearVel(0, 0, 0)
        self.body.setAngularVel(0, 0, self.initial_spin_velocity)
        self.factor = 0
        self.calculate_factor(self.initial_spin_velocity)
Example #22
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))