博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python编写坦克大战(新增无敌模式)-附赠源码
阅读量:2020 次
发布时间:2019-04-28

本文共 41914 字,大约阅读时间需要 139 分钟。

新增功能:
1、q键直接退出游戏  -》  进行结算然后返回模式选择界面
2、 新增全屏按钮u ,并且切换的时候会造成3s的冻结效果
3、静音键m
4、暂停键p
5、无敌模式,进入下一关条件是只能打败20个坦克
6、代码注释完整
7、z键打印当前坦克的情况
8、可自定义地图
9、可自定义起始关卡

废话不多说,直接上源码,老规矩,需要打包好的软件关注小编,QQ群:721195303领取。

#!/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

在这里还是要推荐下我自己建的Python开发学习群:721195303(即可获取使用到的代码文件及数据),群里都是学Python开发的,如果你想学或者正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2020最新的Python进阶资料和高级开发教程,欢迎进阶中和进想深入Python的小伙伴!

转载地址:http://rfhxf.baihongyu.com/

你可能感兴趣的文章
移动web特殊样式处理
查看>>
移动端尺寸基础知识
查看>>
移动端优化
查看>>
移动端Touch事件
查看>>
转:vue-cli的webpack模板项目配置文件分析
查看>>
webpack3学习笔记
查看>>
vue系列之项目优化
查看>>
前端基础
查看>>
转:localStorage 还能这么用
查看>>
使用mongoose操作mongodb数据库
查看>>
Vue 实现countDown倒计时
查看>>
idea配置tomcat
查看>>
IDEA 2017的插件mybatis plugin
查看>>
前端JavaScript高级面试笔记
查看>>
手把手从零打造企业级电商平台-前端实战
查看>>
Charles
查看>>
模板引擎--hogan
查看>>
idea导入maven项目,包没有自动下载
查看>>
webpack4
查看>>
启动tomcat的时候爆出如下错误
查看>>