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)
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)
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 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 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 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