Python3.8.10每日一练(丧尸生存游戏)

import tkinter as tk
import random
import math
import time
from tkinter import messagebox


class ZombieGame:
    def __init__(self, root):
        self.root = root
        self.root.title("丧尸生存游戏")
        self.root.geometry("800x600")
        self.root.resizable(False, False)
        self.root.bind("<KeyPress>", self.on_key_press)
        self.root.bind("<KeyRelease>", self.on_key_release)
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

        # 游戏画布
        self.canvas = tk.Canvas(self.root, width=800, height=600, bg="black")
        self.canvas.pack()

        # 游戏状态
        self.game_over = False
        self.paused = False
        self.score = 0
        self.level = 1
        self.lives = 3
        self.bullets = 30
        self.last_shot = 0
        self.shoot_cooldown = 300  # 射击冷却时间(毫秒)

        # 玩家属性
        self.player_size = 20
        self.player_x = 400
        self.player_y = 300
        self.player_speed = 5
        self.player_dx = 0
        self.player_dy = 0
        self.player_angle = 0

        # 键盘状态
        self.keys = {
            'w': False, 'a': False, 's': False, 'd': False,
            'up': False, 'down': False, 'left': False, 'right': False,
            'space': False
        }

        # 创建游戏对象
        self.player = self.canvas.create_oval(
            self.player_x - self.player_size,
            self.player_y - self.player_size,
            self.player_x + self.player_size,
            self.player_y + self.player_size,
            fill="blue"
        )

        # 玩家方向指示
        self.direction_line = self.canvas.create_line(
            self.player_x, self.player_y,
            self.player_x + self.player_size * math.cos(math.radians(self.player_angle)),
            self.player_y - self.player_size * math.sin(math.radians(self.player_angle)),
            fill="white", width=2
        )

        # 游戏元素
        self.zombies = []
        self.bullets_list = []
        self.obstacles = []
        self.power_ups = []

        # 生成障碍物
        self.generate_obstacles(10)

        # 显示游戏信息
        self.score_text = self.canvas.create_text(50, 20, text="分数: 0", fill="white", anchor="w")
        self.level_text = self.canvas.create_text(50, 40, text="等级: 1", fill="white", anchor="w")
        self.lives_text = self.canvas.create_text(50, 60, text="生命: 3", fill="white", anchor="w")
        self.bullets_text = self.canvas.create_text(50, 80, text="子弹: 30", fill="white", anchor="w")
        self.status_text = self.canvas.create_text(400, 300, text="", fill="red", font=("Arial", 24))

        # 开始游戏
        self.spawn_zombies(3)
        self.update()

    def generate_obstacles(self, count):
        for _ in range(count):
            x = random.randint(100, 700)
            y = random.randint(100, 500)
            size = random.randint(30, 60)

            # 确保障碍物不会生成在玩家附近
            if math.sqrt((x - self.player_x) ** 2 + (y - self.player_y) ** 2) > 100:
                obstacle = self.canvas.create_rectangle(
                    x - size, y - size, x + size, y + size,
                    fill="brown"
                )
                self.obstacles.append({
                    'id': obstacle,
                    'x': x,
                    'y': y,
                    'size': size
                })

    def spawn_zombies(self, count):
        for _ in range(count):
            # 在屏幕边缘生成丧尸
            if random.random() < 0.5:
                x = random.choice([-50, 850])
                y = random.randint(0, 600)
            else:
                x = random.randint(0, 800)
                y = random.choice([-50, 650])

            zombie_size = random.randint(15, 25)
            zombie_speed = random.uniform(1.0, 2.5 - self.level * 0.1)
            if zombie_speed < 1.0:
                zombie_speed = 1.0

            zombie = self.canvas.create_oval(
                x - zombie_size, y - zombie_size,
                x + zombie_size, y + zombie_size,
                fill="red"
            )

            self.zombies.append({
                'id': zombie,
                'x': x,
                'y': y,
                'size': zombie_size,
                'speed': zombie_speed,
                'health': 100
            })

    def update(self):
        if not self.game_over and not self.paused:
            # 更新玩家位置
            self.update_player_position()

            # 更新子弹位置
            self.update_bullets()

            # 更新丧尸位置
            self.update_zombies()

            # 检查碰撞
            self.check_collisions()

            # 生成补给
            if random.random() < 0.005:
                self.spawn_power_up()

            # 检查游戏状态
            if len(self.zombies) == 0:
                self.level_up()

            # 更新游戏信息
            self.canvas.itemconfig(self.score_text, text=f"分数: {self.score}")
            self.canvas.itemconfig(self.level_text, text=f"等级: {self.level}")
            self.canvas.itemconfig(self.lives_text, text=f"生命: {self.lives}")
            self.canvas.itemconfig(self.bullets_text, text=f"子弹: {self.bullets}")

            # 显示游戏状态
            if self.lives <= 0:
                self.game_over = True
                self.canvas.itemconfig(self.status_text, text="游戏结束!按R重新开始")

        elif self.game_over:
            self.canvas.itemconfig(self.status_text, text="游戏结束!按R重新开始")

        elif self.paused:
            self.canvas.itemconfig(self.status_text, text="游戏暂停!按P继续")

        # 继续更新
        self.root.after(16, self.update)

    def update_player_position(self):
        # 计算玩家移动方向
        dx = 0
        dy = 0

        if self.keys['w'] or self.keys['up']:
            dy -= self.player_speed
        if self.keys['s'] or self.keys['down']:
            dy += self.player_speed
        if self.keys['a'] or self.keys['left']:
            dx -= self.player_speed
        if self.keys['d'] or self.keys['right']:
            dx += self.player_speed

        # 归一化速度向量,防止对角线移动过快
        if dx != 0 or dy != 0:
            length = math.sqrt(dx ** 2 + dy ** 2)
            dx = dx / length * self.player_speed
            dy = dy / length * self.player_speed

            # 计算玩家角度
            self.player_angle = math.degrees(math.atan2(-dy, dx))

            # 更新玩家位置
            new_x = self.player_x + dx
            new_y = self.player_y + dy

            # 检查边界碰撞
            if new_x - self.player_size > 0 and new_x + self.player_size < 800:
                self.player_x = new_x
            if new_y - self.player_size > 0 and new_y + self.player_size < 600:
                self.player_y = new_y

            # 移动玩家图形
            self.canvas.coords(
                self.player,
                self.player_x - self.player_size,
                self.player_y - self.player_size,
                self.player_x + self.player_size,
                self.player_y + self.player_size
            )

            # 更新方向线
            self.canvas.coords(
                self.direction_line,
                self.player_x, self.player_y,
                self.player_x + self.player_size * math.cos(math.radians(self.player_angle)),
                self.player_y - self.player_size * math.sin(math.radians(self.player_angle))
            )

        # 处理射击
        current_time = time.time() * 1000
        if self.keys['space'] and current_time - self.last_shot > self.shoot_cooldown and self.bullets > 0:
            self.shoot()
            self.last_shot = current_time

    def shoot(self):
        # 减少子弹数量
        self.bullets -= 1

        # 创建子弹
        bullet_size = 5
        bullet_speed = 10

        # 子弹起始位置在玩家前方
        bullet_x = self.player_x + self.player_size * math.cos(math.radians(self.player_angle))
        bullet_y = self.player_y - self.player_size * math.sin(math.radians(self.player_angle))

        bullet = self.canvas.create_oval(
            bullet_x - bullet_size, bullet_y - bullet_size,
            bullet_x + bullet_size, bullet_y + bullet_size,
            fill="yellow"
        )

        self.bullets_list.append({
            'id': bullet,
            'x': bullet_x,
            'y': bullet_y,
            'size': bullet_size,
            'speed': bullet_speed,
            'angle': self.player_angle
        })

    def update_bullets(self):
        bullets_to_remove = []

        for bullet in self.bullets_list:
            # 计算新位置
            angle_radians = math.radians(bullet['angle'])
            bullet['x'] += bullet['speed'] * math.cos(angle_radians)
            bullet['y'] -= bullet['speed'] * math.sin(angle_radians)

            # 更新子弹图形
            self.canvas.coords(
                bullet['id'],
                bullet['x'] - bullet['size'],
                bullet['y'] - bullet['size'],
                bullet['x'] + bullet['size'],
                bullet['y'] + bullet['size']
            )

            # 检查是否超出边界
            if (bullet['x'] < 0 or bullet['x'] > 800 or
                    bullet['y'] < 0 or bullet['y'] > 600):
                bullets_to_remove.append(bullet)

            # 检查子弹与障碍物的碰撞
            for obstacle in self.obstacles:
                distance = math.sqrt(
                    (bullet['x'] - obstacle['x']) ** 2 +
                    (bullet['y'] - obstacle['y']) ** 2
                )
                if distance < bullet['size'] + obstacle['size']:
                    bullets_to_remove.append(bullet)
                    break

        # 移除需要删除的子弹
        for bullet in bullets_to_remove:
            self.canvas.delete(bullet['id'])
            if bullet in self.bullets_list:
                self.bullets_list.remove(bullet)

    def update_zombies(self):
        for zombie in self.zombies:
            # 计算丧尸朝向玩家的角度
            dx = self.player_x - zombie['x']
            dy = self.player_y - zombie['y']
            angle = math.degrees(math.atan2(-dy, dx))

            # 移动丧尸
            speed = zombie['speed']
            zombie['x'] += speed * math.cos(math.radians(angle))
            zombie['y'] -= speed * math.sin(math.radians(angle))

            # 更新丧尸图形
            self.canvas.coords(
                zombie['id'],
                zombie['x'] - zombie['size'],
                zombie['y'] - zombie['size'],
                zombie['x'] + zombie['size'],
                zombie['y'] + zombie['size']
            )

    def check_collisions(self):
        # 检查子弹与丧尸的碰撞
        bullets_to_remove = []
        zombies_to_remove = []

        for bullet in self.bullets_list:
            for zombie in self.zombies:
                distance = math.sqrt(
                    (bullet['x'] - zombie['x']) ** 2 +
                    (bullet['y'] - zombie['y']) ** 2
                )

                if distance < bullet['size'] + zombie['size']:
                    # 减少丧尸生命值
                    zombie['health'] -= 50

                    # 如果丧尸死亡,添加到移除列表
                    if zombie['health'] <= 0:
                        zombies_to_remove.append(zombie)
                        self.score += 10

                    # 添加子弹到移除列表
                    bullets_to_remove.append(bullet)
                    break

        # 移除死亡的丧尸和子弹
        for zombie in zombies_to_remove:
            self.canvas.delete(zombie['id'])
            if zombie in self.zombies:
                self.zombies.remove(zombie)

        for bullet in bullets_to_remove:
            self.canvas.delete(bullet['id'])
            if bullet in self.bullets_list:
                self.bullets_list.remove(bullet)

        # 检查玩家与丧尸的碰撞
        for zombie in self.zombies:
            distance = math.sqrt(
                (self.player_x - zombie['x']) ** 2 +
                (self.player_y - zombie['y']) ** 2
            )

            if distance < self.player_size + zombie['size']:
                # 玩家受伤
                self.lives -= 1
                zombies_to_remove.append(zombie)

                # 显示受伤效果
                self.canvas.itemconfig(self.player, fill="red")
                self.root.after(200, lambda: self.canvas.itemconfig(self.player, fill="blue"))

                # 检查游戏是否结束
                if self.lives <= 0:
                    self.game_over = True

        # 移除与玩家碰撞的丧尸
        for zombie in zombies_to_remove:
            if zombie in self.zombies:
                self.canvas.delete(zombie['id'])
                self.zombies.remove(zombie)

        # 检查玩家与补给的碰撞
        power_ups_to_remove = []
        for power_up in self.power_ups:
            distance = math.sqrt(
                (self.player_x - power_up['x']) ** 2 +
                (self.player_y - power_up['y']) ** 2
            )

            if distance < self.player_size + power_up['size']:
                # 应用补给效果
                if power_up['type'] == 'health':
                    self.lives = min(3, self.lives + 1)
                elif power_up['type'] == 'ammo':
                    self.bullets += 15

                power_ups_to_remove.append(power_up)

        # 移除被收集的补给
        for power_up in power_ups_to_remove:
            self.canvas.delete(power_up['id'])
            if power_up in self.power_ups:
                self.power_ups.remove(power_up)

    def spawn_power_up(self):
        # 确保补给不会生成在玩家附近
        x = random.randint(100, 700)
        y = random.randint(100, 500)

        if math.sqrt((x - self.player_x) ** 2 + (y - self.player_y) ** 2) > 100:
            power_up_type = random.choice(['health', 'ammo'])
            size = 15

            if power_up_type == 'health':
                color = 'green'
            else:  # ammo
                color = 'yellow'

            power_up = self.canvas.create_oval(
                x - size, y - size, x + size, y + size,
                fill=color
            )

            self.power_ups.append({
                'id': power_up,
                'x': x,
                'y': y,
                'size': size,
                'type': power_up_type
            })

    def level_up(self):
        self.level += 1
        self.spawn_zombies(self.level * 2)
        self.bullets += 10  # 每升一级增加子弹

    def on_key_press(self, event):
        key = event.keysym.lower()
        if key in self.keys:
            self.keys[key] = True
        elif key == 'r' and self.game_over:
            self.restart_game()
        elif key == 'p':
            self.paused = not self.paused

    def on_key_release(self, event):
        key = event.keysym.lower()
        if key in self.keys:
            self.keys[key] = False

    def restart_game(self):
        # 清除所有游戏对象
        for zombie in self.zombies:
            self.canvas.delete(zombie['id'])
        for bullet in self.bullets_list:
            self.canvas.delete(bullet['id'])
        for obstacle in self.obstacles:
            self.canvas.delete(obstacle['id'])
        for power_up in self.power_ups:
            self.canvas.delete(power_up['id'])

        # 重置游戏状态
        self.game_over = False
        self.score = 0
        self.level = 1
        self.lives = 3
        self.bullets = 30

        # 重置玩家位置
        self.player_x = 400
        self.player_y = 300

        # 更新玩家图形
        self.canvas.coords(
            self.player,
            self.player_x - self.player_size,
            self.player_y - self.player_size,
            self.player_x + self.player_size,
            self.player_y + self.player_size
        )

        # 更新方向线
        self.canvas.coords(
            self.direction_line,
            self.player_x, self.player_y,
            self.player_x + self.player_size * math.cos(math.radians(self.player_angle)),
            self.player_y - self.player_size * math.sin(math.radians(self.player_angle))
        )

        # 重新生成障碍物
        self.obstacles = []
        self.generate_obstacles(10)

        # 生成初始丧尸
        self.zombies = []
        self.spawn_zombies(3)

        # 清空子弹和补给
        self.bullets_list = []
        self.power_ups = []

        # 更新游戏信息
        self.canvas.itemconfig(self.score_text, text=f"分数: {self.score}")
        self.canvas.itemconfig(self.level_text, text=f"等级: {self.level}")
        self.canvas.itemconfig(self.lives_text, text=f"生命: {self.lives}")
        self.canvas.itemconfig(self.bullets_text, text=f"子弹: {self.bullets}")
        self.canvas.itemconfig(self.status_text, text="")

    def on_closing(self):
        if messagebox.askokcancel("退出", "确定要退出游戏吗?"):
            self.root.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    game = ZombieGame(root)
    root.mainloop()

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容