Python Pygame 坦克大战

在坦克大战游戏开发中,坦克移动控制子弹碰撞检测敌方AI行为游戏状态管理是四大核心模块。以下截取关键代码片段,结合文字详解其实现逻辑与设计思路。

一、坦克类(Tank):移动与射击的核心实现

坦克是游戏的核心实体,需处理移动、转向、射击和受击逻辑。下面两段代码分别对应网格移动机制射击功能,是坦克类的核心。

1. 网格移动:实现精准的格子化移动(避免自由移动的杂乱)

def move(self, dx, dy, walls):
    # 如果正在移动,不接受新的移动指令(仅对玩家坦克)
    if self.is_player and self.moving:
        return False

    new_x = self.x + dx
    new_y = self.y + dy

    # 1. 边界检查:防止坦克移出屏幕
    if new_x < 0 or new_x > SCREEN_WIDTH - self.width or new_y < 0 or new_y > SCREEN_HEIGHT - self.height:
        return False

    # 2. 墙体碰撞检查:通过矩形碰撞检测判断是否撞墙
    tank_rect = pygame.Rect(new_x, new_y, self.width, self.height)
    for wall in walls:
        if tank_rect.colliderect(wall):
            return False

    # 3. 设置目标位置,开启移动状态
    self.target_x = new_x
    self.target_y = new_y
    self.moving = True
    return True

def update_position(self):
    """更新网格移动位置(实现平滑移动到目标格子)"""
    if not self.moving:
        return

    # 计算当前位置与目标位置的差值
    dx = self.target_x - self.x
    dy = self.target_y - self.y

    # 1. 到达目标位置:停止移动
    if abs(dx) < self.move_speed and abs(dy) < self.move_speed:
        self.x = self.target_x
        self.y = self.target_y
        self.moving = False
        return

    # 2. 未到达:按速度逐步靠近目标
    if dx > 0:
        self.x += min(dx, self.move_speed)  # 避免超调
    elif dx < 0:
        self.x -= min(-dx, self.move_speed)
    if dy > 0:
        self.y += min(dy, self.move_speed)
    elif dy < 0:
        self.y -= min(-dy, self.move_speed)
代码逻辑说明:
  • 网格移动设计:玩家坦克每次移动固定距离(GRID_SIZE = 40,与坦克宽度一致),避免自由移动的“滑步”感,还原经典坦克大战的格子化操作。
  • 双重检测:先检查是否超出屏幕边界,再通过 pygame.Rect.colliderect 检测是否与墙体重叠,确保移动合法性。
  • 平滑移动update_position 方法通过“逐步靠近目标”的逻辑,让坦克从当前位置平滑移动到目标格子,而非瞬间跳转,提升视觉体验。

2. 射击功能:根据坦克朝向生成子弹

def shoot(self):
    current_time = pygame.time.get_ticks()
    # 1. 射速限制:通过时间差控制射击间隔(避免连发)
    if current_time - self.last_shot > self.shoot_delay:
        self.last_shot = current_time
        # 2. 计算炮管发射点(确保子弹从炮管顶端射出,而非坦克中心)
        barrel_x = self.x + self.width // 2
        barrel_y = self.y + self.height // 2

        # 3. 根据坦克朝向,生成对应方向的子弹
        if self.direction == 0:  # 上
            return Bullet(barrel_x, barrel_y - BARREL_LENGTH, 0, -BULLET_SPEED)
        elif self.direction == 1:  # 右
            return Bullet(barrel_x + BARREL_LENGTH, barrel_y, BULLET_SPEED, 0)
        elif self.direction == 2:  # 下
            return Bullet(barrel_x, barrel_y + BARREL_LENGTH, 0, BULLET_SPEED)
        elif self.direction == 3:  # 左
            return Bullet(barrel_x - BARREL_LENGTH, barrel_y, -BULLET_SPEED, 0)
    return None
代码逻辑说明:
  • 射速控制:通过 pygame.time.get_ticks() 获取当前时间,与上次射击时间对比,确保两次射击间隔不小于 SHOOT_DELAY = 500 毫秒(0.5秒),防止玩家“作弊式连发”。
  • 发射点精准计算:以坦克中心为基准,根据炮管长度(BARREL_LENGTH = 25)和朝向,计算子弹的初始位置,确保子弹从炮管顶端射出,符合视觉逻辑。
  • 方向与速度绑定:不同朝向对应不同的子弹速度分量(如向上时 dy = -BULLET_SPEED,向左时 dx = -BULLET_SPEED),确保子弹沿炮管方向飞行。

二、子弹碰撞检测:实现“子弹打坦克/墙体”的物理逻辑

子弹是交互的关键载体,需处理“出界删除”“撞墙消失”“击中坦克掉血”三大核心逻辑,以下是 update_bullets 方法的核心片段:

def update_bullets(self):
    # 1. 处理玩家子弹
    for bullet in self.player.bullets[:]:  # 用切片遍历(避免删除元素时索引异常)
        bullet.update()  # 更新子弹位置(x/y += 速度)

        # (1)子弹出界:从列表中删除
        if bullet.is_off_screen():
            self.player.bullets.remove(bullet)
            continue

        # (2)子弹撞墙:通过矩形碰撞检测
        bullet_rect = pygame.Rect(bullet.x - bullet.radius, bullet.y - bullet.radius,
                                bullet.radius * 2, bullet.radius * 2)
        for wall in self.walls:
            if bullet_rect.colliderect(wall.rect):
                self.player.bullets.remove(bullet)
                break

        # (3)子弹击中敌方坦克
        for enemy in self.enemies[:]:
            enemy_rect = pygame.Rect(enemy.x, enemy.y, enemy.width, enemy.height)
            if bullet_rect.colliderect(enemy_rect):
                # 移除子弹
                self.player.bullets.remove(bullet)
                # 敌方掉血(玩家子弹伤害更高:25点)
                enemy.take_damage(PLAYER_BULLET_DAMAGE)
                # 敌方血量为0:删除坦克+加分
                if enemy.health <= 0:
                    self.enemies.remove(enemy)
                    self.score += 10
                break

    # 2. 处理敌方子弹(逻辑与玩家子弹类似,仅伤害值不同)
    for enemy in self.enemies:
        for bullet in enemy.bullets[:]:
            bullet.update()
            if bullet.is_off_screen():
                enemy.bullets.remove(bullet)
                continue

            # 敌方子弹撞墙
            bullet_rect = pygame.Rect(bullet.x - bullet.radius, bullet.y - bullet.radius,
                                    bullet.radius * 2, bullet.radius * 2)
            for wall in self.walls:
                if bullet_rect.colliderect(wall.rect):
                    enemy.bullets.remove(bullet)
                    break

            # 敌方子弹击中玩家
            player_rect = pygame.Rect(self.player.x, self.player.y, self.player.width, self.player.height)
            if bullet_rect.colliderect(player_rect):
                enemy.bullets.remove(bullet)
                self.player.take_damage(ENEMY_BULLET_DAMAGE)  # 敌方子弹伤害低:10点
                if self.player.health <= 0:
                    self.game_over = True  # 玩家死亡,游戏结束
                break
代码逻辑说明:
  • 安全遍历:使用 for bullet in self.player.bullets[:](切片复制列表)遍历,避免删除子弹时修改原列表导致的索引错位问题。
  • 碰撞检测核心:将圆形子弹转为矩形(bullet_rect),通过 colliderect 方法与墙体/坦克的矩形碰撞,简化物理计算(圆形碰撞需计算距离,矩形更高效)。
  • 伤害差异化:玩家子弹伤害(25点)高于敌方子弹(10点),符合“玩家主导”的游戏平衡设计;敌方死亡后加分(score += 10),提供游戏目标激励。

三、敌方AI:实现“自动移动+随机射击”的基础智能

敌方坦克需具备简单的自主行为,避免“静止不动”,以下是 update_enemies 方法的核心逻辑:

def update_enemies(self):
    for enemy in self.enemies:
        # 1. 更新敌方坦克位置(与玩家坦克共用网格移动逻辑)
        enemy.update_position()

        # 2. 随机改变方向(2%概率):避免敌方“一条路走到黑”
        if not enemy.moving and random.random() < ENEMY_DIRECTION_CHANGE_PROBABILITY:
            enemy.rotate(random.randint(0, 3))  # 0-3对应上右下左

        # 3. 自动移动(仅当未移动时尝试)
        if not enemy.moving:
            dx, dy = 0, 0
            # 根据当前朝向计算移动方向(与玩家移动逻辑一致)
            if enemy.direction == 0:
                dy = -GRID_SIZE
            elif enemy.direction == 1:
                dx = GRID_SIZE
            elif enemy.direction == 2:
                dy = GRID_SIZE
            elif enemy.direction == 3:
                dx = -GRID_SIZE

            # 尝试移动:若撞墙(返回False),则随机改变方向
            if not enemy.move(dx, dy, self.walls):
                enemy.rotate(random.randint(0, 3))

        # 4. 随机射击(1%概率):模拟敌方“攻击意图”
        if random.random() < ENEMY_SHOOT_PROBABILITY:
            bullet = enemy.shoot()
            if bullet:
                enemy.bullets.append(bullet)
代码逻辑说明:
  • 随机转向:通过 random.random() < 0.02 实现2%的转向概率,让敌方坦克偶尔改变方向,避免“卡死在墙角”或“直线撞墙”的尴尬情况。
  • 撞墙重试:若移动时撞墙(enemy.move 返回False),立即随机转向,模拟“敌方发现撞墙后调整方向”的智能行为。
  • 低频率射击:1%的射击概率(ENEMY_SHOOT_PROBABILITY = 0.01)确保敌方不会“弹幕攻击”,同时保持一定的威胁性,平衡游戏难度。

四、游戏状态管理:实现“游戏结束+重启”的完整流程

游戏需明确“胜利/失败”判定,并支持重启功能,以下是核心代码片段:

def check_game_over(self):
    # 1. 玩家死亡:游戏失败
    if self.player.health <= 0:
        self.game_over = True
    # 2. 消灭所有敌人:游戏胜利
    elif len(self.enemies) == 0:
        self.game_over = True

def handle_events(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            self.running = False  # 关闭窗口
        elif event.type == pygame.KEYDOWN:
            # 游戏结束时按R键重启
            if event.key == pygame.K_r and self.game_over:
                self.restart_game()
            # 非游戏结束时按空格射击
            elif event.key == pygame.K_SPACE and not self.game_over:
                bullet = self.player.shoot()
                if bullet:
                    self.player.bullets.append(bullet)

def restart_game(self):
    # 重置所有游戏状态
    self.player = Tank(100, 100, GREEN, is_player=True)  # 玩家回到初始位置
    self.enemies = []
    self.create_enemies()  # 重新生成敌人
    self.create_walls()    # 重新生成随机墙体
    self.score = 0         # 分数重置
    self.game_over = False # 游戏状态重置
代码逻辑说明:
  • 胜负判定check_game_over 方法明确两种结束条件——玩家血量为0(失败)、敌人全部消灭(胜利),清晰界定游戏目标。
  • 重启机制:按R键触发 restart_game,重置玩家位置、敌人、墙体和分数,让玩家无需重启程序即可再次游玩,提升体验。
  • 事件绑定:通过 pygame.KEYDOWN 事件区分“射击”(空格)和“重启”(R键),并通过 self.game_over 状态限制功能触发时机(如游戏结束时无法射击)。

总结

以上核心代码片段覆盖了坦克大战的“实体控制-交互逻辑-状态管理”全流程,其设计思路可迁移到其他2D游戏开发中:

  1. 实体封装:将坦克、子弹、墙体封装为类,每个类负责自身的绘制、更新和交互,代码结构更清晰;
  2. 碰撞检测:用 pygame.Rect 简化矩形碰撞计算,平衡性能与效果;
  3. 平衡设计:通过“玩家伤害高+敌方AI简单”“射速限制”等规则,确保游戏难度适中;
  4. 体验优化:网格移动、平滑过渡、重启功能等细节,提升玩家操作感和重复游玩意愿。

若需扩展功能(如添加道具、升级系统),可基于现有类结构逐步迭代,例如给 Tank 类添加“射速提升”属性,或新增 Prop 类实现道具掉落逻辑。

运行效果

在这里插入图片描述
在这里插入图片描述

完整代码

import pygame
import random
import math
import sys

# 初始化pygame
pygame.init()

# 游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 60
GRID_SIZE = 40  # 网格大小,与坦克大小一致

# 游戏参数
PLAYER_SPEED = 3
ENEMY_SPEED = 2  # 稍微降低敌方速度
SHOOT_DELAY = 500  # 毫秒
ENEMY_SHOOT_PROBABILITY = 0.01
ENEMY_DIRECTION_CHANGE_PROBABILITY = 0.02
TANK_WIDTH = 40
TANK_HEIGHT = 40
BARREL_LENGTH = 25
BARREL_WIDTH = 9  # 炮管宽度
BULLET_SPEED = 7
BULLET_RADIUS = 3
HEALTH_BAR_HEIGHT = 5
WALL_BOUNDARY_SIZE = 20
WALL_THICKNESS = 30
WALL_LENGTH = 100
PLAYER_BULLET_DAMAGE = 25
ENEMY_BULLET_DAMAGE = 10
MAX_ENEMY_COUNT = 6
PLAYER_MAX_HEALTH = 100
ENEMY_MAX_HEALTH = 100

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
BROWN = (139, 69, 19)
GRAY = (128, 128, 128)
DARK_GRAY = (64, 64, 64)  # 炮管颜色

class Tank:
    def __init__(self, x, y, color, is_player=False):
        self.x = x
        self.y = y
        self.width = TANK_WIDTH
        self.height = TANK_HEIGHT
        self.color = color
        self.direction = 0  # 0:上, 1:右, 2:下, 3:左
        self.speed = PLAYER_SPEED if is_player else ENEMY_SPEED
        self.is_player = is_player
        self.bullets = []
        self.last_shot = 0
        self.shoot_delay = SHOOT_DELAY  # 毫秒
        self.health = PLAYER_MAX_HEALTH if is_player else ENEMY_MAX_HEALTH
        self.max_health = PLAYER_MAX_HEALTH if is_player else ENEMY_MAX_HEALTH

        # 网格移动相关属性
        self.target_x = x
        self.target_y = y
        self.moving = False
        self.move_speed = self.speed

    def draw(self, screen, font):
        # 绘制坦克主体
        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))

        # 绘制坦克顶部(炮塔)
        turret_width = 20
        turret_height = 20
        turret_x = self.x + (self.width - turret_width) // 2
        turret_y = self.y + (self.height - turret_height) // 2
        pygame.draw.rect(screen, DARK_GRAY, (turret_x, turret_y, turret_width, turret_height))

        # 绘制炮管
        barrel_length = BARREL_LENGTH
        barrel_width = BARREL_WIDTH
        center_x = self.x + self.width // 2
        center_y = self.y + self.height // 2

        if self.direction == 0:  # 上
            # 垂直向上的炮管
            pygame.draw.rect(screen, DARK_GRAY,
                           (center_x - barrel_width//2, center_y - barrel_length,
                            barrel_width, barrel_length))
        elif self.direction == 1:  # 右
            # 水平向右的炮管
            pygame.draw.rect(screen, DARK_GRAY,
                           (center_x, center_y - barrel_width//2,
                            barrel_length, barrel_width))
        elif self.direction == 2:  # 下
            # 垂直向下的炮管
            pygame.draw.rect(screen, DARK_GRAY,
                           (center_x - barrel_width//2, center_y,
                            barrel_width, barrel_length))
        elif self.direction == 3:  # 左
            # 水平向左的炮管
            pygame.draw.rect(screen, DARK_GRAY,
                           (center_x - barrel_length, center_y - barrel_width//2,
                            barrel_length, barrel_width))

        # 绘制血条
        if self.health < self.max_health:
            bar_width = self.width
            bar_height = HEALTH_BAR_HEIGHT
            pygame.draw.rect(screen, RED, (self.x, self.y - 10, bar_width, bar_height))
            health_width = int(bar_width * (self.health / self.max_health))
            pygame.draw.rect(screen, GREEN, (self.x, self.y - 10, health_width, bar_height))

    def move(self, dx, dy, walls):
        # 如果正在移动,不接受新的移动指令(仅对玩家坦克)
        if self.is_player and self.moving:
            return False

        new_x = self.x + dx
        new_y = self.y + dy

        # 边界检查
        if new_x < 0 or new_x > SCREEN_WIDTH - self.width or new_y < 0 or new_y > SCREEN_HEIGHT - self.height:
            return False

        # 墙体碰撞检查
        tank_rect = pygame.Rect(new_x, new_y, self.width, self.height)
        for wall in walls:
            if tank_rect.colliderect(wall):
                return False

        # 设置目标位置,开始移动
        self.target_x = new_x
        self.target_y = new_y
        self.moving = True
        return True

    def update_position(self):
        """更新网格移动位置"""
        if not self.moving:
            return

        # 计算移动方向
        dx = self.target_x - self.x
        dy = self.target_y - self.y

        # 如果已经到达目标位置
        if abs(dx) < self.move_speed and abs(dy) < self.move_speed:
            self.x = self.target_x
            self.y = self.target_y
            self.moving = False
            return

        # 根据移动速度更新位置
        if dx > 0:
            self.x += min(dx, self.move_speed)
        elif dx < 0:
            self.x -= min(-dx, self.move_speed)

        if dy > 0:
            self.y += min(dy, self.move_speed)
        elif dy < 0:
            self.y -= min(-dy, self.move_speed)

    def rotate(self, direction):
        self.direction = direction

    def shoot(self):
        current_time = pygame.time.get_ticks()
        if current_time - self.last_shot > self.shoot_delay:
            self.last_shot = current_time
            barrel_x = self.x + self.width // 2
            barrel_y = self.y + self.height // 2
            bullet_speed = BULLET_SPEED

            if self.direction == 0:  # 上
                return Bullet(barrel_x, barrel_y - BARREL_LENGTH, 0, -bullet_speed)
            elif self.direction == 1:  # 右
                return Bullet(barrel_x + BARREL_LENGTH, barrel_y, bullet_speed, 0)
            elif self.direction == 2:  # 下
                return Bullet(barrel_x, barrel_y + BARREL_LENGTH, 0, bullet_speed)
            elif self.direction == 3:  # 左
                return Bullet(barrel_x - BARREL_LENGTH, barrel_y, -bullet_speed, 0)
        return None

    def take_damage(self, damage):
        self.health -= damage
        if self.health < 0:
            self.health = 0

class Bullet:
    def __init__(self, x, y, dx, dy):
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.radius = BULLET_RADIUS
        self.color = YELLOW
        self.speed = BULLET_SPEED

    def update(self):
        self.x += self.dx
        self.y += self.dy

    def draw(self, screen):
        pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.radius)

    def is_off_screen(self):
        return (self.x < 0 or self.x > SCREEN_WIDTH or
                self.y < 0 or self.y > SCREEN_HEIGHT)

class Wall:
    def __init__(self, x, y, width, height):
        self.rect = pygame.Rect(x, y, width, height)
        self.color = BROWN

    def draw(self, screen):
        pygame.draw.rect(screen, self.color, self.rect)

class Game:
    def __init__(self):
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption("坦克大战")
        self.clock = pygame.time.Clock()

        # 字体初始化,支持中文显示
        try:
            # 尝试使用系统中文字体
            self.font_large = pygame.font.SysFont("simhei", 36)  # 黑体
            self.font_medium = pygame.font.SysFont("simhei", 24)
            self.font_small = pygame.font.SysFont("simhei", 18)
        except:
            # 备用方案:使用默认字体
            self.font_large = pygame.font.Font(None, 36)
            self.font_medium = pygame.font.Font(None, 24)
            self.font_small = pygame.font.Font(None, 18)

        # 创建玩家坦克
        self.player = Tank(100, 100, GREEN, is_player=True)

        # 创建敌方坦克
        self.enemies = []
        self.create_enemies()

        # 创建障碍物
        self.walls = []
        self.create_walls()

        # 游戏状态
        self.score = 0
        self.game_over = False
        self.running = True

    def create_enemies(self):
        enemy_positions = [
            (600, 100), (600, 400), (100, 400),
            (300, 200), (500, 300), (200, 500)
        ]

        for pos in enemy_positions:
            enemy = Tank(pos[0], pos[1], RED)
            # 随机设置初始方向
            enemy.direction = random.randint(0, 3)
            self.enemies.append(enemy)

    def create_walls(self):
        """创建随机障碍物"""
        self.walls = []

        # 边界墙
        self.walls.append(Wall(0, 0, SCREEN_WIDTH, WALL_BOUNDARY_SIZE))  # 上边界
        self.walls.append(Wall(0, SCREEN_HEIGHT - WALL_BOUNDARY_SIZE, SCREEN_WIDTH, WALL_BOUNDARY_SIZE))  # 下边界
        self.walls.append(Wall(0, 0, WALL_BOUNDARY_SIZE, SCREEN_HEIGHT))  # 左边界
        self.walls.append(Wall(SCREEN_WIDTH - WALL_BOUNDARY_SIZE, 0, WALL_BOUNDARY_SIZE, SCREEN_HEIGHT))  # 右边界

        # 随机生成内部障碍物
        # 定义一些可能的障碍物位置,避免与坦克起始位置重叠
        possible_positions = [
            (150, 150), (250, 150), (350, 150), (450, 150), (550, 150),
            (150, 250), (250, 250), (350, 250), (450, 250), (550, 250),
            (150, 350), (250, 350), (350, 350), (450, 350), (550, 350),
            (150, 450), (250, 450), (350, 450), (450, 450), (550, 450)
        ]

        # 随机选择一部分位置生成障碍物
        num_obstacles = random.randint(3, 8)  # 随机生成3-8个障碍物
        selected_positions = random.sample(possible_positions, num_obstacles)

        for pos in selected_positions:
            # 随机决定障碍物是横向还是纵向
            if random.choice([True, False]):
                # 横向障碍物
                self.walls.append(Wall(pos[0], pos[1], WALL_LENGTH, WALL_THICKNESS))
            else:
                # 纵向障碍物
                self.walls.append(Wall(pos[0], pos[1], WALL_THICKNESS, WALL_LENGTH))

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r and self.game_over:
                    self.restart_game()
                elif event.key == pygame.K_SPACE and not self.game_over:
                    bullet = self.player.shoot()
                    if bullet:
                        self.player.bullets.append(bullet)

        # 处理持续按键
        if not self.game_over and not self.player.moving:
            keys = pygame.key.get_pressed()
            dx, dy = 0, 0
            # 网格移动:每次移动一个坦克宽度的距离
            if keys[pygame.K_UP] or keys[pygame.K_w]:
                dy = -GRID_SIZE
                self.player.rotate(0)
            elif keys[pygame.K_DOWN] or keys[pygame.K_s]:
                dy = GRID_SIZE
                self.player.rotate(2)
            elif keys[pygame.K_LEFT] or keys[pygame.K_a]:
                dx = -GRID_SIZE
                self.player.rotate(3)
            elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
                dx = GRID_SIZE
                self.player.rotate(1)

            if dx != 0 or dy != 0:
                self.player.move(dx, dy, self.walls)

    def update_enemies(self):
        for enemy in self.enemies:
            # 更新敌方坦克位置
            enemy.update_position()

            # 简单AI:随机移动和射击
            if not enemy.moving and random.random() < ENEMY_DIRECTION_CHANGE_PROBABILITY:  # 2%概率改变方向
                enemy.rotate(random.randint(0, 3))

            # 尝试移动(敌方坦克使用网格移动)
            if not enemy.moving:
                dx, dy = 0, 0
                if enemy.direction == 0:  # 上
                    dy = -GRID_SIZE
                elif enemy.direction == 1:  # 右
                    dx = GRID_SIZE
                elif enemy.direction == 2:  # 下
                    dy = GRID_SIZE
                elif enemy.direction == 3:  # 左
                    dx = -GRID_SIZE

                if dx != 0 or dy != 0:
                    # 尝试移动
                    if not enemy.move(dx, dy, self.walls):
                        # 如果不能移动,随机改变方向
                        enemy.rotate(random.randint(0, 3))

            # 随机射击
            if random.random() < ENEMY_SHOOT_PROBABILITY:  # 1%概率射击
                bullet = enemy.shoot()
                if bullet:
                    enemy.bullets.append(bullet)

    def check_tank_collisions(self):
        """检查坦克之间的碰撞"""
        player_rect = pygame.Rect(self.player.x, self.player.y, self.player.width, self.player.height)

        # 检查玩家坦克与敌方坦克的碰撞
        for enemy in self.enemies[:]:
            enemy_rect = pygame.Rect(enemy.x, enemy.y, enemy.width, enemy.height)
            if player_rect.colliderect(enemy_rect):
                # 双方都死亡
                self.player.health = 0
                enemy.health = 0
                self.enemies.remove(enemy)
                self.game_over = True
                break

    def update_bullets(self):
        # 更新玩家子弹
        for bullet in self.player.bullets[:]:
            bullet.update()
            if bullet.is_off_screen():
                self.player.bullets.remove(bullet)
                continue

            # 检查与墙壁的碰撞
            bullet_rect = pygame.Rect(bullet.x - bullet.radius, bullet.y - bullet.radius,
                                    bullet.radius * 2, bullet.radius * 2)
            for wall in self.walls:
                if bullet_rect.colliderect(wall.rect):
                    if bullet in self.player.bullets:
                        self.player.bullets.remove(bullet)
                    break

            # 检查与敌方坦克的碰撞
            for enemy in self.enemies[:]:
                enemy_rect = pygame.Rect(enemy.x, enemy.y, enemy.width, enemy.height)
                if bullet_rect.colliderect(enemy_rect):
                    if bullet in self.player.bullets:
                        self.player.bullets.remove(bullet)
                    enemy.take_damage(PLAYER_BULLET_DAMAGE)
                    if enemy.health <= 0:
                        self.enemies.remove(enemy)
                        self.score += 10
                    break

        # 更新敌方子弹
        for enemy in self.enemies:
            for bullet in enemy.bullets[:]:
                bullet.update()
                if bullet.is_off_screen():
                    enemy.bullets.remove(bullet)
                    continue

                # 检查与墙壁的碰撞
                bullet_rect = pygame.Rect(bullet.x - bullet.radius, bullet.y - bullet.radius,
                                        bullet.radius * 2, bullet.radius * 2)
                for wall in self.walls:
                    if bullet_rect.colliderect(wall.rect):
                        enemy.bullets.remove(bullet)
                        break

                # 检查与玩家坦克的碰撞
                player_rect = pygame.Rect(self.player.x, self.player.y, self.player.width, self.player.height)
                if bullet_rect.colliderect(player_rect):
                    enemy.bullets.remove(bullet)
                    self.player.take_damage(ENEMY_BULLET_DAMAGE)
                    if self.player.health <= 0:
                        self.game_over = True
                    break

    def check_game_over(self):
        if self.player.health <= 0:
            self.game_over = True
        elif len(self.enemies) == 0:
            self.game_over = True

    def draw(self):
        self.screen.fill(BLACK)

        # 绘制墙壁
        for wall in self.walls:
            wall.draw(self.screen)

        # 绘制玩家坦克
        self.player.draw(self.screen, self.font_small)

        # 绘制敌方坦克
        for enemy in self.enemies:
            enemy.draw(self.screen, self.font_small)

        # 绘制子弹
        for bullet in self.player.bullets:
            bullet.draw(self.screen)
        for enemy in self.enemies:
            for bullet in enemy.bullets:
                bullet.draw(self.screen)

        # 绘制UI
        score_text = self.font_medium.render(f"得分: {self.score}", True, WHITE)
        self.screen.blit(score_text, (10, 10))

        health_text = self.font_medium.render(f"生命: {self.player.health}", True, WHITE)
        self.screen.blit(health_text, (10, 50))

        enemies_text = self.font_medium.render(f"敌人: {len(self.enemies)}", True, WHITE)
        self.screen.blit(enemies_text, (10, 90))

        # 游戏结束界面
        if self.game_over:
            if self.player.health <= 0:
                game_over_text = self.font_large.render("游戏结束! 按R键重新开始", True, RED)
            else:
                game_over_text = self.font_large.render("胜利! 按R键重新开始", True, GREEN)

            text_rect = game_over_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
            self.screen.blit(game_over_text, text_rect)

        pygame.display.flip()

    def restart_game(self):
        self.player = Tank(100, 100, GREEN, is_player=True)
        self.enemies = []
        self.create_enemies()
        self.create_walls()  # 重新生成随机障碍物
        self.score = 0
        self.game_over = False

    def run(self):
        while self.running:
            self.handle_events()

            if not self.game_over:
                # 更新坦克位置(网格移动)
                self.player.update_position()
                self.update_enemies()
                self.update_bullets()
                self.check_tank_collisions()  # 检查坦克碰撞
                self.check_game_over()

            self.draw()
            self.clock.tick(FPS)

        pygame.quit()
        sys.exit()

# 运行游戏
if __name__ == "__main__":
    game = Game()
    game.run()

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐