20222201阎如玉 实验四实验报告

椰子fighting 2024-05-31 21:56:44

20222201 2023-2024-2 《Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2222
姓名: 阎如玉
学号:20222201
实验教师:王志强
实验日期:2024年5月25日
必修/选修: 公选课

1.实验内容

推箱子小游戏的实现。

2. 实验过程及结果

环境搭建

Python环境:pycharm软件
python库:pygame,numpy等

游戏设计与规划

定义游戏规则:玩家通过上下左右键控制角色移动,推动箱子到指定位置,完成所有箱子的放置即获胜。不能将箱子推到墙或另一个箱子无法到达的位置。
设计游戏元素:
地图:二维数组表示,0为空地,1为墙壁,2为目标点,3为箱子,4为带箱子的目标点。
玩家:可移动,能推动箱子。
箱子:可被玩家推动,遇墙停止。
确定游戏界面:考虑使用图形界面(如tkinter库)展示游戏状态。

编码实现

基础类定义:

Map类:负责地图的加载、显示和更新。
Player类:包含玩家位置、移动方法。
Box类:包含箱子位置、推动逻辑。

def createWidget(self):  # 创建并配置游戏界面
        if self.can:  # 若画布存在,则先销毁旧画布
            self.can.destroy()
        self.can = tk.Canvas(self.master, bg='LightYellow', width=1000, height=600)  # 新建画布
        self.lbl = tk.Label(self.can, text=f'关卡:{self.gq}     返回上一步:b', bg='LightYellow', fg='red', font=('', 17))
        self.lbl.place(x=5, y=5)  # 显示当前关卡标签
        map_shape = np.array(self.maps.maps_list[self.gq - 1]).shape  # 获取地图尺寸
        for r in range(map_shape[0]):  # 遍历地图,绘制地图元素
            for c in range(map_shape[1]):
                cell_type = self.maps.maps_list[self.gq - 1][r][c]
                if cell_type == 9:  # 跳过特殊标记(假设9为不需要绘制的元素)
                    continue
                elif cell_type == 34:  # 玩家在终点
                    self.can.create_image((c + 1) * 50, (r + 1) * 50, anchor='nw', image=self.list2[5])
                elif cell_type == 23:  # 箱子在非终点
                    self.can.create_image((c + 1) * 50, (r + 1) * 50, anchor='nw', image=self.list2[2])
                else:
                    img = self.list2[cell_type]
                    self.can.create_image((c + 1) * 50, (r + 1) * 50, anchor='nw', image=img)
        self.can.focus_set()  # 设置画布焦点,以便接收键盘事件
        self.can.bind("<Key>", self.move)  # 绑定键盘事件处理函数
        self.can.pack()  # 将画布添加至窗口

def get_person_position(self):  # 获取玩家当前位置
        for row_index, row in enumerate(self.maps.maps_list[self.gq - 1]):
            for col_index, cell in enumerate(row):
                if cell == 4:  # 找到玩家位置
                    self.px, self.py = row_index, col_index
                    return

游戏逻辑:

输入处理

监听键盘事件,根据玩家输入改变角色位置。
我这里为了游戏的舒适体验,还设置了回退功能,可以退回到上一步。

    def move(self, event):
        keysym = event.keysym
        print('你按了', keysym, '键')
        y = copy.deepcopy(self.maps.maps_list[self.gq - 1])
        self.old_list.append(y)
        if keysym == 'Right' or keysym == 'Down' or keysym == 'd' or keysym == 's':
            a_d = 1
        else:
            a_d = -1
                if keysym == 'Right' or keysym == 'Left' or keysym == 'd' or keysym == 'a':   #左右
            uy = self.py
            self.py += a_d
            ……
          # 向上或向下
        elif keysym == 'Down' or keysym == 'Up' or keysym == 'w' or keysym == 's':
            ux = self.px
            self.px += a_d
……
    def roll_back(self):   # 回退功能
        if len(self.old_list) == 0:
            return
        self.maps.maps_list[self.gq - 1] = self.old_list.pop()
        self.get_person_position()
        self.createWidget()

碰撞检测

检查玩家或箱子移动后是否碰到墙壁或其他障碍。以及对人物和箱子移动后位置的判断。

 # 人物移动后的位置是否是箱子处在终点上,是的话尝试移动箱子
            if self.maps.maps_list[self.gq - 1][self.px][self.py] == 23:
                # 箱子移动后的位置是否是墙,是的话就撤销
                if self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] == 1:
                    self.py = uy
                    self.old_list.pop()
                # 箱子移动后的位置是否有箱子处在终点上,是的话撤销
                elif self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] == 23:
                    self.py = uy
                    self.old_list.pop()
                # 箱子移动后的位置是否是终点,是的话移动
                elif self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] == 3:
                    self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] = 23
                    self.maps.maps_list[self.gq - 1][self.px][self.py] = 34
                    if self.maps.maps_list[self.gq - 1][self.px][uy] == 34:
                        self.maps.maps_list[self.gq - 1][self.px][uy] = 3
                    else:
                        self.maps.maps_list[self.gq - 1][self.px][uy] = 0
                # 箱子移动后的位置为空
                else:
                    self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] = 2
                    self.maps.maps_list[self.gq - 1][self.px][self.py] = 34
                    if self.maps.maps_list[self.gq - 1][self.px][uy] == 34:
                        self.maps.maps_list[self.gq - 1][self.px][uy] = 3
                    else:
                        self.maps.maps_list[self.gq - 1][self.px][uy] = 0
            # 人物移动后的位置是否为空,是的话移动
            elif self.maps.maps_list[self.gq - 1][self.px][self.py] == 0:
                self.maps.maps_list[self.gq - 1][self.px][self.py] = 4
                if self.maps.maps_list[self.gq - 1][self.px][uy] == 34:
                    self.maps.maps_list[self.gq - 1][self.px][uy] = 3
                else:
                    self.maps.maps_list[self.gq - 1][self.px][uy] = 0
            # 人物移动后的位置是否有箱子,有的话尝试移动箱子
            elif self.maps.maps_list[self.gq - 1][self.px][self.py] == 2:
                # 箱子移动后位置是否是墙,是的话撤销
                if self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] == 1:
                    self.py = uy
                    self.old_list.pop()
                # 箱子移动后位置是否是终点,是的话移动
                elif self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] == 3:
                    self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] = 23
                    self.maps.maps_list[self.gq - 1][self.px][self.py] = 4
                    self.maps.maps_list[self.gq - 1][self.px][uy] = 0

                elif self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] == 0:
                    self.maps.maps_list[self.gq - 1][self.px][self.py + a_d] = 2
                    self.maps.maps_list[self.gq - 1][self.px][self.py] = 4
                    if self.maps.maps_list[self.gq - 1][self.px][uy] == 34:
                        self.maps.maps_list[self.gq - 1][self.px][uy] = 3
                    else:
                        self.maps.maps_list[self.gq - 1][self.px][uy] = 0
                else:
                    self.py = uy
                    self.old_list.pop()
            elif self.maps.maps_list[self.gq - 1][self.px][self.py] == 1:
                self.py = uy
                self.old_list.pop()
            else:
                self.maps.maps_list[self.gq - 1][self.px][self.py] = 34
                if self.maps.maps_list[self.gq - 1][self.px][uy] == 34:
                    self.maps.maps_list[self.gq - 1][self.px][uy] = 3
                else:
                    self.maps.maps_list[self.gq - 1][self.px][uy] = 0

胜利条件检查

每一张地图都有设置目标点,判断所有箱子是否都位于目标点上,来判断是否过关。

 def is_win(self):  # 判断是否获胜
        for row in self.maps.maps_list[self.gq - 1]:  # 检查每行
            if 34 in row or 3 in row:  # 存在箱子未推到终点或玩家未站在终点
                return False
        return True

主循环

实现游戏的主循环,包括画面刷新、用户输入处理、游戏状态更新。

if __name__ == '__main__':
    root = tk.Tk()
    root.title('推箱子')
    # 初始化
    py.mixer.init()
    # 文件加载
    py.mixer.music.load(r'.\music\1.mp3')
    # 播放  第一个是播放值 -1 代表循环播放, 第二个参数代表开始播放的时间
    py.mixer.music.play(-1)
    wall = tk.PhotoImage(file='image/墙.png')
    person = tk.PhotoImage(file='image/人物.png')
    box = tk.PhotoImage(file='image/箱子.png')
    flag = tk.PhotoImage(file='image/可放位置.png')
    blank = tk.PhotoImage(file='image/空.png')
    person_flag = tk.PhotoImage(file='image/人物与旗帜.png')
    Window(root)
    root.mainloop()

游戏关卡地图

我用的是txt文档为关卡地图文件,用maps函数用来控制关卡地图的读取和建设。


class Maps(object):

    def __init__(self):
        with open('maps.txt', 'r', encoding='utf-8') as f:
            datas = f.readlines()
        self.maps_list = []
        for i in datas:
            i = json.loads(i)
            self.maps_list.append(i)

图形化界面所用的图片和音频

img

成果展示

3. 实验过程中遇到的问题和解决过程

  • 问题1:游戏的地图是我上网找的资源,在导入这个txt文件时遇到了困难,导入失败。
  • 问题1解决方案:上网寻找解决方法,我想试试自己不熟悉的模块导入,最后的这个关卡地图是用模块导入的方式写的。尝试模块导入时出现了很多问题,我通过网上的讲解编写了读取文档的python文件,这次就成功了。
  • 问题2:在设计任务推着箱子走的时候,有些地方没有考虑全面,运行出来出现穿模的情况
  • 问题2解决方案:仔细测试了代码,发现是在设置箱子被推到墙边的时候,只设置了箱子不动,没有设置人物的限制,导致人物可以走出去。

其他(感悟、思考等)

完成Python学习之旅后,我亲自动手开发了一款经典的推箱子小游戏,这一实践不仅让我深刻体会到了编程的乐趣与挑战,更赋予了我巨大的成就感。通过这个过程,我将所学知识转化为实际作品,亲眼见证了理论到实践的跨越,这种从无到有的创造过程异常宝贵。这次经历不仅是对自我能力的一次验证,也是对Python语言强大灵活性和易用性的再次肯定,它进一步激发了我对编程的热爱与探索欲。由此,我深切感受到,掌握Python这样强大的工具,能够让我们在实现创意与解决问题的道路上行得更远,成就感满满的同时,也更加坚定了我在编程领域持续探索和成长的决心。

课程感想

在这段宝贵的Python学习旅程中,我有幸遇到了一位极其出色的教师,他不仅拥有深厚的专业知识,更难能可贵的是,他对待学生亲切友善,营造了一个积极向上、鼓励探索的学习氛围。老师的教学方法独到而高效,他擅长将复杂的编程概念拆解成易于理解的小块,通过生动的实例、有趣的互动和适时的引导,让我们能够逐步消化吸收,将抽象的理论知识转化为实际操作技能。

课程设计巧妙,从Python的基础语法入门,到函数、模块的使用,再到面向对象编程等高级主题,每一步都循序渐进,既注重基础知识的巩固,又鼓励我们探索实践,解决实际问题。课堂上,老师经常采用项目驱动的方式,比如指导我们动手开发小程序,比如那个令人难忘的猜数字游戏,这些实践不仅加深了我们对知识的理解,更激发了学习的热情,让我们在实践中收获满满,成就感倍增。

此外,老师还非常注重培养我们的自学能力和批判性思维,鼓励我们在遇到难题时先独立思考,再小组讨论,最后才是求助于他,这样的教学策略极大地提升了我们的解决问题能力。在他的引领下,我不仅掌握了Python这门强大语言的精髓,更学会了如何高效学习,如何在编程的世界里持续探索和创新。

总之,这门Python课程不仅是一次知识的积累,更是一次思维的飞跃,老师的优秀与课程的精心设计使我受益匪浅,这段学习经历无疑为我的编程生涯奠定了坚实的基础,让我对未来充满了信心和期待。

...全文
178 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

110

社区成员

发帖
与我相关
我的任务
社区描述
人生苦短,我用Python!
python3.11 高校
社区管理员
  • blackwall0321
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧