综述
这篇教程介绍了什么是特效以及如何创建它们
特效是建立在曲线集(线、三角形、矩形、)之上的,它们具有不同参数如:大小、旋度、位置、速度、颜色等。
特效在配置文件中设置,仅仅只需要一行代码就可以在对象上使用这些特效。
8条任意类型的曲线组合在一起就可以形成一个特效。
在同一时间,可以有多达4个特效应用于同一个对象上面。
特效可以使用绝对值或者相对值,这取决于配置文件中Absolute标签。
控制曲线的周期、相位、和大小都是允许的。
对于位置和速度特效,输出值可以使用对象的原始大小,这是为了可以更贴近对象当前的状态。这也就允许我们创造极其拉风的视觉特效。
除非特效已经缓存在内存中,否则特效参数全部在配置文件中进行调整,并且使用退格键来即时重载。
比如说:你不能调整正在运行的循环特效,因为他已经在默认的配置文件中定义好了。在这个测试程序运行的时候,所有其它的特效能够被更新。
通常说来,随机值的使用可以给特效带来更多的变化。
比如:摇摆的刻度(译者:实在不知如何翻译这个词组 the wobble scale),闪光色调还有那个攻击特效都是用了少量的随机值。
为了显示特效播放和停止,我们也需要注册特效事件。
因为特效是在一个标记为循环模式的盒对象上面,所以它不会停下来。因此,同步事件(orxFX_EVENT_STOP)将永远不会被发送出去。
我们也会简单的介绍一下如何一些个性数据到orxOBJECT(这里包换一个boolean值)中。
在事件的回调函数中,我们通过它,在特效开始的时候为对象加锁,在结束的时候解锁。
这个锁的作用就是在同一时刻,只有一个特效在使用。
详细内容
通常,我们先载入配置文件,创建一个时钟,然后注册更新函数,最后,创建我们的soldier(译者:不知翻译成哪个名字好)和盒对象。请在之前的教程中获取更多信息。
注册 输入和特效事件
orxEvent_AddHandler(orxEVENT_TYPE_FX, EventHandler);
orxEvent_AddHandler(orxEVENT_TYPE_INPUT, EventHandler);
大家可以看到,在这两个事件中,我们使用了同一个回调函数(EventHandler).
现在我们迅速的扫一眼自己的“对象”数据结构。
typedef struct MyObject
{
orxBOOL bLock;
} MyObject;
接下来,看看如何用orxObject_SetUserData()
将它绑定到soldier上
MyObject *pstMyObject;
pstMyObject = orxMemory_Allocate(sizeof(MyObject), orxMEMORY_TYPE_MAIN);
pstMyObject->bLock = orxFALSE;
orxObject_SetUserData(pstSoldier, pstMyObject);
现在看看如何在Update函数中使用特效
orxSTRING zSelectedFX;
if(orxInput_IsActive("SelectWobble"))
{
zSelectedFX = "WobbleFX";
}
else if(orxInput_IsActive("SelectCircle"))
{
zSelectedFX = "CircleFX";
}
[]
// Soldier not locked?
if(!((MyObject *)orxObject_GetUserData(pstSoldier))->bLock)
{
if(orxInput_IsActive("ApplyFX") && orxInput_HasNewStatus("ApplyFX"))
{
orxObject_AddFX(pstSoldier, zSelectedFX);
}
}
可以看到,我们通过orxObject_GetUserData()这个函数得到了我们想要的数据,向solder里添加特效的方法跟添加声音的方法如出一辙,用的都是这个函数orxObject_AddFX()。
接下来,看看EventHandler这个函数
首先是输入方面,这里只展示了每次输入时哪个按键被使用了。
if(_pstEvent->eType == orxEVENT_TYPE_INPUT)
{
if(_pstEvent->eID == orxINPUT_EVENT_ON)
{
orxINPUT_EVENT_PAYLOAD *pstPayload;
pstPayload = (orxINPUT_EVENT_PAYLOAD *)_pstEvent->pstPayload;
if(pstPayload->aeType[1] != orxINPUT_TYPE_NONE)
{
orxLOG("[%s] triggered by '%s' + '%s'.", pstPayload->zInputName, orxInput_GetBindingName(pstPayload->aeType[0], pstPayload->aeID[0]), orxInput_GetBindingName(pstPayload->aeType[1], pstPayload->aeID[1]));
}
else
{
orxLOG("[%s] triggered by '%s'.", pstPayload->zInputName, orxInput_GetBindingName(pstPayload->aeType[0], pstPayload->aeID[0]));
}
}
}
正如你所见,我们通过按下的是一个单键还是一个组合键来判断展示不同的信息。
我们仅使用了两个首次输入点,因为我们知道,我们的配置文件中没有超过两个的组合键。尽管orx支持最多四个组合键来做为一个单键。
orxInput_GetBindingName()
函数给了我们一个输入的文字显示。
注意:这些名称在配置文件中也绑定到了对应的按键上面。
现在来看下如何处理这个事件
if(_pstEvent->eType == orxEVENT_TYPE_FX)
{
orxFX_EVENT_PAYLOAD *pstPayload;
orxOBJECT *pstObject;
pstPayload = _pstEvent->pstPayload;
pstObject = orxOBJECT(_pstEvent->hRecipient);
switch(_pstEvent->eID)
{
case orxFX_EVENT_START:
orxLOG("FX <%s>@<%s> has started!", pstPayload->zFXName, orxObject_GetName(pstObject));
if(pstObject == pstSoldier)
{
// Locks it
((MyObject *)orxObject_GetUserData(pstObject))->bLock = orxTRUE;
}
break;
case orxSOUND_EVENT_STOP:
orxLOG("FX <%s>@<%s> has stoped!", pstPayload->zFXName, orxObject_GetName(pstObject));
if(pstObject == pstSoldier)
{
// Unlocks it
((MyObject *)orxObject_GetUserData(pstObject))->bLock = orxFALSE;
}
break;
}
}
在soldier上的动画开始的时候,我们用自己的数据结构来锁定它,相应的,停止的时候解锁。
看完了代码部分,我们再去看看配置文件。
首先看个简单的特效 :盒子上旋转的特效。
[RotateLoopFX]
SlotList = Rotate
Loop = true
[Rotate]
Type = rotation
StartTime = 0.0
EndTime = 2.0
Curve = sine
Pow = 2.0
StartValue = 0
EndValue = 360
[Box]
FXList = RotateLoopFX
看到了吧,特效是在它创建之初直接应用在盒对象上面的,而不是在代码中。
RotateLoopFX
包含仅包含一个时间段(Rotate)并且一直循环(attribute Loop)
然后定义Rotates时间段。时间的单位都是秒,角度的单位都是度。
定义这个旋转动画的时候,我们使用了一个正弦曲线,让他每两秒旋转360度。
下面看下我们的摇摆特效。
[WobbleFX]
SlotList = Wobble
[Wobble]
Type = scale
StartTime = 0.0
EndTime = 1.0
Period = 0.2
Curve = sine
Amplification = 0.0
StartValue = (1.0, 1.0, 1.0)
EndValue = (2.0, 2.0, 1.0) ~ (6.0, 6.0, 1.0)
我们修改了scale属性,并赋予它一个开始值和结束值。
他们都是用向量来表示的,如果不想使用任何异向值(译者注:专业名字anisotropic value去知道确切意思)的话,也可是使用float类型来表示。
虽然看起来我们正在使用一个isotropic值,这个结束值也不过是一个随机值。
它的X和Y部分可能是完全统统的随机值!
除此之外,我们使用了一个简单的周期为0.2秒的正弦曲线,它将会播放1秒钟。
看到了吧,我们将Amplification的值设为0,这就是说,随着时间的推进,曲线的振幅会逐渐变低。
注意:默认的振幅是1,当值大于1时,振幅就会加大;当值小于1时,振幅就会减少。
看看圆是如何运动的。
[CircleFX]
SlotList = CircleX#CircleY
KeepInCache = true
[CircleX]
Type = position
StartTime = 0.0
EndTime = 1.0
Curve = sine
StartValue = (0.0, 0.0, 0.0)
EndValue = (-50.0, 0.0, 0.0)
UseOrientation = true
UseScale = true
[CircleY@CircleX]
Phase = 0.25
StartValue = (0.0, -25.0, 0.0)
EndValue = (0.0, 25.0, 0.0)
我们使用两个时间段来控制它的位置,这样才能做出一个圆形的运动。第一个时间段是CircleX,他将会应用在对象的X轴向的振幅。第二个时间段CircleY,会产生一个同样幅度的作用效果在Y轴上。
如果我们不更改CircleY
的相位,是不会发生圆形的运动。
现在假设一个正弦曲线,在初始值是相位0,准备增加
在相位0。25的时候,到达中间点,将会继续增加
在相位0.5的时候,到达最高值,准备下降
在相位0.75的时候,回到中间点,继续下降
在相位1.0的时候,就跟相位0是一样的了
注意:这段描述正弦曲线的工作过程也同样适用于三角形,但是却不适用于线形。
我们将略过大多数其他的特效,因为那里没有什么我们不知道的新知识了。
但是我们还是要迅速的看一眼翻转的特效,他将会向我们展示如何翻转一个对象。
[FlipFX]
SlotList = Flip
[Flip@Wobble]
EndTime = 0.5
Period = 1.0
Amplification = 1.0
EndValue = (-1.0, 1.0, 1.0)
看到了吧,我们很简单的使用负值完成了这个效果。
同时也注意到,我们给周期设了一个明确的值。
我们选了一个两倍于定义的正弦曲线的周期,这样我们就只使用了正弦曲线的上升的那一半。同时,我们也将振幅改回了1
资源
源代码: 07_FX.c
配置文件: 07_FX.ini