• 技术文章 >头条

    曾经迷恋的坦克大战,自己动手试试吧!

     Ly Ly2020-06-10 12:09:58转载2233

    小时候玩的“坦克大战”,你还记得吗?

    p1.jpg

    环境依赖

    python3.7

    pygame1.9.6

    urllib

    内置库,如random、sys、time、os等

    pygame介绍

    Pygame被设计用来写游戏的python模块集合,基于SDL库开发。使用python可以导入pygame来开发具有全部特性的游戏和多媒体软件,Pygame是极度轻便的并且可以运行在几乎所有的平台和操作系统上。

    1. 导入依赖 & 通用配置

    import random
    import sys
    import time
    from urllib.request import urlretrieve
    import os
    import pygame
     
    SCREEN_WIDTH, SCREEN_HEIGHT = 1200, 700  # 画面大小
    MY_BIRTH_LEFT, MY_BIRTH_TOP = SCREEN_WIDTH / 2, SCREEN_HEIGHT - 60
    DIRECTION = [U, D, L, R] = [ U ,  D ,  L ,  R ]  # 控制键
    Tank_IMAGE_POSITION = r D:/tank_img
    URL =  https://gitee.com/tyoui/logo/raw/master/img/

    2. 通用加载函数

    # 加载图片
    def load_img(name_img):
        save = Tank_IMAGE_POSITION + os.sep + name_img +  .gif
        if not os.path.exists(save):
            urlretrieve(URL + name_img +  .gif , save)
        return pygame.image.load(save)
     
    # 加载背景音乐
    def load_music(name_music):
        save = Tank_IMAGE_POSITION + os.sep + name_music +  .wav
        if not os.path.exists(save):
            urlretrieve(URL + name_music +  .wav , save)
        pygame.mixer.music.load(save)
        pygame.mixer.music.play()

    3. 通用基础类

    * pygame.sprite模块,官方文档上说这个模块是轻量级的,在游戏开发中也未必要使用。
    * sprite翻译为精灵,在游戏动画一般是指一个独立运动的画面元素,在pygame中,
    就可以是一个带有图像(Surface)和大小位置(Rect)的对象。
    * pygame.sprite.Sprite是pygame精灵的基类,一般来说,需要写一个自己的精灵类继承一下它然后加入自己的代码。
       
    class BaseItem(pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()

    4. 定义bullet类

    class Bullet(BaseItem):
        # 参数初始化
        def __init__(self, tank, window):
            super().__init__()
            self.direction = tank.direction
            self.speed = tank.speed * 3
            self.img = load_img( bullet )
            self.rect = self.img.get_rect()
            self.window = window
            self.live = True
            if self.direction == U:
                self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
                self.rect.top = tank.rect.top - self.rect.height
            elif self.direction == D:
                self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
                self.rect.top = tank.rect.top + tank.rect.height
            elif self.direction == L:
                self.rect.left = tank.rect.left - self.rect.width / 2 - self.rect.width / 2
                self.rect.top = tank.rect.top + tank.rect.height / 2 - self.rect.height / 2
            else:
                self.rect.left = tank.rect.left + tank.rect.width
                self.rect.top = tank.rect.top + tank.rect.height / 2 - self.rect.height / 2
     
        # 子弹显示
        def display_bullet(self):
            self.window.blit(self.img, self.rect)
     
        # 通过按键控制子弹移动
        def bullet_move(self):
            if self.direction == U:
                if self.rect.top > 0:
                    self.rect.top -= self.speed
                    return
            elif self.direction == D:
                if self.rect.top < SCREEN_HEIGHT:
                    self.rect.top += self.speed
                    return
            elif self.direction == L:
                if self.rect.left > 0:
                    self.rect.left -= self.speed
                    return
            else:
                if self.rect.left < SCREEN_WIDTH:
                    self.rect.left += self.speed
                    return
            self.live = False
     
        # 我方坦克子弹击中对方坦克
        def hit_enemy_tank(self):
            for enemy in TankGame.enemy_tank_list:
                hit = pygame.sprite.collide_rect(self, enemy)
                if hit:
                    self.live = False
                    if enemy.click_count == 1:
                        enemy.live = False
                        return None
                    enemy.click_count -= 1
                    if enemy.click_count == 2:
                        enemy.load_image = enemy.img32
                    if enemy.click_count == 1:
                        enemy.load_image = enemy.img31
                    load_music( hit )
     
        # 对方坦克子弹击中我方坦克
        def hit_my_tank(self, tank):
            hit = pygame.sprite.collide_rect(self, tank)
            if hit:
                self.live = False
                tank.live = False
     
        # 子弹击中围墙
        def bullet_collide_wall(self):
            for wall in TankGame.wall_list:
                result = pygame.sprite.collide_rect(self, wall)
                if result:
                    self.live = False
                    if wall.count == 1:
                        wall.live = False
                    else:
                        load_music( hit )
     
        # 子弹击中子弹
        def bullet_collide_bullet(self):
            for bullet in TankGame.enemy_bullet_list:
                if pygame.sprite.collide_rect(bullet, self):
                    bullet.live = False
                    self.live = False

    5. 定义tank类

    class Tank(BaseItem):
        # 参数初始化
        def __init__(self, left, top, window, image, direction, speed):
            super().__init__()
            self.window = window
            self.load_image = image
            self.direction = direction
            self.img = self.load_image[self.direction]
            self.rect = self.img.get_rect()
            self.rect.left = left
            self.rect.top = top
            self.speed = speed
            self.tank_width = self.rect.width
            self.tank_height = self.rect.height
            self.wall_switch = False
            self.move_stop = True
            self.live = True
            self.old_left = 0
            self.old_top = 0
     
        # 开火
        def fire(self):
            return Bullet(self, self.window)
     
        # 显示
        def display(self):
            self.img = self.load_image[self.direction]
            self.window.blit(self.img, self.rect)
     
        def wall_not(self, direction):
            if direction == U:
                return self.rect.top > 0
            elif direction == D:
                return self.rect.top <= SCREEN_HEIGHT - self.tank_height
            elif direction == L:
                return self.rect.left > 0
            else:
                return self.rect.left <= SCREEN_WIDTH - self.tank_width
     
        def wall_yes(self, direction):
            if direction == U:
                if self.rect.top < 0:
                    self.rect.top = SCREEN_HEIGHT
            elif direction == D:
                self.rect.top %= SCREEN_HEIGHT
            elif direction == L:
                if self.rect.left < 0:
                    self.rect.left = SCREEN_WIDTH
            else:
                self.rect.left %= SCREEN_WIDTH
     
        def move(self, direction):
            self.old_left = self.rect.left
            self.old_top = self.rect.top
            if self.wall_switch:
                self.wall_yes(direction)
            elif not self.wall_not(direction):
                return None
            if direction == U:
                self.rect.top -= self.speed
            elif direction == D:
                self.rect.top += self.speed
            elif direction == L:
                self.rect.left -= self.speed
            else:
                self.rect.left += self.speed
     
        def stay(self):
            self.rect.left = self.old_left
            self.rect.top = self.old_top
     
        def tank_collide_wall(self):
            for wall in TankGame.wall_list:
                if pygame.sprite.collide_rect(self, wall):
                    self.stay()
     
        def tank_collide_tank(self):
            for tank in TankGame.enemy_tank_list:
                if pygame.sprite.collide_rect(self, tank):
                    self.stay()

    6. 定义我方 & 对方tank类

    class MyTank(Tank):
        def __init__(self, left, top, window):
            self.img = dict(U=load_img( p2tankU ), D=load_img( p2tankD ), L=load_img( p2tankL ), R=load_img( p2tankR ))
            self.my_tank_speed = 4
            super().__init__(left, top, window, self.img, U, self.my_tank_speed)
     
     
    class EnemyTank(Tank):
        def __init__(self, left, top, window):
            self.img1 = dict(U=load_img( enemy1U ), D=load_img( enemy1D ), L=load_img( enemy1L ), R=load_img( enemy1R ))
            self.img2 = dict(U=load_img( enemy2U ), D=load_img( enemy2D ), L=load_img( enemy2L ), R=load_img( enemy2R ))
            self.img3 = dict(U=load_img( enemy3U ), D=load_img( enemy3D ), L=load_img( enemy3L ), R=load_img( enemy3R ))
            self.img31 = dict(U=load_img( enemy3U_1 ), D=load_img( enemy3D_1 ), L=load_img( enemy3L_1 ),
                              R=load_img( enemy3R_1 ))
            self.img32 = dict(U=load_img( enemy3U_2 ), D=load_img( enemy3D_2 ), L=load_img( enemy3L_2 ),
                              R=load_img( enemy3R_2 ))
            # 不同的坦克击中的次数不一样
            image, self.click_count, speed = random.choice([(self.img1, 1, 4), (self.img3, 3, 3), (self.img2, 1, 5)])
            super().__init__(left, top, window, image, self.random_direction(), speed)
            self.step = 100
     
        @staticmethod
        def random_direction():
            n = random.randint(0, 3)
            return DIRECTION[n]
     
        def random_move(self):
            if self.step == 0:
                self.direction = self.random_direction()
                self.step = random.randint(10, 100)
            else:
                self.move(self.direction)
                self.step -= 1
     
        def random_fire(self):
            if random.randint(0, 50) == 1 and len(TankGame.enemy_bullet_list) < 30:
                enemy_bullet = self.fire()
                TankGame.enemy_bullet_list.append(enemy_bullet)

    7. 爆炸动作类

    class Explode(BaseItem):
        def __init__(self, tank, window):
            super().__init__()
            self.img = [load_img( blast0 ), load_img( blast1 ), load_img( blast2 ), load_img( blast3 ), load_img( blast4 ),
                        load_img( blast5 ), load_img( blast6 )]
            self.rect = tank.rect
            self.stop = 0
            self.window = window
            self.rect.left = tank.rect.left - tank.rect.width / 2
        def display_explode(self):
            load_music( blast )
            while self.stop < len(self.img):
                self.window.blit(self.img[self.stop], self.rect)
                self.stop += 1

    8. 定义wall类

    class Wall(BaseItem):
        def __init__(self, left, top, window):
            super().__init__()
            self.count = random.randint(0, 1)
            self.img = [load_img( steels ), load_img( walls )][self.count]
            self.rect = self.img.get_rect()
            self.rect.left = left
            self.rect.top = top
            self.window = window
            self.live = True
     
        def display_wall(self):
            self.window.blit(self.img, self.rect)

    9. 定义坦克大战类

    class TankGame:
        my_bullet_list = list()
        enemy_bullet_list = list()
        enemy_tank_list = list()
        wall_list = list()
     
        def __init__(self):
            if not os.path.exists(Tank_IMAGE_POSITION):
                os.makedirs(Tank_IMAGE_POSITION)
            pygame.init()
            pygame.font.init()
            self.display = pygame.display
            self.window = self.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.RESIZABLE, 32)
            self.display.set_caption( 坦克世界 )
            self.my_tank = MyTank(MY_BIRTH_LEFT, MY_BIRTH_TOP, self.window)
            self.creat_enemy_number = 10
            self.my_tank_lift = 3
            self.creat_enemy(self.creat_enemy_number)
            self.creat_walls()
            self.font = pygame.font.SysFont( kai_ti , 18)
            self.number = 1
     
        def creat_enemy(self, number):
            for _ in range(number):
                left = random.randint(0, SCREEN_WIDTH - self.my_tank.tank_width)
                enemy_tank = EnemyTank(left, 20, self.window)
                TankGame.enemy_tank_list.append(enemy_tank)
     
        def creat_walls(self):
            for i in range(SCREEN_WIDTH // 60 + 1):
                wall_h = random.randint(100, 500)
                w = Wall(60 * i, wall_h, self.window)
                TankGame.wall_list.append(w)
     
        @staticmethod
        def show_walls():
            for w in TankGame.wall_list:
                if w.live:
                    w.display_wall()
                else:
                    TankGame.wall_list.remove(w)
     
        def start_game(self):
            load_music( start )
            while True:
                self.window.fill([0, 0, 0])
                self.get_event()
                len_enemy = len(TankGame.enemy_tank_list)
                self.window.blit(
                    self.draw_text( 敌方坦克*{0},我方生命值*{1},当前{2}关 .format(len_enemy, self.my_tank_lift, self.number)), (10, 10))
                if len_enemy == 0:
                    self.creat_enemy_number += 10
                    self.number += 1
                    self.my_tank_lift += 1
                    self.creat_enemy(self.creat_enemy_number)
                    self.wall_list.clear()
                    self.creat_walls()
                self.show_my_tank()
                self.show_enemy_tank()
                self.show_bullet(TankGame.enemy_bullet_list)
                self.show_bullet(TankGame.my_bullet_list)
                self.show_walls()
                self.display.update()
                time.sleep(0.02)
     
        def show_my_tank(self):
            if self.my_tank.live:
                self.my_tank.display()
                self.my_tank.tank_collide_tank()
                self.my_tank.tank_collide_wall()
            else:
                Explode(self.my_tank, self.window).display_explode()
                del self.my_tank
                if self.my_tank_lift == 0:
                    self.end_game()
                self.my_tank_lift -= 1
                load_music( add )
                self.my_tank = MyTank(MY_BIRTH_LEFT, MY_BIRTH_TOP, self.window)
            if not self.my_tank.move_stop:
                self.my_tank.move(self.my_tank.direction)
     
        def show_enemy_tank(self):
            for e in TankGame.enemy_tank_list:
                e.random_move()
                e.tank_collide_wall()
                if e.live:
                    e.display()
                else:
                    TankGame.enemy_tank_list.remove(e)
                    Explode(e, self.window).display_explode()
                e.random_fire()
     
        def show_bullet(self, ls):
            for b in ls:
                b.bullet_move()
                b.bullet_collide_wall()
                if ls is TankGame.my_bullet_list:
                    b.hit_enemy_tank()
                    b.bullet_collide_bullet()
                else:
                    b.hit_my_tank(self.my_tank)
                if b.live:
                    b.display_bullet()
                else:
                    ls.remove(b)
     
        def get_event(self):
            global SCREEN_WIDTH, SCREEN_HEIGHT
            event_list = pygame.event.get()
            for event in event_list:
                if event.type == pygame.VIDEORESIZE:
                    SCREEN_WIDTH, SCREEN_HEIGHT = event.size
                    self.window = self.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.RESIZABLE, 32)
     
                if event.type == pygame.QUIT:
                    self.end_game()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_w:
                        self.my_tank.direction = U
                    elif event.key == pygame.K_s:
                        self.my_tank.direction = D
                    elif event.key == pygame.K_a:
                        self.my_tank.direction = L
                    elif event.key == pygame.K_d:
                        self.my_tank.direction = R
                    else:
                        return None
                    self.my_tank.move_stop = False
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if len(TankGame.my_bullet_list) < 3:
                        bullet = self.my_tank.fire()
                        load_music( fire )
                        TankGame.my_bullet_list.append(bullet)
                elif event.type == pygame.KEYUP:
                    self.my_tank.move_stop = True
     
        def end_game(self):
            self.display.quit()
            sys.exit()
     
        def draw_text(self, content):
            text_sf = self.font.render(content, True, [255, 0, 0])
            return text_sf

    10. 入口

    if __name__ ==  __main__ :
        g = TankGame()
        g.start_game()

    执行界面

    p1.jpg

    专题推荐:python
    上一篇:Python教你随时看美剧! 下一篇:超好看的3D绘图方式,Python厉害了!

    相关文章推荐

    • python如何爬取网页数据步骤图解• python里怎么调用函数• python的字符如何保存• python input函数如何不要引号• python如何解决报表显示中文乱码• python的ide PyCharm怎么放大字体

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网