cnCalc计算器论坛

 找回密码
 注册
搜索
查看: 6439|回复: 9

[Nspire] TI-BASIC 计算器游戏开发之文字、图形、音频教程 II:图形处理

[复制链接]
发表于 2012-7-2 15:37:50 | 显示全部楼层 |阅读模式
TI-BASIC 计算器游戏开发之文字、图形、音频教程 II:图形处理

【第二部分】
TI-BASIC 图形处理教程
还没到结束的时候,我们查看一下内存,就会发现,一个8*8的汉字,用点阵数据保存,只需要 8 byte,但是用行列坐标数据保存,行坐标和列坐标都需要好多个 byte 来保存,这就是空间换时间的策略,不过这个行列坐标确实太占地方了,我们看看怎么把它再压缩一下,不妨继续粗暴一下,把这个已经显示到屏幕上的汉字截个图如何?反正就那几个点,这里要用到 TI-BASIC 的另一个函数 StoPic ,专门保存屏幕图形的,用法如下:

1 StoPic picName,raw,col,weith,heigth

意思就是把计算器屏幕上,先找到坐标为(raw,col)的点,从这个点出发,向右宽度为 weigth,向下高度为 heigth 的矩形区域内的图形保存到图形变量 picName 里,现在查看一下内存,看看这个 picName 只占了很少的几个 byte ,你就会觉得我们这么从点阵图到坐标值,再从坐标值到图形变量折腾来折腾去还是有所收获的。以后就可以通过直接调用这个图形变量来显示这个图形。

这样我们就可以把游戏中用到的汉字先转换为行列坐标列表数据,再转换为图形变量数据,就可以在程序中使用汉字了,这其实也是一种适合TI-89T下显示汉字的解决方案。

【局限性】只能在你自己的程序中显示汉字,没办法在TI自己的程序中显示汉字菜单,没怎么研究过汉化技术,理论上应该是可以的,因为程序菜单显示英文其实也是调用的英文字符的点阵图形,不过在TI计算器上搞估计比较麻烦,所以就不深入研究了。

简单说一下在屏幕上显示图形变量的函数,TI-BASIC提供了多个函数来通过调研内存中的图形变量来显示图形,有RlcPic,RplcPic,XorPic,AndPic,OrPic,这些函数的功能有细微的差别,具体可以查看TI-89T的手册,我们这里会用到RlcPic,RplcPic,XorPic这3种。
先说RplPic,用法如下:
1 RplPic picName,raw,col

上面的语句直接把计算器内存中保存为 picName 的图形绘制到左上角坐标为 (raw,col) 的区域内,那么右下角坐标就是 (raw + heigth , col + weigth),所以在用这条语句时一定要注意计算好位置,免得因为你的坐标值超过了屏幕范围而出错。

用这个函数可以把你指定的汉字图形显示在屏幕上的任何位置,等等,任何位置?那么如果用循环语句来让raw和col递增会如何呢?聪明,递增或者递减都会让汉字图形在屏幕上动起来,这个就是动态图形的基本原理,短时间内让指定图形不停地在不同的位置出现,那么我们用循环来试试,代码如下:

先来一个向右平行移动的

1 For i,1,30,1  
2  RplPic picName,raw,col+i  
3 EndFor

哈,是不是发现图形经过的位置都变成一道黑影了,为什么会这样呢?因为你只是把图形画到一个位置上,然后改变坐标值,再把它画到新的位置上,但是你没去管原来位置的图形,所以只需一会儿功夫你的屏幕就被画满了,怎么办?先把原来位置的图形擦掉,再画到新位置,然后再把新位置的图形擦掉,再画到下一个新位置,这样就可以实现清晰的动态图形效果了。
这里需要用到擦除图形的函数,TI-BASIC提供了两个类似的函数: PxlOff 和 XorPic ,一看就明白,PxlOff 是操作像素点的,XorPic 是操作图形变量的,我们现阶段需要的是 XorPic,XorPic 有个好处,就是第一次执行时是画图,第二次在同一个坐标执行时就是擦图了,也就是说原来的位置如果有图,就擦掉它,原来位置如果没有图就显示它,是不是不太好理解?没关系,实际执行几个例子就清楚了,具体用法如下:

1 XorPic picName,raw,col

那么上面的例程就改成这样:
向右平行移动,raw不变,只要把col的值循环增加就可以了

1 For i,1,80,1  
2  XorPic picName,raw,col+i  
3  XorPic picName,raw,col+i  
4 EndFor

向下平行移动,col不变,只要把raw的值循环增加就可以了

1 For i,1,80,1  
2  XorPic picName,raw+i,col  
3  XorPic picName,raw+i,col  
4 EndFor

向左平行移动是raw不变,把col循环减少:

1 For i,1,80,1  
2  XorPic picName,raw,col-i  
3  XorPic picName,raw,col-i  
4 EndFor

向上平行移动是col不变,把raw值循环减少。

1 For i,1,80,1  
2  XorPic picName,raw-i,col  
3  XorPic picName,raw-i,col  
4 EndFor

有人希望能斜着移动,这个问题提得好,斜着移动也有4个方向,只要同时改变raw和col的值就可以了,那么怎么写程序呢?有人想用两个循环,嘿嘿,那就错了,仔细想一下就明白为什么错了,实际只要这样就行:raw+i,col+i,不过这么移动太单调了,你可以给raw增加的i值乘以一个系数,比如0.5,结果就是这样 raw+0.5*i,col+i ,程序就是这样的;

1 For i,1,80,1  
2  XorPic picName,raw+0.5*i,col+i  
3  XorPic picName,raw+0.5*i,col+i  
4 EndFor

使用不同的系数就会以不同的角度斜方向移动。

又有人说了,你移动来移动去都是直线移动,能不能搞个曲线移动,比如迫击炮的炮弹就是抛物线的运动轨迹,地球绕太阳那是椭圆的移动轨迹,很好,我只能说你非常有思想,让我们一起来思考一下,先在 For 的框架内实现,搞个抛物线的运动轨迹,很显然,需要抛物线的方程了,比如用这个最简单的  y = x*x ,我们知道前面的循环主要是拿循环变量 i 作为坐标值的增量(假设为j),也就是说直接使用了i = j ,然后raw和col分别增加i和j,注意这里用的是“+”,也就是说变化后的坐标值跟原值是一种线性变化,而且没哟考虑raw和col之间的关系,那么我们现在要让图形沿着抛物线运动,需要在raw和col之间建立一种对应变化关系,应该满足抛物线方程,具体说就是:

raw = col*col

或者

col = raw*raw

记住这时就不能简单地把增量加到坐标值上去了,我们可以验证一下,程序如下:

1 raw = col*col  
2 For i,1,80,1  
3  XorPic picName,raw,col  
4  XorPic picName,raw,col  
5 EndFor

这里验证了 raw = col*col 的情况,还有  col = raw*raw 的情况,自己验证,不要偷懒啊!

嘿嘿,有人又提问了,上面提到的所有的移动都是保持图形点阵本身的行平行于屏幕,能不能让图形旋转着移动呢?很好,举一反三地提问我最喜欢了,我们先明确定义一下什么是图形的旋转移动,具体说就是点阵图形中的某一像素点的坐标不变,其他像素点以这个点为圆心,顺时针或者逆时针旋转同样的角度,注意这里作为圆心的像素点可以是有内容的,也可以是空白点,既然旋转问题的需求已经清晰地分析出来了,那么问题的解决方案也基本有了,像这种角度计算就不可避免地用到三角函数了,或者自己用距离比值来计算也可以。

一些高级语言会内置的这种旋转图形的操作函数,比如C语言,不过TI-BASIC貌似没提供这个功能,那么我们就自己写一个,经过上述分析,我们发现想要旋转图形,必须做到的就是计算每个像素点到圆点的距离,并提供一个旋转角度作为参数(包括顺时针和逆时针),然后每个点都以自己到圆心的距离作为半径,按照指定角度进行旋转。
好在需要画在屏幕上的是那些黑色点,空白点是不需要考虑得,因此可以节省一点计算量。当然了这个算法只是揭示这种图形变换的基本原理,具体实现时会有很多不同的选择,比如最常见的就是拿坐标数据跟不同类型的矩阵进行计算,来达到各种不同的变换效果,因为矩阵运算的算法不太直观,这里就不写了,感兴趣的拼音可以自行研究,我们的算法代码如下:
(实际还没写这段代码,后面补)

很好,现在对于这个图形的处理已经基本圆满了,什么?有人说我们搞了半天都是在二维平面上打转转,想做一个三维立体空间里的图形变换,太好了,看来我们的讨论又深入了,按照我们解决问题的一贯手段,先来分析三维空间的运动,首先是让我们的图形前进和后退,换句话说也就是放大和缩小,放大好办,比如8*8的图形,每个像素点扩充4倍,变成32*32,从一个“口”字型变为一个“田”字型,不光黑色点要扩充,白色点也要扩充,这样一个图形就变大了,看起来就好像是离它更近了,那么如果持续地做这种变化,带来的效果就是图形好像在朝我们走近一样。这种变化是三维空间变化的基础,其他方式的变换都可以在此基础上推导得出,再结合前面提到的各种平行移动、斜线移动、曲线轨迹移动以及三角函数旋转等方法,我们的图形想要实现各种三维空间里的移动就都不成问题了。

说到这里,想必有人也看出来了,计算机上所有的图形处理,说到底就是对图形坐标值的计算,只要预先设置好计算的方法,基本上就没什么神秘了,唯一限制的因素就是计算量的大小,因此程序员们想出了各种技巧来回避复杂计算,用简单计算来取代,以便提升效率。比如求三角函数时可以用查表法来代替计算,这种思想在人类历史上由来已久,在人类还没有发明电子计算机前,人类就把各种角度的三角函数值预先计算出来,然后印刷成书,等到使用时直接查表就可以获取到较为精确的数值,这样就避免了每次的计算。可见提升效率的思路是一致的,这种简化思路正是我前面提到过的“以空间换时间”,当然也可以逆过来用,以“时间换空间”。这里再给一个放大缩小的例子:

(实际还没写这段代码,后面补)

其他的各种三维空间的变换算法就不再一一列举了,自己钻研吧,最好能设计出高效的算法,写成函数,这样就能被其他人使用了,呵呵。

【更多的思考】另外还需要考虑鉴于这种计算的结果不完全是整数值,需要进行四舍五入后才能做为新坐标使用,如果有两个相邻点经过旋转计算的四舍五入之后重叠了该怎么办?(这就意味着图形被有损压缩了),下次再旋转时它们按照一个点来算还是按照两个点来算,如果按两个点来算,是否需要保存原来计算得到的四舍五入之前的数值?以便在下次计算时提供精确的输入,以避免这种因误差引起的信息损失。可见一种算法如果想要做得更完善,满足更多的意外场景,是没有止境的,

【提示】在软件开发的很多时候,如果我们能把一个功能需求清晰地描述出来,那就意味着这个功能需求的具体算法也出来了,或者当我们能够清晰描述出某些高难度的需求时,我们同时也会清楚这个需求是否能在现有系统上实现。是不是图形开始旋转了,很好,这就是图形旋转的数学原理,是不是觉得很简单?确实很多东西的基本原理都是非常简单的。还有无数的典型数学函数可以放到坐标增量来玩,比如什么对数函数、指数函数等等。

现在既然图形已经动起来了,我们稍微关注一下图形的动态效果,是不是发现移动得很慢,而且闪烁得很厉害,都快成了淡淡的灰影了,怎么办?简单,调整我们的参数,移动得慢是因为移动步子迈得小,把 For 语句最后一个参数 step 修改得大一些,图形就跑得快多了,图形太淡是因为画图和擦图的间隔太短,所以它在屏幕上就显示得太淡,唯一的办法就是画完图形之后不要马上擦,停留那么一小会儿,还以向右平行移动为例:

1 For i,1,80,1  
2  XorPic picName,raw,col+i  
3  Loop
4   u+1->u  
5  EndLoop  
6  XorPic picName,raw,col+i  
7 EndFor

这里我们在画图和擦图命令之间加了一个累加的循环,加到一定值之后停止循环,可以通过设置这个值的大小来控制中间的停顿时间。(也许还有其他更好的办法,期待有人给出)。

常用的图形操作就这些内容了,基本上掌握了这些就可以在TI-89T计算器上做出动画片头、动画效果来了,后面讲一下如何通过键盘来控制图形在屏幕上的运动。

评分

参与人数 3金钱 +8 收起 理由
Cyvre + 3 支持
936854586 + 3 没有8x系列,顶下吧
GWHBOB + 2 优秀文章

查看全部评分

 楼主| 发表于 2012-7-2 16:02:26 | 显示全部楼层
【小承诺】
改天有时间了,我会把对应的屏幕截图,动画效果什么的附件发上来,毕竟纯文字的东西看着太无趣了
发表于 2012-7-2 16:56:08 | 显示全部楼层
【小承诺】
改天有时间了,我会把对应的屏幕截图,动画效果什么的附件发上来,毕竟纯文字的东西看着太无趣了
FreeBlues 发表于 2012-7-2 16:02

承诺的背后是责任。
 楼主| 发表于 2012-7-2 18:14:02 | 显示全部楼层
承诺的背后是责任。
imath 发表于 2012-7-2 16:56


别吓唬我,只要我说到做到就行了
发表于 2012-7-2 19:01:09 | 显示全部楼层
用空间换时间不是不可以,前提是有足够的空间
不知道89的tibasic是否支持文件操作?
 楼主| 发表于 2012-7-2 20:09:49 | 显示全部楼层
用空间换时间不是不可以,前提是有足够的空间
不知道89的tibasic是否支持文件操作?
wtof1996 发表于 2012-7-2 19:01


选择空间还是时间反正就是开发者自己权衡了,TI-BASIC没有文件操作函数,不过文件无非是数据的集合,把文件转换成BASIC可以识别的变量数据就可以了,也可以用TI-BASIC调用C程序,把打开文件、读取文件、数据变量转换、关闭文件的操作用C来实现,然后用TI-BASIC调用就可以了。
发表于 2012-7-2 23:19:19 | 显示全部楼层
6# FreeBlues
那么配合flash mem空间大小还是相当可观的
这样看来,native 编程ti89 比9系有潜力的多
 楼主| 发表于 2012-7-3 11:28:37 | 显示全部楼层
7# wtof1996
其实结合TI-89的硬件规格来说,并不适合编写规模太大的程序,也不适合编写计算量太多的程序(16MHZ的CPU,用EEPRO做个数目很小的FFT变换感觉都有延迟),不过一般性的算法程序也不必搞得太大,这么一来也就不会要求太大的存储空间。
因此,我个人感觉TI-89的优势就是全面的编程语言支持、还算完善的掌上开发环境、比较稳定的系统,再加上便携性和低能耗,所以非常适合做一款编程学习机,所有有志于持续提升编程水平的人都可以用TI-89作为随身练习的工具。
我其实还有个想法,就是用GTC写一个C语言的学习教程,主要是用GTC演示C的基本语法功能,针对每个语法结构写一些短小的例程,循序渐进,后面可以搞一些经典算法,比如排序什么的,每个小程序都直接在计算器上编译、运行、显示结果,让人在这个过程中熟悉C的语法,这样肯定比单独看书要效果好,而且最关键是非常方便,随时可以练习。
发表于 2012-7-5 13:15:38 | 显示全部楼层
说几句:
1.3D显示的变换:近大远小是反比例函数,具体说
width'=width/distance;height'=height/distance;
就是距离增加到5倍大小就变小到5分之1.画个小孔成像图用相似三角形就能推出来
2.关于旋转、放缩时几个点挤一块或一个点被分到几个像素里去了:换种思路。
你一开始的思路是遍历原图片上的点,求出在屏幕上的对应坐标,涂上去。
逆转一下:遍历屏幕上的点,反求出在原图片的坐标,得到颜色,涂上去。这样屏幕上每个点就会且仅会被涂过一次。
 楼主| 发表于 2012-7-6 18:18:23 | 显示全部楼层
说几句:
1.3D显示的变换:近大远小是反比例函数,具体说
width'=width/distance;height'=height/distance;
就是距离增加到5倍大小就变小到5分之1.画个小孔成像图用相似三角形就能推出来
2.关于旋转、放缩时几个 ...
GWHBOB 发表于 2012-7-5 13:15


哈!多谢指教,我会在更新版本的教程里里把你提到的算法思路写进去,当然,作者列表也会增加GWHBOB
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|cnCalc计算器论坛

GMT+8, 2024-11-23 17:44 , Processed in 0.056768 second(s), 24 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表