```
`
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.obstacles = [
# 外墙
(50, 50, 974, 100), (50, 618, 974, 668),
(50, 50, 100, 618), (924, 50, 974, 618),
# 大厅柱子
(200, 200, 250, 250), (400, 200, 450, 250),
(600, 200, 650, 250), (800, 200, 850, 250),
(200, 400, 250, 450), (400, 400, 450, 450),
(600, 400, 650, 450), (800, 400, 850, 450),
# 金库外墙
(450, 300, 574, 350), (450, 424, 574, 474),
(450, 300, 500, 474), (524, 300, 574, 474),
# 金库内室
(475, 325, 550, 450),
# 内部墙壁
(300, 150, 350, 300), (650, 150, 700, 300),
(300, 400, 350, 550), (650, 400, 700, 550),
# 柜台
(350, 250, 674, 300),
# 可破坏障碍物
(150, 150, 200, 200, "breakable"),
(824, 150, 874, 200, "breakable"),
(150, 450, 200, 500, "breakable"),
(824, 450, 874, 500, "breakable"),
]
# 银行内部结构
self.bank_structure = {
"floors": 2, # 地面层和地下层
"elevators": [
{"x": 200, "y": 300, "width": 50, "height": 50},
{"x": 800, "y": 300, "width": 50, "height": 50}
],
"doors": [
{"x": 100, "y": 300, "width": 50, "height": 50, "state": "closed"},
{"x": 924, "y": 300, "width": 50, "height": 50, "state": "closed"},
{"x": 500, "y": 300, "width": 24, "height": 50, "state": "locked"} # 金库门
]
}
# 玩家控制变量
self.player_speed = 5
self.key_pressed = {"w": False, "a": False, "s": False, "d": False}
self.mouse_x = 512 # 鼠标X坐标
self.mouse_y = 384 # 鼠标Y坐标
self.player_direction = 0 # 玩家朝向角度
# 创建开始界面
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_realistic_bank()
# 创建状态面板
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_realistic_bank(self):
# 绘制银行外部轮廓
self.canvas.create_rectangle(50, 50, 974, 618, fill="#2c497f", outline="#e94560", width=2)
# 绘制玻璃幕墙
self.canvas.create_rectangle(100, 100, 924, 568, fill="#16213e", outline="#2c497f", width=5)
# 绘制大理石柱子
for x in [200, 400, 600, 800]:
for y in [200, 400]:
# 柱子底部
self.canvas.create_oval(x-20, y-20, x+20, y+20, fill="#d0d0d0", outline="#a0a0a0")
# 柱子主体
self.canvas.create_rectangle(x-15, y-20, x+15, y+100, fill="#e0e0e0", outline="#c0c0c0")
# 柱子顶部
self.canvas.create_oval(x-20, y+100, x+20, y+120, fill="#d0d0d0", outline="#a0a0a0")
# 绘制银行标志
self.canvas.create_text(512, 75, text="BANK OF RAINBOW", font=(self.font_family, 24, "bold"), fill="#e94560")
# 绘制金库区域
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="#1a1a2e", outline="#e94560", width=3)
# 绘制金库门
self.canvas.create_rectangle(500, 300, 524, 350, fill="#808080", outline="#404040", width=2)
self.canvas.create_text(512, 325, text="金库", font=(self.font_family, 12), fill="white")
# 绘制入口
self.canvas.create_rectangle(100, 284, 150, 334, fill="#16213e", outline="#e94560", width=2) # 左入口
self.canvas.create_rectangle(874, 284, 924, 334, fill="#16213e", outline="#e94560", width=2) # 右入口
# 绘制银行柜台
self.canvas.create_rectangle(350, 250, 674, 300, fill="#8b4513", outline="#a0522d", width=2)
self.canvas.create_rectangle(360, 260, 664, 290, fill="#a0522d", width=0)
# 绘制ATM机
self.canvas.create_rectangle(200, 150, 250, 200, fill="#808080", outline="#a0a0a0", width=2)
self.canvas.create_rectangle(800, 150, 850, 200, fill="#808080", outline="#a0a0a0", width=2)
# 绘制障碍物
for obs in self.obstacles:
if len(obs) == 5 and obs[4] == "breakable":
# 可破坏障碍物
self.canvas.create_rectangle(obs[0], obs[1], obs[2], obs[3], fill="#8b4513", outline="#a0522d")
self.canvas.create_rectangle(obs[0]+5, obs[1]+5, obs[2]-5, obs[3]-5, fill="#a0522d", width=0)
else:
# 普通障碍物
self.canvas.create_rectangle(obs[0], obs[1], obs[2], obs[3], fill="#1a1a2e", outline="#e94560")
self.canvas.create_rectangle(obs[0]+5, obs[1]+5, obs[2]-5, obs[3]-5, fill="#2d3748", width=0)
# 绘制灯光效果
self.draw_lighting_system()
def draw_lighting_system(self):
# 绘制天花板灯光
for x in range(150, 900, 150):
for y in range(150, 550, 150):
# 主光源
self.canvas.create_oval(x-10, y-10, x+10, y+10, fill="#f0e68c", outline="#fffacd", width=1)
# 光晕效果
self.canvas.create_oval(x-20, y-20, x+20, y+20, fill="#f0e68c", outline="", width=0, stipple="gray50")
# 绘制应急灯
self.canvas.create_oval(50, 300, 70, 320, fill="#ff0000", outline="#8b0000", width=1)
self.canvas.create_oval(954, 300, 974, 320, fill="#ff0000", outline="#8b0000", width=1)
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",
"ai": None, "state": "patrol", "path": [], "target": None, "cover_points": self.generate_cover_points()}
self.defenders.append(player_defender)
# 绘制玩家
self.draw_unit(player_defender, "blue")
# 创建AI控制的防守方
for i in range(1, self.total_players):
# 随机位置,确保不在障碍物内
while True:
x = random.randint(200, 800)
y = random.randint(200, 500)
if not self.is_in_obstacle(x, y):
break
ai_defender = {"id": i, "x": x, "y": y,
"health": 100, "is_player": False, "role": "defender",
"ai": AdvancedAI(self), "state": "patrol", "path": [],
"target": None, "cover_points": self.generate_cover_points(),
"difficulty": random.choice([1, 2, 3])} # 1=简单,2=中等,3=困难
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",
"ai": None, "state": "patrol", "path": [], "target": None, "cover_points": self.generate_cover_points()}
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",
"ai": AdvancedAI(self), "state": "patrol", "path": [],
"target": None, "cover_points": self.generate_cover_points(),
"difficulty": random.choice([1, 2, 3])} # 1=简单,2=中等,3=困难
self.attackers.append(ai_attacker)
# 绘制AI
self.draw_unit(ai_attacker, "red")
def generate_cover_points(self):
# 自动生成地图掩体点(障碍物边缘)
cover = []
for obs in self.obstacles:
if len(obs) >= 4: # 确保是有效的障碍物
cover.append((obs[0]-10, obs[1]-10)) # 左上
cover.append((obs[2]+10, obs[1]-10)) # 右上
cover.append((obs[0]-10, obs[3]+10)) # 左下
cover.append((obs[2]+10, obs[3]+10)) # 右下
return cover
def draw_unit(self, unit, color):
size = 10 # 统一单位大小
if unit["is_player"]:
size = 15 # 玩家略大
# 绘制单位
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))
# 绘制玩家朝向指示器
if unit["is_player"]:
unit["direction_line"] = self.canvas.create_line(
unit["x"], unit["y"],
unit["x"] + math.cos(0) * 20,
unit["y"] + math.sin(0) * 20,
fill="yellow", width=2)
# 绘制AI状态指示器
if not unit["is_player"]:
unit["state_indicator"] = self.canvas.create_text(
unit["x"], unit["y"] - 20,
text="P", # P=巡逻,A=攻击,D=防御,R=撤退
fill="white",
font=(self.font_family, 8)
)
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.8: # 提高布置概率
# 放置摄像头
cam_x = self.bomb_site["x"] + random.randint(-150, 150)
cam_y = self.bomb_site["y"] + random.randint(-150, 150)
if not self.is_in_obstacle(cam_x, cam_y):
self.defense_objects.append({"type": "camera", "x": cam_x, "y": cam_y, "health": 100})
# 绘制摄像头
cam_obj = self.canvas.create_oval(cam_x - 5, cam_y - 5, cam_x + 5, cam_y + 5, fill="yellow")
# 绘制摄像头视野
self.canvas.create_arc(cam_x - 50, cam_y - 50, cam_x + 50, cam_y + 50,
start=0, extent=120, fill="#32cd32", stipple="gray25")
# 放置陷阱
if random.random() < 0.8: # 提高布置概率
trap_x = self.bomb_site["x"] + random.randint(-100, 100)
trap_y = self.bomb_site["y"] + random.randint(-100, 100)
if not self.is_in_obstacle(trap_x, trap_y):
self.defense_objects.append({"type": "trap", "x": trap_x, "y": trap_y, "health": 100})
# 绘制陷阱
self.canvas.create_rectangle(trap_x - 5, trap_y - 5, trap_x + 5, trap_y + 5, fill="purple")
# 分配防守区域
self.assign_defense_positions()
def assign_defense_positions(self):
# 为防守方AI分配防守位置
defense_positions = [
(450, 300), (574, 300), # 金库上方
(450, 474), (574, 474), # 金库下方
(450, 384), (574, 384), # 金库两侧
(512, 250), (512, 518) # 金库前后
]
# 随机分配位置
random.shuffle(defense_positions)
for i, defender in enumerate(self.defenders):
if not defender["is_player"] and i < len(defense_positions):
pos = defense_positions[i]
defender["defense_position"] = pos
defender["path"] = self.astar((defender["x"], defender["y"]), pos)
def update_ai_defense_prep(self):
# 继续更新AI防御布置
for defender in self.defenders:
if not defender["is_player"]:
# 如果有防御位置,移动到指定位置
if "defense_position" in defender:
self.follow_path(defender)
elif random.random() < 0.5: # 提高行动概率
# 随机巡逻
target_x = self.bomb_site["x"] + random.randint(-150, 150)
target_y = self.bomb_site["y"] + random.randint(-150, 150)
# 生成路径
defender["path"] = self.astar((defender["x"], defender["y"]), (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:
# 更新状态指示器
self.canvas.itemconfig(defender["state_indicator"], text=defender["state"][0])
# 根据AI难度调整行为
difficulty_modifier = 1.0 + (defender["difficulty"] - 1) * 0.5
# 检测进攻方
nearest_attacker = self.find_nearest_enemy(defender, self.attackers)
if nearest_attacker and self.distance(defender, nearest_attacker) < 300 * difficulty_modifier:
# 发现敌人
if self.has_line_of_sight(defender, nearest_attacker):
# 有视线,进入攻击状态
defender["state"] = "attack"
defender["target"] = nearest_attacker
# 移动到有利位置
if random.random() < 0.7 * difficulty_modifier:
# 寻找掩体
cover = self.find_best_cover(defender, nearest_attacker)
if cover:
defender["path"] = self.astar((defender["x"], defender["y"]), cover)
# 计算朝向角度
angle = math.atan2(nearest_attacker["y"] - defender["y"], nearest_attacker["x"] - defender["x"])
# 根据难度调整命中率
hit_chance = 0.5 + (defender["difficulty"] - 1) * 0.15
# 射击
if random.random() < 0.6 * difficulty_modifier:
self.shoot_at(defender, nearest_attacker, angle, hit_chance)
else:
# 没有视线,进入搜索状态
defender["state"] = "search"
# 移动到最后看到敌人的位置
if defender["target"]:
last_seen = (defender["target"]["x"], defender["target"]["y"])
defender["path"] = self.astar((defender["x"], defender["y"]), last_seen)
else:
# 没有发现敌人
if defender["state"] == "attack" or defender["state"] == "search":
# 从战斗状态恢复,回到防守位置
defender["state"] = "return"
if "defense_position" in defender:
defender["path"] = self.astar((defender["x"], defender["y"]), defender["defense_position"])
elif defender["state"] == "return" and not defender["path"]:
# 已回到防守位置,进入巡逻状态
defender["state"] = "patrol"
# 巡逻或守卫
if defender["state"] == "patrol" and random.random() < 0.3 * difficulty_modifier:
# 随机巡逻
target_x = self.bomb_site["x"] + random.randint(-150, 150)
target_y = self.bomb_site["y"] + random.randint(-150, 150)
defender["path"] = self.astar((defender["x"], defender["y"]), (target_x, target_y))
# 跟随路径移动
self.follow_path(defender)
# 检查是否需要拆除拆弹器
if self.bomb_planted and self.distance(defender, self.defuser) < 30:
self.root.after(0, self.defend_defuser)
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)
attacker["path"] = self.astar((attacker["x"], attacker["y"]), (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:
# 更新状态指示器
self.canvas.itemconfig(attacker["state_indicator"], text=attacker["state"][0])
# 根据AI难度调整行为
difficulty_modifier = 1.0 + (attacker["difficulty"] - 1) * 0.5
# 检查是否可以安装拆弹器
if not self.bomb_planted and self.is_in_bomb_site(attacker) and random.random() < 0.05 * difficulty_modifier:
self.plant_defuser(attacker)
continue
# 检测防守方
nearest_defender = self.find_nearest_enemy(attacker, self.defenders)
if nearest_defender and self.distance(attacker, nearest_defender) < 300 * difficulty_modifier:
# 发现敌人
if self.has_line_of_sight(attacker, nearest_defender):
# 有视线,进入攻击状态
attacker["state"] = "attack"
attacker["target"] = nearest_defender
# 移动到有利位置
if random.random() < 0.7 * difficulty_modifier:
# 寻找掩体
cover = self.find_best_cover(attacker, nearest_defender)
if cover:
attacker["path"] = self.astar((attacker["x"], attacker["y"]), cover)
# 计算朝向角度
angle = math.atan2(nearest_defender["y"] - attacker["y"], nearest_defender["x"] - attacker["x"])
# 根据难度调整命中率
hit_chance = 0.5 + (attacker["difficulty"] - 1) * 0.15
# 射击
if random.random() < 0.6 * difficulty_modifier:
self.shoot_at(attacker, nearest_defender, angle, hit_chance)
else:
# 没有视线,进入搜索状态
attacker["state"] = "search"
# 移动到最后看到敌人的位置
if attacker["target"]:
last_seen = (attacker["target"]["x"], attacker["target"]["y"])
attacker["path"] = self.astar((attacker["x"], attacker["y"]), last_seen)
else:
# 没有发现敌人
if attacker["state"] == "attack" or attacker["state"] == "search":
# 从战斗状态恢复,继续前往炸弹点
attacker["state"] = "advance"
# 继续向炸弹点移动
if not self.is_in_bomb_site(attacker) or attacker["state"] == "advance":
target_x = self.bomb_site["x"] + random.randint(-50, 50)
target_y = self.bomb_site["y"] + random.randint(-50, 50)
attacker["path"] = self.astar((attacker["x"], attacker["y"]), (target_x, target_y))
else:
# 已经在炸弹点,巡逻或防守
attacker["state"] = "defend"
if random.random() < 0.3 * difficulty_modifier:
# 随机巡逻
target_x = self.bomb_site["x"] + random.randint(-30, 30)
target_y = self.bomb_site["y"] + random.randint(-30, 30)
attacker["path"] = self.astar((attacker["x"], attacker["y"]), (target_x, target_y))
# 跟随路径移动
self.follow_path(attacker)
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 is_in_obstacle(self, x, y):
# 检测点是否在障碍物内
for obs in self.obstacles:
if len(obs) >= 4: # 确保是有效的障碍物
if (x >= obs[0] and x <= obs[2] and
y >= obs[1] and y <= obs[3]):
return True
return False
def has_line_of_sight(self, unit, target):
# 射线检测障碍物
dx = target["x"] - unit["x"]
dy = target["y"] - unit["y"]
steps = max(abs(dx), abs(dy))
for i in range(steps):
x = unit["x"] + (dx/steps)*i
y = unit["y"] + (dy/steps)*i
if self.is_in_obstacle(x, y):
return False
return True
def find_best_cover(self, unit, enemy):
# 寻找最佳掩体位置
best_cover = None
best_score = -1
# 计算敌人方向
enemy_angle = math.atan2(enemy["y"] - unit["y"], enemy["x"] - unit["x"])
for cover in unit["cover_points"]:
# 计算掩体与敌人的距离
cover_to_enemy = math.sqrt((cover[0] - enemy["x"])**2 + (cover[1] - enemy["y"])**2)
# 计算掩体与当前位置的距离
cover_to_unit = math.sqrt((cover[0] - unit["x"])**2 + (cover[1] - unit["y"])**2)
# 计算掩体到敌人的角度
cover_angle = math.atan2(enemy["y"] - cover[1], enemy["x"] - cover[0])
# 计算角度差
angle_diff = abs(enemy_angle - cover_angle)
if angle_diff > math.pi:
angle_diff = 2 * math.pi - angle_diff
# 评分系统
score = 0
score += cover_to_enemy * 0.5 # 离敌人越远越好
score += (math.pi/2 - angle_diff) * 10 # 角度越接近90度越好
score -= cover_to_unit * 0.3 # 离自己越近越好
# 检查掩体是否有视线
if not self.has_line_of_sight({"x": cover[0], "y": cover[1]}, enemy):
score += 20 # 没有视线加分
if score > best_score:
best_score = score
best_cover = cover
return best_cover
def astar(self, start, end):
# A*寻路算法
open_set = {start}
closed_set = set()
came_from = {}
g_score = {start: 0}
f_score = {start: self.heuristic(start, end)}
while open_set:
current = min(open_set, key=lambda pos: f_score[pos])
if current == end:
return self.reconstruct_path(came_from, current)
open_set.remove(current)
closed_set.add(current)
for neighbor in self.get_neighbors(current):
if neighbor in closed_set:
continue
tentative_g_score = g_score[current] + 1
if neighbor not in open_set:
open_set.add(neighbor)
elif tentative_g_score >= g_score.get(neighbor, float('inf')):
continue
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score[neighbor] = g_score[neighbor] + self.heuristic(neighbor, end)
return [] # 没有找到路径
def heuristic(self, a, b):
# 曼哈顿距离启发式
return abs(a[0] - b[0]) + abs(a[1] - b[1])
def get_neighbors(self, pos):
# 获取相邻位置
x, y = pos
neighbors = [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
# 过滤掉障碍物中的位置
return [(nx, ny) for nx, ny in neighbors if not self.is_in_obstacle(nx, ny)]
def reconstruct_path(self, came_from, current):
# 重建路径
path = [current]
while current in came_from:
current = came_from[current]
path.append(current)
path.reverse()
return path
def follow_path(self, unit):
# 跟随路径移动
if unit["path"]:
next_pos = unit["path"][0]
# 计算移动方向
dx = next_pos[0] - unit["x"]
dy = next_pos[1] - unit["y"]
distance = math.sqrt(dx*dx + dy*dy)
if distance < 5:
# 到达路径点,移除它
unit["path"].pop(0)
else:
# 移动
speed = 3
move_x = (dx / distance) * speed
move_y = (dy / distance) * speed
# 检查是否会碰到障碍物
new_x = unit["x"] + move_x
new_y = unit["y"] + move_y
# 边界检查
if new_x < 50:
new_x = 50
elif new_x > 974:
new_x = 974
if new_y < 50:
new_y = 50
elif new_y > 618:
new_y = 618
# 障碍物碰撞检测
if not self.is_in_obstacle(new_x, new_y):
# 更新位置
unit["x"] = new_x
unit["y"] = new_y
# 更新画布上的位置
size = 10
if unit["is_player"]:
size = 15
self.canvas.coords(unit["canvas_obj"],
unit["x"] - size, unit["y"] - size,
unit["x"] + size, unit["y"] + size)
self.canvas.coords(unit["canvas_text"], unit["x"], unit["y"])
# 更新AI状态指示器
if not unit["is_player"]:
self.canvas.coords(unit["state_indicator"], unit["x"], unit["y"] - 20)
def setup_player_controls(self):
# 绑定键盘事件
self.root.bind("<KeyPress>", self.on_key_press)
self.root.bind("<KeyRelease>", self.on_key_release)
# 绑定鼠标事件
self.root.bind("<Motion>", self.on_mouse_move)
self.root.bind("<Button-1>", self.on_mouse_click)
# 启动玩家控制循环
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
def on_key_release(self, event):
key = event.keysym.lower()
if key in self.key_pressed:
self.key_pressed[key] = False
def on_mouse_move(self, event):
# 更新鼠标位置
self.mouse_x = event.x
self.mouse_y = event.y
# 更新玩家朝向
player = self.get_player()
if player and player["health"] > 0:
angle = math.atan2(self.mouse_y - player["y"], self.mouse_x - player["x"])
player["direction"] = angle
self.canvas.coords(player["direction_line"],
player["x"], player["y"],
player["x"] + math.cos(angle) * 20,
player["y"] + math.sin(angle) * 20)
def on_mouse_click(self, event):
# 玩家射击
player = self.get_player()
if player and player["health"] > 0:
# 计算射击方向
angle = math.atan2(event.y - player["y"], event.x - player["x"])
# 寻找该方向上的敌人
target = self.find_enemy_in_direction(player, angle)
if target:
self.shoot_at(player, target, angle, 0.7) # 玩家命中率70%
else:
# 检查是否射击到防御设施
for defense in self.defense_objects:
if defense["type"] != "camera" and defense["type"] != "trap":
continue
dist = math.sqrt((event.x - defense["x"])**2 + (event.y - defense["y"])**2)
if dist < 15: # 射击范围
defense["health"] -= 34
if defense["health"] <= 0:
# 移除防御设施
self.defense_objects.remove(defense)
def get_player(self):
if self.defender_turn:
return next((d for d in self.defenders if d["is_player"]), None)
elif self.attacker_turn:
return next((a for a in self.attackers if a["is_player"]), None)
return None
def find_enemy_in_direction(self, shooter, angle):
# 寻找射击方向上的敌人
max_distance = 300
nearest_enemy = None
min_distance = float('inf')
# 根据玩家阵营选择敌人列表
enemies = self.attackers if shooter["role"] == "defender" else self.defenders
for enemy in enemies:
if enemy["health"] > 0:
# 计算敌人与射击方向的角度差
enemy_angle = math.atan2(enemy["y"] - shooter["y"], enemy["x"] - shooter["x"])
angle_diff = abs(angle - enemy_angle)
# 考虑角度差的范围(例如±30度)
if angle_diff > math.pi:
angle_diff = 2 * math.pi - angle_diff
if angle_diff < math.radians(30): # ±30度范围内
dist = self.distance(shooter, enemy)
if dist < max_distance and dist < min_distance:
# 检查视线
if self.has_line_of_sight(shooter, enemy):
min_distance = dist
nearest_enemy = enemy
return nearest_enemy
def shoot_at(self, shooter, target, angle, hit_chance=0.7):
# 显示子弹轨迹
bullet = self.canvas.create_line(
shooter["x"], shooter["y"],
target["x"], target["y"],
fill="yellow", width=2
)
# 100ms后删除子弹
self.root.after(100, lambda: self.canvas.delete(bullet))
# 射击逻辑
if random.random() < hit_chance:
# 命中
damage = 34
target["health"] -= damage
# 显示伤害效果
self.show_damage(target, damage)
if target["health"] <= 0:
# 敌人被消灭
self.canvas.delete(target["canvas_obj"])
self.canvas.delete(target["canvas_text"])
if not target["is_player"]:
self.canvas.delete(target["state_indicator"])
# 检查胜利条件
self.check_win_conditions()
else:
# 受伤AI行为
if not target["is_player"]:
# 被击中后寻找掩体
if random.random() < 0.8: # 80%概率寻找掩体
shooter_pos = (shooter["x"], shooter["y"])
cover = self.find_best_cover(target, shooter)
if cover:
target["state"] = "retreat"
target["path"] = self.astar((target["x"], target["y"]), cover)
def show_damage(self, unit, damage):