作者:Nathan Ranney
翻译:highway★
译注:这是基础系列第一篇,超级基础,本来感觉不用翻译,不过后来想想里面有些跟动画控制相关的东西,还挺有用的,所以……还是翻了发上来吧,对刚接触GMS2的朋友应该会有些帮助。 btw 别在意题图 ,如果你用机翻一些教程,可能他们就会说,画雪碧。 嗯,那咱们下面就开始画雪碧了~
大家好,我是Nathan Ranney,我使用GameMaker大概6年了。当我刚开始做游戏时,我完全不懂编程和游戏开发。从GameMaker开始对我来说是一个非常好的选择,因为它有自己的编程语言GML,它比其他许多语言对新手来说友好多啦~ 到现在我已经制作了数十个原型和一些小型完成的游戏。blablabla
概述和设置
精灵可以是单个图像,也可以是组成动画的一堆图像。
下面我们仔细说说draw_sprite_ext(),还有它所用到的参数。
draw_sprite_ext()就是draw_sprite()的扩展版本,给我们提供更多的控制选项。见下表:
参数 | 描述 |
sprite | 要绘制的精灵的索引 |
frame | 您正在绘制的精灵的单个帧 |
x | 绘制精灵的位置的X坐标 |
y | 绘制精灵的位置的Y坐标 |
xscale | 精灵的水平缩放 |
yscale | 精灵的垂直缩放 |
rot | 精灵的角度/旋转 |
color | 颜色混合(默认c_white为正常显示) |
alpha | 精灵的alpha值,范围从透明(0)到不透明(1) |
在我们真正有效地使用此功能之前,需要进行一些设置。我们将这些参数定义为变量,并将其全部抛入脚本中,以便我们可以在任何对象上使用。
创建一个脚本,命名为animation_init:
//初始化绘制及动画会用到的变量 //绘制用 sprite = sprite_index; frame = 0; xPos = x; yPos = y; xScale = 1; yScale = 1; angle = 0; color = c_white; alpha = 1; //动画用 frameSpeed = 1; facing = 1;
通过将sprite变量设置为sprite_index,它将使用该对象设置的精灵图。现在,我们再创建一些我们稍后要用到的帮助脚本。创建一个名为approach的新脚本并加入下面的代码:
//approach(start, end, shift); if(argument0 < argument1) { return min(argument0 + argument2, argument1); } else { return max(argument0 - argument2, argument1); }
此脚本可以让你将start值加上shift值,直到达到最大end值(反之同理)。我会告诉你我们稍后可以做些什么。继续!创建另一个脚本并将其命名为player_buttons。添加以下代码:
(译注:这里只是教程用的,你的项目里如果有这些input相关的东西,那就没必要跟着做这些了,当然将input存储在变量中,对于新手来说,还是很重要的,不然移动相关的代码…好长啊…如果后面你添加了新功能,比如攻击、躲避、攀爬之类的,当阅读代码时候,你看到if keyboard_check_pressed(ord("J")) { blablablabla }时,你还要看看blablabla里写的东西,哦~ 这个J键是干这个用的。如果向下面这样做,就是个比较好的习惯了。如果是其他人(比如帮忙啊、临时或者正式加入你的开发)看到代码,那双方都会有点儿尴尬了~)
left = keyboard_check(vk_left); right = keyboard_check(vk_right); up = keyboard_check(vk_up); down = keyboard_check(vk_down);
我们在这里所做的就是将键盘输入存储到变量中,这些都是布尔值,意味着它们可以是true的也可以是false的。这使得以后更容易处理按钮按下。
现在我们已经准备好了animation_init脚本,我们已经准备好开始绘制了。现在你工程里要有一个动画精灵(sprite),这样我们才能绘制它……
- 这是我用的精灵图(如果你用这个的话,命名sprPlayer_Idle,原点设为16,32)
下面,创建一个对象(object),将sprPlayer_Idle设置为对象精灵图。添加create、step、end step、draw事件。
在create事件中,加入如下代码:
//调用动画初始化脚本
animation_init();
left = false;
right = false;
up = false;
down = false;
在draw事件中,这样写:
//draw sprite draw_sprite_ext(sprite,frame,xPos,yPos,xScale * facing,yScale,angle,color,alpha);
把oPlayer对象放在房间中。当你运行游戏时,你应该看到正在绘制sprPlayer_Idle精灵。可是,精灵动画没播放,它也不能移动。很无聊,下面我们来搞定这些问题。
动画
假设你的精灵有多个帧,我们需要为该精灵设置动画!由于我们手动绘制精灵,我们不能使用像image_speed这样的内置变量来控制动画(译注:当你的player逐渐变得有很多种能力时,也对应着他有很多很多的动画时,这种情况下我们还是使用自定义变量来控制动画会更灵活一些。)。但是我们已经使用frameSpeed定义了我们自己的image_speed。现在创建一个新脚本,将其命名为frame_counter,并添加以下行:
//逐帧增加帧数 frame += frameSpeed;
然后,创建另一个脚本并将其命名为frame_reset。添加以下行:
//如果它大于精灵中的总帧数,则重置帧 if(floor(frame) >= sprite_get_number(sprite)) { frame = 0; }
sprite_get_number()函数返回任何给定精灵中的总帧数。因此,如果我们的帧大于或等于该数字,则将帧重置为0。如果需要更改精灵的动画速度,你只需要更改frameSpeed的值。
现在我们把它们都用上,打开oPlayer,在step事件里加上这些:
//输入用 player_buttons(); //动画用 frame_counter();
在end step事件里加上这些:
//动画用 frame_reset();
运行游戏,你应该看到精灵图在动了!尝试调整frameSpeed值并找到适合你自己的精灵图。
左边的那个人以0.10的frameSpeed动画。他在右边的活跃的朋友是以1的frameSpeed动画。游戏设置为60fps运行。头顶上方的数字表示他们当前的动画帧。
缩放
让我们继续x和y缩放。我们将从向左和向右翻转精灵开始。这是我见过很多人使用image_xscale变量的东西,你并不一定想要这样做。image_xscale将翻转精灵,但它也会翻转精灵蒙版(mask),这可能会导致问题。我们使用draw_sprite_ext()的部分原因,就是我们想尽量避开所有这些可能导致问题的内置变量(译注:那些跟移动相关的也是坑~ 能自定义就自定义吧~)。在step事件中添加几行:
//角色朝向 if(left) { facing = -1; } else if(right) { facing = 1; }
运行游戏,如果一切都正确完成,你应该能够通过按下左右箭头键来翻转新动画精灵现在面向的方向。这是因为在Draw事件中,我们将xScale乘以了facing。关于这一点最好的部分是你的精灵蒙版(mask)在你的精灵被翻转时不会改变!现在,你还记得我们添加的方法脚本吗?使用它来让你的精灵挤压和拉伸是为你的动画添加一些生命力的好方法(译注:如果你对动画也感兴趣,可以去看看迪斯尼动画的12个基本原则,挤压和拉伸排名首位~ btw 至于官方为什么要叫迪士尼,可能遵循了翻译的大舌头原则吧,那个著名的史密斯先生此时打了个冷颤,至于他是不是在尿尿,我也不清楚 =_= )。在我们刚添加的内容下面添加以下行:
//改变缩放 if (keyboard_check_pressed(vk_space)) { xScale = 1.5; yScale = 1.5; } xScale = approach(xScale,1,0.03); yScale = approach(yScale,1,0.03);
运行你的游戏并按下空格键。你的精灵应该变大到1.5倍然后缩回到正常规模。调整精灵的x / y比例会对游戏的感觉产生巨大影响。尝试一下,找到一些对你感觉合适的值。创建一个squash_stretch脚本,我一直都在使用这个技巧(译注:可不要过分使用,也不要滥用 =_=)。代码如下:
//调整 x、y 缩放 xScale = argument0; yScale = argument1;
现在你可以把之前代码里的xScale和yScale那两行删掉了,加上squash_stretch(1.5, 1.5)。
角度和旋转
接下来是角度,基本上只是旋转。使用角度时,请务必使用0到360之间的值。我相信你可以弄清楚它是如何工作的。继续尝试使用向上和向下键调整角度。
//旋转 if (up) { angle -= 2; } else if (down) { angle += 2; }
颜色混合
下一个参数是颜色,具体来说,是指颜色混合。无论你在这里放置什么颜色(比如c_red)都会将你当前的精灵混合成那种颜色。我们现在将使用c_white,这意味着没有颜色混合,并且您的精灵显示为正常。
依次为c_white、c_red、c_lime
Alpha
draw_sprite_ext()中的最后一个参数!Alpha控制着精灵的透明度。它的范围从0(完全透明)到1(完全不透明)。尝试调整alpha变量,看看会发生什么。下面是使用A和S键来减少和增加alpha的代码:
//改变alpha
if(keyboard_check(ord("A")))
{
alpha = approach(alpha,0,0.05);
}else if(keyboard_check(ord("S")))
{
alpha = approach(alpha,1,0.05);
}
这是另一个使用approach的地方,它可以防止alpha值低于0或高于1。
一旦你掌握了draw_sprite_ext(),你就可以创造出许多非常有趣的效果。
(译注:比如你可以给角色绘制武器或者服装什么的,而无需创建对象,你可以把角色拆分成几层来绘制,这样就可以做到替换装备的效果,当然对应的工作量会比较大,对动画拆分来说,也相对复杂一些,尤其是当一些武器的持有状态会改变角色的部分动画的时候,如果你想看看比较极端的例子……建议你去找一下AM2R-银河战士2粉丝重制版的工程文件,去感受一下地狱级的角色拆分 =_=)
hmmmm……一直都用face变量控制xScale的人路过……确实总是会被mask跟随反转的问题搞得很头疼,终于有解决方案了,脑子真是转不过来啊orz
@顺子:我之前都没注意还有这个问题……
@highway★:直接带着mask一起翻转的话,如果精灵的像素+原点的位置不是刚好轴对称的话,那么在碰墙的时候转身就很容易把自己卡墙里去,所以之前我都要刻意去调整这个,现在看来自己画就没必要了
@顺子:这么一说,我好像知道我之前那个弹球卡墙的BUG的源头了…………
我想了解 gms 关于换装系统的思路和教程 能否整理一期呐?非常感谢
@zenzentai:hi~ https://ratcasket.itch.io/hitboxes-and-hurtboxes raycasket的这个工程里有部分替换武器的地方,思路差不多(不过由于武器特点,角色持有后的对应移动状态的sprite也做了对应处理,如果单纯是换装(只是指绘制方面,如果是对应提升角色属性方面的,这工程里就没有了),会简单一些)。你可以看看,有没有帮助~