Изпълнение на Unity WebGL с ASP.NET ядро

Страницата се актуализира :
Дата на създаване на страница :

Среда за проверка

Уиндоус
  • Прозорци 11
Редактор на единство
  • 2020.3.25ф1
Визуално студио
  • Визуално студио 2022
ASP.NET Ядро
  • ASP.NET Ядро 6.0
Интернет информационни услуги (IIS)
  • ИИС 10.0

Отначало

Научете как да стартирате изход от игра като WebGL в Unity на уеб сървър, работещ ASP.NET Core. За програми за игри, използвайте тези, които се извеждат в стъпките със съвети по-долу. Примерът на играта използва 2D Platformer Microgame, който може да бъде създаден от Unity Hub.

Ще обясня как да настроите "Uncompressed WebGL", "WebGL компресиран с Gzip" и "WebGL компресиран с Brotli", за да стартирате WebGL игри. Процедурата е еднаква за всички тях.

Използваме Visual Studio 2022, ASP.NET Core 6.0, но по-старите версии вероятно ще работят. Структурата на първоначалния код обаче е различна за всяка версия, така че моля, разберете разликите сами.

Създаване на ASP.NET основен проект

Стартирайте "Visual Studio 2022" от стартовото меню.

Изберете Създаване на нов проект.

Този път изберете "ASP.NET Core Web App" като образец. Ако работите на ASP.NET Core, можете да изпълнявате други шаблони, но ще трябва да следвате всеки шаблон за това как да го изградите.

Задайте името и местоположението на проекта произволно.

Оставете допълнителната информация такава, каквато е.

Проектът е създаден.

Изпълнение на некомпресиран WebGL

Подгответе WebGL програма, създадена без компресия.

Уверете се, че играта работи бързо

ASP.NET Опитайте да стартирате WebGL игра с по-малко настройки, без да следвате етикета на ядрото.

В ASP.NET Core нямате достъп до някои WebGL файлове, излъчвани от Unity в състоянието по подразбиране. Направете това достъпно.

Програма.cs

Отворете от вашия Program.cs проект. Отнася се за по-ранни ASP.NET основни версии Startup.cs .

Добавете пространство на имената в горната част на кода и заменете следното в кода app.UseStaticFiles(); :

// ここから追加
using Microsoft.AspNetCore.StaticFiles;
// ここまで追加

var builder = WebApplication.CreateBuilder(args);

// --- 省略 ---

app.UseHttpsRedirection();

//app.UseStaticFiles();
// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
});
// ここまで追加

app.UseRouting();

// --- 省略 ---

.data, така че когато се осъществи достъп до даден файл, .wasm той да може да бъде върнат на клиента с указания Content-Type .

Разполагане на WebGL

Поставете следните папки с файлове от Unity във вашия проект wwwroot .

  • индекс.html
  • Строя
  • Данни за шаблон

Index.cshtmlindex.html Отворете връзката, за да имате достъп до нея.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<a href="index.html">index.html</a>

Стартирайте програмата и се уверете, че играта работи.

Изпълнение на програма WebGL на страница на Razor

Предишната игра се изпълняваше на статичен HTML файл, така че работи на място, което няма нищо общо с ASP.NET Core. Това не е много желателно за еднородност на програмата, така че ще преместим поведението на HTML файла в Razor Pages.

Щракнете с десния бутон върху папката Страници от вашия проект, за да добавите нов елемент.

Изберете Страница за бръснач - празна. Не е посочено конкретно име, но е добавено тук WebGL.cshtml .

Кодът се показва.

index.html Вижте съдържанието на файла и порта към WebGL.cshtml . link Има някои странни моменти, като например как да поставите етикета, но ще го оставя такъв, какъвто е, за да се улесни обяснението.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <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">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="TemplateData/favicon.ico">
  <link rel="stylesheet" href="TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    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");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == '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();
    }

    var buildUrl = "Build";
    var loaderUrl = buildUrl + "/WebGL.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL.data",
      frameworkUrl: buildUrl + "/WebGL.framework.js",
      codeUrl: buildUrl + "/WebGL.wasm",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Index.cshtmlWebGL Добавяне на връзка към .

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
</ul>

Опитайте се да изпълните програмата. Можете да видите, че горният и долният колонтитул _Layout.cshtml се показват на страницата WebGL според .

Промяна на местоположението на WebGL файлове

Поставих файла WebGL директно под , но този метод ще го презапише, когато поставите два или повече WebGL wwwroot файла. Ще обясня как да сложа това в отделни папки и да го преместя.

На първо място, създайте нова папка, наречена "webgl" и я преместете там. Двете папки, които трябва да Buildбъдат преместени, са , TemplateData . index.html Вече го пренесох в Razor Pages и мога спокойно да го изтрия.

Тъй като WebGL.cshtml сме задълбочили йерархията на папките, ще задълбочим и пътя, описан в . Корекцията е 3 реда.

Преди корекцията

<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
    var buildUrl = "Build";

След корекция

<link rel="shortcut icon" href="webgl/TemplateData/favicon.ico">
<link rel="stylesheet" href="webgl/TemplateData/style.css">
    var buildUrl = "webgl/Build";

Стартирайте програмата, за да видите дали работи правилно.

Изпълнение на WebGL компресиран с Gzip

Разширението на файла, компресиран от Gzip е , и това е .gz файл, който може да се обработва от ASP.NET Core, Unity WebGL Content-Type и се обработват по различен начин и изискват преобразуване.

Първо, създайте разполагане на WebGL файл и страница.

Разположение на WebGL файлове

wwwrootwebgl-gzip Създайте папка под Gzip и копирайте папката , от WebGL файлаBuildTemplateData, който създадохте с Gzip.

Създаване на страница за бръснене

Този път WebGLGzip.cshtml създайте файла, като използвате същата процедура, както когато не е компресиран.

Кодът е следният по отношение на изхода в index.html единство. Пътят съвпада с папката, която създадохте webgl-gzip по-рано за WebGL файловете.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLGzipModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <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">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="webgl-gzip/TemplateData/favicon.ico">
  <link rel="stylesheet" href="webgl-gzip/TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    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");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == '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();
    }

    var buildUrl = "webgl-gzip/Build";
    var loaderUrl = buildUrl + "/WebGL_Gzip.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL_Gzip.data.gz",
      frameworkUrl: buildUrl + "/WebGL_Gzip.framework.js.gz",
      codeUrl: buildUrl + "/WebGL_Gzip.wasm.gz",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Модифицирай, за да разрешиш навигация до Index.cshtml тази страница.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
  <li><a href="WebGLGzip">WebGLGzip</a></li>
</ul>

Програма за фиксиране.cs

app.UseStaticFiles Променете частта, която обработва метода, както следва.

Преди корекцията

// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
});
// ここまで追加

След корекция

// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";
provider.Mappings[".br"] = "application/octet-stream";   // .br ファイルにアクセスできるように追加
provider.Mappings[".js"] = "application/javascript";     // 後の変換の為に追加

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
  OnPrepareResponse = context =>
  {
    var path = context.Context.Request.Path.Value;
    var extension = Path.GetExtension(path);

    // 「.gz」「.br」ファイルにアクセスした場合は Content-Type と Content-Encoding を設定する
    if (extension == ".gz" || extension == ".br")
    {
      var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path) ?? "";
      if (provider.TryGetContentType(fileNameWithoutExtension, out string? contentType))
      {
        context.Context.Response.ContentType = contentType;
        context.Context.Response.Headers.Add("Content-Encoding", extension == ".gz" ? "gzip" : "br");
      }
    }
  },
});
// ここまで追加

В ASP.NET Core .gz файлът Content-Type application/x-gzip се връща с . Както е, Unity WebGL на клиента не може да Content-Type го определи, така че .gz аз пренаписвам и го връщам според разширението на файла, което изключва . Content-Encoding Аз също го поставям, gzip защото е необходимо.

Между другото, аз също сложих кода на Бротли заедно, така че можете да използвате този код, както е в кореспонденцията на Бротли на следващия елемент. Brotli също задава .br пренаписване Content-Encoding br, за да съответства Content-Type на разширението на файла без . Файлът обаче е недостъпен по подразбиране в ASP.NET Core,.br затова provider.Mappings го добавих с .br .

След това стартирайте отстраняването на грешки и проверете дали играта работи правилно.

Ако сте го настроили правилно и играта все още няма да се показва, опитайте да изчистите кеша на уеб браузъра си, за да изчистите бисквитките.

Изпълнение на WebGL компресиран с Brotli

Процедурата е почти същата като Gzip, заменяйки Gzip частта с Brotli. Файловете Brotli (.br) обаче не са достъпни по подразбиране в ASP.NET Core. Трябва да го конфигурирате така, че да имате достъп до него, но ако използвате кода по време на Gzip, той се поддържа.

Първо, създайте разполагане на WebGL файл и страница.

Разположение на WebGL файлове

wwwrootwebgl-brotli Под Създаване на папка копирайте папката BuildTemplateData от WebGL файла, който създадохте с Brotli.

Създаване на страница за бръснене

Създайте файла, като използвате същите стъпки като WebGLBrotli.cshtml за Gzip.

Кодът е следният по отношение на изхода в index.html единство. Пътят съвпада с папката, която създадохте webgl-brotli по-рано за WebGL файловете.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLBrotliModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <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">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="webgl-brotli/TemplateData/favicon.ico">
  <link rel="stylesheet" href="webgl-brotli/TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    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");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == '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();
    }

    var buildUrl = "webgl-brotli/Build";
    var loaderUrl = buildUrl + "/WebGL_Brotli.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL_Brotli.data.br",
      frameworkUrl: buildUrl + "/WebGL_Brotli.framework.js.br",
      codeUrl: buildUrl + "/WebGL_Brotli.wasm.br",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Модифицирай, за да разрешиш навигация до Index.cshtml тази страница.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
  <li><a href="WebGLGzip">WebGLGzip</a></li>
  <li><a href="WebGLBrotli">WebGLBrotli</a></li>
</ul>

Програма за фиксиране.cs

Ако го промените, когато се поддържа Gzip, можете да използвате същия код.

След като го поправите, стартирайте отстраняване на грешки и проверете дали играта работи.

Ако сте го настроили правилно и играта все още няма да се показва, опитайте да изчистите кеша на уеб браузъра си, за да изчистите бисквитките.

Разбиране на симптомите на достъп до файлове на Brotli на IIS уеб сървър

Brotli не се поддържа от IIS по подразбиране, така че се изисква конфигурация от страна на IIS. Изглежда, че може да се борави с него, като се направят разширени настройки, но няма да го обяснявам в този съвет. Моля, вижте информацията, свързана по-долу.

Съобщение за грешка

Unable to load file webgl-brotli/Build/WebGL_Brotli.framework.js.br! Check that the file exists on the remote server. (also check browser Console and Devtools Network tab to debug)