找回密码
 立即注册
查看: 698|回复: 0

游戏开发工具箱(1) 打造游戏感的利器——Unity Feel 插件浅析

[复制链接]
发表于 2023-2-2 07:06 | 显示全部楼层 |阅读模式
前言

你是不是曾在GameJam最后的1个小时里,还在为游戏的手感不佳、打击感不强而抓耳挠腮?
你是不是也曾在开发游戏Demo时,苦于要解决玩家反馈的“操作好飘”、“反应太迟钝”等问题却没有头绪?
那么,这款Unity商店中能够【帮你快速实现各种交互和反馈效果】的Feel插件,将是你的不二之选。


简要介绍

Feel是什么?

Feel是一款开箱即用的为游戏提供游戏感(反馈)的Unity平台下的工具插件。
模块化的设计,易于扩展;编辑器下的预览,十足便捷。
在《游戏感——游戏操控感和体验设计指南》一书中,Steve Swink将游戏感拆解为了——实时操控(real-time control)、模拟空间(simulated space)和润色(polish)——三个基本要素,在本文中提及Feel插件相关的游戏感,主要在润色层面
游戏感是一个比较有深度的话题,感兴趣的读者可以在文末的扩展阅读中,了解更多如何在设计层面上为游戏注入游戏感的内容。
Feel解决了什么痛点?

游戏感是为玩家打开游戏魔法门的钥匙。
当玩家在游戏中有所行动时,合理的反馈,比如一个受击时刻的镜头晃动、一个物体起跳前的弹性缩放都令人更加沉浸其中。


虽然在讨论游戏感时,感受是主观的,但Feel将其拆解成了100+个基本的反馈操作(MMF_Feedback),主要覆盖了 音频、镜头、动画、GameObject、特效、后处理、UI、文字等方面。所有的反馈操作可以在文末的扩展阅读中查看。
像拼积木一样组合好这些反馈操作,游戏感便跃然纸上了。
核心概念

反馈器(MMF_Feedback)

MMF_Feedback是所有反馈行为的基类,处理了反馈效果的基于时间的状态管理(播放、暂停、恢复、停止等)。
不同反馈器的参数大相径庭,以一个旋转(Rotation)操作为例,我们看下它的参数配置:


这是一个在0.2秒内,把BgWhite对象在Z轴上按照Animate Rotation Z曲线进行旋转的操作。
点开Timing页签,有更细致的 时间模式、延迟、冷却、重复、正反向播放等微操配置。


播放器(MMF_Player)

MMF_Player是MMF_Feedback的容器及管理器,开发者在MMF Player组件下配置好所需的Feedback操作,在运行时调用该实例的PlayFeedbacks()即可触发效果的播放。


在Player播放时,该组件可以显示当前所有Feedback的播放状态。可以看作是另一种形式的timeline。


振动器(Shakers)

MMF_Player既可以控制游戏实体的表现,也需要能控制游戏内的,像是镜头(Camera)、音频监听器(Audio Listener)等组件。出于解耦的考虑,Feel在镜头、音乐监听器上添加Shaker来监听Feedback抛出的广播。对,Shaker就是特定Feedback的Listener。
信道(Channel)

每个Shaker和触发Shaker的Feedback都有一个信道(Channel)参数,信道用来控制Feedback触发哪个相匹配的Shaker。



Shaker监听128信道



Feedback广播消息到信道128

暂停器(Pauses)

默认情况下,Player管理的所有Feedback同时播放。Feel插件中有两种类型的暂停器,分别是Pause和Holding Pause。
Pause会和其他在它之上的Feedback一起被激活,而之后的Feedback会在Pause执行之后再执行。在Feedback列表中添加Pause,相当于为Pause之后的Feedback统一增加一个延迟时间。



Pause的执行

Holding Pause在等待其之上(前面)的所有操作完成之后才会执行。在Feedback列表中添加Holding Pause相当于等待之前的所有Feedback完成,再等待Holding Pause的Pause Duration之后才继续执行。


循环(Loops)

虽然在所有的Feelback的Feelback Setting->Timing下,可以通过设置Repeat相关的选项来控制Feelback的循环播放;但如果想循环播放一系列的Feelback操作,就需要使用Looper操作了。


可以通过Looper操作中Loop的配置,配置(1)从上一次最近的Pause到Looper之间的操作进行重复播放,或者(2)从定义好的Looper Start操作到Looper之间的操作进行重复播放。


比如上图,就是重复播放Looper Start和Looper之间两个的操作无限循环下去。
使用说明

导入插件

Feel插件支持Unity2019.4.3及以上的版本。以下以Unity2020.3.39f1为例,新建一个默认的3D项目。



创建一个空3d项目

然后打开Package Manager,下载并导入已经购买的Feel插件。



从Package Manager中导入Feel插件

Feel插件依赖了几个Unity的包资源,如果想预览所有Demo,或者实际应用中会用到这些功能,可以导入。(不导入也不会影响到其他功能的使用)



导入Feel依赖的所有包资源

依赖的四个package分别是:Cinemachine、Postprocessing、TextMeshPro和2d Animation。
在Assets/Feel/FeelDemos/目录下是部分Demo,我们随机打开一个Barbarians/FeelBarbarians.unity的场景,可以正常运行,即Feel插件导入成功。


使用插件示意

使用Feel的流程分为两步,一步是通过MMF_Player建立Feedback列表,另一步是触发MMF_Player播放效果。现在我们来一步一步实现一个方块受击的反馈。
我们在这个示意中将为方块添加4个反馈效果:击退、闪白、飘字镜头摇晃
(1)准备工作
新建一个场景,在场景中创建一个Cube名为Enemy。



创建一个Cube,命名为Enemy

为Enemy添加MMF Player组件。



为Enemy添加MMF Player组件

将MMF Player的Initialization Mode设置为Awake。



设置Initialization Mode为Awake

(2)添加击退位移效果
为MMF Player添加一个击退的位移Feedback。



添加Position反馈

为Position->Position Target->Animate PositionTarget绑定Enemy实体。



将Target绑定为Enemy

通过修改Position->Transition下的配置,调整物体根据曲线进行位移的效果。
Transition->Mode 选择Along Curve,表示物体在Animate Position Duration的时间内,根据Animate X/Y/Z下的曲线进行位移。位移的幅度(曲线的[0,1]的范围)为[Remap Curve Zero, Remap Curve One]。



设置位移遵循曲线设置

点击Unity的运行,在Hierarchy窗口选中Enemy,在Inspector窗口点击MMF Player下的Play按钮,即可看到方块受击的位移反馈。



编辑器下预览所有反馈效果



击退效果预览

(3)添加闪白效果
既然要闪白,我们就得先把Enemy变个颜色。新建一个材质球名为SlashMat,设置Shader为MoreMountains/MMToon。



新建材质并设置Shader为MMToon

修改材质球的DiffuseColor为红色,勾选Emission选项,将EmissionColor设为白色,EmissionForce设置为0。



修改SlashMat材质的表现

将新的SlashMat材质球赋给Enemy。



将SlashMat赋给Enemy的Mesh Renderer

然后我们为Enemy添加一个MMBlink组件。修改Method为Shader Float Value,将Enemy赋给Target Renderer,将Shader Property Name改为_EmissionForce,并新建一个Phases,赋值如下图。



为Enemy添加MMBlink组件,并修改配置

接下来我们在Enemy的MMF Player中添加新的Renderer/MMBlink的反馈。



给MMF Player添加MMBlink反馈

将Enemy赋给Blink->Target Blink,然后点击Grab Duration From Blink Component,它会将Enemy身上的MMBlink的Phase Duration的配置自动同步。



绑定MMBlink的Target,手动同步Duration

点击Unity的运行,在Hierarchy窗口选中Enemy,在Inspector窗口点击MMF Player下的Play按钮,即可看到方块受击的位移+闪白反馈。



击退+闪白效果预览

(4)添加飘字效果
在场景中新建一个空GameObject命名为FloatTextSpawner,为其添加MMFloatingTextSpawner组件。这个组件是创建飘字的工厂(池)。



新建飘字工厂,并添加MMFloatingTextSpawner组件

为Pooler->Pooled SimpleMMFloatingText 附上一个飘字的Prefab。我们直接用工程中已有的Prefab:Assets/Feel/FeelDemos/Tactical/Prefabs/FeelTacticalSimpleFloatingText.prefab。



为MMFloatingTextSpawner组件绑定飘字Prefab

可以修改Spawn Settings 的Lifetime来改变飘字效果持续的时长。修改Spawn Offset来改变飘字的初始偏移。



调整飘字持续时长和偏移

可以修改Animate Position来调整飘字的移动距离。



调整飘字位移曲线

可以修改Animate Scale来调整飘字的缩放。



调整飘字缩放

配置完成飘字生成器后,我们开始为Enemy的MMF Player添加UI->FloatingText的反馈效果。



为MMF Player添加Floating Text反馈

点击Unity的运行,在Hierarchy窗口选中Enemy,在Inspector窗口点击MMF Player下的Play按钮,即可看到方块受击的位移+闪白反馈+飘字效果。



击退+闪白+飘字效果预览

(5)添加镜头摇晃
在场景中新建空GameObject命名为CameraRig,在它之下建立空GameObject命名为CameraShaker,将Main Camera作为CameraShaker的子节点。



更改Main Camera的嵌套

为CameraShaker添加MMCameraShaker组件。



为CameraShaker添加MMCameraShaker组件

MMCameraShaker会为CameraShaker附加添加上MMWiggle组件。


在MMWiggle组件中,我们勾选上Position,取消勾选Wiggle Permitted,设置Wiggle Type为Noise。增加Amplitude的振幅。



调整默认的镜头位移配置

设置完成振动器后,我们为Enemy的MMF Player添加新的Camera/Camera Shake反馈效果。



为MMF Player添加Camera Shake反馈触发器

配置镜头晃动的时间、振幅、频率和不同轴向上的振幅比例。



调整镜头摇晃的参数

点击Unity的运行,在Hierarchy窗口选中Enemy,在Inspector窗口点击MMF Player下的Play按钮,即可看到方块受击的位移+闪白反馈+飘字+镜头摇晃的效果。



击退+闪白+飘字+镜头摇晃效果预览

(6)见证奇迹的时刻
做到上面的几步,虽然好像加上了反馈,但是效果却好像什么也没加,难道是加了个寂寞吗?


让我们为场景添加一个地面(此处我从Feel的其他Demo中直接借来了一个地面)
再次运行:



见证魔法

是不是有点Feeling了?
再加上开枪的音效和击中的特效,当当当当~



加点调料

是内(那)味了。
在结合了击退、闪白、飘字、镜头摇晃再加上音效特效之后,最终受击的反馈便有Feeling了。
(7)通过UI Button触发反馈(示意)
在Hierarchy窗口中新加一个Button。



添加Button

微调Button的位置和文字,然后将选中Button,在OnClick列表中添加一个新条目。



添加一个OnClick条目

将Enemy拖拽到OnClick新条目上,选择触发的Function为MMF Player->PlayFeedbacks()



绑定触发反馈效果

点击Unity的运行,点击Button即可触发反馈效果播放。


(8)通过代码触发反馈(示意)
在工程中新建一个MonoBehavior脚本,命名为TestClickTrigger,编写如下内容:
using MoreMountains.Feedbacks;
using UnityEngine;

public class TestClickTrigger : MonoBehaviour
{
    private MMF_Player _enemyPlayer;

    private void Awake()
    {
        _enemyPlayer = GetComponent<MMF_Player>();
    }

    private void OnMouseUp()
    {
        if (_enemyPlayer)
        {
            _enemyPlayer.PlayFeedbacks();
        }
    }
}
为Enemy添加上TestClickTrigger组件。



给Enemy添加TestClickTrigger组件

运行Unity,鼠标点击到Enemy即可触发反馈。



鼠标点击Enemy触发反馈效果

编辑器预览

虽然上文中【使用插件示意】的图文内容一气呵成,但实际我们在使用Feel插件的过程中,最多的时间是用来在运行时进行效果调整。Feel在编辑器上提供的预览功能极大地提高了编辑效率,值得好评!
前文中我们在运行时,通过点击MMF Player的All Feedbacks Debug的Play按钮来预览效果。



通过All Feedback Debug来预览

实际上,每一个Feedback页签内部都有一个Play按钮,可以单独调试相应的反馈效果。



Feedback单独播放效果

当调整完成,得到合适的参数,点击Keep Playmode Changes按钮即可保存运行时的修改。(这一步真是贴心)



保存运行时修改

在Shaker、MMBlink和MMFloatingTextSpawner等组件上,也都有预览选项,此处就不再吝述。
代码控制

通过代码修改MMF_Player的MMF_Feedback上的参数,就像是通过GameObject修改挂载其上的Component。我们为前面编写的TestClickTrigger添加一个功能,在播放反馈前修改飘字的文字和颜色。
using MoreMountains.Feedbacks;
using UnityEngine;
using Random = UnityEngine.Random;

public class TestClickTrigger : MonoBehaviour
{
    private MMF_Player _enemyPlayer;
    private MMF_FloatingText _floatingText;
   
    private Gradient _normalHitGradient;
    private Gradient _largeHitGradient;

    private void Awake()
    {
        _enemyPlayer = GetComponent<MMF_Player>();
        _floatingText = _enemyPlayer.GetFeedbackOfType<MMF_FloatingText>();
        
        InitFloatingTextColor();
    }

    private void InitFloatingTextColor()
    {
        _normalHitGradient = new Gradient();
        var normalGradientKey = new GradientColorKey[2];
        normalGradientKey[0].color = Color.white;
        normalGradientKey[0].time = 0.0f;
        normalGradientKey[1].color = Color.white;
        normalGradientKey[1].time = 1.0f;
        var normalAlphaKey = new GradientAlphaKey[2];
        normalAlphaKey[0].alpha = 1.0f;
        normalAlphaKey[0].time = 0.0f;
        normalAlphaKey[1].alpha = 0.0f;
        normalAlphaKey[1].time = 1.0f;
        _normalHitGradient.SetKeys(normalGradientKey, normalAlphaKey);
        
        _largeHitGradient = new Gradient();
        var largeGradientKey = new GradientColorKey[2];
        largeGradientKey[0].color = Color.yellow;
        largeGradientKey[0].time = 0.0f;
        largeGradientKey[1].color = Color.red;
        largeGradientKey[1].time = 1.0f;
        var largeAlphaKey = new GradientAlphaKey[2];
        largeAlphaKey[0].alpha = 1.0f;
        largeAlphaKey[0].time = 0.0f;
        largeAlphaKey[1].alpha = 0.0f;
        largeAlphaKey[1].time = 1.0f;
        _largeHitGradient.SetKeys(largeGradientKey, largeAlphaKey);
    }

    private void OnMouseUp()
    {
        if (_enemyPlayer)
        {
            SetRandomFloatText();
            _enemyPlayer.PlayFeedbacks();
        }
    }

    private void SetRandomFloatText()
    {
        if (_floatingText == null)
        {
            return;
        }

        var randomVal = Random.Range(1, 100);
        _floatingText.Value = randomVal.ToString();
        _floatingText.ForceColor = true;
        _floatingText.AnimateColorGradient = randomVal < 50 ? _normalHitGradient : _largeHitGradient;
    }
}



修改飘字后的效果

其中关键的代码是通过MMF_Player获取其上的MMF_FloatingText:
_floatingText = _enemyPlayer.GetFeedbackOfType<MMF_FloatingText>();
通过_floatingText修改飘字的大小和颜色:
var randomVal = Random.Range(1, 100);
_floatingText.Value = randomVal.ToString();
_floatingText.ForceColor = true;
_floatingText.AnimateColorGradient = randomVal < 50 ? _normalHitGradient : _largeHitGradient;
通过代码修改Feedback上参数的步骤就是以上内容。具体到每一个Feedback相关的参数和接口,可以通过下方文档进行查询:
注意事项

Feel插件在制作游戏Demo以及参加GameJam时请放心使用,但是在制作上线稍大规模的游戏项目时,需要谨慎使用。
限制Feedback的使用范围

简单拖拽就能处理各种绑定关系,看似方便了开发者,可是随着时间和项目规模的变迁,不经限制的绑定关系将变成一场灾难。这不是Feel插件的问题,而是本身Unity在设计方面的灵活性导致的。
只要我们保证MMF_Player的所有Feedback(除去Shaker触发监听)处理的绑定关系都是其子节点,即可防止混乱的绑定关系。
Feel只用于表现,不用于逻辑

虽然Feel插件的功能可以天花乱坠地处理各种表现和异步操作,但是请只用它来处理表现上的反馈。务必不要让游戏逻辑依赖于Feel的反馈。理想情况下,我们一键移除所有的MMF_Player的Feedback,虽然表现上的效果没了,但是逻辑应该还能够正常运行。
如果你使用了Feel上的各种回调来耦合游戏的逻辑,等到有一天项目要增加联网模式时,请不要挠头发。


注意资源引用和性能

在制作Demo时我们可能拖拖拽拽不用考虑太多,但是一旦开始正式制作游戏项目资源管理性能优化就是我们不能忽略的重点。使用Feel插件时,要像没有使用它时一样小心去处理资源的依赖和引用。如果本身Feel内置的池没有满足需求,我们可以通过自己重写Feedback和使用自己的Pool Manager来提高性能。
其他

虽然通篇没有提到时间线(Timeline)和曲线(Curve),但这两个元素才是Feel反馈能够提升游戏感的关键因素。它们在Feel中无处不在以至于容易被忽略。就像空气一样,虽然没有存在感,但却是最最不可或缺的。
如果你还是一个游戏开发的萌新,不妨一边使用Feel,一边学习如何打造更好的游戏感。
如果你已经开发游戏有些年头了,或许Feel的设计思路和对工作流的改进,能为你提供一些新鲜的思路。
游戏感是一个令游戏开发者着迷的话题,我们以后再接着聊它的方方面面。
以上。
扩展阅读

《游戏感——游戏操控感和体验设计指南》

这是一本讨论游戏感的书籍,主要讲述了如何来打造出色的游戏体验。


下面的链接是关于这本书的简要介绍。
Best Practices for fast game design in Unity - Unite LA

这是Feel插件的作者在2018年Unity开发者大会上做的关于快速游戏原型开发的分享。


他在2019年的Unity开发者大会上还做了一场更细致的“How to design with feedback and game feel in mind”的分享。



Juice it or lose it - a talk by Martin Jonasson & Petri Purho

这是Martin Jonasson和Petri Purho在开发者大会上的分享,通过使用不同的Tween曲线,从0到1为一个简单的打砖块游戏赋予了游戏感的灵魂。


The art of screenshake at INDIGO Classes 2013

这是Jan Willem Nijman在INDIGO Classes 2013上做的为一款平平无奇的2d横屏射击游戏Demo注入游戏感的分享。


Feel官方文档

下图便是当前所有Feel支持的反馈操作。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 16:12 , Processed in 0.095682 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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