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")
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)
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 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
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 __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 __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 __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 __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)
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 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 __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 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 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 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 __init__(self, game, color): self.POWER = 200 self.game = game self.SHIP_TYPE = "RAKETTI" self.Ball_offset = 10.0 # self.hasBall = False 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) #self.body.setGravityMode(False) #odespheregeom(... , size of hitbox sphere) self.collGeom = OdeSphereGeom( self.game.physicsSpace, 3) 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('spaceship.egg') model.setH(180) model.setY(15) model.reparentTo(self.visualNode) self.visualNode.setScale(0.4) 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)
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 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))
# Load the ball ball = loader.loadModel("cilindroB") ball.flattenLight() # Apply transform 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
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
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()
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 )
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()
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
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
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)
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)
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
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
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)