项目名称:守卫家园游戏文档

简介

"守卫家园"是一个基于SimpleGUI库开发的简单游戏,玩家需要控制一个战士,消灭敌人并保护城堡不被攻击。游戏具有简单直观的操作和有趣的游戏性。

功能特点

  • 控制战士进行移动和射击
  • 定时产生敌人
  • 碰撞检测和计分系统
  • 背景音乐和音效
  • 游戏成功和失败判定

环境依赖

  • Python 2.7或以上版本
  • SimpleGUI库

安装步骤

  1. 安装Python和SimpleGUI库。
  2. 下载游戏代码文件或者直接复制示例代码。
  3. 运行代码文件即可启动游戏。

使用方法

  1. 使用鼠标点击来发射箭矢,按下键盘上的W、A、S、D键来控制战士移动。
  2. 消灭敌人并保护城堡,避免城堡被攻击。
  3. 当游戏结束时,根据得分显示游戏成功或失败的结果。

示例运行结果

在这里插入图片描述

示例代码

import simpleguitk as gui

import math
import random

# 全局变量
WIDTH = 800  # 画布宽度
HEIGHT = 600  # 画布高度
enemy_killed = 0  # 消灭敌人数量
castle_left = 4  # 画布完好数量
enemy_escaped = 0  # 逃脱敌人数量
escaped_limit = 10  # 运行逃脱敌人的数量上限
success_limit = 100  # 消灭敌人数量
game_over = False  # 守卫是否以失败结束
game_success = False  # 守卫是否以成功结束
soldier = None  # 战士对象
enemy_group = set([])  # 所有敌人对象的集合
castle_group = set([])  # 所有城堡对象的集合
arrow_group = set([])  # 所有箭对象的集合
explosion_group = set([])  # 所有爆炸对象的集合


# 图片信息类
class ImageInfo:
    def __init__(self, center, size, radius=0, lifespan=None, animated=False, frame=None):
        self.center = center
        self.size = size
        self.radius = radius
        if lifespan:
            self.lifespan = lifespan
        else:
            self.lifespan = float('inf')
        self.animated = animated
        self.frame = frame

    def get_center(self):
        return self.center

    def get_size(self):
        return self.size

    def get_radius(self):
        return self.radius

    def get_lifespan(self):
        return self.lifespan

    def get_animated(self):
        return self.animated

    def get_frame(self):
        return self.frame


# 加载图片资源
grassland_info = ImageInfo([960, 600], [1920, 1200])
grassland_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/grassland.jpg")  # 地面背景
arrow_info = ImageInfo([21, 5], [42, 10], 5, 60)
arrow_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/arrow.png")  # 箭
castle_info = ImageInfo([54, 52], [109, 105], 50)
castle_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/castle.png")  # 城堡
enemy_info = ImageInfo([32, 15], [64, 29], 15, 1000, True, 4)
enemy_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/enemy.png")  # 敌人,图像文件中包含4副图片用来实现动画
soldier_info = ImageInfo([32, 26], [64, 52])
soldier_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/soldier.png")  # 战士,图像文件中包含2副图片用来实现动画
win_info = ImageInfo([320, 240], [640, 480])
win_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/win.png")  # 游戏成功图片
game_over_info = ImageInfo([320, 240], [640, 480])
game_over_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/gameover.png")  # 游戏结束图片
explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True, 24)
explosion_image = gui.load_image(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/explosion.png")  # 爆炸,图像文件中包含多副图片用来实现动画

# 加载音效资源
back_sound = gui.load_sound(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/moonlight.wav")  # 背景音乐
shoot_sound = gui.load_sound(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/shoot.wav")  # 箭发射声音
explode_sound = gui.load_sound(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/explode.wav")  # 箭击中敌人的声音
enemy_sound = gui.load_sound(
    "http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/enemy.wav")  # 敌人击中城堡的声音


# 游戏初始化辅助函数
def init():
    global soldier, enemy_group, castle_group, arrow_group, enemy_killed, castle_left, explosion_group, game_over, enemy_escaped, game_success
    game_over = False
    game_success = False
    enemy_killed = 0
    castle_left = 4
    enemy_escaped = 0
    soldier = Soldier([castle_info.get_size()[0], HEIGHT / 2], [0, 0], 0, soldier_image, soldier_info)
    castle_group = set([])
    for i in range(4):
        castle = Sprite((castle_info.get_size()[0] / 2, HEIGHT / 8 + i * (HEIGHT / 4)), (0, 0), 0, castle_image,
                        castle_info)
        castle_group.add(castle)
    enemy_group = set([])
    arrow_group = set([])
    explosion_group = set([])
    back_sound.rewind()
    back_sound.set_volume(0.5)
    back_sound.play()


# 计算两点距离的辅助函数
def distance(p, q):
    return math.sqrt((p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2)


# 处理一组精灵的辅助函数
def process_sprite_group(sprites, canvas):
    set_sprites = set(sprites)
    for sprite in set_sprites:
        sprite.draw(canvas)
        if not game_over and not game_success:
            if not sprite.update():
                sprites.discard(sprite)


# 检查越过左边界敌人的辅助函数
def enemy_escape_check():
    global enemy_escaped
    set_enemy = set(enemy_group)
    for enemy in set_enemy:
        if enemy.get_pos()[0] < 0:
            enemy_escaped += 1
            enemy_group.discard(enemy)


#
# 检测一组对象和另一个对象是否发生碰撞的辅助函数
def group_collide(group, other_object):
    global explosion_group
    tmp_group = set(group)
    collided = False
    for sprite in tmp_group:
        if sprite.collide(other_object):
            explosion_pos = sprite.get_pos()
            a_explosion = Sprite(explosion_pos, [0, 0], 0, explosion_image, explosion_info, explode_sound)
            explosion_group.add(a_explosion)
            group.discard(sprite)
            collided = True
    return collided


# 检测两组对象是否发生碰撞的辅助函数
def group_group_collide(group1, group2):
    global explosion_group
    tmp_group1 = set(group1)
    i = 0
    for object in tmp_group1:
        if group_collide(group2, object):
            # explosion_pos = object.get_pos()
            # a_explosion = Sprite(explosion_pos, [0,0], 0, explosion_image,explosion_info, explode_sound)
            # explosion_group.add(a_explosion)
            group1.discard(object)
            i += 1
    return i


# 战士类
class Soldier:
    def __init__(self, pos, vel, angle, image, info):
        self.pos = [pos[0], pos[1]]
        self.vel = [vel[0], vel[1]]
        self.shooting = False
        self.angle = angle
        self.image = image
        self.image_center = info.get_center()
        self.image_size = info.get_size()

    def get_pos(self):
        return self.pos

    def shoot(self):
        global arrow_group
        arrow_pos = [self.pos[0] + self.image_size[0] * math.cos(self.angle),
                     self.pos[1] + self.image_size[0] * math.sin(self.angle)]
        arrow_vel = [0, 0]
        arrow_vel[0] = 10 * math.cos(self.angle)
        arrow_vel[1] = 10 * math.sin(self.angle)
        a_arrow = Sprite(arrow_pos, arrow_vel, self.angle, arrow_image, arrow_info, shoot_sound)
        arrow_group.add(a_arrow)

    def set_angle(self, angle):
        self.angle = angle

    def set_shooting(self, is_shooting):
        self.shooting = is_shooting

    def set_vel(self, new_vel):
        self.vel = new_vel

    def draw(self, canvas):
        source_center = [0, 0]
        if self.shooting:
            source_center = [self.image_center[0] + self.image_size[0], self.image_center[1]]
            self.shooting = False
        else:
            source_center = self.image_center
        canvas.draw_image(self.image, source_center, self.image_size, self.pos, self.image_size, self.angle)

    def update(self):
        self.pos[0] += self.vel[0]
        self.pos[0] = self.pos[0] % WIDTH
        self.pos[1] += self.vel[1]
        self.pos[1] = self.pos[1] % HEIGHT


# 精灵类
class Sprite:
    def __init__(self, pos, vel, ang, image, info, sound=None):
        self.pos = [pos[0], pos[1]]
        self.vel = [vel[0], vel[1]]
        self.angle = ang
        self.image = image
        self.image_center = info.get_center()
        self.image_size = info.get_size()
        self.radius = info.get_radius()
        self.lifespan = info.get_lifespan()
        self.animated = info.get_animated()
        self.frame = info.get_frame()
        self.age = 0
        if sound:
            sound.set_volume(0.05)
            sound.rewind()
            sound.play()

    def get_radius(self):
        return self.radius

    def get_pos(self):
        return self.pos

    def collide(self, other_object):
        if distance(self.pos, other_object.get_pos()) <= self.radius + other_object.get_radius():
            return True
        else:
            return False

    def draw(self, canvas):
        if self.animated and self.frame > 1:
            source_center = [self.image_center[0] + self.age % self.frame * self.image_size[0], self.image_center[1]]
            canvas.draw_image(self.image, source_center, self.image_size, self.pos, self.image_size, self.angle)
        else:
            canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle)

    def update(self):
        self.pos[0] += self.vel[0]
        self.pos[1] += self.vel[1]
        self.age += 1
        if self.age < self.lifespan:
            return True
        else:
            return False


# 主绘制函数
def draw(canvas):
    global enemy_killed, castle_left, game_over, enemy_escaped, game_success

    # 绘制背景
    canvas.draw_image(grassland_image, grassland_info.get_center(), grassland_info.get_size(), [WIDTH / 2, HEIGHT / 2],
                      [WIDTH, HEIGHT])
    soldier.draw(canvas)  # 绘制战士
    soldier.update()
    process_sprite_group(castle_group, canvas)  # 绘制城堡
    process_sprite_group(enemy_group, canvas)  # 绘制敌人
    process_sprite_group(arrow_group, canvas)  # 绘制箭
    process_sprite_group(explosion_group, canvas)  # 绘制爆炸
    enemy_escape_check()
    enemy_killed += group_group_collide(enemy_group, arrow_group)
    i = group_group_collide(enemy_group, castle_group)
    castle_left -= i
    enemy_escaped += i
    if castle_left == 0 or enemy_escaped >= escaped_limit:
        game_over = True
    if enemy_killed >= success_limit:
        game_success = True
    if game_over:
        canvas.draw_image(game_over_image, game_over_info.get_center(), game_over_info.get_size(),
                          [WIDTH / 2, HEIGHT / 2], [320, 240])
        back_sound.pause()
    if game_success:
        canvas.draw_image(win_image, win_info.get_center(), win_info.get_size(), [WIDTH / 2, HEIGHT / 2], [320, 240])
        back_sound.pause()


# 处理鼠标点击事件的函数
def mouse_handler(pos):
    global soldier
    if not game_over and not game_success:
        angle = math.atan2((pos[1] - soldier.get_pos()[1]), (pos[0] - soldier.get_pos()[0]))
        soldier.set_angle(angle)
        soldier.set_shooting(True)
        soldier.shoot()


# 处理键盘按下事件的函数
def key_down(key):
    global soldier
    if key == gui.KEY_MAP["w"]:  # 向上
        soldier.set_vel([0, -10])
    elif key == gui.KEY_MAP["a"]:  # 向左
        soldier.set_vel([-10, 0])
    elif key == gui.KEY_MAP["d"]:  # 向右
        soldier.set_vel([10, 0])
    elif key == gui.KEY_MAP["s"]:  # 向下
        soldier.set_vel([0, 10])


# 处理键盘释放事件
def key_up(key):
    global soldier
    soldier.set_vel([0, 0])


# 用来产生敌人的时间事件处理函数
def enemy_spawner():
    global enemy_group, enemy_killed, castle_left, enemy_escaped
    if not game_over and not game_success:
        random_pos = [WIDTH, abs(random.randrange(HEIGHT) - 80) + 40]
        random_vel = [-1.5 * (1.0 + random.random() * 0.8), 0]
        random_ang = 0
        a_enemy = Sprite(random_pos, random_vel, random_ang, enemy_image, enemy_info)
        enemy_group.add(a_enemy)
        label_killed.set_text("消灭敌人 = " + str(enemy_killed))
        label_escaped.set_text("逃脱敌人 = " + str(enemy_escaped))
        label_attacked.set_text("完好城堡 = " + str(castle_left))


# 创建窗口
frame = gui.create_frame("守卫家园", WIDTH, HEIGHT)
# 添加按钮
frame.add_button("重新开始", init, 100)

# 添加标签
label_killed = frame.add_label("消灭敌人 = 0")
label_escaped = frame.add_label("逃脱敌人 = 0")
label_attacked = frame.add_label("受到袭击 = 0")

# 注册事件处理函数
frame.set_mouseclick_handler(mouse_handler)
frame.set_keydown_handler(key_down)
frame.set_keyup_handler(key_up)
frame.set_draw_handler(draw)

# 创建定时器
timer = gui.create_timer(1000.0, enemy_spawner)

init()
timer.start()
frame.start()

注意事项

  • 如遇到问题,请确保已安装所需的环境依赖。
  • 可能需要调整屏幕分辨率以获得最佳游戏体验。

联系方式

如果您有任何问题或建议,请通过邮箱t18699741793@outlook.com联系博主或者私信。

三连:点赞、转发、订阅 🌟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

力江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值