扭曲激光最早出现自东方妖妖梦,在东方星莲船和文花帖DS中登场较多。其轨迹较为独特,给玩家留下了深刻的印象。
本帖便来探讨GameMaker下扭曲激光的一种实现方法。
扭曲激光便是一条可任意弯曲的激光,且激光的贴图基本保持连续。同时,它也有与视觉效果相符的判定范围。
同时扭曲激光也具有以下一些细节:
• 文花帖DS中出现的扭曲激光,有些可被部分消去,留下较短的一截继续运动
• 在SC 宝塔「闪亮宝枪」中,激光不是全部都有攻击判定,有些可以穿越过去
一种可行的做法是,扭曲激光由多个运动节点和一个描绘节点组成。各个运动节点前后跟随,构成了激光运动路径和轮廓;描绘节点则负责根据各个运动节点的位置,将整条激光画出来。碰撞检测也根据运动节点的位置进行计算。
如下图:
蓝点表示运动节点,箭头表示运动节点当前的运动方向。各个运动节点前后运动轨迹一致,互相跟随,形成了激光的骨骼。
而描绘节点则根据各个运动节点的位置、当前运动方向、下一个运动节点的位置,将激光的形状画出。
从图中可以看出,运动节点数量越多,激光便就越平滑,但同时更多的运动节点意味着更多的计算。
经过这样处理后,我们可以解决激光的运动与碰撞检测,描绘区域也做了大体划分,但此时描绘区域仍然不规整,要怎样才能将一整条激光的贴图部分分别放置到指定的位置,并保持连贯呢?
GameMaker中提供了高级绘图函数,能够完成这样的功能。
其原理便是将贴图拉伸/放缩至我们指定的区域。
首先,我们要了解GameMaker中对贴图纹理的处理。
贴图在gm里,其实是将他看做一个2的次方的纹理,纹理的左右分别在gm里使用0-1来表示,下面的图可以让你理解:
对于一条激光来说,他的纹理坐标自然是这样的:
然后,我们要了解高级绘图函数如何识别我们所指定的不规整的贴图区域
高级绘图函数是通过一系列点的坐标来确定贴图区域的。对于这些点,可以选择不同的方式进行识别。
而说到制作扭曲激光,个人认为比较好用的识别方式便是pr_trianglestrip
pr_trianglestrip将每连续的三个点识别为一个三角形。
比如说我们顺次定义了A,B,C,D,E,F六个点,则他会识别出4个三角形abc、bcd、cde、def,如下图。
举个栗子(糖炒的!),如果我们定义点A的实际坐标为(0,100),点A对应的贴图纹理坐标为(0,0)
定义点B的实际坐标为(0,150),点B对应的贴图纹理坐标为(0,1)
定义点C的实际坐标为(50,50),点C对应的贴图纹理坐标为(0.25,0)
那么原贴图纹理中(0,0) (0,1) (0.25,0)这个三角形的纹理部分便被扭曲并填入到了(0,100) (0,150) (50,50)这个三角形区域中。
具体到我们制作扭曲激光,则可以按照这种办法取点:
对每个运动节点,获取其运动方向,再取其运动方向的垂线,在垂线上 运动节点的两侧各取一个点。
如下图表示(图上垂线取得不够标准):
顺次定义A,B,C,D,E,F......
将各个点定义完毕后,便可以绘制出扭曲的激光了。
总结一下,这种绘制扭曲激光的大概步骤是:
1. 创造描绘节点。描绘节点负责根据各个运动节点的信息进行描绘,同时也负责对整条激光的管理。
2. 创造许多运动节点,这些运动节点具有相同的运动轨迹,前后跟随,形成激光的骨骼。同时,这些运动节点要和之前创造的描绘节点相关联(比如描绘节点中创建一个列表,列表内存有他管理的所有运动节点),使描绘节点可以获取运动节点的信息并进行描绘、管理。
运动节点越多,激光就越平滑。一般来说,保证每个运动节点的间隔为4像素便足够平滑了。
3. 每当要描绘的时候,描绘节点获得其管理的运动节点信息,对各个运动节点定义对应的点坐标。各个运动节点的纹理坐标不变,但实际运动坐标在不断的变化,所以每次描绘时都要重新定义。
4. 根据第3步定义的纹理坐标,描绘出扭曲激光。
描绘部分的相关代码如下:
//预处理,在初始化时写入
_tex=sprite_get_texture(S_Laser,0) // 获取激光的纹理
//以下写入描绘节点的draw事件中
//假设运动节点均存入在一个列表list内
var i,j,size;
size=ds_list_size(list)
if size<1{
instance_destroy();
exit;
}
//如果运动节点均已经销毁,则本条激光也销毁
draw_primitive_begin_texture ( pr_trianglestrip , _tex );
//开始使用高级绘图函数进行描绘,所使用的贴图纹理是刚才初始化的激光纹理_tex,使用pr_trianglestrip方式进行点的识别
//之后开始加入各个定义点
i=0;
var _x,_y;
while i<size{
j=ds_list_find_value(list,i); // 获取一个运动节点
_x=j.x+lengthdir_x(12,j.direction+90);
_y=j.y+lengthdir_y(12,j.direction+90);
//j.x j.y为运动节点的坐标,_x,_y为运动节点一侧的定义点坐标
draw_vertex_texture_color(_x,_y,i/(max(size,2)-1),0,c_white,1);
//定义点的坐标,前两个参数为实际坐标,之后两个参数为对应的纹理坐标,最后两个参数为混合颜色(一般为c_white)及透明度
//假设共有10个节点,,因i从0开始,至9结束,则第i个节点的两个定义点坐标应为(i/9,0)和(i/9,1)
//此处共有size个节点,因而对应纹理的x坐标为i/(size-1),考虑到size等于1时不能除以0,因而最后为i/(max(size,2)-1)
//不同结构此处的算法不同,但只要保证运动坐标们对应的最小纹理x坐标为0,最大为1即可
//再取另一侧的定义点坐标
_x=j.x+lengthdir_x(12,j.direction-90);
_y=j.y+lengthdir_y(12,j.direction-90);
draw_vertex_texture_color(_x,_y,i/(max(size,2)-1),0,c_white,1);
i+=1;
}
draw_primitive_end();
最后附上一个gmk范例,作者为53rdturtle。具体实现方式稍有不同,但本帖的思路与该范例相同。
本帖引用了tifaice所写教程中的部分图片及文字。关于GameMaker高级绘图功能的更多资料,可以参看此教程:
http://tieba.baidu.com/f?kz=855302720 关于扭曲激光的制作,小镇也有一篇值得参考的帖子:
http://bbs.thproject.org/read.php?tid=74050&fpage=5 [ 此帖被萃香西瓜在2011-02-04 11:01重新编辑 ]