import tkinter as tk
from tkinter import messagebox, font
import random
import time
import threading
import math
class Game:
def __init__(self, root):
self.root = root
self.root.title("彩虹六号:炸弹冲锋2D简化版")
self.root.geometry("1024x768")
self.root.resizable(False, False)
# 设置中文字体
self.font_family = "SimHei"
# 游戏状态
self.game_active = False
self.defender_turn = False
self.attacker_turn = False
self.bomb_planted = False
self.bomb_defused = False
self.defender_wins = False
self.attacker_wins = False
# 计时器相关
self.defense_timer = 60 # 1分钟防御准备时间
self.game_timer = 300 # 5分钟游戏时间
self.timer_running = False
# 玩家和AI数量
self.player_count = 1
self.ai_count = 4
self.total_players = self.player_count + self.ai_count
# 游戏对象
self.defenders = []
self.attackers = []
self.defense_objects = []
self.bomb_site = {"x": 512, "y": 384, "radius": 50}
self.defuser = None
# 玩家控制变量
self.player_speed = 5
self.key_pressed = {"w": False, "a": False, "s": False, "d": False}
# 创建开始界面
self.create_start_screen()
def create_start_screen(self):
# 清除现有界面
for widget in self.root.winfo_children():
widget.destroy()
# 创建开始界面
start_frame = tk.Frame(self.root, bg="#1a1a2e")
start_frame.pack(fill=tk.BOTH, expand=True)
# 游戏标题
title_font = font.Font(family=self.font_family, size=36, weight="bold")
title_label = tk.Label(start_frame, text="彩虹六号:炸弹冲锋2D简化版", font=title_font, fg="#e94560", bg="#1a1a2e")
title_label.pack(pady=50)
# 版权信息
copyright_font = font.Font(family=self.font_family, size=12)
copyright_label = tk.Label(start_frame, text="Ubisoft&BCZOZ70371", font=copyright_font, fg="#e94560", bg="#1a1a2e")
copyright_label.pack(pady=10)
# 操作说明
controls_font = font.Font(family=self.font_family, size=14)
controls_label = tk.Label(start_frame, text="WASD移动,空格射击", font=controls_font, fg="white", bg="#1a1a2e")
controls_label.pack(pady=20)
# 阵营选择按钮
button_frame = tk.Frame(start_frame, bg="#1a1a2e")
button_frame.pack(pady=100)
defender_btn = tk.Button(button_frame, text="选择防守方", command=self.select_defender,
font=(self.font_family, 16), bg="#4CAF50", fg="white",
width=15, height=2, cursor="hand2")
defender_btn.pack(side=tk.LEFT, padx=20)
attacker_btn = tk.Button(button_frame, text="选择进攻方", command=self.select_attacker,
font=(self.font_family, 16), bg="#F44336", fg="white",
width=15, height=2, cursor="hand2")
attacker_btn.pack(side=tk.LEFT, padx=20)
def select_defender(self):
self.defender_turn = True
self.create_game_screen()
self.initialize_defenders()
self.start_defense_prep_phase()
self.setup_player_controls()
def select_attacker(self):
self.attacker_turn = True
self.create_game_screen()
self.initialize_attackers()
self.initialize_defenders() # AI防守方
self.start_attack_phase()
self.setup_player_controls()
def create_game_screen(self):
# 清除现有界面
for widget in self.root.winfo_children():
widget.destroy()
# 创建游戏界面
self.game_frame = tk.Frame(self.root, bg="#0f3460")
self.game_frame.pack(fill=tk.BOTH, expand=True)
# 创建游戏画布
self.canvas = tk.Canvas(self.game_frame, bg="#16213e", width=1024, height=668)
self.canvas.pack()
# 绘制银行地图
self.draw_bank_map()
# 创建状态面板
self.status_frame = tk.Frame(self.game_frame, bg="#0f3460", height=100)
self.status_frame.pack(fill=tk.X)
# 计时器
self.timer_label = tk.Label(self.status_frame, text="01:00", font=(self.font_family, 24), fg="white", bg="#0f3460")
self.timer_label.pack(side=tk.LEFT, padx=20)
# 玩家状态
self.player_status_label = tk.Label(self.status_frame, text="玩家状态", font=(self.font_family, 14), fg="white", bg="#0f3460")
self.player_status_label.pack(side=tk.LEFT, padx=20)
# 游戏状态
self.game_status_label = tk.Label(self.status_frame, text="游戏状态", font=(self.font_family, 14), fg="white", bg="#0f3460")
self.game_status_label.pack(side=tk.RIGHT, padx=20)
def draw_bank_map(self):
# 绘制银行外部轮廓
self.canvas.create_rectangle(100, 100, 924, 568, fill="#2c497f", outline="#e94560", width=2)
# 绘制金库区域
self.canvas.create_rectangle(self.bomb_site["x"] - self.bomb_site["radius"],
self.bomb_site["y"] - self.bomb_site["radius"],
self.bomb_site["x"] + self.bomb_site["radius"],
self.bomb_site["y"] + self.bomb_site["radius"],
fill="#4a5568", outline="#e94560", width=2)
self.canvas.create_text(self.bomb_site["x"], self.bomb_site["y"], text="金库",
font=(self.font_family, 12), fill="white")
# 绘制入口
self.canvas.create_rectangle(100, 284, 150, 384, fill="#16213e", outline="#e94560", width=2) # 左入口
self.canvas.create_rectangle(874, 284, 924, 384, fill="#16213e", outline="#e94560", width=2) # 右入口
# 绘制一些障碍物
obstacles = [
(200, 200, 300, 250), (400, 200, 500, 250), (600, 200, 700, 250),
(200, 400, 300, 450), (400, 400, 500, 450), (600, 400, 700, 450)
]
for obs in obstacles:
self.canvas.create_rectangle(obs[0], obs[1], obs[2], obs[3], fill="#1a1a2e", outline="#e94560")
def initialize_defenders(self):
# 清空现有防守方
self.defenders = []
# 创建玩家控制的防守方
if self.defender_turn:
player_defender = {"id": 0, "x": 512, "y": 384, "health": 100, "is_player": True, "role": "defender"}
self.defenders.append(player_defender)
# 绘制玩家
self.draw_unit(player_defender, "blue")
# 创建AI控制的防守方
for i in range(1, self.total_players):
ai_defender = {"id": i, "x": random.randint(200, 800), "y": random.randint(200, 500),
"health": 100, "is_player": False, "role": "defender"}
self.defenders.append(ai_defender)
# 绘制AI
self.draw_unit(ai_defender, "blue")
def initialize_attackers(self):
# 清空现有进攻方
self.attackers = []
# 创建玩家控制的进攻方
if self.attacker_turn:
player_attacker = {"id": 0, "x": 100, "y": 334, "health": 100, "is_player": True, "role": "attacker"}
self.attackers.append(player_attacker)
# 绘制玩家
self.draw_unit(player_attacker, "red")
# 创建AI控制的进攻方
for i in range(1, self.total_players):
# 随机选择左侧或右侧入口
if random.choice([True, False]):
x = 100
y = random.randint(284, 384)
else:
x = 924
y = random.randint(284, 384)
ai_attacker = {"id": i, "x": x, "y": y, "health": 100, "is_player": False, "role": "attacker"}
self.attackers.append(ai_attacker)
# 绘制AI
self.draw_unit(ai_attacker, "red")
def draw_unit(self, unit, color):
size = 15
if unit["is_player"]:
size = 20
# 绘制单位
unit["canvas_obj"] = self.canvas.create_oval(unit["x"] - size, unit["y"] - size,
unit["x"] + size, unit["y"] + size,
fill=color)
# 绘制单位ID
unit["canvas_text"] = self.canvas.create_text(unit["x"], unit["y"],
text=str(unit["id"]),
fill="white",
font=(self.font_family, 10))
def start_defense_prep_phase(self):
self.game_status_label.config(text="防守方准备阶段")
self.timer_label.config(text="{:02d}:{:02d}".format(self.defense_timer//60, self.defense_timer%60))
self.timer_running = True
# 启动计时器线程
timer_thread = threading.Thread(target=self.run_defense_timer)
timer_thread.daemon = True
timer_thread.start()
# 启动AI防守准备
if not self.defender_turn: # 如果玩家是进攻方,AI需要准备防守
self.run_ai_defense_prep()
def run_defense_timer(self):
while self.defense_timer > 0 and self.timer_running:
time.sleep(1)
self.defense_timer -= 1
self.root.after(0, lambda: self.timer_label.config(
text="{:02d}:{:02d}".format(self.defense_timer//60, self.defense_timer%60)))
# 更新AI防御布置
if not self.defender_turn:
self.root.after(0, self.update_ai_defense_prep)
if self.timer_running:
self.root.after(0, self.start_attack_phase)
def run_ai_defense_prep(self):
# AI防守准备逻辑
for defender in self.defenders:
if not defender["is_player"]:
# 在炸弹区域附近布置防御
if random.random() < 0.7:
# 放置摄像头
cam_x = self.bomb_site["x"] + random.randint(-100, 100)
cam_y = self.bomb_site["y"] + random.randint(-100, 100)
self.defense_objects.append({"type": "camera", "x": cam_x, "y": cam_y})
# 绘制摄像头
self.canvas.create_oval(cam_x - 5, cam_y - 5, cam_x + 5, cam_y + 5, fill="yellow")
# 放置陷阱
if random.random() < 0.5:
trap_x = self.bomb_site["x"] + random.randint(-80, 80)
trap_y = self.bomb_site["y"] + random.randint(-80, 80)
self.defense_objects.append({"type": "trap", "x": trap_x, "y": trap_y})
# 绘制陷阱
self.canvas.create_rectangle(trap_x - 5, trap_y - 5, trap_x + 5, trap_y + 5, fill="purple")
def update_ai_defense_prep(self):
# 继续更新AI防御布置
for defender in self.defenders:
if not defender["is_player"] and random.random() < 0.3:
# 随机移动到炸弹区域附近
target_x = self.bomb_site["x"] + random.randint(-100, 100)
target_y = self.bomb_site["y"] + random.randint(-100, 100)
# 移动AI
self.move_unit(defender, target_x, target_y)
def start_attack_phase(self):
self.timer_running = False
self.defense_timer = 60 # 重置防御计时器
# 开始攻击阶段
self.game_active = True
self.game_status_label.config(text="战斗阶段")
self.game_timer = 300 # 5分钟游戏时间
self.timer_label.config(text="{:02d}:{:02d}".format(self.game_timer//60, self.game_timer%60))
self.timer_running = True
# 启动游戏计时器线程
game_timer_thread = threading.Thread(target=self.run_game_timer)
game_timer_thread.daemon = True
game_timer_thread.start()
# 启动AI行动
if self.attacker_turn:
# 玩家是进攻方,AI控制防守方
self.start_ai_defense_actions()
else:
# 玩家是防守方,AI控制进攻方
self.start_ai_attack_actions()
def run_game_timer(self):
while self.game_timer > 0 and self.timer_running and not self.defender_wins and not self.attacker_wins:
time.sleep(1)
self.game_timer -= 1
self.root.after(0, lambda: self.timer_label.config(
text="{:02d}:{:02d}".format(self.game_timer//60, self.game_timer%60)))
# 更新AI行动
if self.attacker_turn:
self.root.after(0, self.update_ai_defense_actions)
else:
self.root.after(0, self.update_ai_attack_actions)
if self.timer_running and not self.defender_wins and not self.attacker_wins:
# 时间到,检查胜利条件
self.root.after(0, self.check_win_conditions)
def start_ai_defense_actions(self):
# 防守AI初始行动
pass
def update_ai_defense_actions(self):
# 更新防守AI行动
for defender in self.defenders:
if not defender["is_player"] and defender["health"] > 0:
# 检测进攻方
nearest_attacker = self.find_nearest_enemy(defender, self.attackers)
if nearest_attacker and self.distance(defender, nearest_attacker) < 200:
# 发现敌人,向敌人移动
target_x = nearest_attacker["x"] + random.randint(-20, 20)
target_y = nearest_attacker["y"] + random.randint(-20, 20)
self.move_unit(defender, target_x, target_y)
# 有几率射击
if random.random() < 0.3:
self.shoot_at(defender, nearest_attacker)
else:
# 没有发现敌人,巡逻或守卫炸弹点
if random.random() < 0.05:
# 随机巡逻
target_x = self.bomb_site["x"] + random.randint(-150, 150)
target_y = self.bomb_site["y"] + random.randint(-150, 150)
self.move_unit(defender, target_x, target_y)
else:
# 守卫当前位置
pass
def start_ai_attack_actions(self):
# 进攻AI初始行动
for attacker in self.attackers:
if not attacker["is_player"] and attacker["health"] > 0:
# 移动到炸弹区域
target_x = self.bomb_site["x"] + random.randint(-100, 100)
target_y = self.bomb_site["y"] + random.randint(-100, 100)
self.move_unit(attacker, target_x, target_y)
def update_ai_attack_actions(self):
# 更新进攻AI行动
for attacker in self.attackers:
if not attacker["is_player"] and attacker["health"] > 0:
# 检查是否可以安装拆弹器
if not self.bomb_planted and self.is_in_bomb_site(attacker) and random.random() < 0.01:
self.plant_defuser(attacker)
continue
# 检测防守方
nearest_defender = self.find_nearest_enemy(attacker, self.defenders)
if nearest_defender and self.distance(attacker, nearest_defender) < 200:
# 发现敌人,向敌人移动
target_x = nearest_defender["x"] + random.randint(-20, 20)
target_y = nearest_defender["y"] + random.randint(-20, 20)
self.move_unit(attacker, target_x, target_y)
# 有几率射击
if random.random() < 0.3:
self.shoot_at(attacker, nearest_defender)
else:
# 没有发现敌人,继续向炸弹点移动
if not self.is_in_bomb_site(attacker):
target_x = self.bomb_site["x"] + random.randint(-50, 50)
target_y = self.bomb_site["y"] + random.randint(-50, 50)
self.move_unit(attacker, target_x, target_y)
else:
# 已经在炸弹点,巡逻
target_x = attacker["x"] + random.randint(-30, 30)
target_y = attacker["y"] + random.randint(-30, 30)
self.move_unit(attacker, target_x, target_y)
def find_nearest_enemy(self, unit, enemies):
nearest = None
min_dist = float('inf')
for enemy in enemies:
if enemy["health"] > 0:
dist = self.distance(unit, enemy)
if dist < min_dist:
min_dist = dist
nearest = enemy
return nearest
def distance(self, unit1, unit2):
return math.sqrt((unit1["x"] - unit2["x"])**2 + (unit1["y"] - unit2["y"])**2)
def is_in_bomb_site(self, unit):
return (unit["x"] >= self.bomb_site["x"] - self.bomb_site["radius"] and
unit["x"] <= self.bomb_site["x"] + self.bomb_site["radius"] and
unit["y"] >= self.bomb_site["y"] - self.bomb_site["radius"] and
unit["y"] <= self.bomb_site["y"] + self.bomb_site["radius"])
def move_unit(self, unit, target_x, target_y):
# 简单移动逻辑
dx = target_x - unit["x"]
dy = target_y - unit["y"]
distance = math.sqrt(dx*dx + dy*dy)
if distance > 5: # 避免微小移动
# 移动速度
speed = 3
# 计算移动方向和距离
move_x = (dx / distance) * speed
move_y = (dy / distance) * speed
# 更新位置
unit["x"] += move_x
unit["y"] += move_y
# 更新画布上的位置
self.canvas.coords(unit["canvas_obj"],
unit["x"] - 15 if unit["is_player"] else unit["x"] - 10,
unit["y"] - 15 if unit["is_player"] else unit["y"] - 10,
unit["x"] + 15 if unit["is_player"] else unit["x"] + 10,
unit["y"] + 15 if unit["is_player"] else unit["y"] + 10)
self.canvas.coords(unit["canvas_text"], unit["x"], unit["y"])
def setup_player_controls(self):
# 绑定键盘事件
self.root.bind("<KeyPress>", self.on_key_press)
self.root.bind("<KeyRelease>", self.on_key_release)
# 启动玩家控制循环
self.update_player_position()
def on_key_press(self, event):
key = event.keysym.lower()
if key in self.key_pressed:
self.key_pressed[key] = True
elif key == "space":
self.player_shoot()
def on_key_release(self, event):
key = event.keysym.lower()
if key in self.key_pressed:
self.key_pressed[key] = False
def update_player_position(self):
if not self.game_active:
self.root.after(10, self.update_player_position)
return
# 获取玩家对象
player = None
if self.defender_turn:
player = next((d for d in self.defenders if d["is_player"]), None)
elif self.attacker_turn:
player = next((a for a in self.attackers if a["is_player"]), None)
if player and player["health"] > 0:
dx, dy = 0, 0
# 根据按键计算移动方向
if self.key_pressed["w"]:
dy -= self.player_speed
if self.key_pressed["s"]:
dy += self.player_speed
if self.key_pressed["a"]:
dx -= self.player_speed
if self.key_pressed["d"]:
dx += self.player_speed
# 边界检查
new_x = player["x"] + dx
new_y = player["y"] + dy
if new_x < 100:
new_x = 100
elif new_x > 924:
new_x = 924
if new_y < 100:
new_y = 100
elif new_y > 568:
new_y = 568
# 更新玩家位置
player["x"] = new_x
player["y"] = new_y
# 更新画布上的位置
self.canvas.coords(player["canvas_obj"],
player["x"] - 20, player["y"] - 20,
player["x"] + 20, player["y"] + 20)
self.canvas.coords(player["canvas_text"], player["x"], player["y"])
# 继续更新
self.root.after(10, self.update_player_position)
def player_shoot(self):
# 获取玩家对象
player = None
enemies = []
if self.defender_turn:
player = next((d for d in self.defenders if d["is_player"]), None)
enemies = self.attackers
elif self.attacker_turn:
player = next((a for a in self.attackers if a["is_player"]), None)
enemies = self.defenders
if player and player["health"] > 0:
# 寻找最近的敌人
nearest_enemy = self.find_nearest_enemy(player, enemies)
if nearest_enemy and self.distance(player, nearest_enemy) < 300:
# 玩家射击
self.shoot_at(player, nearest_enemy)
def shoot_at(self, shooter, target):
# 射击逻辑
hit_chance = 0.7 # 命中率
if random.random() < hit_chance:
# 命中
target["health"] -= 34 # 每次射击造成34点伤害
if target["health"] <= 0:
# 敌人被消灭
self.canvas.delete(target["canvas_obj"])
self.canvas.delete(target["canvas_text"])
# 检查胜利条件
self.check_win_conditions()
else:
# 显示伤害效果
self.show_damage(target)
def show_damage(self, unit):
# 创建伤害数字
damage_text = self.canvas.create_text(unit["x"], unit["y"] - 20,
text=str(34), fill="red",
font=(self.font_family, 12))
# 2秒后删除伤害数字
self.root.after(2000, lambda: self.canvas.delete(damage_text))
def plant_defuser(self, attacker):
if not self.bomb_planted:
self.bomb_planted = True
self.defuser = {"x": attacker["x"], "y": attacker["y"], "defuse_time": 30}
# 绘制拆弹器
self.defuser["canvas_obj"] = self.canvas.create_rectangle(
self.defuser["x"] - 10, self.defuser["y"] - 10,
self.defuser["x"] + 10, self.defuser["y"] + 10,
fill="orange")
# 更新游戏状态
self.game_status_label.config(text="拆弹器已放置!防守方需要阻止拆除")
# 启动拆弹计时器
defuse_thread = threading.Thread(target=self.run_defuse_timer)
defuse_thread.daemon = True
defuse_thread.start()
def run_defuse_timer(self):
while self.defuser["defuse_time"] > 0 and self.timer_running and not self.defender_wins:
time.sleep(1)
self.defuser["defuse_time"] -= 1
# 更新拆弹器显示 - 使用str.format()替代f-string
color_value = int(255 * (self.defuser["defuse_time"] / 30))
hex_color = "{:02x}0000".format(color_value)
self.root.after(0, lambda c=hex_color: self.canvas.itemconfig(
self.defuser["canvas_obj"], outline="#" + c))
# 检查是否有防守方在附近可以拆除
for defender in self.defenders:
if defender["health"] > 0 and self.distance(defender, self.defuser) < 30:
# 防守方在附近,可以拆除
self.root.after(0, self.defend_defuser)
return
if self.timer_running and not self.defender_wins:
# 拆弹成功
self.root.after(0, self.attacker_wins_game)
def defend_defuser(self):
# 防守方拆除拆弹器
self.bomb_planted = False
self.canvas.delete(self.defuser["canvas_obj"])
self.game_status_label.config(text="拆弹器已被防守方拆除!")
# 延迟后检查胜利条件
self.root.after(2000, self.check_win_conditions)
def check_win_conditions(self):
# 检查进攻方是否全灭
all_attackers_dead = all(attacker["health"] <= 0 for attacker in self.attackers)
# 检查防守方是否全灭
all_defenders_dead = all(defender["health"] <= 0 for defender in self.defenders)
# 检查炸弹是否被拆除
bomb_defused = self.bomb_planted and self.defuser["defuse_time"] <= 0
# 胜利条件判断
if all_attackers_dead and not self.bomb_planted:
self.defender_wins_game()
elif all_defenders_dead or bomb_defused:
self.attacker_wins_game()
elif self.game_timer <= 0 and not self.bomb_planted:
# 时间到,炸弹未放置,防守方胜利
self.defender_wins_game()
def defender_wins_game(self):
self.timer_running = False
self.defender_wins = True
self.game_status_label.config(text="防守方胜利!")
messagebox.showinfo("游戏结束", "防守方胜利!")
self.root.after(3000, self.create_start_screen)
def attacker_wins_game(self):
self.timer_running = False
self.attacker_wins = True
self.game_status_label.config(text="进攻方胜利!")
messagebox.showinfo("游戏结束", "进攻方胜利!")
self.root.after(3000, self.create_start_screen)
if __name__ == "__main__":
root = tk.Tk()
game = Game(root)
root.mainloop()