用Racket做一个拼图游戏——1 前言、2 设计目标、3 设计思路

52 篇文章 16 订阅
2 篇文章 0 订阅

前言

Racket作为Lisp语言的一个分支,拥有强大的编程逻辑构建能力,其强大的宏构建能力更是让他成为了创建语言的语言。Racket在原Scheme简洁的基础上得到更广泛的发展,在系统编程、图形界面编程、网络编程等均有不俗的表现。

经常遇到一些朋友提问说能用Racket做什么?如何用Racket做桌面GUI应用程序?本文通过一个拼图游戏的构建,展示如何从0开始用Racket完成一个桌面GUI游戏程序,其间涵盖了Racket做桌面应用的主要功能,同时也可以作为Racket入门的读物。

文内会在每一部分析完成步骤和思路,也会详细解析各使用的函数的功能,力图使读者清晰地理解用Racket是如何完成每一步编程的,以从中感受Racket的魅力。

设计目标

本文实现一个基本的拼图游戏。游戏者能够通过调换小块图片位置来重新把打乱的图块恢复成一张完整的图片。用户可以自己更换图片,设定图块分隔复杂度等。

设计思路

拼图本质上就是将一张完整的图片通过行列分割成相同大小的小块,然后打乱重排,并将重排后的图像展示给用户,有用户重新恢复拼合的过程。

由此,我们把游戏分为两大部分,一部分是将图片分割打乱的过程,这部分工作在后台完成;另一部分是将打乱重排的图片展示给用户,由用户重新拼合的交互过程,这部分通过图形界面和用户交互完成。

在Racket中是可以直接通过在交互栏内显示结果的,这个结果可以使文本内容,也可以是图形内容,这就给调试有图形输出的程序提供了极大的便利。

有了这个便利,我们可以先把有关图片操作的相关函数全部先写出来,然后把这些函数进行按需组合,就能实现了我们需要的程序——这就是自底向上的程序设计。然后我们设计好GUI中的相应功能界面,把相应的功能一个个和GUI功能界面连接,就完成了整个游戏了——这就是自顶向下的程序设计。

好了,我们先来看看底层需求有哪些?

3.1 图片操作功能

具体每个功能对应哪个函数,后续程序设计部分可以看到,也可以对应源代码说明。

  • 取得源图片——从存储介质中读取图片;

  • 设置拼图图片尺寸——给定一个拼图图片大小的尺寸;

  • 调整图片大小——读取的图片不一定是需要的尺寸,需要根据需要进行调整;

  • 设置单元格行数列数——这个用来分割拼图图片,行列数越多拼起来越复杂;

  • 调换单元格——将分割的图片中的指定两个单元格调换,这是打乱拼图的基础,对所有单元格进行调换就实现了打乱单元格的功能;

  • 设置混合图片——将打乱混合的各个单元格图块组合成一张待拼图,这个用来展示给用户;

  • 重置混合图片——考虑到用户可能觉得显示出来的拼图不够乱,可以再来打乱一次;

  • 恢复混合图——考虑到用户拼到半途觉得没过瘾,需要再拼一次拼过的拼图,再给他一次机会;

  • 绘制混合图片——把混合拼图绘制出来;

  • 绘制目标图片——这个用来给用户一个完成的目标图片小样作为参照,可以提示或引导用户完成拼图操作;

  • 根据坐标位置转id——因为我们使用鼠标操作,这里把鼠标光标位置转换成单元格图片的标志号(ID号。具体为什么要用ID号,下边专门做解释);

  • 绘制空白单元格——把单元格图块移走了,还没有填充图片的状态,就留下空白单元格,这是为了交互动画而需要的,具体原因下边解释;

  • 在指定单元格位置绘制指定单元格内容——这个比较直白,就是在指定的单元格把指定的图块画上;

  • 在指定坐标位置绘制指定单元格——把一个单元格的图块移到了其他单元格放上,就得在那个位置上把新的图块画出来;

  • 绘制焦点单元格——如果鼠标移到某个单元格上,给出一个框做提示;

  • 绘制失焦单元格——如果鼠标移出某个单元格,清除焦点提示;

  • 取得当前单元格id——通过给定单元格行列号得到单元格ID号;

  • 指定的id有效——判断给出的ID号是否属于拼图图块列表中的,防止误给出ID号;

  • 根据拖动的坐标位置判断单元格id——当用鼠标按住一个单元格图块并拖动的时候,需要随时知道拖到哪个位置了,以便于后续的操作;

  • 判断是否成功完成拼图——完成拼图了吗?这个需要随时检查判断一下,很多时候拼没拼对用户是无法判断的,因为图块之间太相似了;

  • 初始化拼图数据——每个程序开始之前,难免要做些准备,这个就干这个的。

大致就是这些吧,如果有需要,后续还可以添加。

***解释两个问题,当然对于熟系的朋友来说并不一定需要。***

  • 一、为什么要对每个图块标记ID号?

    这涉及到数据结构问题。数据结构我们在下边做一个简略说明,这里不做叙述,单就ID号的作用做一个说明。

    必须的是,每个单元格图块都要唯一进行标记才能操作,这是没有疑问的。本来单元格图块直接用行号及列号就可以表示,也能够唯一标识,但是在用户拼图的时候,总会调来调去,位置一定会打乱的,这样我们就无法重新定位图块在原图上的位置(原图位置的一个用处是判断拼图是否完成),也不能定位刚打乱的时候的位置(为了恢复混合图,需要记住打乱时的位置),而且采用标志ID号也比较简单。

  • 二、交互动画是如何实现的?

    大家应该都清楚我们看的影视动画都是在固定时间里通过显示静态图片实现的(比如每秒钟显示24帧)。

    在我们程序的交互动画里边也可以是一帧一帧画面显示。比如鼠标每移动一次,画面刷新显示一次(根据鼠标移动情况随机发生)。可以这样来区分,于影视动画是固定时间变换帧动画,程序交互动画是随机变换帧动画。在交互动画中,很多时候我们实际只涉及图像里边的很小一块图像的变化,为了增加变换效率,减少每次变化计算机需要应对的数据量,可以把原交互图像作为背景,修改图像中变化的那一块图像,这样可提升交互操作的实时性。

3.2 界面功能设计

首先,肯定需要一个图片显示区域来显示拼图;

其次,需要一张缩略图给予用户提示完成的目标图像;

然后就是提供给用户的一些操作功能,暂时考虑功能(实现控件)有:选择图片(按钮)、混合拼图(按钮)、再来一次(按钮)、退出(按钮)、行数设置(文本框)、列数设置(文本框)、行列数选择等(下拉列表框)。

如上所述,我们可以将图形框架界面划分为以下4个区域:缩略图显示区、拼图显示区、操作功能区、信息显示区。如下:

从这个简单的框架图我们可以看出,所谓的软件界面,就是将图形框架视图通过合理的逻辑分块,将软件的各类功能展示给用户,以便用户能逻辑清楚地进行操作。最好的软件界面可以使用户不经过对软件的学习直接上手正确使用(这也是界面设计者追求的目标)。

Racket的界面是使用框架容纳软件界面元素,在框架内通过容器的嵌套分隔对界面组件进行逻辑分类并排列来实现界面的展示。具体怎么用代码来实现,后边安排专门一节来讲,敬请期待。

一些软件功能比较多,还会设计菜单栏、工具栏,以方便把更多的软件操作功能集成起来,以便用户使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值