关于python:Python编写坦克大战新增无敌模式

67次阅读

共计 48859 个字符,预计需要花费 123 分钟才能阅读完成。

新增性能:

1、q 键间接退出游戏 -》进行结算而后返回模式抉择界面

2、新增全屏按钮 u,并且切换的时候会造成 3s 的解冻成果

3、静音键 m

4、暂停键 p

5、无敌模式,进入下一关条件是只能战胜 20 个坦克

6、代码正文残缺

7、z 键打印以后坦克的状况

8、可自定义地图

9、可自定义起始关卡
外汇常见问题 https://www.kaifx.cn/lists/qu…

!/usr/bin/python# coding=utf-8import datetimeimport os, pygame, time, random, uuid, sys, psutilfrom datetime import datefrom time import ctime, sleep # 矩阵的 长宽高 class myRect(pygame.Rect): “”” 增加类型属性 “”” def __init__(self, left, top, width, height, type): # 矩阵地位 pygame.Rect.__init__(self, left, top, width, height) self.type = type # 取得一个惟一的随机的 uidclass Timer(object): def __init__(self): self.timers = [] # 取得一个惟一的随机的 uid def add(self, interval, f, repeat=-1): options = {“interval”: interval, “callback”: f, “repeat”: repeat, “times”: 0, “time”: 0, “uuid”: uuid.uuid4() # 生成一个随机的 UUID } self.timers.append(options) return options[“uuid”] # 销毁指定的 uid(uuid_nr) def destroy(self, uuid_nr): for timer in self.timers: if timer[“uuid”] == uuid_nr: self.timers.remove(timer) return # 定时器 def update(self, time_passed): for timer in self.timers: timer[“time”] += time_passed if timer[“time”] > timer[“interval”]: timer[“time”] -= timer[“interval”] timer[“times”] += 1 if timer[“repeat”] > -1 and timer[“times”] == timer[“repeat”]: self.timers.remove(timer) try: timer[“callback”]() except: try: self.timers.remove(timer) except: pass # 堡垒类 class Castle(): “”” Player’s castle/fortress 堡垒的地位 ””” (STATE_STANDING, STATE_DESTROYED, STATE_EXPLODING) = range(3) def __init__(self): global sprites # images ,subsurface()从父外表创立一个新外表 self.img_undamaged = sprites.subsurface(0, 15 * 2, 16 * 2, 16 * 2) self.img_destroyed = sprites.subsurface(16 * 2, 15 * 2, 16 * 2, 16 * 2) # init position 初始化地位 self.rect = pygame.Rect(12 * 16, 24 * 16, 32, 32) # start w/ undamaged and shiny castle 从未损坏和闪亮的城堡开始 self.rebuild() def draw(self): “”” Draw castle 画一个城堡 ””” global screen # blit()对图片进行操作, 将一个立体的一部分或全副图象整块从这个立体复制到另一个立体 screen.blit(self.image, self.rect.topleft) # 判断城堡是否被扎破 if self.state == self.STATE_EXPLODING: if not self.explosion.active: self.state = self.STATE_DESTROYED del self.explosion else: self.explosion.draw() def rebuild(self): “”” Reset castle 重置城堡 “”” self.state = self.STATE_STANDING self.image = self.img_undamaged # 城堡残缺的图片 self.active = True def destroy(self): “”” Destroy castle 销毁城堡 ””” self.state = self.STATE_EXPLODING self.explosion = Explosion(self.rect.topleft) # 图片的左上被销毁 self.image = self.img_destroyed # 城堡被销毁的图片 if god == False: self.active = False # 道具 class Bonus(): “”” Various power-ups 各种道具 When bonus is spawned, it begins flashing and after some time dissapears 当处分产生时,它开始闪动,一段时间后隐没 Available bonusses: 可用处分列表 手雷 grenade : Picking up the grenade power up instantly wipes out ever enemy presently on the screen, including Armor Tanks regardless of how many times you’ve hit them. You do not, however, get credit for destroying them during the end-stage bonus points. 头盔 helmet : The helmet power up grants you a temporary force field that makes you invulnerable to enemy shots, just like the one you begin every stage with. 铲子 shovel : The shovel power up turns the walls around your fortress from brick to stone. This makes it impossible for the enemy to penetrate the wall and destroy your fortress, ending the game prematurely. The effect, however, is only temporary, and will wear off eventually. 星星 star : The star power up grants your tank with new offensive power each time you pick one up, up to three times. The first star allows you to fire your bullets as fast as the power tanks can. The second star allows you to fire up to two bullets on the screen at one time. And the third star allows your bullets to destroy the otherwise unbreakable steel walls. You carry this power with you to each new stage until you lose a life. 坦克 tank : The tank power up grants you one extra life. The only other way to get an extra life is to score 20000 points. 定时器 timer : The timer power up temporarily freezes time, allowing you to harmlessly approach every tank and destroy them until the time freeze wears off. 手雷: 拿起手雷的电源,立刻革除屏幕上的任何敌人,包含装甲坦克,无论你击中他们多少次。然而,你不会因为在最初阶段捣毁它们而失去积分。头盔: 头盔能量晋升给你一个长期力场,使你对敌人的射击无坚不摧,就像你在每个阶段开始的时候一样。铲子: 铲子的力量把堡垒四周的墙从砖变成石头。这使得敌人不可能穿透墙壁并捣毁你的堡垒,从而提前结束游戏。然而,这种影响只是临时的,最终会逐步隐没。星型: 每次你拿起一辆星型坦克,它就会给你的坦克提供新的防御能力,最多三次。第一颗星能够让你发射子弹的速度与能源坦克一样快。第二颗星容许你在屏幕上同时发射两颗子弹。第三颗星能够让你的子弹捣毁本来坚不可摧的钢铁墙。你带着这种力量进入每一个新的阶段,直到你失去一条生命。坦克: 坦克的能量减少能够让你多活一次。取得额定生命的惟一办法是取得 20000 分。定时器: 定时器临时解冻工夫,容许你有害地靠近每一辆坦克并捣毁它们,直到解冻工夫隐没。“”” # bonus types 道具类型 (BONUS_GRENADE, BONUS_HELMET, BONUS_SHOVEL, BONUS_STAR, BONUS_TANK, BONUS_TIMER) = range(6) def __init__(self, level): global sprites # to know where to place 在哪个地图 (关卡) self.level = level # bonus lives only for a limited period of time 处分只在无限的一段时间内无效 self.active = True # blinking state 闪动状态 self.visible = True # 道具随机呈现的地点 self.rect = pygame.Rect(random.randint(0, 416 – 32), random.randint(0, 416 – 32), 32, 32) # 随机选一个道具 self.bonus = random.choice([self.BONUS_GRENADE, self.BONUS_HELMET, self.BONUS_SHOVEL, self.BONUS_STAR, self.BONUS_TANK, self.BONUS_TIMER]) self.image = sprites.subsurface(16 * 2 * self.bonus, 32 * 2, 16 * 2, 15 * 2) def draw(self): “”” draw bonus 画道具 ””” global screen if self.visible: screen.blit(self.image, self.rect.topleft) def toggleVisibility(self): “”” Toggle bonus visibility 道具开关可见??””” self.visible = not self.visible # self.visible = self.visible # 子弹 class Bullet(): # direction constants 子弹的方向的常量 (DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT) = range(4) # bullet’s stated 申明子弹 (STATE_REMOVED, STATE_ACTIVE, STATE_EXPLODING) = range(3) (OWNER_PLAYER, OWNER_ENEMY) = range(2) # 子弹初始化是:damage = 100, speed = 5 def __init__(self, level, position, direction, damage=100, speed=5): global sprites self.level = level self.direction = direction self.damage = damage self.owner = None self.owner_class = None # 1-regular everyday normal bullet 惯例子弹 # 2-can destroy steel 能捣毁钢铁的子弹 self.power = 1 # 1/2 self.image = sprites.subsurface(75 * 2, 74 * 2, 3 * 2, 4 * 2) # position is player’s top left corner, so we’ll need to 子弹地位在坦克的左上角 # recalculate a bit. also rotate image itself. 旋转图像自身 if direction == self.DIR_UP: self.rect = pygame.Rect(position[0] + 11, position[1] – 8, 6, 8) elif direction == self.DIR_RIGHT: self.image = pygame.transform.rotate(self.image, 270) self.rect = pygame.Rect(position[0] + 26, position[1] + 11, 8, 6) elif direction == self.DIR_DOWN: self.image = pygame.transform.rotate(self.image, 180) self.rect = pygame.Rect(position[0] + 11, position[1] + 26, 6, 8) elif direction == self.DIR_LEFT: self.image = pygame.transform.rotate(self.image, 90) self.rect = pygame.Rect(position[0] – 8, position[1] + 11, 8, 6) self.explosion_images = [# 子弹爆炸图片 sprites.subsurface(0, 80 * 2, 32 * 2, 32 * 2), sprites.subsurface(32 * 2, 80 * 2, 32 * 2, 32 * 2), ] self.speed = speed self.state = self.STATE_ACTIVE def find(self): print “ 玩家射出的子弹移挫伤为:” + str(self.damage) +”, 子弹飞行速度为:” + str(self.speed) def draw(self): “”” draw bullet 画子弹 ””” global screen if self.state == self.STATE_ACTIVE: # 子弹射出的时候的样子 screen.blit(self.image, self.rect.topleft) elif self.state == self.STATE_EXPLODING: # 子弹爆炸时候的样子 self.explosion.draw() def update(self): global castle, players, enemies, bullets # 城堡, 玩家, 敌人, 子弹 if self.state == self.STATE_EXPLODING: if not self.explosion.active: self.destroy() del self.explosion if self.state != self.STATE_ACTIVE: return “”” move bullet 子弹挪动 ””” if self.direction == self.DIR_UP: self.rect.topleft = [self.rect.left, self.rect.top – self.speed] if self.rect.top < 0: if play_sounds and self.owner == self.OWNER_PLAYER: try: sounds[“steel”].play() # time.sleep(1) except: print “ 无奈播放子弹击中屏幕顶端墙边 bgm” print “ 子弹从顶端到底部花了 ” self.explode() return elif self.direction == self.DIR_RIGHT: self.rect.topleft = [self.rect.left + self.speed, self.rect.top] if self.rect.left > (416 – self.rect.width): if play_sounds and self.owner == self.OWNER_PLAYER: try: sounds[“steel”].play() except: print “ 无奈播放子弹击中屏幕左边墙边 bgm” self.explode() return elif self.direction == self.DIR_DOWN: self.rect.topleft = [self.rect.left, self.rect.top + self.speed] if self.rect.top > (416 – self.rect.height): if play_sounds and self.owner == self.OWNER_PLAYER: try: sounds[“steel”].play() except: print “ 无奈播放子弹击中屏幕上面墙边 bgm” self.explode() return elif self.direction == self.DIR_LEFT: self.rect.topleft = [self.rect.left – self.speed, self.rect.top] if self.rect.left < 0: if play_sounds and self.owner == self.OWNER_PLAYER: try: sounds[“steel”].play() except: print “ 无奈播放子弹击中屏幕右边墙边 bgm” self.explode() return # 是否抵触 has_collided = False # check for collisions with walls. one bullet can destroy several (1 or 2) 查看是否与墙壁碰撞。一颗子弹能够捣毁数颗(1 颗或 2 颗) # tiles but explosion remains 1 打到瓷砖,但仍然显示爆炸特效 rects = self.level.obstacle_rects collisions = self.rect.collidelistall(rects) # collidelistall 抵触(爆炸) 列表 if collisions != []: for i in collisions: if self.level.hitTile(rects[i].topleft, self.power, self.owner == self.OWNER_PLAYER): has_collided = True if has_collided: self.explode() return # check for collisions with other bullets 查看是否与其余子弹产生碰撞 for bullet in bullets: if self.state == self.STATE_ACTIVE and bullet.owner != self.owner and bullet != self and self.rect.colliderect( bullet.rect): self.explode() return # check for collisions with players 查看是否与玩家产生碰撞 for player in players: if player.state == player.STATE_ALIVE and self.rect.colliderect(player.rect): if player.bulletImpact(self.owner == self.OWNER_PLAYER, self.damage, self.owner_class): self.destroy() return # check for collisions with enemies 查看与敌人的碰撞 for enemy in enemies: if enemy.state == enemy.STATE_ALIVE and self.rect.colliderect(enemy.rect): if enemy.bulletImpact(self.owner == self.OWNER_ENEMY, self.damage, self.owner_class): self.destroy() return # check for collision with castle 查看是否与城堡产生碰撞 if castle.active and self.rect.colliderect(castle.rect): castle.destroy() self.destroy() return def explode(self): “”” start bullets’s explosion 开始子弹爆炸 ””” global screen if self.state != self.STATE_REMOVED: self.state = self.STATE_EXPLODING self.explosion = Explosion([self.rect.left – 13, self.rect.top – 13], None, self.explosion_images) def destroy(self): self.state = self.STATE_REMOVED # 标签类 (游戏画面的左边)class Label(): def __init__(self, position, text=””, duration=None): self.position = position self.active = True self.text = text self.font = pygame.font.SysFont(“Arial”, 13) # 字体 if duration != None: # duration gtimer.add(duration, lambda: self.destroy(), 1) def draw(self): “”” draw label 画标签 ””” global screen screen.blit(self.font.render(self.text, False, (200, 200, 200)), [self.position[0] + 20, self.position[1] + 8]) def destroy(self): self.active = False # 爆炸类 class Explosion(): def __init__(self, position, interval=None, images=None): global sprites self.position = [position[0] – 16, position[1] – 16] self.active = True if interval == None: interval = 100 if images == None: images = [sprites.subsurface(0, 80 * 2, 32 * 2, 32 * 2), sprites.subsurface(32 * 2, 80 * 2, 32 * 2, 32 * 2), sprites.subsurface(64 * 2, 80 * 2, 32 * 2, 32 * 2)] images.reverse() self.images = [] + images self.image = self.images.pop() gtimer.add(interval, lambda: self.update(), len(self.images) + 1) def draw(self): global screen “”” draw current explosion frame “”” screen.blit(self.image, self.position) def update(self): “”” Advace to the next image “”” if len(self.images) > 0: self.image = self.images.pop() else: self.active = False # 瓷砖 class Level(): # tile constants (TILE_EMPTY, TILE_BRICK, TILE_STEEL, TILE_WATER, TILE_GRASS, TILE_FROZE) = range(6) # tile width/height in px 平铺宽度 / 高度 16 个像素(px) TILE_SIZE = 16 def __init__(self, level_nr=None): “”” There are total 35 different levels. If level_nr is larger than 35, loop over to next according level so, for example, if level_nr ir 37, then load level 2 总共有 35 个不同的等级。如果 level_nr 大于 35,循环; 例如,如果 level_nr ir 37,则加载 level 2 “”” global sprites # max number of enemies simultaneously being on map 最大数量的敌人同时在地图上是 4 self.max_active_enemies = 4 tile_images = [pygame.Surface((8 * 2, 8 * 2)), sprites.subsurface(48 * 2, 64 * 2, 8 * 2, 8 * 2), sprites.subsurface(48 * 2, 72 * 2, 8 * 2, 8 * 2), sprites.subsurface(56 * 2, 72 * 2, 8 * 2, 8 * 2), sprites.subsurface(64 * 2, 64 * 2, 8 * 2, 8 * 2), sprites.subsurface(64 * 2, 64 * 2, 8 * 2, 8 * 2), sprites.subsurface(72 * 2, 64 * 2, 8 * 2, 8 * 2), sprites.subsurface(64 * 2, 72 * 2, 8 * 2, 8 * 2)] self.tile_empty = tile_images[0] self.tile_brick = tile_images[1] self.tile_steel = tile_images[2] self.tile_grass = tile_images[3] self.tile_water = tile_images[4] self.tile_water1 = tile_images[4] self.tile_water2 = tile_images[5] self.tile_froze = tile_images[6] self.obstacle_rects = [] # 关卡等级 level_nr = 1 if level_nr == None else level_nr % 35 if level_nr == 0: level_nr = 35 self.loadLevel(level_nr) # tiles’ rects on map, tanks cannot move over 瓷砖在地图上的 rects,坦克不能挪动 self.obstacle_rects = [] # update these tiles 更新障碍物列表 self.updateObstacleRects() gtimer.add(400, lambda: self.toggleWaves()) # 依据子弹是 1 还是 2 来更新子弹打的显示成果 def hitTile(self, pos, power=1, sound=False): “”” Hit the tile @param pos Tile’s x, y in px @return True if bullet was stopped, False otherwise 如果子弹被进行,返回 True,否则返回 False “”” global play_sounds, sounds for tile in self.mapr: if tile.topleft == pos: if tile.type == self.TILE_BRICK: if play_sounds and sound: try: sounds[“brick”].play() except: print “ 无奈播放子弹击中墙砖时 bgm” self.mapr.remove(tile) self.updateObstacleRects() return True elif tile.type == self.TILE_STEEL: if play_sounds and sound: try: sounds[“steel”].play() except: print “ 无奈播放子弹击中墙砖时 bgm” if power == 2: # 能捣毁钢铁的子弹为 2 self.mapr.remove(tile) self.updateObstacleRects() return True else: return False def toggleWaves(self): “”” Toggle water image 切换图片 ””” if self.tile_water == self.tile_water1: self.tile_water = self.tile_water2 else: self.tile_water = self.tile_water1 def loadLevel(self, level_nr=1): “”” Load specified level 加载指定关卡等级 @return boolean Whether level was loaded 返回的是布尔值, 是 - 加载 , 否 - 没有加载 “”” filename = “levels/” + str(level_nr) # 读取关卡文件 if (not os.path.isfile(filename)): return False level = [] f = open(filename, “r”) data = f.read().split(“\n”) self.mapr = [] x, y = 0, 0 for row in data: # 把文件的符号翻译成对应的瓷砖类型 for ch in row: if ch == “#”: self.mapr.append(myRect(x, y, self.TILE_SIZE, self.TILE_SIZE, self.TILE_BRICK)) elif ch == “@”: self.mapr.append(myRect(x, y, self.TILE_SIZE, self.TILE_SIZE, self.TILE_STEEL)) elif ch == “~”: self.mapr.append(myRect(x, y, self.TILE_SIZE, self.TILE_SIZE, self.TILE_WATER)) elif ch == “%”: self.mapr.append(myRect(x, y, self.TILE_SIZE, self.TILE_SIZE, self.TILE_GRASS)) elif ch == “-“: self.mapr.append(myRect(x, y, self.TILE_SIZE, self.TILE_SIZE, self.TILE_FROZE)) x += self.TILE_SIZE x = 0 y += self.TILE_SIZE return True def draw(self, tiles=None): “”” Draw specified map on top of existing surface 在现有外表上绘制指定的地图 ””” global screen if tiles == None: tiles = [TILE_BRICK, TILE_STEEL, TILE_WATER, TILE_GRASS, TILE_FROZE] for tile in self.mapr: # 开始画图 if tile.type in tiles: if tile.type == self.TILE_BRICK: screen.blit(self.tile_brick, tile.topleft) elif tile.type == self.TILE_STEEL: screen.blit(self.tile_steel, tile.topleft) elif tile.type == self.TILE_WATER: screen.blit(self.tile_water, tile.topleft) elif tile.type == self.TILE_FROZE: screen.blit(self.tile_froze, tile.topleft) elif tile.type == self.TILE_GRASS: screen.blit(self.tile_grass, tile.topleft) def updateObstacleRects(self): “”” Set self.obstacle_rects to all tiles’ rects that players can destroy with bullets 设定能够捣毁瓷砖的子弹 ””” global castle self.obstacle_rects = [castle.rect] for tile in self.mapr: if tile.type in (self.TILE_BRICK, self.TILE_STEEL, self.TILE_WATER): self.obstacle_rects.append(tile) def buildFortress(self, tile): “”” Build walls around castle made from tile 用瓷砖在城堡四周筑墙 ””” positions = [(11 * self.TILE_SIZE, 23 * self.TILE_SIZE), (11 * self.TILE_SIZE, 24 * self.TILE_SIZE), (11 * self.TILE_SIZE, 25 * self.TILE_SIZE), (14 * self.TILE_SIZE, 23 * self.TILE_SIZE), (14 * self.TILE_SIZE, 24 * self.TILE_SIZE), (14 * self.TILE_SIZE, 25 * self.TILE_SIZE), (12 * self.TILE_SIZE, 23 * self.TILE_SIZE), (13 * self.TILE_SIZE, 23 * self.TILE_SIZE)] obsolete = [] for i, rect in enumerate(self.mapr): if rect.topleft in positions: obsolete.append(rect) for rect in obsolete: self.mapr.remove(rect) for pos in positions: self.mapr.append(myRect(pos[0], pos[1], self.TILE_SIZE, self.TILE_SIZE, tile)) self.updateObstacleRects() # 坦克类 class Tank(): # possible directions 可能会呈现的地位 (DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT) = range(4) # states 坦克的状态 (STATE_SPAWNING, STATE_DEAD, STATE_ALIVE, STATE_EXPLODING) = range(4) # sides 坦克类型: 玩家 \ 机器人 (SIDE_PLAYER, SIDE_ENEMY) = range(2) def __init__(self, level, side, position=None, direction=None, filename=None): global sprites # health. 0 health means dead, 衰弱。0 衰弱意味着死亡 / 坦克默认是 100 血 self.health = 100 # tank can’t move but can rotate and shoot 坦克不能挪动,但能够旋转和射击 self.paralised = False # tank can’t do anything 坦克什么也做不了 self.paused = False # tank is protected from bullets 坦克不受子弹的挫伤 self.shielded = False self.speed = 2 # how many bullets can tank fire simultaneously 坦克能同时发射多少子弹 self.max_active_bullets = 1 self.side = side # flashing state. 0-off, 1-on 坦克闪动状态 0 不闪动, 1 闪动 self.flash = 0 # 0 – no superpowers # 1 – faster bullets # 2 – can fire 2 bullets # 3 – can destroy steel “”” 0 - 没有超能力 1- 更快的子弹 2 - 能够发射 2 颗子弹 3- 能捣毁钢铁 “”” self.superpowers = 0 # each tank can pick up 1 bonus 每个坦克能够取得 1 加值 self.bonus = None # navigation keys: fire, up, right, down, left 坦克挪动键: 火,上,右,下,左 self.controls = [pygame.K_SPACE, pygame.K_UP, pygame.K_RIGHT, pygame.K_DOWN, pygame.K_LEFT] # currently pressed buttons (navigation only) 以后按下的按钮 (仅供导航) 坦克有 4 个键位 self.pressed = [False] * 4 self.shield_images = [# 坦克的盾 sprites.subsurface(0, 48 * 2, 16 * 2, 16 * 2), sprites.subsurface(16 * 2, 48 * 2, 16 * 2, 16 * 2)] self.shield_image = self.shield_images[0] self.shield_index = 0 self.spawn_images = [# 坦克刚下来的样子? sprites.subsurface(32 * 2, 48 * 2, 16 * 2, 16 * 2), sprites.subsurface(48 * 2, 48 * 2, 16 * 2, 16 * 2)] self.spawn_image = self.spawn_images[0] self.spawn_index = 0 self.level = level if position != None: self.rect = pygame.Rect(position, (26, 26)) else: self.rect = pygame.Rect(0, 0, 26, 26) if direction == None: self.direction = random.choice([self.DIR_RIGHT, self.DIR_DOWN, self.DIR_LEFT]) else: self.direction = direction self.state = self.STATE_SPAWNING # spawning animation 坦克生成的动画? self.timer_uuid_spawn = gtimer.add(100, lambda: self.toggleSpawnImage()) # duration of spawning 坦克生成的工夫? self.timer_uuid_spawn_end = gtimer.add(1000, lambda: self.endSpawning()) def endSpawning(self): “”” End spawning Player becomes operational 从生产状态转变为玩家操控状态 “”” self.state = self.STATE_ALIVE gtimer.destroy(self.timer_uuid_spawn_end) def toggleSpawnImage(self): “”” advance to the next spawn image 推动到下一个衍生图像 ””” if self.state != self.STATE_SPAWNING: gtimer.destroy(self.timer_uuid_spawn) return self.spawn_index += 1 if self.spawn_index >= len(self.spawn_images): self.spawn_index = 0 self.spawn_image = self.spawn_images[self.spawn_index] # 护盾图像 def toggleShieldImage(self): “”” advance to the next shield image 进入下一个盾牌图像 “”” if self.state != self.STATE_ALIVE: gtimer.destroy(self.timer_uuid_shield) return if self.shielded: self.shield_index += 1 if self.shield_index >= len(self.shield_images): self.shield_index = 0 self.shield_image = self.shield_images[self.shield_index] def draw(self): “”” draw tank 画坦克 ””” global screen if self.state == self.STATE_ALIVE: screen.blit(self.image, self.rect.topleft) if self.shielded: screen.blit(self.shield_image, [self.rect.left – 3, self.rect.top – 3]) elif self.state == self.STATE_EXPLODING: self.explosion.draw() elif self.state == self.STATE_SPAWNING: screen.blit(self.spawn_image, self.rect.topleft) def explode(self): “”” start tanks’s explosion 开始坦克的爆炸 ””” if self.state != self.STATE_DEAD: self.state = self.STATE_EXPLODING self.explosion = Explosion(self.rect.topleft) if self.bonus: self.spawnBonus() # 坦克发射子弹 def fire(self, forced=False): “”” Shoot a bullet 坦克射出一个子弹 @param boolean forced. If false, check whether tank has exceeded his bullet quota. Default: True 如果谬误,查看坦克是否超过子弹限额。默认值: 真正的 @return boolean True if bullet was fired, false otherwise 如果子弹被发射,为真,否则为假 “”” global bullets, labels if self.state != self.STATE_ALIVE: gtimer.destroy(self.timer_uuid_fire) return False if self.paused: return False if not forced: active_bullets = 0 for bullet in bullets: if bullet.owner_class == self and bullet.state == bullet.STATE_ACTIVE: active_bullets += 1 if active_bullets >= self.max_active_bullets: return False bullet = Bullet(self.level, self.rect.topleft, self.direction) # 坦克超能力 # if superpower level is at least 1 如果子弹速度超能力级别至多为 1 if self.superpowers > 0: bullet.speed = 8 # 子弹速度是 8 # if superpower level is at least 3 如果超能力等级至多为 3 if self.superpowers > 2: # 子弹为 2 bullet.power = 2 if self.side == self.SIDE_PLAYER: bullet.owner = self.SIDE_PLAYER else: bullet.owner = self.SIDE_ENEMY self.bullet_queued = False bullet.owner_class = self bullets.append(bullet) return True # 坦克依据方向键旋转 def rotate(self, direction, fix_position=True): “”” Rotate tank rotate, update image and correct position 旋转槽旋转,更新图像和正确的地位 “”” self.direction = direction if direction == self.DIR_UP: self.image = self.image_up elif direction == self.DIR_RIGHT: self.image = self.image_right elif direction == self.DIR_DOWN: self.image = self.image_down elif direction == self.DIR_LEFT: self.image = self.image_left if fix_position: new_x = self.nearest(self.rect.left, 8) + 3 new_y = self.nearest(self.rect.top, 8) + 3 if (abs(self.rect.left – new_x) < 5): self.rect.left = new_x if (abs(self.rect.top – new_y) < 5): self.rect.top = new_y # 把坦克转向相同的方向 def turnAround(self): “”” Turn tank into opposite direction 把坦克转向相同的方向 ””” if self.direction in (self.DIR_UP, self.DIR_RIGHT): self.rotate(self.direction + 2, False) else: self.rotate(self.direction – 2, False) # 更新计时器和爆炸 def update(self, time_passed): “”” Update timer and explosion (if any) 更新计时器和爆炸(如果有的话)””” if self.state == self.STATE_EXPLODING: if not self.explosion.active: self.state = self.STATE_DEAD del self.explosion # 整数到最能整除的数 def nearest(self, num, base): “”” Round number to nearest divisible ?? 整数到最能整除的数 ””” return int(round(num / (base * 1.0)) * base) # 如果子弹在撞击时被捣毁,返回 True , 只有敌人交火才是 False def bulletImpact(self, friendly_fire=False, damage=100, tank=None): “”” Bullet impact Return True if bullet should be destroyed on impact. Only enemy friendly-fire 如果子弹在撞击时被捣毁,返回 True。只有敌人交火 doesn’t trigger bullet explosion 不会引起子弹爆炸 “”” # 子弹声音 global play_sounds, sounds if self.shielded: return True if not friendly_fire: self.health -= damage if self.health < 1: if self.side == self.SIDE_ENEMY: tank.trophies[“enemy” + str(self.type)] += 1 points = (self.type + 1) * 100 tank.score += points if play_sounds: try: sounds[“explosion”].play() except: print “ 无奈播放爆炸 bgm” labels.append(Label(self.rect.topleft, str(points), 500)) self.explode() return True if self.side == self.SIDE_ENEMY: return False elif self.side == self.SIDE_PLAYER: if not self.paralised: self.setParalised(True) self.timer_uuid_paralise = gtimer.add(10000, lambda: self.setParalised(False), 1) # 玩家之间互殴后停留 10 秒 return True def setParalised(self, paralised=True): “”” set tank paralise state 双人模式坦克互殴,设置坦克状态 @param boolean paralised @return None “”” if self.state != self.STATE_ALIVE: gtimer.destroy(self.timer_uuid_paralise) return self.paralised = paralised “”” 实例化坦克对象 ”””# 敌人坦克 class Enemy(Tank): (TYPE_BASIC, TYPE_FAST, TYPE_POWER, TYPE_ARMOR) = range(4) def __init__(self, level, type, position=None, direction=None, filename=None): Tank.__init__(self, level, type, position=None, direction=None, filename=None) global enemies, sprites # if true, do not fire 为真则不停火 self.bullet_queued = False # chose type on random 随机抉择类型 if len(level.enemies_left) > 0: self.type = level.enemies_left.pop() else: self.state = self.STATE_DEAD return if self.type == self.TYPE_BASIC: self.speed = 1 elif self.type == self.TYPE_FAST: self.speed = 3 elif self.type == self.TYPE_POWER: self.superpowers = 1 elif self.type == self.TYPE_ARMOR: self.health = 400 # 1 in 5 chance this will be bonus carrier, but only if no other tank is 五分之一的机会,这将是处分载体,但只有当没有其余坦克 # 地图以后只能呈现一个处分载体坦克(批改这里能够刷出更多的道具坦克) if random.randint(1, 5) == 1: self.bonus = True for enemy in enemies: if enemy.bonus: self.bonus = False break images = [sprites.subsurface(32 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(48 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(64 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(80 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(32 * 2, 16 * 2, 13 * 2, 15 * 2), sprites.subsurface(48 * 2, 16 * 2, 13 * 2, 15 * 2), sprites.subsurface(64 * 2, 16 * 2, 13 * 2, 15 * 2), sprites.subsurface(80 * 2, 16 * 2, 13 * 2, 15 * 2)] self.image = images[self.type + 0] self.image_up = self.image; self.image_left = pygame.transform.rotate(self.image, 90) self.image_down = pygame.transform.rotate(self.image, 180) self.image_right = pygame.transform.rotate(self.image, 270) if self.bonus: self.image1_up = self.image_up; self.image1_left = self.image_left self.image1_down = self.image_down self.image1_right = self.image_right self.image2 = images[self.type + 4] self.image2_up = self.image2; self.image2_left = pygame.transform.rotate(self.image2, 90) self.image2_down = pygame.transform.rotate(self.image2, 180) self.image2_right = pygame.transform.rotate(self.image2, 270) self.rotate(self.direction, False) if position == None: self.rect.topleft = self.getFreeSpawningPosition() if not self.rect.topleft: self.state = self.STATE_DEAD return # list of map coords where tank should go next 坦克下一步应该去的地图坐标列表 self.path = self.generatePath(self.direction) # 1000 is duration between shots 1000 毫秒 =10 秒是设计的持续时间?? self.timer_uuid_fire = gtimer.add(1000, lambda: self.fire()) # turn on flashing 开始闪光 if self.bonus: self.timer_uuid_flash = gtimer.add(200, lambda: self.toggleFlash()) def find(self): # 自定义一个办法去查问坦克实例的属性 if self.type == self.TYPE_BASIC: if self.bonus: print “ 存在一般坦克, 它是道具坦克, 移速为: ” + str(self.speed) + “, 血量为: ” +str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) else: print “ 存在一般坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) elif self.type == self.TYPE_FAST: if self.bonus: print “ 存在移速坦克, 它是道具坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) else: print “ 存在移速坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) elif self.type == self.TYPE_POWER: if self.bonus: print “ 存在力量坦克, 它是道具坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) else: print “ 存在力量坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) elif self.type == self.TYPE_ARMOR: if self.bonus: print “ 存在护甲坦克, 它是道具坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) else: print “ 存在护甲坦克, 移速为: ” + str(self.speed) + “, 血量为: ” + str(self.health) + “, 它的能力等级为: ” + str(self.superpowers) # print self.type , self.speed, self.bonus # 道具坦克的发光状态 def toggleFlash(self): “”” Toggle flash state 发光状态 ””” if self.state not in (self.STATE_ALIVE, self.STATE_SPAWNING): gtimer.destroy(self.timer_uuid_flash) return self.flash = not self.flash if self.flash: self.image_up = self.image2_up self.image_right = self.image2_right self.image_down = self.image2_down self.image_left = self.image2_left else: self.image_up = self.image1_up self.image_right = self.image1_right self.image_down = self.image1_down self.image_left = self.image1_left self.rotate(self.direction, False) # 道具闪动频率和存在时长 def spawnBonus(self): “”” Create new bonus if needed “”” global bonuses if len(bonuses) > 0: return bonus = Bonus(self.level) bonuses.append(bonus) gtimer.add(500, lambda: bonus.toggleVisibility()) # 道具闪动频率 gtimer.add(10000, lambda: bonuses.remove(bonus), 1) # 道具存在时长 # 坦克的三个出世点 def getFreeSpawningPosition(self): global players, enemies # 坦克的三个出世点 available_positions = [[(self.level.TILE_SIZE * 2 – self.rect.width) / 2, (self.level.TILE_SIZE * 2 – self.rect.height) / 2], [12 * self.level.TILE_SIZE + (self.level.TILE_SIZE * 2 – self.rect.width) / 2, (self.level.TILE_SIZE * 2 – self.rect.height) / 2], [24 * self.level.TILE_SIZE + (self.level.TILE_SIZE * 2 – self.rect.width) / 2, (self.level.TILE_SIZE * 2 – self.rect.height) / 2]] # 随机打乱出世点的程序 random.shuffle(available_positions) for pos in available_positions: enemy_rect = pygame.Rect(pos, [26, 26]) # collisions with other enemies 与其余敌人的抵触 collision = False for enemy in enemies: if enemy_rect.colliderect(enemy.rect): collision = True continue if collision: continue # collisions with players 与玩家抵触 collision = False for player in players: if enemy_rect.colliderect(player.rect): collision = True continue if collision: continue return pos return False def move(self): “”” move enemy if possible 尽可能挪动敌人 ””” global players, enemies, bonuses if self.state != self.STATE_ALIVE or self.paused or self.paralised: return if self.path == []: self.path = self.generatePath(None, True) new_position = self.path.pop(0) # move enemy 敌人挪动 if self.direction == self.DIR_UP: if new_position[1] < 0: self.path = self.generatePath(self.direction, True) return elif self.direction == self.DIR_RIGHT: if new_position[0] > (416 – 26): self.path = self.generatePath(self.direction, True) return elif self.direction == self.DIR_DOWN: if new_position[1] > (416 – 26): self.path = self.generatePath(self.direction, True) return elif self.direction == self.DIR_LEFT: if new_position[0] < 0: self.path = self.generatePath(self.direction, True) return new_rect = pygame.Rect(new_position, [26, 26]) # collisions with tiles 与瓷砖的碰撞 if new_rect.collidelist(self.level.obstacle_rects) != -1: self.path = self.generatePath(self.direction, True) return # collisions with other enemies 与其余敌人的抵触 , 敌人之间不会产生碰撞 # for enemy in enemies: # if enemy != self and new_rect.colliderect(enemy.rect): # self.turnAround() # self.path = self.generatePath(self.direction) # return # collisions with players 玩家之间的碰撞 for player in players: if new_rect.colliderect(player.rect): self.turnAround() self.path = self.generatePath(self.direction) return # collisions with bonuses 碰撞带着道具 for bonus in bonuses: if new_rect.colliderect(bonus.rect): bonuses.remove(bonus) # if no collision, move enemy 如果没有碰撞,挪动敌人 self.rect.topleft = new_rect.topleft def update(self, time_passed): Tank.update(self, time_passed) if self.state == self.STATE_ALIVE and not self.paused: self.move() def generatePath(self, direction=None, fix_direction=False): “”” If direction is specified, try continue that way, otherwise choose at random 如果指定了方向,持续尝试,否则随机抉择 “”” all_directions = [self.DIR_UP, self.DIR_RIGHT, self.DIR_DOWN, self.DIR_LEFT] if direction == None: if self.direction in [self.DIR_UP, self.DIR_RIGHT]: opposite_direction = self.direction + 2 else: opposite_direction = self.direction – 2 directions = all_directions random.shuffle(directions) directions.remove(opposite_direction) directions.append(opposite_direction) else: if direction in [self.DIR_UP, self.DIR_RIGHT]: opposite_direction = direction + 2 else: opposite_direction = direction – 2 if direction in [self.DIR_UP, self.DIR_RIGHT]: opposite_direction = direction + 2 else: opposite_direction = direction – 2 directions = all_directions random.shuffle(directions) directions.remove(opposite_direction) directions.remove(direction) directions.insert(0, direction) directions.append(opposite_direction) # at first, work with general units (steps) not px 首先,应用个别单位(步骤) 而不是 px x = int(round(self.rect.left / 16)) y = int(round(self.rect.top / 16)) new_direction = None for direction in directions: if direction == self.DIR_UP and y > 1: new_pos_rect = self.rect.move(0, -8) if new_pos_rect.collidelist(self.level.obstacle_rects) == -1: new_direction = direction break elif direction == self.DIR_RIGHT and x < 24: new_pos_rect = self.rect.move(8, 0) if new_pos_rect.collidelist(self.level.obstacle_rects) == -1: new_direction = direction break elif direction == self.DIR_DOWN and y < 24: new_pos_rect = self.rect.move(0, 8) if new_pos_rect.collidelist(self.level.obstacle_rects) == -1: new_direction = direction break elif direction == self.DIR_LEFT and x > 1: new_pos_rect = self.rect.move(-8, 0) if new_pos_rect.collidelist(self.level.obstacle_rects) == -1: new_direction = direction break # if we can go anywhere else, turn around 如果咱们能去别的中央,就掉头吧 if new_direction == None: new_direction = opposite_direction print “nav izejas. griezhamies” # fix tanks position 修复坦克的地位 if fix_direction and new_direction == self.direction: fix_direction = False self.rotate(new_direction, fix_direction) positions = [] x = self.rect.left y = self.rect.top if new_direction in (self.DIR_RIGHT, self.DIR_LEFT): axis_fix = self.nearest(y, 16) – y else: axis_fix = self.nearest(x, 16) – x axis_fix = 0 pixels = self.nearest(random.randint(1, 12) * 32, 32) + axis_fix + 3 if new_direction == self.DIR_UP: for px in range(0, pixels, self.speed): positions.append([x, y – px]) elif new_direction == self.DIR_RIGHT: for px in range(0, pixels, self.speed): positions.append([x + px, y]) elif new_direction == self.DIR_DOWN: for px in range(0, pixels, self.speed): positions.append([x, y + px]) elif new_direction == self.DIR_LEFT: for px in range(0, pixels, self.speed): positions.append([x – px, y]) return positions # 玩家 class Player(Tank): def __init__(self, level, type, position=None, direction=None, filename=None): Tank.__init__(self, level, type, position=None, direction=None, filename=None) global sprites if filename == None: filename = (0, 0, 16 * 2, 16 * 2) self.start_position = position self.start_direction = direction self.lives = 3 # 初始生命条数 , 生命数 # total score 初始总分是 0 self.score = 0 # 贮存这个玩家在这关的战绩 self.trophies = {“bonus”: 0, “enemy0”: 0, “enemy1”: 0, “enemy2”: 0, “enemy3”: 0} self.image = sprites.subsurface(filename) self.image_up = self.image; self.image_left = pygame.transform.rotate(self.image, 90) self.image_down = pygame.transform.rotate(self.image, 180) self.image_right = pygame.transform.rotate(self.image, 270) if direction == None: self.rotate(self.DIR_UP, False) else: self.rotate(direction, False) def move(self, direction): “”” move player if possible 玩家挪动 ””” global players, enemies, bonuses if self.state == self.STATE_EXPLODING: if not self.explosion.active: self.state = self.STATE_DEAD del self.explosion if self.state != self.STATE_ALIVE: return # rotate player 旋转玩家 if self.direction != direction: self.rotate(direction) if self.paralised: return # move player 挪动玩家 if direction == self.DIR_UP: new_position = [self.rect.left, self.rect.top – self.speed] if new_position[1] < 0: return elif direction == self.DIR_RIGHT: new_position = [self.rect.left + self.speed, self.rect.top] if new_position[0] > (416 – 26): return elif direction == self.DIR_DOWN: new_position = [self.rect.left, self.rect.top + self.speed] if new_position[1] > (416 – 26): return elif direction == self.DIR_LEFT: new_position = [self.rect.left – self.speed, self.rect.top] if new_position[0] < 0: return player_rect = pygame.Rect(new_position, [26, 26]) # collisions with tiles 与瓷砖碰撞 if player_rect.collidelist(self.level.obstacle_rects) != -1: return # collisions with other players 与其余玩家碰撞 for player in players: if player != self and player.state == player.STATE_ALIVE and player_rect.colliderect(player.rect) == True: return # collisions with enemies 与敌人碰撞 for enemy in enemies: if player_rect.colliderect(enemy.rect) == True: return # collisions with bonuses 碰撞道具坦克 for bonus in bonuses: if player_rect.colliderect(bonus.rect) == True: self.bonus = bonus # if no collision, move player 如果没有碰撞,挪动玩家 self.rect.topleft = (new_position[0], new_position[1]) def reset(self): “”” reset player 重置玩家 ””” self.rotate(self.start_direction, False) self.rect.topleft = self.start_position if god == False: self.superpowers = 0 self.max_active_bullets = 1 else: # 批改无敌模式的数值 self.superpowers = 3 self.max_active_bullets = 2 self.speed = 5 self.health = 100 self.paralised = False self.paused = False self.pressed = [False] * 4 self.state = self.STATE_ALIVE # 开始游戏 class Game(): # direction constants (DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT) = range(4) TILE_SIZE = 16 # 瓷砖大小是 16 def __init__(self): global screen, sprites, play_sounds, sounds, Fullscreen,textList,bullets # center window os.environ[‘SDL_VIDEO_WINDOW_POS’] = ‘center’ if play_sounds: pygame.mixer.pre_init(44100, -16, 1, 512) pygame.init() pygame.display.set_caption(“Battle City”) global size size = width, height = 480, 416 # 玩家输出 - f 能够取得全屏 if “-f” in sys.argv[1:]: screen = pygame.display.set_mode(size, pygame.FULLSCREEN) else: screen = pygame.display.set_mode(size) self.clock = pygame.time.Clock() # load sprites (funky version) # sprites = pygame.transform.scale2x(pygame.image.load(“images/sprites.gif”)) # load sprites (pixely version) sprites = pygame.transform.scale(pygame.image.load(“images/sprites.gif”), [192, 224]) # screen.set_colorkey((0,138,104)) pygame.display.set_icon(sprites.subsurface(0, 0, 13 * 2, 13 * 2)) # load sounds try: if play_sounds: pygame.mixer.init(44100, -16, 1, 512) sounds[“start”] = pygame.mixer.Sound(“sounds/gamestart.ogg”) sounds[“end”] = pygame.mixer.Sound(“sounds/gameover.ogg”) sounds[“score”] = pygame.mixer.Sound(“sounds/score.ogg”) sounds[“bg”] = pygame.mixer.Sound(“sounds/background.ogg”) sounds[“fire”] = pygame.mixer.Sound(“sounds/fire.ogg”) sounds[“bonus”] = pygame.mixer.Sound(“sounds/bonus.ogg”) sounds[“explosion”] = pygame.mixer.Sound(“sounds/explosion.ogg”) sounds[“brick”] = pygame.mixer.Sound(“sounds/brick.ogg”) sounds[“steel”] = pygame.mixer.Sound(“sounds/steel.ogg”) except: print “ 没有插耳机 ” # 不插耳机报错 # finally: # pygame.mixer.init(44100, -16, 1, 512) # sounds[“start”] = pygame.mixer.Sound(“sounds/gamestart.ogg”) # sounds[“end”] = pygame.mixer.Sound(“sounds/gameover.ogg”) # sounds[“score”] = pygame.mixer.Sound(“sounds/score.ogg”) # sounds[“bg”] = pygame.mixer.Sound(“sounds/background.ogg”) # sounds[“fire”] = pygame.mixer.Sound(“sounds/fire.ogg”) # sounds[“bonus”] = pygame.mixer.Sound(“sounds/bonus.ogg”) # sounds[“explosion”] = pygame.mixer.Sound(“sounds/explosion.ogg”) # sounds[“brick”] = pygame.mixer.Sound(“sounds/brick.ogg”) # sounds[“steel”] = pygame.mixer.Sound(“sounds/steel.ogg”) self.enemy_life_image = sprites.subsurface(81 * 2, 57 * 2, 7 * 2, 7 * 2) self.player_life_image = sprites.subsurface(89 * 2, 56 * 2, 7 * 2, 8 * 2) self.flag_image = sprites.subsurface(64 * 2, 49 * 2, 16 * 2, 15 * 2) # this is used in intro screen 这在介绍屏幕中应用 self.player_image = pygame.transform.rotate(sprites.subsurface(0, 0, 13 * 2, 13 * 2), 270) # if true, no new enemies will be spawn during this time 如果是这样,在此期间不会产生新的敌人 self.timefreeze = False # load custom font 加载自定义字体 self.font = pygame.font.Font(“fonts/prstart.ttf”, 16) # pre-render game over text 事后渲染游戏的文字 self.im_game_over = pygame.Surface((64, 40)) self.im_game_over.set_colorkey((0, 0, 0)) self.im_game_over.blit(self.font.render(“GAME”, False, (127, 64, 64)), [0, 0]) self.im_game_over.blit(self.font.render(“OVER”, False, (127, 64, 64)), [0, 20]) self.game_over_y = 416 + 40 # number of players. here is defined preselected menu value 默认的玩家数量是 1(菜单默认 1 开始,) self.nr_of_players = 1 del players[:] del bullets[:] del enemies[:] del bonuses[:] def gameLoop(self, flag): while flag: if flag == False: break # 触发道具 def triggerBonus(self, bonus, player): “”” Execute bonus powers 执行额定的势力 ””” global enemies, labels, play_sounds, sounds if play_sounds: try: sounds[“bonus”].play() except: print “ 无奈播放取得道具时 bgm” player.trophies[“bonus”] += 1 player.score += 500 # 触发道具 +500 分 if bonus.bonus == bonus.BONUS_GRENADE: for enemy in enemies: enemy.explode() elif bonus.bonus == bonus.BONUS_HELMET: if god == False: self.shieldPlayer(player, True, 10000) # 护盾继续 10000 毫秒 =10 秒 elif bonus.bonus == bonus.BONUS_SHOVEL: self.level.buildFortress(self.level.TILE_STEEL) gtimer.add(10000, lambda: self.level.buildFortress(self.level.TILE_BRICK), 1) elif bonus.bonus == bonus.BONUS_STAR: player.superpowers += 1 if player.superpowers == 2: player.max_active_bullets = 2 # 坦克最多同时发射的子弹 elif bonus.bonus == bonus.BONUS_TANK: player.lives += 1 # 生命 +1 elif bonus.bonus == bonus.BONUS_TIMER: self.toggleEnemyFreeze(True) # 敌人被冻住 10 秒 gtimer.add(10000, lambda: self.toggleEnemyFreeze(False), 1) bonuses.remove(bonus) labels.append(Label(bonus.rect.topleft, “500”, 500)) def shieldPlayer(self, player, shield=True, duration=None): “”” 增加 / 移除护盾 玩家: 玩家 (非敌人) 护盾: 真 / 假 (布尔型) 持续时间: 在(持续时间) 毫秒内. 如果没有, 不要主动移除护盾 “”” player.shielded = shield if shield: player.timer_uuid_shield = gtimer.add(100, lambda: player.toggleShieldImage()) # 工作定时器 else: gtimer.destroy(player.timer_uuid_shield) if shield and duration != None: # 如果有护盾,持续时间不为空 gtimer.add(duration, lambda: self.shieldPlayer(player, False), 1) # 生成坦克 def spawnEnemy(self): “”” Spawn new enemy if needed 如果有须要就产生新的坦克 Only add enemy if: – there are at least one in queue 至多有一个在排队 – map capacity hasn’t exceeded its quota 地图容量没有超过限额 – now isn’t timefreeze 当初不是工夫解冻 “”” global enemies if len(enemies) >= self.level.max_active_enemies: return if len(self.level.enemies_left) < 1 or self.timefreeze: return enemy = Enemy(self.level, 1) enemies.append(enemy) # 玩家新生 def respawnPlayer(self, player, clear_scores=False): “”” 玩家新生 “”” player.reset() if clear_scores: player.trophies = {“bonus”: 0, “enemy0”: 0, “enemy1”: 0, “enemy2”: 0, “enemy3”: 0} if god == False: self.shieldPlayer(player, True, 4000) else: # 无敌模式 self.shieldPlayer(player, True, 99999999999) print “ 进入无敌模式 ” # 设定 self.game_over = True def gameOver(self): “”” 完结游戏 返回到菜单 “”” global play_sounds, sounds print “Game Over” if play_sounds: try: for sound in sounds: sounds[sound].stop() sounds[“end”].play() except: print “ 无奈播放游戏完结 bgm” self.game_over_y = 416 + 40 self.game_over = True gtimer.add(3000, lambda: self.showScores(), 1) # 展现分数 def gameOverScreen(self): # 游戏完结时界面 global screen, Fullscreen Fullscreen = False # 进行游戏主循环 self.running = False screen.fill([0, 0, 0]) # 游戏完结时背景色彩 self.writeInBricks(“game”, [125, 140]) # [x,y] x 为横坐标,y 为纵坐标,意思是字体显示地位 self.writeInBricks(“over”, [125, 220]) pygame.display.flip() # 更新整个待显示的 Surface 对象到屏幕上 while 1: # 循环 time_passed = self.clock.tick(50) for event in pygame.event.get(): # 监听用户事件 if event.type == pygame.QUIT: # 判断用户是否点击了敞开按钮 print “quit()3” quit() # 敞开所有相关联的窗口 elif event.type == pygame.KEYDOWN: # 判断用户是否按下键盘 if event.key == pygame.K_p : # 游戏结算界面暂停 Flag = True print “ 结算界面暂停 ” while Flag: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: #sleep(1) if event.key == pygame.K_p: # self.writeInBricks(“stopping”, [65, 80]) # print “ 开始 ” Flag = False else: continue if event.key == pygame.K_u: # u 键切换窗口为全屏或窗口 Fullscreen = not Fullscreen if Fullscreen: print “ 菜单进入全屏 ” screen = pygame.display.set_mode(size, pygame.FULLSCREEN) self.FreezeAll(True) # 解冻 3 秒, 让程序卡过图 gtimer.add(3000, lambda: self.FreezeAll(False), 1) else: print “ 菜单进入窗口 ” screen = pygame.display.set_mode(size) self.FreezeAll(True) # 解冻 3 秒, 让程序卡过图 gtimer.add(3000, lambda: self.FreezeAll(False), 1) # elif event.key == pygame.K_RETURN: # 判断按键输出为 Enter 时 self.showMenu() # 调用 showMenu 回到主菜单 return def showMenu(self): # 显示游戏菜单 # 仅当按下向上或向下键时从新绘制屏幕。# 当按下回车键时,退出这个屏幕,跳转到主界面中进行玩家人数抉择 global players, screen # stop game main loop (if any)进行游戏主循环 (如果有的话) self.running = False # clear all timers 革除所有计时器 del gtimer.timers[:] # 设置以后阶段为 0 , 等于 1 时, 是第 2 关, 所以是从 0 开始才对,初始关卡(设置关卡) # self.stage = 1 self.stage = 0 self.animateIntroScreen() main_loop = True Fullscreen = False running = 0 flag = False while main_loop: time_passed = self.clock.tick(50) # 各种事件 for event in pygame.event.get(): if event.type == pygame.QUIT: quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_u: # f 键切换窗口为全屏或窗口 Fullscreen = not Fullscreen if Fullscreen: print “ 菜单进入全屏 ” screen = pygame.display.set_mode(size, pygame.FULLSCREEN) self.FreezeAll(True) # 解冻 3 秒, 让程序卡过图 gtimer.add(30000, lambda: self.FreezeAll(False), 1) else: print “ 菜单进入窗口 ” screen = pygame.display.set_mode(size) self.FreezeAll(True) # 解冻 3 秒, 让程序卡过图 gtimer.add(30000, lambda: self.FreezeAll(False), 1) elif event.key == pygame.K_p : # 菜单暂停 Flag = True print “ 菜单界面停 ” while Flag: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: #sleep(1) if event.key == pygame.K_p: # self.writeInBricks(“stopping”, [65, 80]) # print “ 开始 ” Flag = False else: continue elif event.key == pygame.K_q: quit() elif event.key == pygame.K_UP: if self.nr_of_players == 2: self.nr_of_players = 1 self.drawIntroScreen() elif self.nr_of_players == 3: self.nr_of_players = 2 self.drawIntroScreen() elif event.key == pygame.K_DOWN: if self.nr_of_players == 1: self.nr_of_players = 2 self.drawIntroScreen() elif self.nr_of_players == 2: self.nr_of_players = 3 self.drawIntroScreen() elif event.key == pygame.K_RETURN: main_loop = False del players[:] self.nextLevel() # 从新载入玩家, 包含玩家出世点 def reloadPlayers(self): “”” 初始化玩家 如果玩家曾经存在,只需重置他们 “”” global players, textList if len(players) == 0: # first player 第一个玩家 x = 8 * self.TILE_SIZE + (self.TILE_SIZE * 2 – 26) / 2 y = 24 * self.TILE_SIZE + (self.TILE_SIZE * 2 – 26) / 2 player = Player(self.level, 0, [x, y], self.DIR_UP, (0, 0, 13 * 2, 13 * 2)) players.append(player) # second player 第二个玩家 if self.nr_of_players == 2: x = 16 * self.TILE_SIZE + (self.TILE_SIZE * 2 – 26) / 2 y = 24 * self.TILE_SIZE + (self.TILE_SIZE * 2 – 26) / 2 player = Player(self.level, 0, [x, y], self.DIR_UP, (16 * 2, 0, 13 * 2, 13 * 2)) player.controls = [102, 119, 100, 115, 97] players.append(player) for player in players: player.level = self.level if player.lives == 0: player.lives += 1 self.respawnPlayer(player, True) else: self.respawnPlayer(player, True) # 展现关卡分数 def showScores(self): “”” 展现关卡分数 “”” global screen, sprites, players, play_sounds, sounds # 进行游戏主循环 self.running = False # 革除所有计时器 del gtimer.timers[:] if play_sounds: for sound in sounds: sounds[sound].stop() hiscore = self.loadHiscore() # 如果须要更新最高分 if players[0].score > hiscore: hiscore = players[0].score self.saveHiscore(hiscore) if self.nr_of_players == 2 and players[1].score > hiscore: hiscore = players[1].score self.saveHiscore(hiscore) img_tanks = [# 敌方坦克图片加载 sprites.subsurface(32 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(48 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(64 * 2, 0, 13 * 2, 15 * 2), sprites.subsurface(80 * 2, 0, 13 * 2, 15 * 2)] img_arrows = [# 箭头加载 sprites.subsurface(81 * 2, 48 * 2, 7 * 2, 7 * 2), sprites.subsurface(88 * 2, 48 * 2, 7 * 2, 7 * 2)] screen.fill([0, 0, 0]) # 色彩 black = pygame.Color(“black”) white = pygame.Color(“white”) purple = pygame.Color(127, 64, 64) pink = pygame.Color(191, 160, 128) screen.blit(self.font.render(“HI-SCORE”, False, purple), [105, 35]) screen.blit(self.font.render(str(hiscore), False, pink), [295, 35]) screen.blit(self.font.render(“STAGE” + str(self.stage).rjust(3), False, white), [170, 65]) screen.blit(self.font.render(“I-PLAYER”, False, purple), [25, 95]) # 玩家一的分数 screen.blit(self.font.render(str(players[0].score).rjust(8), False, pink), [25, 125]) print players[0].score if self.nr_of_players == 2: screen.blit(self.font.render(“II-PLAYER”, False, purple), [310, 95]) # 玩家二的分数 screen.blit(self.font.render(str(players[1].score).rjust(8), False, pink), [325, 125]) # 坦克和箭头 for i in range(4): screen.blit(img_tanks[i], [226, 160 + (i * 45)]) screen.blit(img_arrows[0], [206, 168 + (i * 45)]) if self.nr_of_players == 2: screen.blit(img_arrows[1], [258, 168 + (i * 45)]) screen.blit(self.font.render(“TOTAL”, False, white), [70, 335]) # 总计 下划线 pygame.draw.line(screen, white, [170, 330], [307, 330], 4) pygame.display.flip() self.clock.tick(2) interval = 5 # 分数和击杀数 for i in range(4): # 特定坦克总数 tanks = players[0].trophies[“enemy” + str(i)] for n in range(tanks + 1): if n > 0 and play_sounds: try: sounds[“score”].play() except: print “ 无奈播放结算 bgm” # 删除之前的文本 screen.blit(self.font.render(str(n – 1).rjust(2), False, black), [170, 168 + (i * 45)]) # 打印新的敌人数量 screen.blit(self.font.render(str(n).rjust(2), False, white), [170, 168 + (i * 45)]) # 删除之前的文本 screen.blit(self.font.render(str((n – 1) * (i + 1) * 100).rjust(4) + ” PTS”, False, black), [25, 168 + (i * 45)]) # 打印每个敌人的总分数 screen.blit(self.font.render(str(n * (i + 1) * 100).rjust(4) + ” PTS”, False, white), [25, 168 + (i * 45)]) pygame.display.flip() self.clock.tick(interval+5) if self.nr_of_players == 2: tanks = players[1].trophies[“enemy” + str(i)] for n in range(tanks + 1): if n > 0 and play_sounds: try: sounds[“score”].play() except: print “ 无奈播放结算 bgm” screen.blit(self.font.render(str(n – 1).rjust(2), False, black), [277, 168 + (i * 45)]) screen.blit(self.font.render(str(n).rjust(2), False, white), [277, 168 + (i * 45)]) screen.blit(self.font.render(str((n – 1) * (i + 1) * 100).rjust(4) + ” PTS”, False, black), [325, 168 + (i * 45)]) screen.blit(self.font.render(str(n * (i + 1) * 100).rjust(4) + ” PTS”, False, white), [325, 168 + (i * 45)]) pygame.display.flip() self.clock.tick(interval) self.clock.tick(interval) # 坦克总数 tanks = sum([i for i in players[0].trophies.values()]) – players[0].trophies[“bonus”] screen.blit(self.font.render(str(tanks).rjust(2), False, white), [170, 335]) if self.nr_of_players == 2: tanks = sum([i for i in players[1].trophies.values()]) – players[1].trophies[“bonus”] screen.blit(self.font.render(str(tanks).rjust(2), False, white), [277, 335]) pygame.display.flip() # 什么都不做两秒钟 self.clock.tick(1) self.clock.tick(1) if self.game_over: self.gameOverScreen() #self.nextLevel() 无敌模式 else: self.nextLevel() # 画游戏界面的图 def draw(self): global screen, castle, players, enemies, bullets, bonuses screen.fill([0, 0, 0]) self.level.draw([self.level.TILE_EMPTY, self.level.TILE_BRICK, self.level.TILE_STEEL, self.level.TILE_FROZE, self.level.TILE_WATER]) castle.draw() for enemy in enemies: enemy.draw() for label in labels: label.draw() for player in players: player.draw() for bullet in bullets: bullet.draw() for bonus in bonuses: bonus.draw() self.level.draw([self.level.TILE_GRASS]) if self.game_over: if self.game_over_y > 188: self.game_over_y -= 4 screen.blit(self.im_game_over, [176, self.game_over_y]) # 176=(416-64)/2 self.drawSidebar() pygame.display.flip() # 画左边的标签栏 def drawSidebar(self): global screen, players, enemies x = 416 y = 0 screen.fill([100, 100, 100], pygame.Rect([416, 0], [64, 416])) xpos = x + 16 ypos = y + 16 # 敌方坦克数量显示 for n in range(len(self.level.enemies_left) + len(enemies)): screen.blit(self.enemy_life_image, [xpos, ypos]) if n % 2 == 1: xpos = x + 16 ypos += 17 else: xpos += 17 # 玩家生命数 if pygame.font.get_init(): text_color = pygame.Color(‘black’) for n in range(len(players)): if n == 0: screen.blit(self.font.render(str(n + 1) + “P”, False, text_color), [x + 16, y + 200]) screen.blit(self.font.render(str(players[n].lives), False, text_color), [x + 31, y + 215]) screen.blit(self.player_life_image, [x + 17, y + 215]) else: screen.blit(self.font.render(str(n + 1) + “P”, False, text_color), [x + 16, y + 240]) screen.blit(self.font.render(str(players[n].lives), False, text_color), [x + 31, y + 255]) screen.blit(self.player_life_image, [x + 17, y + 255]) screen.blit(self.flag_image, [x + 17, y + 280]) screen.blit(self.font.render(str(self.stage), False, text_color), [x + 17, y + 312]) # 画模式抉择界面 def drawIntroScreen(self, put_on_surface=True): “”” 游戏主界面菜单 @param boolean put_on_surface If True, flip display after drawing put_on_surface 如果为真,在绘制后翻转显示 @return None “”” global screen global god god = False screen.fill([0, 0, 0]) if pygame.font.get_init(): # hiscore 是最高分 hiscore = self.loadHiscore() screen.blit(self.font.render(“HI- ” + str(hiscore), True, pygame.Color(‘white’)), [170, 35]) screen.blit(self.font.render(“1 PLAYER”, True, pygame.Color(‘white’)), [165, 250]) screen.blit(self.font.render(“2 PLAYERS”, True, pygame.Color(‘white’)), [165, 275]) screen.blit(self.font.render(“GOD MODE”, True, pygame.Color(‘white’)), [165, 300]) screen.blit(self.font.render(“(c) 1980 1985 NAMCO LTD.”, True, pygame.Color(‘white’)), [50, 350]) screen.blit(self.font.render(“ALL RIGHTS RESERVED”, True, pygame.Color(‘white’)), [85, 380]) if self.nr_of_players == 1: screen.blit(self.player_image, [125, 245]) elif self.nr_of_players == 2: screen.blit(self.player_image, [125, 270]) elif self.nr_of_players == 3: screen.blit(self.player_image, [125, 300]) god = True self.writeInBricks(“battle”, [65, 80]) self.writeInBricks(“city”, [129, 160]) if put_on_surface: pygame.display.flip() # 按下 Enter 键,立刻实现模式抉择界面的动画 def animateIntroScreen(self): “”” 从下到上滑动介绍(菜单) 屏幕 如果按下 Enter 键,立刻实现动画 @return None “”” global screen self.drawIntroScreen(False) screen_cp = screen.copy() screen.fill([0, 0, 0]) y = 416 while (y > 0): time_passed = self.clock.tick(50) for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_RETURN: y = 0 break screen.blit(screen_cp, [0, y]) pygame.display.flip() y -= 5 screen.blit(screen_cp, [0, 0]) pygame.display.flip() # 将文本字符串宰割成指定大小的块 def chunks(self, l, n): “”” 将文本字符串宰割成指定大小的块 @param string l Input string @param int n Size (number of characters) of each chunk @return list “”” return [l[i:i + n] for i in range(0, len(l), n)] # 以“砖块字体”写入指定文本, 组成单词“Battle City”和“Game Over”def writeInBricks(self, text, pos): “”” 以“砖块字体”写入指定文本只有这些字母能够组成单词“Battle City”和“Game Over”小写和大写都是无效的输出,然而输入总是大写的每个字母由 7 ×7 块砖块组成,砖块被转换成 49 个字符的字符串而后将其转换为十六进制以节俭一些字节 @return None “”” global screen, sprites bricks = sprites.subsurface(56 * 2, 64 * 2, 8 * 2, 8 * 2) brick1 = bricks.subsurface((0, 0, 8, 8)) brick2 = bricks.subsurface((8, 0, 8, 8)) brick3 = bricks.subsurface((8, 8, 8, 8)) brick4 = bricks.subsurface((0, 8, 8, 8)) # 字母表 alphabet alphabet = {“a”: “0071b63c7ff1e3”, “b”: “01fb1e3fd8f1fe”, “c”: “00799e0c18199e”, “e”: “01fb060f98307e”, “g”: “007d860cf8d99f”, “i”: “01f8c183060c7e”, “l”: “0183060c18307e”, “m”: “018fbffffaf1e3”, “o”: “00fb1e3c78f1be”, “r”: “01fb1e3cff3767”, “t”: “01f8c183060c18”, “v”: “018f1e3eef8e08”, “y”: “019b3667860c18”} abs_x, abs_y = pos for letter in text.lower(): binstr = “” for h in self.chunks(alphabet[letter], 2): binstr += str(bin(int(h, 16)))[2:].rjust(8, “0”) binstr = binstr[7:] x, y = 0, 0 letter_w = 0 surf_letter = pygame.Surface((56, 56)) for j, row in enumerate(self.chunks(binstr, 7)): for i, bit in enumerate(row): if bit == “1”: if i % 2 == 0 and j % 2 == 0: surf_letter.blit(brick1, [x, y]) elif i % 2 == 1 and j % 2 == 0: surf_letter.blit(brick2, [x, y]) elif i % 2 == 1 and j % 2 == 1: surf_letter.blit(brick3, [x, y]) elif i % 2 == 0 and j % 2 == 1: surf_letter.blit(brick4, [x, y]) if x > letter_w: letter_w = x x += 8 x = 0 y += 8 screen.blit(surf_letter, [abs_x, abs_y]) abs_x += letter_w + 16 # 道具解冻敌人 def toggleEnemyFreeze(self, freeze=True): “”” 解冻 / 冻结所有敌人 “”” global enemies for enemy in enemies: enemy.paused = freeze self.timefreeze = freeze # 卡过图的时候解冻敌人和玩家 def FreezeAll(self, freeze=True): “”” 解冻所有坦克, 绝对暂停 ””” global enemies,players for e in enemies: e.paused = freeze for p in players: p.paused = freeze self.timefreeze = freeze # 加载最高分, 查看本地是否有.hiscore 文件 def loadHiscore(self): “”” 加载最高分, 查看本地是否有.hiscore 文件 如果某种原因不能加载最高分,返回 20000 返回值为 int 型 “”” filename = “.hiscore” if (not os.path.isfile(filename)): return 20000 f = open(filename, “r”) hiscore = int(f.read()) if hiscore > 19999 and hiscore < 1000000: # 最高分在 19999 0: self.respawnPlayer(player) if player.lives == 0: Deadnums += 1 if Deadnums ==2: self.gameOver() for bullet in bullets: if bullet.state == bullet.STATE_REMOVED: bullets.remove(bullet) else: bullet.update() for bonus in bonuses: if bonus.active == False: bonuses.remove(bonus) for label in labels: if not label.active: labels.remove(label) if not self.game_over: if not castle.active: self.gameOver() gtimer.update(time_passed) self.draw() if __name__ == “__main__”: gtimer = Timer() god = False sprites = None screen = None players = [] enemies = [] bullets = [] bonuses = [] labels = [] Fullscreen = False play_sounds = True sounds = {} textList = [] game = Game() castle = Castle() game.showMenu()

正文完
 0