Python Pygame 坦克大战【完整代码】
实体封装:将坦克、子弹、墙体封装为类,每个类负责自身的绘制、更新和交互,代码结构更清晰;碰撞检测:用简化矩形碰撞计算,平衡性能与效果;平衡设计:通过“玩家伤害高+敌方AI简单”“射速限制”等规则,确保游戏难度适中;体验优化:网格移动、平滑过渡、重启功能等细节,提升玩家操作感和重复游玩意愿。若需扩展功能(如添加道具、升级系统),可基于现有类结构逐步迭代,例如给Tank类添加“射速提升”属性,或新增P
·
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游戏开发中:
- 实体封装:将坦克、子弹、墙体封装为类,每个类负责自身的绘制、更新和交互,代码结构更清晰;
- 碰撞检测:用
pygame.Rect
简化矩形碰撞计算,平衡性能与效果; - 平衡设计:通过“玩家伤害高+敌方AI简单”“射速限制”等规则,确保游戏难度适中;
- 体验优化:网格移动、平滑过渡、重启功能等细节,提升玩家操作感和重复游玩意愿。
若需扩展功能(如添加道具、升级系统),可基于现有类结构逐步迭代,例如给 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()
更多推荐
所有评论(0)