成就中心 DouJin Terraria! 社区服务 统计排行 帮助
  • 7136阅读
  • 8回复

[制作范例]GameMaker实现扭曲激光

发帖
130
信仰
6
蓝点
114
符卡
0
扭曲激光最早出现自东方妖妖梦,在东方星莲船和文花帖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重新编辑 ]
附件: banana.rar (11 K) 下载次数:31
发帖
130
信仰
6
蓝点
114
符卡
0
只看该作者 沙发  发表于: 2011-01-25


天工殿搭建中~!
发帖
136
信仰
0
蓝点
23
符卡
0
只看该作者 板凳  发表于: 2011-01-25
噢噢噢!找这个找了好久,之前在小镇看到过讨论,但是貌似没有结论。

这个mark一下,算法抽空看。
发帖
661
信仰
0
蓝点
651
符卡
0
只看该作者 地板  发表于: 2011-01-25
嗯 扭曲激光现在不再是难题了。
发帖
133
信仰
0
蓝点
110
符卡
0
只看该作者 4楼 发表于: 2011-01-30
好东西~
发帖
14
信仰
0
蓝点
15
符卡
0
只看该作者 5楼 发表于: 2011-02-27
唔,有个感觉很菜的问题也很想问下,如何做成全方位发射扭曲光线呢?貌似这里的示例加入了发射坐标的说
发帖
661
信仰
0
蓝点
651
符卡
0
只看该作者 6楼 发表于: 2011-02-27
回 6楼(Lokya) 的帖子
全方位属于基本弹幕,找本版我的教学参考。把弹换成激光即可。
发帖
14
信仰
0
蓝点
15
符卡
0
只看该作者 7楼 发表于: 2011-02-27
回 7楼(franniss) 的帖子
全方位的具体原理已经弄清楚了,只是不知道把哪个object放在x,y之后来定义,看来还是要摸索下(<==GM初学+弹幕爱好者)

有时间咱发个演示(配自机)上来,请教这里的GM高手,多多指教哦
发帖
661
信仰
0
蓝点
651
符卡
0
只看该作者 8楼 发表于: 2011-02-27
嗯 欢迎发布试作品。
描述
快速回复

您目前还是游客,请 登录注册
如果您在写长篇帖子又不马上发表,建议存为草稿
认证码: