如何在Unity中使用流媒体资产(附代码)

528 阅读8分钟

资产可以是Unity中的任何资源;这些资源可以是图像、音频、视频、脚本、文本等等。

当构建一个Unity项目到任何平台时,你的游戏中的所有资产将被 "打包 "在一个文件中(或更多,取决于你的平台),由此产生的构建大小将取决于你决定在游戏中打包的资产的大小。

用多个高清纹理而不是用地图图集来创建游戏,或者用240p的视频而不是用1080p,这都是不一样的。预计你的资产规模越大,你最终构建的规模就越大。

一般来说,保持你的构建尽可能的轻量级是一个很好的做法,这样玩家就不会因为你的尺寸而不愿意下载你的游戏,而且你的场景运行速度也会大大加快。

有多种技巧可以实现这一点,在这篇文章中我们将讨论其中的一些技巧,首先是流媒体资产。

什么是流媒体资产?

假设你的游戏中有一个很好的场景,所有的动作都发生在这里。玩家在敌人的基地里,在一个特定的房间里,你决定在电脑上播放一段视频作为复活节彩蛋。

这段视频非常大,超过300MB,玩家可能会进入那个特定的房间,也可能不会真正看到它。在你的场景中默认加载它可以吗?这可能会在你的伟大场景中造成不必要的缓慢。因此,当我们真正需要它的时候再加载它可能会很好。

流媒体资产就是这样:一个放置在特定文件夹中的资产,当需要的时候会被Unity Player加载。该资产将被放置在目标平台内一个容易找到的地址。

请注意,任何放置在流媒体资产文件夹(在Unity内名为StreamingAssets)上的资产将被复制到目标平台,如果用户在项目文件夹内搜索,就能看到它们。

一些游戏的MOD就是这样制作的。

改变一个角色的纹理?进入数据文件夹,找到使用的纹理,然后修改它。改变一个难缠的老板的声线?只需进入数据文件夹并找到音轨,然后用另一个同名的音轨替换它。

流动资产让游戏顺利运行,而不需要从内存中加载所有的资产,并将较大的资产放在一个容易到达的路径上。

让我们建立一个简单的流资产的例子

我们将用一个简单的例子来说明流媒体资产是如何工作的,在你的游戏中展示一个视频。

为了这个例子,我从iStockPhoto下载了一个视频的预览

确保你想使用的视频有以下扩展名之一:.mov, .mpeg, .mp4, .avi, .asf。

对于我们最初的例子,我们将创建一个名为 "视频"的新文件夹,并将我们的视频放在该文件夹内:

Video Inside Folder

然后,在我们的层次结构面板上,我们将设置我们的视频播放器。

右键点击你的层次结构,添加一个空的游戏对象。我把我的对象称为VideoObject

在它里面,我创建了一个立方体,我们将在那里播放视频;它可以是任何你想要的形状,但为了方便,我选择了一个立方体。我把它叫做Video_Canvas

在Video**_Canvas的同一层,在VideoObject里面,我通过右键单击VideoObject**,选择Video,然后选择VideoPlayer,添加了一个新的Video Player对象:

Video Object Folder Structure

下面是我如何设置我们的视频播放器对象的:

Video Player Setup

我们将源设置为视频剪辑,然后从我们创建的视频文件夹中选择视频剪辑,然后我们选择循环,这样视频就会无限地播放下去。

然后,选择渲染模式材质覆盖,拖放你想播放视频的对象--在我们的例子中,是Video_Canvas立方体。让材料属性为_MainTex。

如果你在Unity编辑器中点击播放,你会看到这样的画面:立方体的每一面都在播放视频:

Video on Each Cube Side

如果你想要一个更平坦的表面,像屏幕一样,你也可以创建一个平面或将立方体的比例缩小到你想要的形状。

这个演示视频有3.5MB。

如果我们为一个独立的平台(Windows、Linux、MacOs)建立这个项目,我们会看到一个带有视频的空白项目是87.6MB。

Black Project Video

现在,让我们看看使用同一视频作为流媒体资产的效果如何。

为此,我们将在Assets文件夹中创建一个名为StreamingAssets的新文件夹;这是一个特殊命名的文件夹,它将把我们的视频文件video_streamingAssets当作一个普通文件,在编辑器的属性窗口中没有任何选项:

StreamingAssets Folder

然后在我们的视频播放器对象中,我们可以将视频播放器游戏组件来源改为URL,而不需要实际的URL。我们将创建一个名为LoadVideo的新脚本,并将其附加到我们的视频播放器游戏对象上,如图所示。

这个脚本需要一个视频播放器作为参数,所以我们将拖放同一个视频播放器,并将其附加到这个脚本上。

Video Player Details

这里是LoadVideo的脚本:

using UnityEngine;
using UnityEngine.Video;

public class LoadVideo : MonoBehaviour
{
   public VideoPlayer myVideoPlayer;
   void Start()
   {
       string videoUrl= Application.streamingAssetsPath +"/"+ "video_streamingAssets" + ".mp4";
       myVideoPlayer.url = videoUrl;
   }
}

基本上,在应用程序的开始,它将使用Application.streamingAssetsPath来获取任何目标平台中的StreamingAssets文件夹的路径。然后它将引用该文件夹中我们的视频名称及其扩展名。

然后,它将采取myVideoPlayer(已经有我们的场景视频播放器的引用),它将用我们的视频的路径写入其url属性。

这将导致在同一个立方体中播放视频:

Video on Each Cube Side

现在,如果我们建立这个项目,我们会看到它的大小与我们之前的例子相同,但有一个主要的区别:

Blank Project with One Difference

如果我们看到这个构建的包的内容,我们可以看到在内容/资源/数据中,有我们的StreamingAssets文件夹和我们的视频。

StreamingAssets Folder with Video

如果我们把StreamingAssets文件夹中的视频替换成 另一个同名的视频,我们就不需要再次构建我们的项目,就能看到反映在我们游戏中的变化。

Cube with Differences

现在我们知道了如何将我们的资产/内容从我们的构建中分离出来。我们也可以从我们的视频播放器上的URL调用远程文件。为了做到这一点,我们将使用这个视频作为例子。它几乎有10分钟长,大约有151MB。

如果我们把我们的代码改为:

using UnityEngine;
using UnityEngine.Video;

public class LoadVideo : MonoBehaviour
{
   public VideoPlayer myVideoPlayer;
   void Start()
   {
       string videoUrl= "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
       myVideoPlayer.url = videoUrl;
   }
}

...并删除StreamingAssets文件夹中的原始视频,我们的结果是这样的:

New Video Cube

同样的功能,但现在的视频资产来自外部来源

现在,如果我们在StreamingAssets文件夹中没有本地视频的情况下构建我们的项目,我们会看到构建的大小有所减少。

Streaming Assets Decreased Size

请记住,这也可以通过异步调用或UnityWebRequest 调用和coroutine来完成,但为了简单起见,我们只是添加一个视频的确切URL来演示流资产的力量。

使用一个coroutine从外部来源获取视频

我们可以像这样修改我们的LoadingScript ,以便使用一个coroutine,而不是将直接链接传递给我们的视频播放器:

using UnityEngine;
using UnityEngine.Video;
using UnityEngine.Networking;
using System.Collections;

public class LoadVideo : MonoBehaviour
{
   public VideoPlayer myVideoPlayer;
   void Start()
   {
       StartCoroutine(LoadExternalVideo("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4"));
   }

     IEnumerator LoadExternalVideo(string url){
      using (UnityWebRequest request = UnityWebRequest.Get(url))
      {
          //Fetches a page and displays the number of characters of the response.
          yield return request.SendWebRequest();
          myVideoPlayer.url = request.url;
      }
  }
}

在这个例子中,我们可以使用一个coroutine来消耗一个API端点并检索视频的URL,但为了简单起见,这是一个关于如何使用外部链接的简单例子。

结果将是非常相似的;我们只需要确保我们的UnityWebRequest 结果是从被消耗的端点检索出来的,并确保视频的URL在设置到视频播放器的URL属性之前是存在的。

最后的想法

流媒体资产只是Unity为你的游戏处理资产的不同方式之一。当你试图让你的玩家群参与进来,允许他们修改你的游戏时,或者你想有一个轻量级的游戏最终构建,然后在第一次启动时,在玩家注意到之前下载你的游戏的其他资产时,它的效果非常好。

有很多网络游戏都是这样做的:他们的游戏非常轻,你可以完成第一关的小教程,然后你会得到一个下载其余资产的加载屏幕。

你必须牢记对你的游戏来说是最好的方法。你不能把所有的资产都放在一个远程服务器上,因为如果玩家第一次玩你的游戏时,他们的设备没有良好的网络连接,那会发生什么?没有资产,你的游戏会是什么样子?

最好的方法之一是将你的资产的一个非常轻的版本作为默认值(如材料、纹理、图像),作为一个占位符,当你确定你的玩家会喜欢这些内容,而且设备已经准备好下载这些信息时,尽可能无缝地下载。

我希望你喜欢这篇文章,并觉得它很有用!祝你游戏开发愉快!