class Driver(object): def __init__(self, surface): self.surface = surface self.gun = Gun(surface) self.ducks = [Duck(surface), Duck(surface)] self.round = 1 self.phase = 'start' self.score = 0 self.timer = int(time.time()) self.roundTime = 10 # Seconds in a round self.controlImgs = pygame.image.load(os.path.join('media', 'screenobjects.png')) self.hitDucks = [False for i in range(10)] self.hitDuckIndex = 0 self.nextRoundSound = os.path.join('media', 'next-round.mp3') self.flyawaySound = os.path.join('media', 'flyaway.mp3') self.notices = () def handleEvent(self, event): # If we are in the shooting phase, pass event off to the gun if event.type == pygame.MOUSEMOTION: self.gun.moveCrossHairs(event.pos) elif event.type == pygame.MOUSEBUTTONDOWN: gunFired = self.gun.shoot() for duck in self.ducks: if gunFired: if duck.isShot(event.pos): self.score += 10 self.hitDucks[self.hitDuckIndex] = True self.hitDuckIndex += 1 else: duck.flyOff = True def update(self): allDone = False # Update game based on phase if self.phase == 'start': self.startRound() elif self.phase == 'shoot': # Update all ducks for duck in self.ducks: duck.update(self.round) self.manageRound() elif self.phase == 'end': self.endRound() def render(self): # If there is a notice, display and return if len(self.notices) > 0: font = pygame.font.Font(FONT, 20) text = font.render(str(self.notices[0]), True, (255, 255, 255)); x, y = NOTICE_POSITION x = x + (NOTICE_WIDTH - text.get_width()) / 2 y = NOTICE_LINE_1_HEIGHT self.surface.blit(self.controlImgs, NOTICE_POSITION, NOTICE_RECT) self.surface.blit(text, (x, y)); if len(self.notices) > 1: text = font.render(str(self.notices[1]), True, (255, 255, 255)); x, y = NOTICE_POSITION x = x + (NOTICE_WIDTH - text.get_width()) / 2 y = NOTICE_LINE_2_HEIGHT self.surface.blit(text, (x, y)); return # Show the ducks for duck in self.ducks: duck.render() # Show round number font = pygame.font.Font(FONT, 20) text = font.render(("R= %d" % self.round), True, (154, 233, 0), (0, 0, 0)); self.surface.blit(text, ROUND_POSITION); # Show the hit counter self.surface.blit(self.controlImgs, HIT_POSITION, HIT_RECT) startingX, startingY = HIT_DUCK_POSITION for i in range(10): x = startingX + (19 * i) y = startingY if self.hitDucks[i]: self.surface.blit(self.controlImgs, (x, y), HIT_DUCK_RED_RECT) else: self.surface.blit(self.controlImgs, (x, y), HIT_DUCK_WHITE_RECT) # Show the score self.surface.blit(self.controlImgs, SCORE_POSITION, SCORE_RECT) font = pygame.font.Font(FONT, 20) text = font.render(str(self.score), True, (255, 255, 255)); x, y = FONT_STARTING_POSITION x -= text.get_width(); self.surface.blit(text, (x,y)); # Show the cross hairs self.gun.render() def manageRound(self): timer = int(time.time()) # Check round end timesUp = (timer - self.timer) > self.roundTime if not (timesUp or (self.ducks[0].isFinished and self.ducks[1].isFinished)): return # Let any remaining ducks fly off for duck in self.ducks: if not duck.isFinished: duck.flyOff = True return # Check for fly offs and increment the index for duck in self.ducks: if not duck.isDead: self.hitDuckIndex += 1 # Start new around if duck index is at the end if self.hitDuckIndex >= 9: pygame.mixer.music.load(self.nextRoundSound) pygame.mixer.music.play() self.phase = 'end' return # Populate screen with new ducks self.ducks = [Duck(self.surface), Duck(self.surface)] self.timer = int(time.time()) self.gun.reloadIt() def startRound(self): timer = int(time.time()) self.notices = ("ROUND", self.round) if (timer - self.timer) > 2: self.phase = 'shoot' self.notices = () def endRound(self): # Pause game for new round music to play while pygame.mixer.music.get_busy(): return # Count missed ducks - more than 4 and you're done missedCount = 0 for i in self.hitDucks: if i == False: missedCount += 1 if missedCount > 4: self.notices = ("GAME OVER", "") return # Prep for new round self.round += 1 self.hitDucks = [False for i in range(10)] self.hitDuckIndex = 0 self.phase = 'start' self.timer = int(time.time())
class Ship: def __init__(self, setting: settings): self.velocity = pygame.Vector2(0, 0) self.sprite_sheet = spriteSheet(setting.ship_filename, 5, 4) self.position = Vector2( setting.screen_width / 2 - self.sprite_sheet.cell_width / 2, setting.screen_height - self.sprite_sheet.cell_height) self.rect = pygame.Rect(self.position.x, self.position.y, self.sprite_sheet.cell_width, self.sprite_sheet.cell_height) self.ship_speed = setting.ship_speed self.life = setting.ship_life self.setting = setting self.gun = Gun(setting) self.moving_right = False self.moving_left = False self.score = score(0, Vector2()) pygame.font.init() self.font = pygame.font.SysFont('Comic Sans', 24, True) def draw(self, surface, frame): # pygame.draw.rect(surface, Color('#ff0000'), self.rect) for bullet in self.gun.bullet_list: bullet.draw(surface) self.sprite_sheet.draw(surface, ((frame % 4) * 5), self.position.x, self.position.y) self.score.draw(surface, self.setting) def draw_score(self, surface): title = self.font.render("SCORE", False, Color('#000000')) surface.blit(title, (self.setting.screen_width - 64, 0)) def move(self): if self.moving_right and self.rect.right < self.setting.screen_width: self.position.x += self.ship_speed if self.moving_left and self.rect.left > 0: self.position.x -= self.ship_speed self.rect.x = self.position.x for bullet in self.gun.bullet_list: bullet.move() self.gun.out_of_bound() def draw_life(self, surface, frame): for i in range(self.life): self.sprite_sheet.draw(surface, ((frame % 4) * 5), 64 * i, 0) def shoot(self): self.gun.shoot(self.setting, Vector2(self.rect.centerx, self.rect.top), 'up') def draw_death(self, surface, frame): row = ((frame % 3) * 5) for i in range(1, 5): print(row + i) self.sprite_sheet.draw(surface, row + i, self.sprite_sheet.cell_width, self.sprite_sheet.cell_height) time.sleep(0.1) def check_alive(self): if self.life == 0: return True return False
class PlayerBase(DirectObject): def __init__(self): # Player Model setup self.player = Actor("Player", {"Run":"Player-Run", "Sidestep":"Player-Sidestep", "Idle":"Player-Idle"}) self.player.setBlend(frameBlend = True) self.player.setPos(0, 0, 0) self.player.pose("Idle", 0) self.player.reparentTo(render) self.player.hide() self.footstep = base.audio3d.loadSfx('footstep.ogg') self.footstep.setLoop(True) base.audio3d.attachSoundToObject(self.footstep, self.player) # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) CamMask = BitMask32.bit(0) AvBufMask = BitMask32.bit(1) self.avbuf = None if base.win: self.avbufTex = Texture('avbuf') self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True) cam = Camera('avbuf') cam.setLens(base.camNode.getLens()) self.avbufCam = base.cam.attachNewNode(cam) dr = self.avbuf.makeDisplayRegion() dr.setCamera(self.avbufCam) self.avbuf.setActive(False) self.avbuf.setClearColor((1, 0, 0, 1)) cam.setCameraMask(AvBufMask) base.camNode.setCameraMask(CamMask) # avbuf renders everything it sees with the gradient texture. tex = loader.loadTexture('gradient.png') np = NodePath('np') np.setTexture(tex, 100) np.setColor((1, 1, 1, 1), 100) np.setColorScaleOff(100) np.setTransparency(TransparencyAttrib.MNone, 100) np.setLightOff(100) cam.setInitialState(np.getState()) #render.hide(AvBufMask) # Setup a texture stage to paint on the player self.paintTs = TextureStage('paintTs') self.paintTs.setMode(TextureStage.MDecal) self.paintTs.setSort(10) self.paintTs.setPriority(10) self.tex = Texture('paint_av_%s'%id(self)) # Setup a PNMImage that will hold the paintable texture of the player self.imageSizeX = 64 self.imageSizeY = 64 self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4) self.p.fill(1) self.p.alphaFill(0) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) # Apply the paintable texture to the avatar self.player.setTexture(self.paintTs, self.tex) # team self.playerTeam = "" # A lable that will display the players team self.lblTeam = DirectLabel( scale = 1, pos = (0, 0, 3), frameColor = (0, 0, 0, 0), text = "TEAM", text_align = TextNode.ACenter, text_fg = (0,0,0,1)) self.lblTeam.reparentTo(self.player) self.lblTeam.setBillboardPointEye() # basic player values self.maxHits = 3 self.currentHits = 0 self.isOut = False self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor") # setup the collision detection # wall and object collision self.playerSphere = CollisionSphere(0, 0, 1, 1) self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self))) self.playerCollision.node().addSolid(self.playerSphere) base.pusher.addCollider(self.playerCollision, self.player) base.cTrav.addCollider(self.playerCollision, base.pusher) # foot (walk) collision self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self))) self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1)) self.playerFootRay.node().setIntoCollideMask(0) self.lifter = CollisionHandlerFloor() self.lifter.addCollider(self.playerFootRay, self.player) base.cTrav.addCollider(self.playerFootRay, self.lifter) # Player weapon setup self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R") self.color = LPoint3f(1, 1, 1) self.gun = Gun(id(self)) self.gun.reparentTo(self.gunAttach) self.gun.hide() self.gun.setColor(self.color) self.hud = None # Player controls setup self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 self.mouseSpeedX = 0.1 self.mouseSpeedY = 0.1 # AI controllable variables self.AIP = 0.0 self.AIH = 0.0 self.movespeed = 5.0 self.userControlled = False self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit) self.accept("window-event", self.recalcAspectRatio) def runBase(self): self.player.show() self.gun.show() taskMgr.add(self.move, "moveTask%d"%id(self), priority=-4) def stopBase(self): taskMgr.remove("moveTask%d"%id(self)) self.ignoreAll() self.gun.remove() self.footstep.stop() base.audio3d.detachSound(self.footstep) self.player.delete() def setKey(self, key, value): self.keyMap[key] = value def setPos(self, pos): self.player.setPos(pos) def setColor(self, color=LPoint3f(0,0,0)): self.color = color self.gun.setColor(color) c = (color[0], color[1], color[2], 1.0) self.lblTeam["text_fg"] = c def setTeam(self, team): self.playerTeam = team self.lblTeam["text"] = team def shoot(self, shotVec=None): self.gun.shoot(shotVec) if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def reload(self): self.gun.reload() if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def recalcAspectRatio(self, window): self.winXhalf = window.getXSize() / 2 self.winYhalf = window.getYSize() / 2 def hit(self, entry, color): self.currentHits += 1 # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") splat = splat * LColorf(color[0], color[1], color[2], 1.0) self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) self.paintAvatar(entry) if self.currentHits >= self.maxHits: base.messenger.send("GameOver-player%d" % id(self)) self.isOut = True def __paint(self, s, t): """ Paints a point on the avatar at texture coordinates (s, t). """ x = (s * self.p.getXSize()) y = ((1.0 - t) * self.p.getYSize()) # Draw in color directly on the avatar p1 = PNMPainter(self.p) p1.setPen(self.colorBrush) p1.drawPoint(x, y) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) self.paintDirty = True def paintAvatar(self, entry): """ Paints onto an avatar. Returns true on success, false on failure (because there are no avatar pixels under the mouse, for instance). """ # First, we have to render the avatar in its false-color # image, to determine which part of its texture is under the # mouse. if not self.avbuf: return False #mpos = base.mouseWatcherNode.getMouse() mpos = entry.getSurfacePoint(self.player) ppos = entry.getSurfacePoint(render) self.player.showThrough(BitMask32.bit(1)) self.avbuf.setActive(True) base.graphicsEngine.renderFrame() self.player.show(BitMask32.bit(1)) self.avbuf.setActive(False) # Now we have the rendered image in self.avbufTex. if not self.avbufTex.hasRamImage(): print "Weird, no image in avbufTex." return False p = PNMImage() self.avbufTex.store(p) ix = int((1 + mpos.getX()) * p.getXSize() * 0.5) iy = int((1 - mpos.getY()) * p.getYSize() * 0.5) x = 1 if ix >= 0 and ix < p.getXSize() and iy >= 0 and iy < p.getYSize(): s = p.getBlue(ix, iy) t = p.getGreen(ix, iy) x = p.getRed(ix, iy) if x > 0.5: # Off the avatar. return False # At point (s, t) on the avatar's map. self.__paint(s, t) return True def move(self, task): if self is None: return task.done if self.userControlled: if not base.mouseWatcherNode.hasMouse(): return task.cont self.pointer = base.win.getPointer(0) mouseX = self.pointer.getX() mouseY = self.pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): p = self.TorsorControl.getP() + (mouseY - self.winYhalf) * self.mouseSpeedY if p <-80: p = -80 elif p > 90: p = 90 self.TorsorControl.setP(p) h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX if h <-360: h = 360 elif h > 360: h = -360 self.player.setH(h) else: self.TorsorControl.setP(self.AIP) self.player.setH(self.AIH) forward = self.keyMap["forward"] != 0 backward = self.keyMap["backward"] != 0 if self.keyMap["left"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, self.movespeed * globalClock.getDt()) elif self.keyMap["right"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, -self.movespeed * globalClock.getDt()) else: self.player.stop("Sidestep") if forward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(5, "Run") self.player.setY(self.player, -self.movespeed * globalClock.getDt()) elif backward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(-5, "Run") self.player.setY(self.player, self.movespeed * globalClock.getDt()) else: self.player.stop("Run") if not (self.keyMap["left"] or self.keyMap["right"] or self.keyMap["forward"] or self.keyMap["backward"] or self.player.getCurrentAnim() == "Idle"): self.player.loop("Idle") self.footstep.stop() else: self.footstep.play() return task.cont
class Fleet: def __init__(self, setting: settings, shoot_sound): self.shoot_sound = shoot_sound self.fleet = list() self.move_speed = setting.alien_speed self.creep_speed = setting.creep_speed self.gun = Gun(setting) self.setting = setting self.saucer = Saucer(setting, Vector2(-64, 64 * 2)) for i in range(10): self.fleet.append(Squid(setting, pygame.Vector2(70 * i, 70))) for i in range(10): self.fleet.append(Squid(setting, pygame.Vector2(70 * i, 70 * 2))) for i in range(10): self.fleet.append(Jelly(setting, pygame.Vector2(70 * i, 70 * 3))) for i in range(10): self.fleet.append(Jelly(setting, pygame.Vector2(70 * i, 70 * 4))) for i in range(10): self.fleet.append(Crab(setting, pygame.Vector2(70 * i, 70 * 5))) for i in range(10): self.fleet.append(Crab(setting, pygame.Vector2(70 * i, 70 * 6))) def draw(self, surface, frame): for alien in self.fleet: alien.draw(surface, frame) self.gun.draw(surface) if self.saucer.spawned and not self.saucer.despawned: self.saucer.draw(surface, frame) def move(self): for alien in self.fleet: alien.move(self.move_speed) if check_shoot(): self.shoot_sound.play() self.gun.shoot( self.setting, Vector2( alien.position.x + alien.sprite_sheet.cell_width / 2, alien.position.y + alien.sprite_sheet.cell_height), 'down') for bullet in self.gun.bullet_list: bullet.move() self.gun.out_of_bound() if self.saucer.spawned and not self.saucer.despawned: self.saucer.move() else: self.saucer.start_move() def creep(self): for alien in self.fleet: alien.creep(self.creep_speed) def out_of_bound(self, setting: settings): hit = False for alien in self.fleet: if alien.rect.left < 0: hit = True if alien.rect.right > setting.screen_width: hit = True if hit: self.move_speed = self.move_speed * -1 self.creep() def speedup(self): self.move_speed *= self.setting.speedup_scale