Unity: WebGL项目添加自定义启动页面

作为游戏制作者,将个人游戏风格和创意融入游戏的每一个方面是非常重要的,特别是启动页面,它不仅是玩家的第一印象,也是展示游戏特色和故事的绝佳机会。通过定制启动页面,您可以:

  • 展示游戏世界观:利用启动页面介绍游戏的背景故事或世界观,为玩家进入游戏做好铺垫。
  • 强化视觉体验:通过精心设计的视觉元素,如艺术插图、动画和颜色方案,可以增强玩家的视觉体验,并与游戏的风格保持一致。
  • 提前暗示游戏玩法:通过启动页面上的元素或小互动,可以暗示或简介游戏的核心玩法,激发玩家的好奇心和期待。

由于原生项目只能通过购买Unity的订阅服务来自定义启动页面,而WebGL项目可以通过HTML的特性来自定义启动页面,因此本文只针对WebGL项目。好了,废话不多说,直接进入主题。

启动阶段

要想自定义启动页面,需要先了解进入游戏前,Unity WebGL做了哪些工作。

这个阶段可以分为两个小阶段:启动加载和Logo展示

1. 启动加载阶段

在这个阶段,Unity会加载必要的系统和资源,准备运行游戏或应用程序。具体步骤包括:

  • 初始化: Unity引擎启动并初始化内部系统,如内存管理、文件系统等。
  • 配置加载: 读取项目的配置信息,包括屏幕分辨率、全屏设置、图形质量等。
  • 资源预加载: 根据项目设置,加载必要的资源到内存中,这可能包括贴图、模型、声音文件等。

这个阶段的持续时间取决于项目的大小和复杂性,以及用户设备的性能。效果如图:

2. Logo展示阶段

这个阶段会显示Unity的Logo。这个阶段主要是出于品牌宣传的目的,但也给了Unity更多时间在背景加载游戏资源。

  • 显示Unity Logo: 显示Unity的Logo,通常持续几秒钟。
  • 继续加载资源: 在显示Logo的同时,Unity继续在后台加载游戏的其他资源。
  • 过渡到游戏界面: 一旦资源加载足够,Unity会从Logo界面过渡到游戏的主界面或菜单。

这个阶段效果如图:

两个阶段的效果如图:

这两个阶段中:

  • 第一个阶段的加载的功能是写在index.html,因此可以直接删除相应节点
  • 第二个阶段的Logo展示已经WebGL渲染了,改不了,除非你是购买了Unity订阅服务

方案

  • 方案一:购买Unity订阅服务
  • 方案二:可以在Unity Canvas节点上再盖一层,隐藏掉Unity Canvas,等到第二阶段结束后再去删掉覆盖的那层,以展示游戏

笔者比较穷,选择方案二😄

要选择方案二,需要了解第二阶段什么时候开始,并且什么时候结束。

  • 开始:即第一阶段结束的时候,在createUnityInstance方法成功返回的时候
  • 结束:通过Build Settings -> Player -> Splash Image -> Draw Mode(选择All Sequential) -> Logos 的Logo Duration得知,第二阶段时长设置最小2秒,最长是10秒,默认是2秒。

因此只需要在createUnityInstance成功返回后,设一个2秒的定时器来删除覆盖在Canvas节点上的节点。

实现

这里以Unity2021版本为例

首先去掉unity的加载节点,及相应的js代码

html 复制代码
<div id="unity-container" class="unity-desktop">
      <canvas id="unity-canvas" width=960 height=600></canvas>
      <!-- 去掉Unity加载节点 和 底部logo显示 -->
      <!-- <div id="unity-loading-bar">
        <div id="unity-logo"></div>
        <div id="unity-progress-bar-empty">
          <div id="unity-progress-bar-full"></div>
        </div>
      </div>
      <div id="unity-warning"> </div>
      <div id="unity-footer">
        <div id="unity-webgl-logo"></div>
        <div id="unity-fullscreen-button"></div>
        <div id="unity-build-title">unity-minigamesdk-demo</div>
      </div> -->
    </div>
    ...
</div>

<script>
      var container = document.querySelector("#unity-container");
      var canvas = document.querySelector("#unity-canvas");
      // 删掉加载画面的js代码
      // var loadingBar = document.querySelector("#unity-loading-bar");
      // var progressBarFull = document.querySelector("#unity-progress-bar-full");
      // var fullscreenButton = document.querySelector("#unity-fullscreen-button");
      // var warningBanner = document.querySelector("#unity-warning");

      // function unityShowBanner(msg, type) {
      //   function updateBannerVisibility() {
      //     warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      //   }
      //   var div = document.createElement('div');
      //   div.innerHTML = msg;
      //   warningBanner.appendChild(div);
      //   if (type == 'error') div.style = 'background: red; padding: 10px;';
      //   else {
      //     if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
      //     setTimeout(function() {
      //       warningBanner.removeChild(div);
      //       updateBannerVisibility();
      //     }, 5000);
      //   }
      //   updateBannerVisibility();
      // }
      // ...
</script>

Unity Canvas节点上添加一个Loading层,以隐藏游戏内容,并添加删除节点的函数

html 复制代码
<div id="loaderContainer">
  <div id="loader">
      <div class="dot"></div>
      <div class="dot"></div>
      <div class="dot"></div>
  </div>
  <div id="loadingText">Loading...</div>
</div>

<script>
function closeLoading() {
  var _0x586046 = document['getElementById']('loaderContainer');
  if (_0x586046)
      _0x586046['remove']();
}
</script>

给Loading层设置好style和一个简单的css动画

css 复制代码
@keyframes pulse {
    0%, 100% {
        opacity: 1;
        transform: scale(1);
    }
    50% {
        opacity: 0.3;
        transform: scale(0.5);
    }
}

@keyframes spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

#loaderContainer {
    background-color: beige;
    background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #d523c6) 0 0/300% 300%;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 9999;
}

#loader {
    display: flex;
    width: 100px;
    height: 100px;
    justify-content: space-around;
    align-items: center;
    animation: spin 2s linear infinite;
}

.dot {
    width: 20px;
    height: 20px;
    background-color: #23a6d5;
    border-radius: 50%;
    animation: pulse 1s ease-in-out infinite;
}

.dot:nth-child(2) {
    animation-delay: 0.3s;
    background-color: #23d5ab;
}

.dot:nth-child(3) {
    animation-delay: 0.6s;
    background-color: #ee7752;
}

#loadingText {
    position: absolute;
    margin-top: 140px;
    font-size: 16px;
    color: #fff;
}

最后在第一阶段结束后,设置一个2秒的定时器,删除新加的Loading层,以展示游戏内容

js 复制代码
var script = document.createElement("script");
script.src = loaderUrl;
script.onload = () => {
  createUnityInstance(canvas, config, (progress) => {
    console.info("progress: " + 100 * progress + "%");
  }).then((unityInstance) => {
    window.unityInstance = unityInstance;
    // 第一阶段结束,第二阶段开始,设置关闭Loading层的计时器
    setTimeout(() => {
      closeLoading();
    }, 2000);
  }).catch((message) => {
    alert(message);
  });
};
document.body.appendChild(script);

运行后,最终效果如图:

相关推荐
Thomas_YXQ4 天前
Unity3D Shader的阴影部分法线效果详解
开发语言·游戏·unity·架构·unity3d
氦客4 天前
Unity3D入门(四) : Android和Unity3D交互 - Unity调用Android
android·unity·交互·unity3d·调用·javaobject·javaclass
Thomas_YXQ7 天前
Unity3D PostLateUpdate为何突然占用大量时间详解
开发语言·数码相机·游戏·unity·架构·unity3d
Thomas_YXQ7 天前
Unity3D 中构建行为树插件详解
游戏·unity·架构·unity3d·游戏开发
随遇而安的生活12 天前
Unity android 接USBCamera
android·unity3d
留待舞人归13 天前
【Unity杂谈】iOS 18中文字体显示问题的调查
游戏·unity·ios·游戏引擎·unity3d
吾名招财14 天前
unity3d入门教程八-飞机大战
游戏引擎·unity3d
吾名招财19 天前
unity3d入门教程五
游戏引擎·unity3d
吾名招财20 天前
unity3d入门教程六
游戏引擎·unity3d
吾名招财20 天前
unity3d入门教程七
游戏引擎·unity3d