可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm looking to integrate a Unity WebGL-project into an Angular2 app. What's the proper way to move all this script into an Angular2 component?
First, the Unity WebGL exports an index.html like this:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | Espoo web manager (Prefab preview)</title>
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/builds.json", {onProgress: UnityProgress});
</script>
</head>
<body>
<div class="webgl-content">
<div id="gameContainer" style="width: 960px; height: 600px"></div>
<div class="footer">
<div class="webgl-logo"></div>
<div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
<div class="title">Espoo web manager (Prefab preview)</div>
</div>
</div>
</body>
</html>
I started to split this and first I moved the stylesheet into the template .css file:
@import './webgl-app/TemplateData/style.css';
Then I moved the javascript into the component .ts-file:
import { Component, AfterViewInit } from '@angular/core';
import './webgl-app/TemplateData/UnityProgress.js';
import './webgl-app/Build/UnityLoader.js';
declare var UnityLoader: any;
declare var UnityProgress: any;
@Component({
selector: 'app-unity-prefab-preview',
templateUrl: './unity-prefab-preview.component.html',
styleUrls: ['./unity-prefab-preview.component.css']
})
export class UnityPrefabPreviewComponent implements AfterViewInit {
constructor() {}
gameInstance: any;
ngAfterViewInit() {
this.gameInstance = UnityLoader.instantiate("gameContainer", "./webgl-app/Build/builds.json", { onProgress: UnityProgress });
}
}
And then for the .html template I left this:
<div class="webgl-content">
<div id="gameContainer" style="width: 960px; height: 600px"></div>
</div>
However, whatever approach I try (like using 'require' on the JS-files instead), the line in the ngAfterViewInit always gives an error: "Reference error: UnityLoader is not defined".
How should this be done properly so it would work?
回答1:
so I was messing around with this quite a time...
I have it up and running using the angular/cli@latest 1.6.5
here my app.component.ts
import { Component, NgZone, OnInit } from '@angular/core';
import * as $ from 'jquery';
declare const UnityLoader;
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
public gameObject: any;
constructor(private ngZone: NgZone) {
window.unity = window.unity || {};
window.unity.GetUnityNumber = this.randomNumberFromUnity.bind(this);
}
public ngOnInit(): void {
this.init();
}
public helloUnity() {
console.log(this.gameObject); // <-- always undefined ?
this.gameObject.SendMessage('SetText', 'HELLO?');
}
private init() {
$.getScript('assets/UnityLoader.js').done(function ( bla , text) {
this.gameObject =
UnityLoader.instantiate('gameContainer','assets/test.json');
//gameObject not undefined at this stage..
});
}
private randomNumberFromUnity(input: string) {
this.ngZone.run(() => {
console.log('call from unity', input);
});
}
}
In the typings.d.ts i have extended the window element.
interface Window {
unity: any;
}
So when I do a call from unity I call it like
Application.ExternalCall("unity.GetUnityNumber", rnd);
All I'm missing right now is the call into unity... maybe you have an idea on this one?
I have the unity-build as a private npm package. When building everything is copied into the assets folder.
回答2:
To add Unity WebGL to your project:
1) Export WebGL project to a /unity folder in your Angular project root (same level as src). Copy the following files from your Build folder to /src/assets/unity:
- unity.json
- unity.data.unityweb
- unity.wasm.code.unityweb
- unity.wasm.framework.unityweb
2) Add UnityProgress.js and UnityLoader.js to your angular.json scripts:
"scripts": [
"unity/TemplateData/UnityProgress.js",
"unity/Build/UnityLoader.js"
],
3) (optional) Add style.css to your angular.json styles
"styles": [
"node_modules/font-awesome/css/font-awesome.css",
"src/assets/theme.scss",
"src/styles.scss",
"unity/TemplateData/style.css"
],
4) Add the base Unity HTML to your component.html:
<div class="webgl-content">
<div id="unityContainer" style="width: 960px; height: 600px"></div>
<div class="footer">
<div class="webgl-logo"></div>
<div class="fullscreen" (click)="unityInstance.SetFullscreen(1)"></div>
<div class="title">UnityProject</div>
</div>
</div>
5) Lastly, instantiate your unityContainer
in your component.ts:
import { Component, OnInit, AfterViewInit } from '@angular/core';
declare var UnityLoader: any;
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit, AfterViewInit {
unityInstance: any;
constructor() { }
ngOnInit() { }
ngAfterViewInit() {
this.unityInstance = UnityLoader.instantiate("unityContainer", "assets/unity/unity.json");
}
}
回答3:
I simplified the Unity WebGL output to
unity-game.html
<body style="margin: 0px">
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/Browser.json", {onProgress: UnityProgress});
</script>
<div class="webgl-content">
<div id="gameContainer" style="width: 800px; height: 600px;"></div>
</div>
</body>
and loaded it into an iframe. This gives you an
unsafe value used in a resource URL context
error. This can be addressed by using a special iframe Angular component.
unity-game.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@Component({
selector: 'app-unity-game',
templateUrl: './unity-game.component.html',
styleUrls: ['./unity-game.component.css']
})
export class UnityGameComponent implements OnInit {
@Input()
url: string;
urlSafe: SafeResourceUrl;
constructor(public sanitizer: DomSanitizer) { }
ngOnInit() {
this.urlSafe= this.sanitizer.bypassSecurityTrustResourceUrl(this.url);
}
}
unity-game.component.html
<iframe width="800" height="600" frameBorder="0" [src]="urlSafe"></iframe>
credit to Lrodriguez84: https://stackoverflow.com/a/50863439/719528
Then just add that special iframe component, passing it that HTML file wherever you would like the Unity project to appear!
<app-unity-game url="assets/unity-game.html"></app-unity-game>
回答4:
I've got stuck on this aswell.
it seems to be your context is not set
$.getScript('assets/UnityLoader.js').done(function ( bla , text) {
this.gameObject =
UnityLoader.instantiate('gameContainer','assets/test.json');
//gameObject not undefined at this stage..
// this does not point towards your container
});
solution :
$.getScript('assets/UnityLoader.js').done(function ( bla , text) {
this.gameObject =
UnityLoader.instantiate('gameContainer','assets/test.json');
//gameObject not undefined at this stage and this points to container
}.bind(this));
more info : https://docs.unity3d.com/2018.3/Documentation/Manual/webgl-interactingwithbrowserscripting.html