Python实现坦克大战(TankWar)游戏(上)

简介: Python实现坦克大战(TankWar)游戏

项目所有的代码与材料:代码下载


Features


双人模式
动画与音效
特殊的场景元素:草丛、河面和可以通行的冰面
各种各样的道具



Rules


玩家一 WASD 控制方向、空格键开火,玩家二上下左右控制方向、小键盘数字 0 键开火。

每个玩家初始时拥有 3 个生命值,初始时坦克等级为 0,吃到道具可以提升坦克等级,被子弹打中若坦克等级为 0 则坦克爆炸(减少生命),否则降低坦克等级,没有生命值时坦克将不能重生(即为死亡),所有玩家坦克都死亡则游戏结束。


击败所有当前关卡的敌方坦克进入下一关,关卡无限制,随机挑选关卡进行游戏(必定与上一局游戏关卡不同)。


子弹可以打破红砖块,升级的坦克发出的子弹可以打破铁砖,坦克可以隐藏进入草丛,可以在冰面上滑行但不能通过河面。


道具可以增加我方坦克生命、令敌人静止不动、使我方坦克升级、破坏所有场上的地方坦克等,我方子弹击中越高等级的敌人越有概率生成道具(每个敌人出生时有概率携带一个道具掉落,等级越高越可能有道具掉落)。


每个坦克每隔一定间隔只能发出一个子弹,子弹必须在撞到其他实体、场景元素或者边界而消失时才能发出下一发,越高等级的坦克子弹飞行速度越快。


电脑方的坦克有三种类型,1)快速坦克:行驶速度比玩家的坦克快,但自身防御力低,可被玩家坦克一炮击毁;2)重型坦克:行驶速度慢,装甲厚,需要三发炮弹才能击毁;3)普通坦克:行驶速度和防御能力介于以上两者之间,需要二发炮弹才能击毁。


第一个关卡的电脑方坦克数量为 20,关卡中最大敌方坦克数量限制为 6,每过一关,电脑方坦克数量增加 1 辆,最大敌方坦克数量限制也增加 1,重装坦克的随机生成权重提高


Design


先从框架讲起,游戏基于 PyGame框架实现,PyGame 框架为开发游戏提供了一套完善的解决方案,pygame.Sprite.Sprite 可以视为游戏里的某个元素,pygame.Sprite.Group 可以看做是元素的聚集,有了这个基础,就可以在此之上进行碰撞检测等等操作


PyGame 框架的游戏核心是基于事件循环,用户也可以自定义事件并在主循环中对事件作出响应,在主循环中可以控制游戏的帧率,使得动画在不同的机器上显示出相同的效果。


在 Python 中,一个 Protected 方法的声明方式是在其前面加一个 _,而 Private 方法的声明是加两个 _,对于 Getter 和 Setter 方法则是使用装饰器 @property / @var.setter 来实现。


TankGame


游戏实例类 TankGame 为单例模式,其内部存储着游戏的关键状态信息(例如当前关卡 level、是否退出游戏 quit_game_flag、多人模式选项 multiplayer_mode、游戏窗体实例 __screen)与界面管理类 ViewManager 进行直接交互,根据当前的状态判断展示哪个界面并在游戏结束时做出最外层的响应。



_init_flag 表示游戏加载完成状态,表示目前是否应该退出游戏,__config 为游戏配置文件,__levels 为游戏关卡列表,


ViewManager


界面管理类负责管理游戏加载 SwitchLevelView、游戏开始 GameStartView、游戏结束 GameOverView、游戏关卡 GameOverView 四个实现了 AbstractView 抽象接口的具体游戏界面类的加载工作。


界面在实例化时自动预加载,只有在调用其 show() 方法时才显示,预加载是将不需要重复加载或初始化的资源提前加载进入内存,在需要显示界面的时候直接显示以提高其效率。


GameLevel


游戏关卡类 GameLevelView 是坦克大战的核心,携带有每次关卡相关的所有状态,并再每次调用 show() 方法时加载关卡文件和初始化状态。对于各种事件的处理和渲染工作,是在一个事件循环 EventLoop 中完成的(重载了 _main_loop() 方法),按顺序分别是:

退出游戏事件捕捉
敌方坦克生成
处理用户按键
碰撞检测(实体与场景、实体与实体)
更新并绘制实体 self.__entities.update——处理实体的移动、道具的生成、实体的湮灭
游戏界面(包含状态面板)_draw_interface()
坦克存亡判断


注:敌方坦克 AI 是在绘制了所有其他的实体后进行的

def _draw_interface(self):
    screen = TankGame().screen
    screen.fill((0, 0, 0))
    screen.blit(self.__background_img, (0, 0))
    self.__scene_elements.draw(screen, 1)
    self.__entities.draw(screen, 1)
    self.__scene_elements.draw(screen, 2)
    self.__home.draw(screen)
    self.__entities.draw(screen, 2)
    self.__draw_game_panel()
    pygame.display.flip()
def _main_loop(self):
    clock = pygame.time.Clock()
    while self.__has_next_loop:
        # 游戏退出事件捕捉
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            # 敌方坦克生成
            elif event.type == self.__generate_enemies_event:
                ......
        # 用户按键处理
        self.__dispatch_player_operation()
        # 碰撞检测
        self.__dispatch_collisions()
        # 更新并绘制实体
        self.__entities.update(self.__scene_elements, self.__home)
        # 绘制界面
        self._draw_interface()
        # 我方坦克都挂了
        if len(self.__entities.player_tanks) == 0:
            self.__is_win_flag = False
            self.__has_next_loop = False
        # 敌方坦克都挂了
        if self.__total_enemy_num <= 0:
            self.__is_win_flag = True
            self.__has_next_loop = False
        clock.tick(60)


Things on a Level


坦克大战的关卡中将游戏中的所有“东西”分为了两个大类,分别是实体(子弹、坦克、道具)和场景元素(家、砖块、铁块、河流、草丛),而道具是拥有场景元素特性的实体,它虽然继承 SceneElement,但属于实体,合成于 EntityGroup


SceneElementGroup 使用了类似于合成模式的设计,合成了所有场景元素的聚集,提供统一的 add()/draw() 方法控制添加进哪个具体 pygame.sprite.Group 和绘制每类场景元素的聚集,而场景元素的创建需经 SceneFactory 工厂进行创建



EntityGroup 使用了类似于适配器模式的设计,与 SceneElementGroup 的功能类似,但若是创建坦克,则要经过 TankFactory 进行创建。提供统一的 add()/draw()/remove()/update() 方法控制实体聚集的创建/绘制/删除/更新、



Tanks


坦克工厂类负责坦克的创建,Tank 是坦克的抽象类,定义了:



通用接口射击 shoot()、滚动轮子特效 roll()、移动 move()、降级 decrease_level()、更新状态 update()
shoot() 进行射击时判断当前是否处于射击冷却,子弹数量是否满足要求,若射击有效则返回一个 Bullet
move() 则与包含家在内的场景元素进行和其他坦克碰撞处理,判断是否移动出游戏边界,从而断定能否进行移动
update() 则根据游戏的状态更新坦克的状态
子弹相关的通用的属性和方法:子弹配置 _bullet_config、初始子弹数量 bullet_limit、是否允许无限子弹 infitity_bullet、是否处于发射冷却 _is_bullet_cooling()
坦克的基本状态:是否已经爆炸 _booming_flag、bullet_count 当前子弹数量、speed 移动速度
坦克的资源图像属性:image 使用装饰器重载的显示当前坦克图像的 Getter(需要根据当前是否爆炸、移动方向来返回坦克的图像)、_level_images 不同坦克等级对应的图片等等。

玩家坦克类 PlayerTank 拥有特有的 health 生命值属性、protected 无敌状态属性、__reborn() 重生方法以及标识是哪个玩家的字段 name


而敌人坦克类 EnemyTank 拥有特有的 food 携带的道具的属性、set_still() 设定静止不动方法、random_change_direction() 随机并自动找到可以走的下一个方向的方法


Bullet


为了实现每个坦克只能发射一定数量在屏幕中飞行的子弹这个需求,则为每个子弹附上一个 tank 字段,标识子弹的所属坦克,并重载 kill() 方法,在子弹湮灭时令 tank.bullet_count+1,enchanced 为子弹是否可以打破铁砖,move() 处理子弹飞行,并检测是否飞出边界

子弹与实体/场景元素的碰撞检测位于游戏关卡界面类中的 __dispatch_collisions(),分别处理子弹与砖块/铁砖的碰撞、子弹与家的碰撞、敌人子弹与玩家坦克的碰撞、玩家子弹与敌人坦克的碰撞。

def __dispatch_collisions(self):
  collision_results = {
  'group': {},
  'sprite': {},
  'foreach_sprite': {},
  }
  for (collision, args) in self.__collisions['group'].items():
  collision_results['group'][collision] = groupcollide(*args)
  for (collision, args) in self.__collisions['sprite'].items():
  collision_results['sprite'][collision] = spritecollide(*args)
  for (collision, args) in self.__collisions['foreach_sprite'].items():
  arg_list = list(args)
  sprite_list = arg_list[0]
  for sprite in sprite_list:
    arg_list[0] = sprite
    args = tuple(arg_list)
    collision_results['foreach_sprite'][sprite] = spritecollide(*args)
  for bullet in self.__entities.player_bullets:
  collision_result = spritecollide(bullet, self.__scene_elements.iron_group, bullet.enhanced, None)
  if collision_result:
    bullet.kill()
  ...
  # --我方子弹撞敌方坦克
  for tank in self.__entities.enemy_tanks:
  if collision_results['foreach_sprite'][tank]:
    if tank.food:
    self.__entities.add(tank.food)
    tank.clear_food()
    if tank.decrease_level():
    self.__play_sound('bang')
    self.__total_enemy_num -= 1
  # --敌方子弹撞我方坦克
  for tank in self.__entities.player_tanks:
  if collision_results['foreach_sprite'][tank]:
    if tank.protected:
    self.__play_sound('blast')
    else:
    if tank.decrease_level():
      self.__play_sound('bang')
    if tank.health < 0:
      self.__entities.remove(tank)
  if collision_results['sprite']['PlayerBulletWithHome'] or collision_results['sprite']['EnemyBulletWithHome']:
  self.__is_win_flag = False
  self.__has_next_loop = False
  self.__play_sound('bang')
  self.__home.destroyed = True
  if collision_results['group']['PlayerTankWithTree']:
  self.__play_sound('hit')
相关文章
|
2月前
|
IDE 开发工具 Python
Python扑克游戏编程---摸大点
Python扑克游戏编程---摸大点
60 1
|
3月前
|
Python
python编写下象棋游戏|4-14
python编写下象棋游戏|4-14
|
3月前
|
人工智能 算法 图形学
总有一个是你想要的分享40个Python游戏源代码
这是一系列基于Python开发的游戏项目集合,包括中国象棋、麻将、足球、坦克大战、扑克等多种类型游戏,运用了Pygame等库实现图形界面与AI算法。此外还包含迷宫、数独、推箱子等益智游戏及经典游戏如《仙剑奇侠传二战棋版》和《星露谷物语》的Python版本,适合编程学习与娱乐。
143 11
|
2月前
|
数据采集 前端开发 Python
Python pygame 实现游戏 彩色 五子棋 详细注释 附源码 单机版
Python pygame 实现游戏 彩色 五子棋 详细注释 附源码 单机版
86 0
|
3月前
|
消息中间件 数据采集 数据库
庆祝吧!Python IPC让进程间的合作,比团队游戏还默契
【9月更文挑战第7天】在这个数字化时代,软件系统日益复杂,单进程已难以高效处理海量数据。Python IPC(进程间通信)技术应运而生,使多进程协作如同训练有素的电竞战队般默契。通过`multiprocessing`模块中的Pipe等功能,进程间可以直接传递数据,无需依赖低效的文件共享或数据库读写。此外,Python IPC还提供了消息队列、共享内存和套接字等多种机制,适用于不同场景,使进程间的合作更加高效、精准。这一技术革新让开发者能轻松应对复杂挑战,构建更健壮的软件系统。
46 1
|
4月前
|
机器学习/深度学习 存储 定位技术
强化学习Agent系列(一)——PyGame游戏编程,Python 贪吃蛇制作实战教学
本文是关于使用Pygame库开发Python贪吃蛇游戏的实战教学,介绍了Pygame的基本使用、窗口初始化、事件处理、键盘控制移动、以及实现游戏逻辑和对象交互的方法。
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
【机器学习】python之人工智能应用篇--游戏生成技术
游戏生成技术,特别是生成式人工智能(Generative Artificial Intelligence, 简称Generative AI),正逐步革新游戏开发的多个层面,从内容创作到体验设计。这些技术主要利用机器学习、深度学习以及程序化内容生成(Procedural Content Generation, PCG)来自动创造游戏内的各种元素,显著提高了开发效率、丰富了游戏内容并增强了玩家体验。以下是生成式AI在游戏开发中的几个关键应用场景概述
89 2
|
Python
Python实现坦克大战
前段时间,也就是国庆节。在寝室闲来无事,用pygame写了一个小游戏,就是标题写的《坦克大战》。这个游戏写了两个版本,第一个版本是按照书上的思想来写的,发现写到后面的时候代码太乱了。于是我又从头开始,用比较合理的面向对象思想重新写了一个版本。说比较合理也只是符合我自己的思想,所以难免会有一些不合理的设计,水平有限,希望各位读者能够包涵一下。
272 0
|
15天前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!
|
14天前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。