unity-webgl
Advanced tools
@@ -1,7 +0,52 @@ | ||
| type CanvasElement = HTMLCanvasElement | string; | ||
| type BooleanLike = 0 | 1; | ||
| interface EventListener { | ||
| (...args: any[]): void; | ||
| _?: EventListener; | ||
| } | ||
| type EventListenerOptions = { | ||
| once?: boolean; | ||
| }; | ||
| declare class UnityWebglEvent { | ||
| private _e; | ||
| constructor(); | ||
| /** | ||
| * Register event listener | ||
| * @param name event name | ||
| * @param listener event listener | ||
| * @param options event listener options | ||
| */ | ||
| on(name: string, listener: EventListener, options?: EventListenerOptions): this; | ||
| /** | ||
| * Remove event listener | ||
| * @param name event name | ||
| * @param listener event listener | ||
| */ | ||
| off(name: string, listener?: EventListener): this; | ||
| /** | ||
| * Dispatch event | ||
| * @param name event name | ||
| * @param args event args | ||
| */ | ||
| emit(name: string, ...args: any[]): this; | ||
| /** | ||
| * clear all event listeners | ||
| */ | ||
| protected clear(): void; | ||
| /** | ||
| * Register event listener for unity client | ||
| * @param name event name | ||
| * @param listener event listener | ||
| */ | ||
| addUnityListener(name: string, listener: EventListener, options?: EventListenerOptions): this; | ||
| /** | ||
| * Remove event listener from unity client | ||
| * @param name event name | ||
| * @param listener event listener | ||
| */ | ||
| removeUnityListener(name: string, listener?: EventListener): this; | ||
| } | ||
| /** | ||
| * UnityWebgl configuration | ||
| */ | ||
| type IUnityConfig = Pick<IUnityArguments, 'dataUrl' | 'frameworkUrl' | 'codeUrl' | 'streamingAssetsUrl' | 'memoryUrl' | 'symbolsUrl' | 'companyName' | 'productName' | 'productVersion' | 'devicePixelRatio' | 'matchWebGLToCanvasSize' | 'webglContextAttributes'> & { | ||
| type UnityConfig = Pick<UnityArguments, 'dataUrl' | 'frameworkUrl' | 'codeUrl' | 'streamingAssetsUrl' | 'memoryUrl' | 'symbolsUrl' | 'companyName' | 'productName' | 'productVersion' | 'devicePixelRatio' | 'matchWebGLToCanvasSize' | 'webglContextAttributes'> & { | ||
| /** | ||
@@ -18,3 +63,3 @@ * The url to the build json file generated by Unity. When using a relative url, | ||
| */ | ||
| interface IUnityArguments { | ||
| interface UnityArguments { | ||
| /** | ||
@@ -130,60 +175,3 @@ * The url to the build data file generated by Unity. When using a relative url, | ||
| } | ||
| type UnityModule = { | ||
| /** | ||
| * Stringifies a pointer to a string. | ||
| * @param pointer The pointer to the string. | ||
| * @param length The length of the string. | ||
| * @deprecated Deprecated in Unity 2021.2, use UTF8ToString instead. | ||
| */ | ||
| Pointer_stringify(pointer: number, length: number): string; | ||
| /** | ||
| * Converts a pointer to a string. | ||
| * @param pointer The pointer to the string. | ||
| */ | ||
| UTF8ToString(pointer: number): string; | ||
| /** | ||
| * Enables or disabled the fullscreen mode of the UnityInstance. | ||
| * @param fullScreen sets the fullscreen mode. | ||
| */ | ||
| SetFullscreen(fullScreen: BooleanLike): void; | ||
| /** | ||
| * A reference to the Unity Instance's Canvas. | ||
| */ | ||
| canvas?: HTMLCanvasElement; | ||
| }; | ||
| /** | ||
| * Type declaration for the UnityInstance. | ||
| */ | ||
| declare class UnityInstance { | ||
| /** | ||
| * Creates a new instance of Unity Instance. | ||
| */ | ||
| constructor(); | ||
| /** | ||
| * Sends a message to the UnityInstance to invoke a public method. | ||
| * @public | ||
| * @param objectName the name of the game object in your Unity scene. | ||
| * @param methodName the name of the public method on the game object. | ||
| * @param parameter an optional parameter to pass along to the method. | ||
| */ | ||
| SendMessage(objectName: string, methodName: string, parameter?: string | number | boolean): void; | ||
| /** | ||
| * Enables or disabled the fullscreen mode of the UnityInstance. | ||
| * @public | ||
| * @param fullScreen sets the fullscreen mode. | ||
| */ | ||
| SetFullscreen(fullScreen: BooleanLike): void; | ||
| /** | ||
| * Quits the Unity WebGL application | ||
| * and removes it from the memory. | ||
| * @public | ||
| * @returns {Promise<void>} a promise whether the application did quit. | ||
| */ | ||
| Quit(): Promise<void>; | ||
| /** | ||
| * The Unity Module. | ||
| */ | ||
| Module: UnityModule; | ||
| } | ||
| /** | ||
| * WebGLContextAttributes object that contains the actual context parameters. | ||
@@ -272,59 +260,88 @@ * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getContextAttributes | ||
| }; | ||
| type EventName = string | symbol; | ||
| type EventHandler = (...args: any[]) => any; | ||
| type EventMap = Record<EventName, EventHandler>; | ||
| declare class EventBus { | ||
| private _eventMap; | ||
| constructor(_eventMap?: EventMap); | ||
| on(name: EventName, handler: EventHandler): this; | ||
| off(name: EventName): this; | ||
| once(name: EventName, handler: EventHandler): this; | ||
| emit(name: EventName, ...args: any[]): void; | ||
| clear(): void; | ||
| } | ||
| type UnityBooleanLike = 0 | 1; | ||
| type UnityModule = { | ||
| /** | ||
| * Stringifies a pointer to a string. | ||
| * @param pointer The pointer to the string. | ||
| * @param length The length of the string. | ||
| * @deprecated Deprecated in Unity 2021.2, use UTF8ToString instead. | ||
| */ | ||
| Pointer_stringify(pointer: number, length: number): string; | ||
| /** | ||
| * Converts a pointer to a string. | ||
| * @param pointer The pointer to the string. | ||
| */ | ||
| UTF8ToString(pointer: number): string; | ||
| /** | ||
| * Enables or disabled the fullscreen mode of the UnityInstance. | ||
| * @param fullScreen sets the fullscreen mode. | ||
| */ | ||
| SetFullscreen(fullScreen: UnityBooleanLike): void; | ||
| /** | ||
| * A reference to the Unity Instance's Canvas. | ||
| */ | ||
| canvas?: HTMLCanvasElement; | ||
| }; | ||
| /** | ||
| * UnityWebgl | ||
| * // new UnityWebgl(canvasElement, unityConfig, bridge) | ||
| * Type declaration for the UnityInstance. | ||
| */ | ||
| declare class UnityWebgl extends EventBus { | ||
| unityConfig: IUnityConfig; | ||
| canvasElement: HTMLCanvasElement | null; | ||
| unityLoader: (() => void) | null; | ||
| unityInstance: UnityInstance | null; | ||
| declare class UnityInstance { | ||
| /** | ||
| * UnityWebgl constructor | ||
| * @param canvas htmlCanvasElement | ||
| * @param config configuration | ||
| * @param bridge Bridge name, global communication collector. | ||
| * Creates a new instance of Unity Instance. | ||
| */ | ||
| constructor(config: IUnityConfig, bridge?: string); | ||
| constructor(canvas: CanvasElement, config: IUnityConfig, bridge?: string); | ||
| get bridge(): string; | ||
| set bridge(name: string); | ||
| constructor(); | ||
| /** | ||
| * 创建 Unity应用实例并渲染至画布 | ||
| * @param canvas 画布 | ||
| * @returns | ||
| * Sends a message to the UnityInstance to invoke a public method. | ||
| * @public | ||
| * @param objectName the name of the game object in your Unity scene. | ||
| * @param methodName the name of the public method on the game object. | ||
| * @param parameter an optional parameter to pass along to the method. | ||
| */ | ||
| create(canvas: CanvasElement): void; | ||
| SendMessage(objectName: string, methodName: string, parameter?: string | number | boolean): void; | ||
| /** | ||
| * 销毁并重新加载Unity应用 | ||
| * @param config 配置项 | ||
| * Enables or disabled the fullscreen mode of the UnityInstance. | ||
| * @public | ||
| * @param fullScreen sets the fullscreen mode. | ||
| */ | ||
| reload(config?: IUnityConfig): void; | ||
| SetFullscreen(fullScreen: UnityBooleanLike): void; | ||
| /** | ||
| * Quits the Unity WebGL application | ||
| * and removes it from the memory. | ||
| * @public | ||
| * @returns {Promise<void>} a promise whether the application did quit. | ||
| */ | ||
| Quit(): Promise<void>; | ||
| /** | ||
| * The Unity Module. | ||
| */ | ||
| Module: UnityModule; | ||
| } | ||
| type CanvasElementOrString = HTMLCanvasElement | string; | ||
| declare class UnityWebgl extends UnityWebglEvent { | ||
| private _config; | ||
| private _unity; | ||
| private _loader; | ||
| private _canvas; | ||
| constructor(canvas: CanvasElementOrString, config: UnityConfig); | ||
| constructor(config: UnityConfig); | ||
| /** | ||
| * Creating Unity Instance | ||
| * @param canvas The target html canvas element. | ||
| */ | ||
| create(canvas: CanvasElementOrString): Promise<void>; | ||
| /** | ||
| * Sends a message to the UnityInstance to invoke a public method. | ||
| * @param {string} objectName Unity scene name. | ||
| * @param {string} methodName public method name. | ||
| * @param {any} params an optional method parameter. | ||
| * @param {any} value an optional method parameter. | ||
| * @returns | ||
| */ | ||
| send(objectName: string, methodName: string, params?: any): this; | ||
| sendMessage(objectName: string, methodName: string, value?: any): this; | ||
| /** | ||
| * Asynchronously ask for the pointer to be locked on current canvas. To track | ||
| * the success or failure of the request, it is necessary to listen for the | ||
| * pointerlockchange and pointerlockerror events at the Document level. | ||
| * @public | ||
| * @deprecated Use sendMessage instead. | ||
| */ | ||
| send(objectName: string, methodName: string, value?: any): this; | ||
| /** | ||
| * Asynchronously ask for the pointer to be locked on current canvas. | ||
| * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestPointerLock | ||
@@ -334,9 +351,8 @@ */ | ||
| /** | ||
| * Takes a screenshot of the canvas and returns a data URL containing image | ||
| * data. The image data is in .png format unless otherwise specified. | ||
| * @param {string} dataType The image format of the screenshot, ["image/png" | "image/jpeg" | "image/webp"] | ||
| * @param {number} quality The quality of the jpg or webp screenshot | ||
| * @returns a data URL containing image data of a snapshot of the canvas | ||
| * Takes a screenshot of the canvas and returns a base64 encoded string. | ||
| * @param {string} dataType Defines the type of screenshot, e.g "image/jpeg" | ||
| * @param {number} quality Defines the quality of the screenshot, e.g 0.92 | ||
| * @returns A base 64 encoded string of the screenshot. | ||
| */ | ||
| takeScreenshot(dataType?: 'image/png' | 'image/jpeg' | 'image/webp', quality?: number): string | undefined; | ||
| takeScreenshot(dataType?: string, quality?: any): string | undefined; | ||
| /** | ||
@@ -352,5 +368,3 @@ * Enables or disabled the Fullscreen mode of the Unity Instance. | ||
| /** | ||
| * Detatches the Unity Instance from the React DOM, by doing so, the Unity | ||
| * Instance can be unloaded from the memory while the Unity component can be | ||
| * unmounted safely. | ||
| * 保障Unity组件可以安全卸载. 在unity实例从内存中销毁之前保障Dom存在. | ||
| * | ||
@@ -361,5 +375,5 @@ * Warning! This is a workaround for the fact that the Unity WebGL instances | ||
| */ | ||
| _unsafe_unload(): Promise<void>; | ||
| unsafe_unload(): Promise<void>; | ||
| } | ||
| export { UnityWebgl as default }; | ||
| export { type IWebGLContextAttributes, type UnityArguments, type UnityConfig, UnityInstance, UnityWebgl as default }; |
| /*! | ||
| * unity-webgl.js v3.5.6 | ||
| * (c) 2024 Mervin<mengqing723@gmail.com> | ||
| * Released under the MIT License. | ||
| * unity-webgl v4.0.0 | ||
| * Copyright (c) 2024 Mariner<mengqing723@gmail.com> | ||
| * Released under the Apache-2.0 License. | ||
| */ | ||
@@ -9,13 +9,13 @@ 'use strict'; | ||
| const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; | ||
| const isPlainObject = arg => Object.prototype.toString.call(arg) === '[object Object]'; | ||
| const msgPrefix = '[UnityWebgl]: '; | ||
| const log = (msg) => { | ||
| console.log(msgPrefix, msg); | ||
| }; | ||
| log.warn = (msg) => console.warn(msgPrefix, msg); | ||
| log.error = (msg) => console.error(msgPrefix, msg); | ||
| const getType = (value) => Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); | ||
| const isObject = (value) => getType(value) === 'object'; | ||
| function omit(obj, keys) { | ||
| const result = Object.assign({}, obj); | ||
| keys.forEach((key) => { | ||
| delete result[key]; | ||
| }); | ||
| return result; | ||
| } | ||
| /** | ||
| * query CanvasElement | ||
| * @param {string | HTMLCanvasElement} canvas | ||
| * @returns | ||
| */ | ||
@@ -26,106 +26,146 @@ function queryCanvas(canvas) { | ||
| } | ||
| else if (typeof canvas === 'string') { | ||
| return document.querySelector(canvas); | ||
| } | ||
| else { | ||
| log.warn('CanvasElement not found.'); | ||
| return null; | ||
| } | ||
| return document.querySelector(canvas); | ||
| } | ||
| class EventBus { | ||
| constructor(_eventMap = {}) { | ||
| this._eventMap = _eventMap; | ||
| class UnityWebglEvent { | ||
| constructor() { | ||
| this._e = {}; | ||
| if (isBrowser) { | ||
| // Register Unity event trigger to the window object | ||
| window.dispatchUnityEvent = (name, ...args) => { | ||
| if (!name.startsWith('unity:')) { | ||
| name = `unity:${name}`; | ||
| } | ||
| this.emit.apply(this, [name, ...args]); | ||
| }; | ||
| } | ||
| } | ||
| on(name, handler) { | ||
| if (typeof handler !== 'function') { | ||
| throw new TypeError(msgPrefix + 'The argument handler must be function'); | ||
| /** | ||
| * Register event listener | ||
| * @param name event name | ||
| * @param listener event listener | ||
| * @param options event listener options | ||
| */ | ||
| on(name, listener, options) { | ||
| if (typeof listener !== 'function') { | ||
| throw new TypeError('listener must be a function'); | ||
| } | ||
| this._eventMap[name] = handler; | ||
| if (!this._e[name]) { | ||
| this._e[name] = []; | ||
| } | ||
| if (options === null || options === void 0 ? void 0 : options.once) { | ||
| const onceListener = (...args) => { | ||
| this.off(name, onceListener); | ||
| listener.apply(this, args); | ||
| }; | ||
| onceListener._ = listener; | ||
| this._e[name].push(onceListener); | ||
| } | ||
| else { | ||
| this._e[name].push(listener); | ||
| } | ||
| return this; | ||
| } | ||
| off(name) { | ||
| delete this._eventMap[name]; | ||
| return this; | ||
| } | ||
| once(name, handler) { | ||
| const ctx = this; | ||
| function fn(...args) { | ||
| if (typeof handler === 'function') { | ||
| ctx.off(name); | ||
| handler.apply(ctx, args); | ||
| /** | ||
| * Remove event listener | ||
| * @param name event name | ||
| * @param listener event listener | ||
| */ | ||
| off(name, listener) { | ||
| if (!listener) { | ||
| delete this._e[name]; | ||
| } | ||
| else { | ||
| const listeners = this._e[name]; | ||
| if (listeners) { | ||
| this._e[name] = listeners.filter((l) => l !== listener && l._ !== listener); | ||
| } | ||
| } | ||
| return this.on(name, fn); | ||
| return this; | ||
| } | ||
| /** | ||
| * Dispatch event | ||
| * @param name event name | ||
| * @param args event args | ||
| */ | ||
| emit(name, ...args) { | ||
| const handler = this._eventMap[name]; | ||
| if (handler) { | ||
| handler.apply(this, args); | ||
| if (!this._e[name]) { | ||
| console.warn(`No listener for event ${name}`); | ||
| return this; | ||
| } | ||
| this._e[name].forEach((listener) => listener(...args)); | ||
| return this; | ||
| } | ||
| /** | ||
| * clear all event listeners | ||
| */ | ||
| clear() { | ||
| for (const name in this._eventMap) { | ||
| delete this._eventMap[name]; | ||
| this._e = {}; | ||
| } | ||
| /** | ||
| * Register event listener for unity client | ||
| * @param name event name | ||
| * @param listener event listener | ||
| */ | ||
| addUnityListener(name, listener, options) { | ||
| if (!name.startsWith('unity:')) { | ||
| name = `unity:${name}`; | ||
| } | ||
| return this.on(name, listener, options); | ||
| } | ||
| /** | ||
| * Remove event listener from unity client | ||
| * @param name event name | ||
| * @param listener event listener | ||
| */ | ||
| removeUnityListener(name, listener) { | ||
| if (!name.startsWith('unity:')) { | ||
| name = `unity:${name}`; | ||
| } | ||
| return this.off(name, listener); | ||
| } | ||
| } | ||
| /** | ||
| * The unity loader | ||
| * @param {string} src loaderUrl | ||
| * @param {object} callbackObj callbackObj | ||
| * @param {Function} callbackObj.resolve resolve | ||
| * @param {Function} callbackObj.reject reject | ||
| * @returns | ||
| * Loading Unity Loader Scripts | ||
| * @param src script src | ||
| * @param callbacks callbacks | ||
| */ | ||
| function unityLoader(src, { resolve, reject }) { | ||
| function unityLoader(src, callbacks = {}) { | ||
| const { resolve, reject } = callbacks; | ||
| if (!isBrowser) | ||
| return; | ||
| return null; | ||
| if (!src) { | ||
| reject && reject(new Error(`${msgPrefix} loaderUrl not found.`)); | ||
| return; | ||
| reject && reject(new Error(`${src} not found.`)); | ||
| return null; | ||
| } | ||
| /* if (typeof window.createUnityInstance === 'function') { | ||
| log('Unity Loader already exists') | ||
| resolve && resolve() | ||
| return | ||
| } */ | ||
| function handler(code) { | ||
| if (code === 'ready') { | ||
| if (code === 'loaded') { | ||
| resolve && resolve(); | ||
| } | ||
| else { | ||
| reject && reject(new Error(`${msgPrefix} ${src} loading failure.`)); | ||
| reject && reject(new Error(`${src} loading failure.`)); | ||
| } | ||
| } | ||
| let script = window.document.querySelector(`script[src="${src}"]`); | ||
| if (script === null) { | ||
| if (!script) { | ||
| script = window.document.createElement('script'); | ||
| script.type = 'text/javascript'; | ||
| script.src = src; | ||
| script.async = true; | ||
| script.setAttribute('data-status', 'loading'); | ||
| function setAttrListener(status) { | ||
| script === null || script === void 0 ? void 0 : script.setAttribute('data-status', status); | ||
| handler(status); | ||
| } | ||
| script.addEventListener('load', () => setAttrListener('loaded')); | ||
| script.addEventListener('error', () => setAttrListener('error')); | ||
| script.src = src; | ||
| window.document.body.appendChild(script); | ||
| const setAttributeFromEvent = function (event) { | ||
| const _status = event.type === 'load' ? 'ready' : 'error'; | ||
| script === null || script === void 0 ? void 0 : script.setAttribute('data-status', _status); | ||
| // handler(_status) | ||
| }; | ||
| script.addEventListener('load', setAttributeFromEvent); | ||
| script.addEventListener('error', setAttributeFromEvent); | ||
| } | ||
| else { | ||
| handler(script.getAttribute('data-status')); | ||
| handler(script.getAttribute('data-status') === 'loaded' ? 'loaded' : 'error'); | ||
| } | ||
| const setStateFromEvent = function (event) { | ||
| handler(event.type === 'load' ? 'ready' : 'error'); | ||
| }; | ||
| script.addEventListener('load', setStateFromEvent); | ||
| script.addEventListener('error', setStateFromEvent); | ||
| return function () { | ||
| if (script) { | ||
| script.removeEventListener('load', setStateFromEvent); | ||
| script.removeEventListener('error', setStateFromEvent); | ||
| window.document.body.removeChild(script); | ||
| // Return cleanup function | ||
| return function remove() { | ||
| if (script && script.parentNode) { | ||
| script.parentNode.removeChild(script); | ||
| } | ||
@@ -135,148 +175,103 @@ }; | ||
| let BRIDGE_NAME = '__UnityLib__'; | ||
| const defaultConfig = { | ||
| streamingAssetsUrl: 'StreamingAssets', | ||
| companyName: 'Unity', | ||
| productName: 'Unity' | ||
| }; | ||
| /** | ||
| * generate UnityInstance arguments | ||
| * @param {object} unityContext unityContext | ||
| * @returns | ||
| */ | ||
| function generateUnityArguments(unity) { | ||
| const unityInstanceArgs = Object.assign({}, unity.unityConfig); | ||
| unityInstanceArgs.print = function (message) { | ||
| unity.emit('debug', message); | ||
| function createUnityArgs(ctx, config) { | ||
| const unityArgs = omit(config, ['loaderUrl']); | ||
| unityArgs.print = function (msg) { | ||
| ctx.emit('debug', msg); | ||
| }; | ||
| unityInstanceArgs.printError = function (message) { | ||
| unity.emit('error', message); | ||
| unityArgs.printError = function (msg) { | ||
| ctx.emit('error', msg); | ||
| }; | ||
| // delete unityInstanceArgs['lodaderUrl'] | ||
| return unityInstanceArgs; | ||
| return unityArgs; | ||
| } | ||
| /** | ||
| * UnityWebgl | ||
| * // new UnityWebgl(canvasElement, unityConfig, bridge) | ||
| */ | ||
| class UnityWebgl extends EventBus { | ||
| constructor(canvas, config, bridge) { | ||
| let window; | ||
| window = globalThis || window; | ||
| bridge = bridge !== null && bridge !== void 0 ? bridge : BRIDGE_NAME; | ||
| if (isPlainObject(canvas) && typeof config === 'string') { | ||
| bridge = config || bridge; | ||
| class UnityWebgl extends UnityWebglEvent { | ||
| constructor(canvas, config) { | ||
| super(); | ||
| this._unity = null; | ||
| this._loader = null; | ||
| this._canvas = null; | ||
| if (!(typeof canvas === 'string' || canvas instanceof HTMLCanvasElement || isObject(canvas))) { | ||
| throw new TypeError('Parameter canvas is not valid'); | ||
| } | ||
| if (bridge in window) { | ||
| log.error(msgPrefix + `window.${bridge} already exists.`); | ||
| // config | ||
| if (isObject(canvas)) { | ||
| config = canvas; | ||
| } | ||
| BRIDGE_NAME = bridge; | ||
| super((window[bridge] = {})); | ||
| this.canvasElement = null; | ||
| this.unityLoader = null; | ||
| this.unityInstance = null; | ||
| if (isPlainObject(canvas)) { | ||
| this.unityConfig = Object.assign({}, defaultConfig, canvas); | ||
| if (!config || | ||
| !config.loaderUrl || | ||
| !config.dataUrl || | ||
| !config.frameworkUrl || | ||
| !config.codeUrl) { | ||
| throw new TypeError('UnityConfig is not valid'); | ||
| } | ||
| else { | ||
| this.unityConfig = Object.assign({}, defaultConfig, config); | ||
| const $canvas = queryCanvas(canvas); | ||
| if ($canvas) { | ||
| this.create($canvas); | ||
| } | ||
| this._config = config; | ||
| // canvas | ||
| if (typeof canvas === 'string' || canvas instanceof HTMLCanvasElement) { | ||
| this.create(canvas); | ||
| } | ||
| } | ||
| get bridge() { | ||
| return BRIDGE_NAME; | ||
| } | ||
| set bridge(name) { | ||
| //!window | ||
| window[name] = window[BRIDGE_NAME]; | ||
| delete window[BRIDGE_NAME]; | ||
| BRIDGE_NAME = name; | ||
| } | ||
| /** | ||
| * 创建 Unity应用实例并渲染至画布 | ||
| * @param canvas 画布 | ||
| * @returns | ||
| * Creating Unity Instance | ||
| * @param canvas The target html canvas element. | ||
| */ | ||
| create(canvas) { | ||
| if (!isBrowser) | ||
| return; | ||
| if (this.unityInstance && this.canvasElement && this.unityLoader) { | ||
| log.warn('Unity Instance already exists!'); | ||
| return void 0; | ||
| return Promise.resolve(); | ||
| if (this._unity && this._canvas && this._loader) { | ||
| console.warn('Unity instance already created'); | ||
| return Promise.resolve(); | ||
| } | ||
| const canvasElement = queryCanvas(canvas); | ||
| if (!canvasElement) { | ||
| log.warn('CanvasElement not found.'); | ||
| return void 0; | ||
| } | ||
| this.canvasElement = canvasElement; | ||
| const ctx = this; | ||
| const unityArguments = generateUnityArguments(this); | ||
| this.emit('beforeMount', this); | ||
| this.unityLoader = unityLoader(this.unityConfig.loaderUrl, { | ||
| resolve() { | ||
| try { | ||
| // Creates the Unity Instance, this method is made available globally by the Unity Loader. | ||
| window | ||
| .createUnityInstance(canvasElement, unityArguments, (val) => ctx.emit('progress', val)) | ||
| .then((unity) => { | ||
| ctx.unityInstance = unity; | ||
| ctx.emit('created', unity); // todo 待删除 | ||
| ctx.emit('mounted', ctx); | ||
| }) | ||
| .catch((err) => { | ||
| return new Promise((resolve, reject) => { | ||
| try { | ||
| const $canvas = queryCanvas(canvas); | ||
| if (!$canvas) { | ||
| throw new Error('CanvasElement is not found'); | ||
| } | ||
| this._canvas = $canvas; | ||
| const ctx = this; | ||
| // Create Unity instantiation Arguments | ||
| const unityArgs = createUnityArgs(this, this._config); | ||
| this.emit('beforeMount', this); | ||
| this._loader = unityLoader(this._config.loaderUrl, { | ||
| resolve() { | ||
| window | ||
| .createUnityInstance($canvas, unityArgs, (val) => ctx.emit('progress', val)) | ||
| .then((ins) => { | ||
| ctx._unity = ins; | ||
| ctx.emit('mounted', ctx, ins); | ||
| resolve(); | ||
| }) | ||
| .catch((err) => { | ||
| throw err; | ||
| }); | ||
| }, | ||
| reject(err) { | ||
| throw err; | ||
| }); | ||
| } | ||
| catch (err) { | ||
| ctx.unityInstance = null; | ||
| ctx.emit('error', err); | ||
| } | ||
| }, | ||
| reject(err) { | ||
| log.error(err.message); | ||
| ctx.emit('error', err); | ||
| }, | ||
| }); | ||
| } | ||
| catch (err) { | ||
| this._unity = null; | ||
| this.emit('error', err); | ||
| reject(err); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * 销毁并重新加载Unity应用 | ||
| * @param config 配置项 | ||
| */ | ||
| reload(config) { | ||
| var _a, _b; | ||
| const canvasElement = this.canvasElement || ((_b = (_a = this.unityInstance) === null || _a === void 0 ? void 0 : _a.Module) === null || _b === void 0 ? void 0 : _b.canvas); | ||
| if (this.unityInstance && canvasElement) { | ||
| this.unityInstance.Quit().then(() => { | ||
| this.unityLoader = null; | ||
| this.unityConfig = Object.assign({}, this.unityConfig, config); | ||
| this.emit('reload', this); | ||
| this.create(canvasElement); | ||
| }).catch(err => { | ||
| this.emit('error', err); | ||
| }); | ||
| } | ||
| } | ||
| /** | ||
| * Sends a message to the UnityInstance to invoke a public method. | ||
| * @param {string} objectName Unity scene name. | ||
| * @param {string} methodName public method name. | ||
| * @param {any} params an optional method parameter. | ||
| * @param {any} value an optional method parameter. | ||
| * @returns | ||
| */ | ||
| send(objectName, methodName, params) { | ||
| if (this.unityInstance) { | ||
| if (params === undefined || params === null) { | ||
| this.unityInstance.SendMessage(objectName, methodName); | ||
| } | ||
| else { | ||
| const _params = typeof params === 'object' ? JSON.stringify(params) : params; | ||
| this.unityInstance.SendMessage(objectName, methodName, _params); | ||
| } | ||
| sendMessage(objectName, methodName, value) { | ||
| if (!this._unity) { | ||
| console.warn('Unable to Send Message while Unity is not Instantiated.'); | ||
| return this; | ||
| } | ||
| if (value === undefined || value === null) { | ||
| this._unity.SendMessage(objectName, methodName); | ||
| } | ||
| else { | ||
| log.warn('Unable to Send Message while Unity is not Instantiated.'); | ||
| const _value = typeof value === 'object' ? JSON.stringify(value) : value; | ||
| this._unity.SendMessage(objectName, methodName, _value); | ||
| } | ||
@@ -286,35 +281,30 @@ return this; | ||
| /** | ||
| * Asynchronously ask for the pointer to be locked on current canvas. To track | ||
| * the success or failure of the request, it is necessary to listen for the | ||
| * pointerlockchange and pointerlockerror events at the Document level. | ||
| * @public | ||
| * @deprecated Use sendMessage instead. | ||
| */ | ||
| send(objectName, methodName, value) { | ||
| return this.sendMessage(objectName, methodName, value); | ||
| } | ||
| /** | ||
| * Asynchronously ask for the pointer to be locked on current canvas. | ||
| * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestPointerLock | ||
| */ | ||
| requestPointerLock() { | ||
| var _a, _b; | ||
| const canvasElement = this.canvasElement || ((_b = (_a = this.unityInstance) === null || _a === void 0 ? void 0 : _a.Module) === null || _b === void 0 ? void 0 : _b.canvas); | ||
| if (canvasElement) { | ||
| canvasElement.requestPointerLock(); | ||
| if (!this._unity || !this._unity.Module.canvas) { | ||
| console.warn('Unable to requestPointerLock while Unity is not Instantiated.'); | ||
| return; | ||
| } | ||
| this._unity.Module.canvas.requestPointerLock(); | ||
| } | ||
| /** | ||
| * Takes a screenshot of the canvas and returns a data URL containing image | ||
| * data. The image data is in .png format unless otherwise specified. | ||
| * @param {string} dataType The image format of the screenshot, ["image/png" | "image/jpeg" | "image/webp"] | ||
| * @param {number} quality The quality of the jpg or webp screenshot | ||
| * @returns a data URL containing image data of a snapshot of the canvas | ||
| * Takes a screenshot of the canvas and returns a base64 encoded string. | ||
| * @param {string} dataType Defines the type of screenshot, e.g "image/jpeg" | ||
| * @param {number} quality Defines the quality of the screenshot, e.g 0.92 | ||
| * @returns A base 64 encoded string of the screenshot. | ||
| */ | ||
| takeScreenshot(dataType = 'image/jpeg', quality) { | ||
| var _a, _b, _c; | ||
| const canvasElement = this.canvasElement || ((_b = (_a = this.unityInstance) === null || _a === void 0 ? void 0 : _a.Module) === null || _b === void 0 ? void 0 : _b.canvas); | ||
| if (!canvasElement) { | ||
| log.warn('Unable to Take Screenshot while Unity is not Instantiated or Canvas is not available.'); | ||
| takeScreenshot(dataType, quality) { | ||
| if (!this._unity || !this._unity.Module.canvas) { | ||
| console.warn('Unable to take Screenshot while Unity is not Instantiated.'); | ||
| return; | ||
| } | ||
| if (((_c = this.unityConfig.webglContextAttributes) === null || _c === void 0 ? void 0 : _c.preserveDrawingBuffer) !== true) { | ||
| log.warn('Taking a screenshot requires "preserveDrawingBuffer".'); | ||
| } | ||
| // Takes a screenshot by converting Canvas's render-context's buffer into | ||
| // a Data URL of the specified data type and quality. | ||
| return canvasElement.toDataURL(dataType, quality); | ||
| return this._unity.Module.canvas.toDataURL(dataType, quality); | ||
| } | ||
@@ -326,8 +316,7 @@ /** | ||
| setFullscreen(enabled) { | ||
| if (!this.unityInstance) { | ||
| // Guarding the Unity Instance. | ||
| log.warn('Unable to Set Fullscreen while Unity is not Instantiated.'); | ||
| if (!this._unity) { | ||
| console.warn('Unable to set Fullscreen while Unity is not Instantiated.'); | ||
| return; | ||
| } | ||
| this.unityInstance.SetFullscreen(enabled ? 1 : 0); | ||
| this._unity.SetFullscreen(enabled ? 1 : 0); | ||
| } | ||
@@ -338,21 +327,23 @@ /** | ||
| unload() { | ||
| if (!this.unityInstance) { | ||
| // Guarding the Unity Instance. | ||
| log.warn('Unable to Quit Unity while Unity is not Instantiated.'); | ||
| return Promise.reject(new Error('Unity is not Instantiated.')); | ||
| if (!this._unity) { | ||
| console.warn('Unable to Quit Unity while Unity is not Instantiated.'); | ||
| return Promise.reject(); | ||
| } | ||
| this.emit('beforeUnmount', this); | ||
| // Unmount unity.loader.js from the DOM | ||
| if (typeof this.unityLoader === 'function') { | ||
| this.unityLoader(); | ||
| this.unityLoader = null; | ||
| // Unmount unity.loader.js from DOM | ||
| if (typeof this._loader === 'function') { | ||
| this._loader(); | ||
| this._loader = null; | ||
| } | ||
| return this.unityInstance.Quit().then(() => { | ||
| this.unityInstance = null; | ||
| this.canvasElement = null; | ||
| delete window[BRIDGE_NAME]; | ||
| // Unmount unityInstance from memory | ||
| return this._unity | ||
| .Quit() | ||
| .then(() => { | ||
| this._unity = null; | ||
| this._canvas = null; | ||
| this.clear(); | ||
| this.emit('unmounted'); | ||
| this.emit('destroyed'); // todo 待删除 | ||
| }).catch((err) => { | ||
| log.error('Unable to Unload Unity'); | ||
| }) | ||
| .catch((err) => { | ||
| console.error('Unable to Unload Unity'); | ||
| this.emit('error', err); | ||
@@ -363,5 +354,3 @@ throw err; | ||
| /** | ||
| * Detatches the Unity Instance from the React DOM, by doing so, the Unity | ||
| * Instance can be unloaded from the memory while the Unity component can be | ||
| * unmounted safely. | ||
| * 保障Unity组件可以安全卸载. 在unity实例从内存中销毁之前保障Dom存在. | ||
| * | ||
@@ -372,7 +361,6 @@ * Warning! This is a workaround for the fact that the Unity WebGL instances | ||
| */ | ||
| _unsafe_unload() { | ||
| unsafe_unload() { | ||
| try { | ||
| if (this.unityInstance === null || !this.unityInstance.Module.canvas) { | ||
| // Guarding the Unity Instance. | ||
| log.warn('No Unity Instance found.'); | ||
| if (!this._unity || !this._unity.Module.canvas) { | ||
| console.warn('No Unity Instance found.'); | ||
| return Promise.reject(); | ||
@@ -383,9 +371,6 @@ } | ||
| // canvas will be hidden while it is being unloaded. | ||
| const canvas = this.unityInstance.Module.canvas; | ||
| const canvas = this._unity.Module.canvas; | ||
| document.body.appendChild(canvas); | ||
| canvas.style.display = 'none'; | ||
| // Unloads the Unity Instance. | ||
| return this.unload().then(() => { | ||
| // Eventually the canvas will be removed from the DOM. This has to be done | ||
| // manually since the canvas is no longer controlled by the React DOM. | ||
| canvas.remove(); | ||
@@ -395,3 +380,2 @@ }); | ||
| catch (e) { | ||
| log.error(e.message); | ||
| return Promise.reject(e); | ||
@@ -398,0 +382,0 @@ } |
| { | ||
| "name": "unity-webgl", | ||
| "version": "3.5.6", | ||
| "version": "4.0.0", | ||
| "description": "Unity-Webgl provides an easy solution for embedding Unity WebGL builds in your webApp or Vue.js project, with two-way communication between your webApp and Unity application with advanced API's.", | ||
| "main": "dist/index.js", | ||
| "module": "dist/index.esm.js", | ||
| "unpkg": "dist/index.global.js", | ||
| "jsdelivr": "dist/index.global.js", | ||
| "module": "dist/index.mjs", | ||
| "unpkg": "dist/index.min.js", | ||
| "jsdelivr": "dist/index.min.js", | ||
| "types": "dist/index.d.ts", | ||
@@ -13,11 +13,11 @@ "exports": { | ||
| "types": "./dist/index.d.ts", | ||
| "require": "./dist/index.js", | ||
| "import": "./dist/index.esm.js", | ||
| "default": "./dist/index.global.js" | ||
| "import": "./dist/index.mjs", | ||
| "module": "./dist/index.mjs", | ||
| "require": "./dist/index.js" | ||
| }, | ||
| "./vue": { | ||
| "types": "./vue/index.d.ts", | ||
| "require": "./vue/index.js", | ||
| "import": "./vue/index.esm.js", | ||
| "default": "./vue/index.global.js" | ||
| "types": "./dist/vue.d.ts", | ||
| "import": "./dist/vue.mjs", | ||
| "module": "./dist/vue.mjs", | ||
| "require": "./dist/vue.js" | ||
| }, | ||
@@ -27,12 +27,15 @@ "./*": "./*" | ||
| "files": [ | ||
| "dist", | ||
| "types", | ||
| "vue" | ||
| "dist" | ||
| ], | ||
| "treeShaking": true, | ||
| "scripts": { | ||
| "clean": "rimraf -rf ./dist && rimraf -rf ./vue", | ||
| "dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -w", | ||
| "build": "npm run clean && cross-env NODE_ENV=production rollup -c rollup.config.mjs" | ||
| "buildOptions": { | ||
| "input": "src/index.ts", | ||
| "filename": "dist/index", | ||
| "name": "UnityWebgl", | ||
| "dts": true | ||
| }, | ||
| "sideEffects": false, | ||
| "publishConfig": { | ||
| "access": "public", | ||
| "registry": "https://registry.npmjs.org/" | ||
| }, | ||
| "keywords": [ | ||
@@ -46,30 +49,17 @@ "unity webgl", | ||
| "unity3d player", | ||
| "vue unity", | ||
| "vue unity webgl", | ||
| "vue unity player" | ||
| "vue unity" | ||
| ], | ||
| "homepage": "https://github.com/Meqn/UnityWebGL.js", | ||
| "author": "Mariner <mengqing723@gmail.com>", | ||
| "license": "Apache-2.0", | ||
| "homepage": "https://github.com/Marinerer/unity-webgl", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/Meqn/UnityWebGL.js.git" | ||
| "url": "git+https://github.com/Marinerer/unity-webgl.git" | ||
| }, | ||
| "author": "Mervin <mengqing723@gmail.com>", | ||
| "license": "MIT", | ||
| "bugs": { | ||
| "url": "https://github.com/Meqn/UnityWebGL.js/issues" | ||
| "url": "https://github.com/Marinerer/jotter/issues" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public", | ||
| "registry": "https://registry.npmjs.org" | ||
| }, | ||
| "devDependencies": { | ||
| "@vue/composition-api": "^1.7.0", | ||
| "vue": "^3.2.38" | ||
| }, | ||
| "dependencies": { | ||
| "vue-demi": "latest" | ||
| }, | ||
| "peerDependencies": { | ||
| "@vue/composition-api": "^1.7.0", | ||
| "vue": "^2.5.0 || >=3.0.0" | ||
| "@vue/composition-api": "^1.7.2", | ||
| "vue": "^2.0.0 || >=3.0.0" | ||
| }, | ||
@@ -80,3 +70,9 @@ "peerDependenciesMeta": { | ||
| } | ||
| }, | ||
| "dependencies": { | ||
| "vue-demi": "latest" | ||
| }, | ||
| "scripts": { | ||
| "build": "node ../../scripts/build.mjs" | ||
| } | ||
| } | ||
| } |
506
README.md
@@ -6,24 +6,24 @@ # unity-webgl | ||
| [](https://bundlephobia.com/package/unity-webgl) | ||
| [](https://github.com/Meqn/UnityWebGL.js) | ||
| [](https://github.com/Meqn/UnityWebGL.js) | ||
| [](https://github.com/Marinerer/unity-webgl) | ||
| [ [English](https://github.com/Meqn/UnityWebGL.js/blob/main/README.md) | [中文](https://github.com/Meqn/UnityWebGL.js/blob/main/README.zh_CN.md) ] | ||
| [ English | [中文](./README.zh_CN.md) ] | ||
| `unity-webgl` provides an easy solution for embedding `Unity WebGL` builds in your web applications, with two-way communication and interaction between your webApp and Unity application with advanced API's. | ||
| > Framework agnostic, usable in any web project. | ||
| > Currently includes Vue components, supporting both Vue 2/3. | ||
| UnityWebGL.js provides an easy solution for embedding `Unity WebGL` builds in your `webApp` or `Vue.js` project, with two-way communication and interaction between your webApp and Unity application with advanced API's. | ||
| Based on [react-unity-webgl](https://github.com/jeffreylanters/react-unity-webgl) | ||
| ## Features | ||
| based on [react-unity-webgl](https://github.com/jeffreylanters/react-unity-webgl) | ||
| - 📦 Easy integration, framework-agnostic | ||
| - 📩 Bidirectional communication between WebApp and Unity | ||
| - ⏰ Comprehensive event handling mechanism | ||
| - 🧲 Built-in Vue components (vue2/3) | ||
| ## Features | ||
| - 📦 No framework restrictions, support any web project. | ||
| - 📬 two-way communication and interaction (`webApp` & `Unity`). | ||
| - 💌 Built-in event-listening mechanism. | ||
| - 🧲 On-demand import vue component. (Supports [Vue@2.x](https://stackblitz.com/edit/unity-webgl-vue2-demo?file=src%2FApp.vue) & [Vue@3.x](https://stackblitz.com/edit/unity-webgl-vue3-demo?file=src%2FApp.vue)) | ||
| ## Installation | ||
| ## Install | ||
| **npm** | ||
| ### npm | ||
| ```bash | ||
@@ -33,384 +33,310 @@ npm install unity-webgl | ||
| ### browser | ||
| ```bash | ||
| https://cdn.jsdelivr.net/npm/unity-webgl/dist/index.global.js | ||
| **Browser** | ||
| # vue component | ||
| https://cdn.jsdelivr.net/npm/unity-webgl/vue/index.global.js | ||
| ```html | ||
| <script src="https://cdn.jsdelivr.net/npm/unity-webgl/dist/index.min.js"></script> | ||
| ``` | ||
| ## Usage | ||
| ## Quick Start | ||
| > 🚨 Reminder: | ||
| > You can only communicate and interact with the web application once the `Unity` instance has been successfully created (i.e. the `mounted` event is triggered). | ||
| > It is recommended to add a loading when opening a page, wait for Unity resources to finish loading and close it. | ||
| - [Live Demo]() | ||
| - [vue2 Demo](https://stackblitz.com/edit/unity-webgl-vue2-demo) | ||
| - [vue3 Demo](https://stackblitz.com/edit/unity-webgl-vue3-demo) | ||
| ### html | ||
| <details> | ||
| <summary>html demo</summary> | ||
| > 🚨 **Important:** | ||
| > Communication and interaction with the web application are only possible after the Unity instance is successfully created (when the `mounted` event is triggered). | ||
| > Recommended to include a loading progress bar when opening the page. | ||
| ```html | ||
| <canvas id="canvas" style="width: 100%; height: 100%"></canvas> | ||
| ```javascript | ||
| import UnityWebgl from 'unity-webgl' | ||
| <button onclick="postMessage()">postMessage</button> | ||
| <button onclick="onFullscreen()">Fullscreen</button> | ||
| <button onclick="onUnload()">Unload</button> | ||
| <script> | ||
| var unityContext = new UnityWebgl('#canvas', { | ||
| loaderUrl: '/Build/unity.loader.js', | ||
| dataUrl: "/Build/unity.data", | ||
| frameworkUrl: "/Build/unity.framework.js", | ||
| codeUrl: "/Build/unity.wasm", | ||
| streamingAssetsUrl: "StreamingAssets", | ||
| companyName: "DefaultCompany", | ||
| productName: "Unity", | ||
| productVersion: "0.1", | ||
| const unityContext = new UnityWebgl('#canvas', { | ||
| loaderUrl: 'path/to/unity.loader.js', | ||
| dataUrl: 'path/to/unity.data', | ||
| frameworkUrl: 'path/to/unity.framework.js', | ||
| codeUrl: 'path/to/unity.code', | ||
| }) | ||
| unityContext | ||
| .on('progress', (progress) => console.log('Loaded: ', progress)) | ||
| .on('mounted', () => { | ||
| // ⚠️ Resources are loaded and ready to communicate with unity | ||
| unityContext.send('mainScene', 'init', {}) | ||
| console.log('Unity Instance created.') | ||
| }) | ||
| .on('unmounted', () => console.log('Unity Instance unmounted.')) | ||
| .on('progress', (progress) => console.log('Loaded: ', progress)) | ||
| .on('mounted', () => { | ||
| // ⚠️ Unity instance created, ready for communication | ||
| unityContext.sendMessage('GameObject', 'ReceiveRole', 'Tanya') | ||
| }) | ||
| function postMessage() { | ||
| unityContext.send('objectName', 'methodName', { | ||
| id: 'B0001', | ||
| name: 'Building#1', | ||
| location: [150, 75] | ||
| }) | ||
| } | ||
| function onUnload() { | ||
| unityContext.unload() | ||
| } | ||
| function onFullscreen() { | ||
| unityContext.setFullscreen(true) | ||
| } | ||
| </script> | ||
| ``` | ||
| You can also: | ||
| ```js | ||
| var unityContext = new UnityWebgl({ | ||
| loaderUrl: '/Build/unity.loader.js', | ||
| dataUrl: "/Build/unity.data", | ||
| frameworkUrl: "/Build/unity.framework.js", | ||
| codeUrl: "/Build/unity.wasm" | ||
| // For Unity to call | ||
| unityContext.addUnityListener('gameStart', (msg) => { | ||
| console.log('from Unity : ', msg) | ||
| }) | ||
| unityContext.create(document.querySelector('#canvas')) | ||
| // window.dispatchUnityEvent('gameStart', '{score: 0}') | ||
| ``` | ||
| </details> | ||
| ### Vue | ||
| - [Vue@2.x Live](https://stackblitz.com/edit/unity-webgl-vue2-demo?file=src%2FApp.vue) | ||
| - [Vue@3.x Live](https://stackblitz.com/edit/unity-webgl-vue3-demo?file=src/App.vue) | ||
| <details> | ||
| <summary>Vue demo</summary> | ||
| <summary>Vue Demo</summary> | ||
| ```html | ||
| <script setup> | ||
| import UnityWebgl from 'unity-webgl'; | ||
| import VueUnity from 'unity-webgl/vue' | ||
| import UnityWebgl from 'unity-webgl' | ||
| import VueUnity from 'unity-webgl/vue' | ||
| const unityContext = new UnityWebgl({ | ||
| loaderUrl: '/Build/OUT_BIM.loader.js', | ||
| dataUrl: "/Build/OUT_BIM.data", | ||
| frameworkUrl: "/Build/OUT_BIM.framework.js", | ||
| codeUrl: "/Build/OUT_BIM.wasm", | ||
| }) | ||
| const unityContext = new UnityWebgl({ | ||
| loaderUrl: 'path/to/unity.loader.js', | ||
| dataUrl: 'path/to/unity.data', | ||
| frameworkUrl: 'path/to/unity.framework.js', | ||
| codeUrl: 'path/to/unity.code', | ||
| }) | ||
| unityContext.on('device', () => alert('click device ...')) | ||
| unityContext.addUnityListener('gameStart', (msg) => { | ||
| console.log('from Unity : ', msg) | ||
| }) | ||
| </script> | ||
| <template> | ||
| <VueUnity :unity="unityContext" width="800" height="600" /> | ||
| <VueUnity :unity="unityContext" width="800" height="600" /> | ||
| </template> | ||
| ``` | ||
| </details> | ||
| ## API | ||
| ### Constructor | ||
| ## API | ||
| ```typescript | ||
| unityContext = new UnityWebgl( | ||
| canvas: HTMLCanvasElement | string, | ||
| config: IUnityConfig, | ||
| bridge?: string | ||
| ) | ||
| ``` | ||
| Or | ||
| ```typescript | ||
| // 1. Initialize UnityWebgl | ||
| unityContext = new UnityWebgl( | ||
| config: IUnityConfig, | ||
| bridge?: string | ||
| ) | ||
| new UnityWebgl(canvas: HTMLCanvasElement | string, config?:UnityConfig) | ||
| // 2. Create unity instance and render on canvas | ||
| // or | ||
| const unityContext = new UnityWebgl(config: UnityConfig) | ||
| unityContext.create(canvas: HTMLCanvasElement | string) | ||
| ``` | ||
| ### canvas | ||
| Rendering Unity's canvas elements | ||
| - type : `string | HTMLCanvasElement` | ||
| - `canvas` : Render Unity canvas elements or selectors. | ||
| - `config` : Initializes the Unity application's configuration items. | ||
| ### bridge | ||
| The name of the bridge to communicate with Unity. It mounts on window and is used to collect registered methods for Unity to call. | ||
| - type : `string` | ||
| - default : `__UnityLib__` | ||
| #### config | ||
| ### config | ||
| Initializes the configuration of the Unity application. | ||
| > The configuration must contain the four most basic properties `loaderUrl`, `dataUrl`, `frameworkUrl`, `codeUrl`, which are the resource files needed to initialize the Unity application. | ||
| Initializes the Unity application's configuration items. | ||
| | Property | Type | Description | | ||
| | ---------------------- | ---- | ----------- | | ||
| | `loaderUrl` ⭐️ | string | The url to the build json file generated by Unity | | ||
| | `dataUrl` ⭐️ | string | The url to the build data file generated by Unity | | ||
| | `frameworkUrl` ⭐️ | string | The url to the framework file generated by Unity | | ||
| | `codeUrl` ⭐️ | string | The url to the unity code file generated by Unity | | ||
| | `streamingAssetsUrl` | string | The url where the streaming assets can be found | | ||
| | `memoryUrl` | string | External memory file | | ||
| | `symbolsUrl` | string | Providing debugging symbols | | ||
| | `companyName` | string | The applications company name | | ||
| | `productName` | string | The applications product name | | ||
| | `productVersion` | string | The applications product version | | ||
| | `devicePixelRatio` | number | Uncomment this to override low DPI rendering on high DPI displays. see [MDN@devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) | | ||
| | `matchWebGLToCanvasSize` | boolean | Uncomment this to separately control WebGL canvas render size and DOM element size. see [unity3d@matchWebGLToCanvasSize](https://issuetracker.unity3d.com/issues/webgl-builds-dont-allow-separate-control-on-canvas-render-buffer-size) | | ||
| | `webglContextAttributes` | object | This object allow you to configure WebGLRenderingContext creation options. see [MDN@WebGLRenderingContext](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getContextAttributes) | | ||
| | Property | Type | Description | Required | | ||
| | ------------------------ | ------- | -------------------------------------------------------------------------------------------------- | -------- | | ||
| | `loaderUrl` | string | Unity resource loader file | ✅ | | ||
| | `dataUrl` | string | File containing resource data and scenes | ✅ | | ||
| | `frameworkUrl` | string | File with runtime and plugin code | ✅ | | ||
| | `codeUrl` | string | WebAssembly binary file with native code | ✅ | | ||
| | `streamingAssetsUrl` | string | URL for streaming resources | Optional | | ||
| | `memoryUrl` | string | URL for generated framework files | Optional | | ||
| | `symbolsUrl` | string | URL for generated Unity code files | Optional | | ||
| | `companyName` | string | Metadata: Company name | Optional | | ||
| | `productName` | string | Metadata: Product name | Optional | | ||
| | `productVersion` | string | Metadata: Product version | Optional | | ||
| | `devicePixelRatio` | number | Canvas device pixel ratio. @see[devicePixelRatio][devicePixelRatio-url] | Optional | | ||
| | `matchWebGLToCanvasSize` | boolean | Disable automatic WebGL canvas size sync. @see[matchWebGLToCanvasSize][matchWebGLToCanvasSize-url] | Optional | | ||
| | `webglContextAttributes` | object | WebGL rendering context options. @see[WebGLRenderingContext][webglContextAttributes-url] | Optional | | ||
| [devicePixelRatio-url]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio | ||
| [matchWebGLToCanvasSize-url]: https://issuetracker.unity3d.com/issues/webgl-builds-dont-allow-separate-control-on-canvas-render-buffer-size | ||
| [webglContextAttributes-url]: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getContextAttributes | ||
| ### Methods | ||
| UnityWebgl Instance Methods | ||
| #### `create(canvasElement: HTMLCanvasElement | string): void` | ||
| Create Unity instances and render them on the canvas. | ||
| - `canvasElement` : canvas canvas elements | ||
| **Instance methods :** | ||
| #### `unload(): Promise<void>` | ||
| Quits the Unity instance and clears it from memory so that Unmount from the DOM. | ||
| > The `unmounted` event will be triggered after the operation is completed. | ||
| #### ⭐️ `create(canvas: HTMLCanvasElement | string): void;` | ||
| #### `send(objectName: string, methodName: string, params?: any)` | ||
| ⭐️ Sends a message to the UnityInstance to invoke a public method. | ||
| - `objectName`: Where objectName is the name of an object in your scene. | ||
| - `methodName`: methodName is the name of a C-Sharp method in the script, currently attached to that object. | ||
| - `params`: Parameters can be any type of value or not defined at all. | ||
| Create a Unity WebGL instance on the specified canvas. | ||
| #### `on(eventName: string, eventListener: Function)` | ||
| ⭐️ Register an event or method to listen for the trigger event or for the Unity script to call. | ||
| - `canvas` : canvas element | ||
| #### `setFullscreen(enabled: boolean): void` | ||
| Enables or disabled the fullscreen mode of the UnityInstance. | ||
| ```javascript | ||
| await unityContext.create('#canvas') | ||
| ``` | ||
| #### `requestPointerLock(): void` | ||
| Allows you to asynchronously request that the mouse pointer be locked to the Canvas element of your Unity application. | ||
| #### ⭐️ `unload(): Promise<void>;` | ||
| #### `takeScreenshot(dataType: 'image/png' | 'image/jpeg' | 'image/webp', quality?: number)` | ||
| Takes a screenshot of the canvas and returns a data URL containing image data. | ||
| - `dataType`: the type of the image data | ||
| - `quality`: the quality of the image | ||
| Unload the Unity WebGL instance. | ||
| #### `once(eventName: string, eventListener: Function)` | ||
| The registration event is executed only once | ||
| ```javascript | ||
| await unityContext.unload() | ||
| ``` | ||
| #### `off(eventName: string)` | ||
| Cancel listening event | ||
| #### ⭐️ `sendMessage(objectName: string, methodName: string, value?: any): this;` | ||
| #### `emit(eventName: string)` | ||
| Trigger listening event | ||
| Send a message to invoke a public method in the Unity scene. | ||
| - `objectName`: Object Name in Unity Scene | ||
| - `methodName`: Unity script method name | ||
| - `value`: Passed value | ||
| ### Events | ||
| Events triggered by a Unity instance from creation to destruction. | ||
| #### beforeMount | ||
| Before Unity resources start loading. (The Unity instance has not been created yet.) | ||
| ```js | ||
| unityContext.on('beforeMount', (unityContext) => {}) | ||
| ```javascript | ||
| unityContext.sendMessage('GameObject', 'gameStart', { role: 'Tanya' }) | ||
| ``` | ||
| #### progress | ||
| Unity resource loading. (Show loading progress) | ||
| ```js | ||
| unityContext.on('progress', (number) => {}) | ||
| ``` | ||
| #### `requestPointerLock(): void;` | ||
| #### mounted | ||
| The Unity instance is successfully created and rendered. (At this point the webApp and Unity can communicate with each other) | ||
| ```js | ||
| unityContext.on('mounted', (unityContext) => {}) | ||
| ``` | ||
| Request pointer lock on the Unity canvas. | ||
| #### beforeUnmount | ||
| Before the Unity instance exits. | ||
| ```js | ||
| unityContext.on('beforeUnmount', (unityContext) => {}) | ||
| ``` | ||
| #### `takeScreenshot(dataType?: string, quality?: any): string | undefined;` | ||
| #### unmounted | ||
| The Unity instance has been exited and cleared from memory. | ||
| ```js | ||
| unityContext.on('unmounted', () => {}) | ||
| Capture a screenshot of the Unity canvas. | ||
| - `dataType`: Type of image data | ||
| - `quality`: Image quality | ||
| ```javascript | ||
| const screenshot = unityContext.takeScreenshot('image/jpeg', 0.92) | ||
| ``` | ||
| #### error | ||
| Error messages caught by Unity instances during creation. | ||
| ```js | ||
| unityContext.on('error', (error) => {}) | ||
| #### `setFullscreen(enabled: boolean): void;` | ||
| Toggle fullscreen mode. | ||
| ```javascript | ||
| unityContext.setFullscreen(true) | ||
| ``` | ||
| **Event methods :** | ||
| #### `on(name: string, listener: EventListener, options?: { once?: boolean }): this;` | ||
| ## Vue component | ||
| Vue components, compatible with `vue2.x` and `vue3.x`. | ||
| Register for listening events. | ||
| ### props | ||
| - `unity` : UnityWebgl instance. | ||
| - `width` : canvas element width, default: `100%` | ||
| - `height` : canvas element height, default: `100%` | ||
| - `tabindex` : Set the Canvas element tabindex. | ||
| ```javascript | ||
| unityContext.on('progress', (progress) => { | ||
| console.log('Progress:', progress) | ||
| }) | ||
| ``` | ||
| #### `off(name: string, listener?: EventListener): this;` | ||
| Remove event listener. | ||
| ## Communication | ||
| ```javascript | ||
| unityContext.off('progress', listener) | ||
| ``` | ||
| * [**WebGL: Interacting with browser scripting**@Unity3d.Docs](https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html) | ||
| **Unity Communication methods :** | ||
| ### Calling JavaScript functions from Unity scripts | ||
| #### `addUnityListener(name: string, listener: EventListener, options?: { once?: boolean }): this;` | ||
| 1, First, you should register a `showDialog` method, which be bind to the `__UnityLib__` global object by default. | ||
| Register a specific listener for Unity to call. | ||
| ```js | ||
| // # in webApp | ||
| const unityContext = new UnityWebgl() | ||
| // Register functions | ||
| unityContext.on('showDialog', (data) => { | ||
| console.log(data) | ||
| $('#dialog').show() | ||
| ```javascript | ||
| unityContext.addUnityListener('GameStarted', (level) => { | ||
| console.log('Game started at level:', level) | ||
| }) | ||
| // you also can call function. | ||
| unityContext.emit('showDialog', data) | ||
| // then call it in Unity | ||
| window.dispatchUnityEvent('GameStarted', 3) | ||
| ``` | ||
| 2, In the Unity project, add the registered `showDialog` method to the project, and then call those functions directly from your script code. To do so, place files with JavaScript code using the `.jslib` extension under a “Plugins” subfolder in your Assets folder. The plugin file needs to have a syntax like this: | ||
| #### `removeUnityListener(name: string, listener?: EventListener): this;` | ||
| ```js | ||
| // javascript_extend.jslib | ||
| Remove registered listeners. | ||
| mergeInto(LibraryManager.library, { | ||
| // this is you code | ||
| showDialog: function (str) { | ||
| // var data = Pointer_stringify(str); | ||
| var data = UTF8ToString(str); // In Unity 2021.2 onwards | ||
| // '__UnityLib__' is a global function collection. | ||
| __UnityLib__.showDialog(data); | ||
| }, | ||
| Hello: function () { | ||
| window.alert("Hello, world!"); | ||
| } | ||
| }); | ||
| ```javascript | ||
| unityContext.removeUnityListener('GameStarted', listener) | ||
| ``` | ||
| Then you can call these functions from your C# scripts like this: | ||
| ### `window.dispatchUnityEvent(name: string, ...args: any[])` | ||
| ```c# | ||
| using UnityEngine; | ||
| using System.Runtime.InteropServices; | ||
| The way to dispatch a registered listener on the Unity side. (Calling JS methods in unity) | ||
| public class NewBehaviourScript : MonoBehaviour { | ||
| ```javascript | ||
| window.dispatchUnityEvent('GameStarted', 3) | ||
| ``` | ||
| [DllImport("__Internal")] | ||
| private static extern void Hello(); | ||
| ### Events | ||
| [DllImport("__Internal")] | ||
| private static extern void showDialog(string str); | ||
| | Event Name | Description | | ||
| | --------------- | ---------------------------------------- | | ||
| | `beforeMount` | Triggered before Unity instance creation | | ||
| | `mounted` | Triggered after Unity instance creation | | ||
| | `beforeUnmount` | Triggered before Unity instance unload | | ||
| | `unmounted` | Triggered after Unity instance unload | | ||
| | `progress` | Unity resource loading progress | | ||
| | `error` | Error events | | ||
| | `debug` | Debug messages from Unity | | ||
| void Start() { | ||
| Hello(); | ||
| showDialog("This is a string."); | ||
| } | ||
| } | ||
| ``` | ||
| ## Unity-JavaScript Communication | ||
| ### Calling Unity scripts functions from JavaScript | ||
| - [Unity Docs: Interaction with browser scripting](https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html) | ||
| ```js | ||
| const Unity = new UnityWebgl() | ||
| ### 1. Call Unity script functions from JavaScript | ||
| ```javascript | ||
| const unityContext = new UnityWebgl() | ||
| /** | ||
| * Sends a message to the UnityInstance to invoke a public method. | ||
| * @param {string} objectName Unity scene name. | ||
| * @param {string} methodName public method name. | ||
| * @param {any} params an optional method parameter. | ||
| * @param {string} objectName Name of an object in your scene. | ||
| * @param {string} methodName Public method name. | ||
| * @param {any} value Passed value. | ||
| */ | ||
| Unity.send(objectName, methodName, params) | ||
| unityContext.sendMessage('GameObject', 'StartGame', { role: 'Tanya' }) | ||
| ``` | ||
| // e.g. Initialize Building#001 data | ||
| Unity.send('mainScene', 'init', { | ||
| id: 'b001', | ||
| name: 'building#001', | ||
| length: 95, | ||
| width: 27, | ||
| height: 120 | ||
| ### 2. Call JavaScript functions from Unity scripts | ||
| 1. First register the listener for Unity to call via `addUnityListener` on the web side. | ||
| ```javascript | ||
| unityContext.addUnityListener('gameStart', (level) => { | ||
| console.log('Game started at level:', level) | ||
| }) | ||
| ``` | ||
| 2. Add the registered `gameStart` method to your Unity project. | ||
| ```javascript | ||
| // javascript_extend.jslib | ||
| mergeInto(LibraryManager.library, { | ||
| Hello: function () { | ||
| window.alert('Hello, world!') | ||
| }, | ||
| ## ChangeLog | ||
| GameStart: function (level) { | ||
| //window.alert(UTF8ToString(str)); | ||
| window.dispatchUnityEvent('gameStart', UTF8ToString(level)) | ||
| }, | ||
| }) | ||
| ``` | ||
| ### v3.5.0 | ||
| #### 🚀 Features | ||
| - feat: Add `reload` method and event. | ||
| - perf: Optimize the `create` and `unload` methods. | ||
| 3. Call these functions in unity's `C#` scripts: | ||
| ```csharp | ||
| using UnityEngine; | ||
| using System.Runtime.InteropServices; | ||
| ### v3.4.0 | ||
| #### 🚀 Features | ||
| - feat: Add configuration and changes to the global object `bridge`. | ||
| - feat: Unify events from creation to destruction of Unity applications. | ||
| - Adds `beforeMount`, `mounted`, `beforeUnmount`, `unmounted` events; | ||
| - Remove `created`, `destroyed` events. | ||
| - perf: Simplify the built-in event listener. | ||
| - perf: Optimize built-in vue components. | ||
| - perf: update typescript types. | ||
| - perf: Unified error message alert. | ||
| - docs: Optimize the use of documentation. | ||
| public class WebGLPluginJS : MonoBehaviour | ||
| { | ||
| [DllImport("__Internal")] | ||
| public static extern void Hello(); | ||
| #### 🐞 Bug Fixes | ||
| - fix: Repair SPA unload error | ||
| [DllImport("__Internal")] | ||
| public static extern void GameStart(string level); | ||
| void Start() | ||
| { | ||
| Hello(); | ||
| GameStart("2"); | ||
| } | ||
| } | ||
| ``` | ||
| ### v3.0.0 | ||
| #### 🚀 Features | ||
| - feat: Rewrite in Typescript | ||
| - feat: Vue components are compatible with vue2.x and vue3.x | ||
| - perf: Introducing vue components on demand | ||
| ## Issues | ||
| #### 🐞 Bug Fixes | ||
| - fix: Fix createUnityInstance multiple times | ||
| - fix: Fix vue component width/height size problem | ||
| - [Keyboard Input and Focus Handling](https://docs.unity3d.com/Manual/webgl-input.html) | ||
| - [Debug and troubleshoot Web builds](https://docs.unity3d.com/Manual/webgl-debugging.html) | ||
| - [Web performance considerations](https://docs.unity3d.com/Manual/webgl-performance.html) | ||
| ### v2.x | ||
| - [v2.x Docs](https://github.com/Meqn/UnityWebGL.js/blob/v2.x/README.md) | ||
| ## Contributing | ||
| ### v1.x | ||
| - [v1.x Docs](https://github.com/Meqn/UnityWebGL.js/blob/v1.x/README.md) | ||
| Contributions are welcome! Please submit a [Pull Request](https://github.com/Marinerer/unity-webgl/pulls). | ||
| ## License | ||
| Apache-2.0 License | ||
| ## Support | ||
| For issues or questions, please file an issue on the [GitHub repository](https://github.com/Marinerer/unity-webgl). |
@@ -6,419 +6,338 @@ # unity-webgl | ||
| [](https://bundlephobia.com/package/unity-webgl) | ||
| [](https://github.com/Meqn/UnityWebGL.js) | ||
| [](https://github.com/Meqn/UnityWebGL.js) | ||
| [](https://github.com/Marinerer/unity-webgl) | ||
| [ [English](https://github.com/Meqn/UnityWebGL.js/blob/main/README.md) | [中文](https://github.com/Meqn/UnityWebGL.js/blob/main/README.zh_CN.md) ] | ||
| [ [English](./README.md) | 中文 ] | ||
| `unity-webgl` 提供了一个简单的解决方案,用于将 `Unity WebGL` 构建嵌入到 Web 应用程序中,同时为 Unity 和 WebApp 应用之间的双向通信和交互提供 API。 | ||
| > 无框架限制,可用于任何 Web 项目。 | ||
| > 目前仅内置vue组件,支持 `vue2/3`。 | ||
| UnityWebgl.js 提供了一种简单的解决方案,用于将 `Unity WebGL` 构建嵌入到 Web 应用程序中,同时为 `Unity` 和 `WebApp` 应用之间的双向通信和交互提供 API。 | ||
| Based on [react-unity-webgl](https://github.com/jeffreylanters/react-unity-webgl) | ||
| > 无框架限制,可用于任何web项目。 | ||
| > 目前仅内置vue组件,支持`vue2.x`和`vue3.x`。 | ||
| based on [react-unity-webgl](https://github.com/jeffreylanters/react-unity-webgl) | ||
| ## Features | ||
| - 📦 无框架限制,支持任何web项目; | ||
| - 📬 支持在`WebApp` 和 `Unity` 之间双向通信和交互; | ||
| - 💌 使用事件监听机制,调用简单灵活; | ||
| - 🧲 按需引入vue组件,兼容[Vue@2.x](https://stackblitz.com/edit/unity-webgl-vue2-demo?file=src%2FApp.vue) 和 [Vue@3.x](https://stackblitz.com/edit/unity-webgl-vue3-demo?file=src%2FApp.vue)。 | ||
| 📦 集成简单,无框架限制 | ||
| 📩 支持 `WebApp` 与 `Unity` 双向通信和交互 | ||
| ⏰ 全面的事件处理机制 | ||
| 🧲 内置 `vue` 组件 (vue2/3) | ||
| ## Installation | ||
| ## Install | ||
| **npm** | ||
| ### npm | ||
| ```bash | ||
| ``` | ||
| npm install unity-webgl | ||
| ``` | ||
| ### browser | ||
| ```bash | ||
| https://cdn.jsdelivr.net/npm/unity-webgl/dist/index.global.js | ||
| **browser** | ||
| # vue component | ||
| https://cdn.jsdelivr.net/npm/unity-webgl/vue/index.global.js | ||
| ``` | ||
| https://cdn.jsdelivr.net/npm/unity-webgl/dist/index.min.js | ||
| ``` | ||
| ## Usage | ||
| ## Quick Start | ||
| - [Live Demo]() | ||
| - [vue2 Demo](https://stackblitz.com/edit/unity-webgl-vue2-demo) | ||
| - [vue3 Demo](https://stackblitz.com/edit/unity-webgl-vue3-demo) | ||
| > 🚨 提醒: | ||
| > 只有当`Unity`实例创建成功之后(即触发 `mounted` 事件)才能和web应用程序进行通信和交互。 | ||
| > 建议在打开页面时添加一个 loading,等待Unity资源加载完毕后关闭即可。 | ||
| > 仅在 `Unity` 实例成功创建后(触发 `mounted` 事件时)才能进行 Web 应用程序的通信和交互。 | ||
| > 建议在页面打开时添加加载进度条。 | ||
| ### html | ||
| <details> | ||
| <summary>html demo</summary> | ||
| ```javascript | ||
| import UnityWebgl from 'unity-webgl' | ||
| ```html | ||
| <canvas id="canvas" style="width: 100%; height: 100%"></canvas> | ||
| <button onclick="postMessage()">postMessage</button> | ||
| <button onclick="onFullscreen()">Fullscreen</button> | ||
| <button onclick="onUnload()">Unload</button> | ||
| <script> | ||
| var unityContext = new UnityWebgl('#canvas', { | ||
| loaderUrl: '/Build/unity.loader.js', | ||
| dataUrl: "/Build/unity.data", | ||
| frameworkUrl: "/Build/unity.framework.js", | ||
| codeUrl: "/Build/unity.wasm", | ||
| streamingAssetsUrl: "StreamingAssets", | ||
| companyName: "DefaultCompany", | ||
| productName: "Unity", | ||
| productVersion: "0.1", | ||
| const unityContext = new UnityWebgl('#canvas', { | ||
| loaderUrl: 'path/to/unity.loader.js', | ||
| dataUrl: 'path/to/unity.data', | ||
| frameworkUrl: 'path/to/unity.framework.js', | ||
| codeUrl: 'path/to/unity.code', | ||
| }) | ||
| unityContext | ||
| .on('progress', (progress) => console.log('Loaded: ', progress)) | ||
| .on('mounted', () => { | ||
| // ⚠️ 资源加载完成,可与unity进行通信 | ||
| unityContext.send('mainScene', 'init', {}) | ||
| console.log('Unity Instance created.') | ||
| }) | ||
| .on('unmounted', () => console.log('Unity Instance unmounted.')) | ||
| .on('progress', (progress) => console.log('Loaded: ', progress)) | ||
| .on('mounted', () => { | ||
| // ⚠️ unity实例已创建,可与unity侧进行通信 | ||
| unityContext.sendMessage('GameObject', 'ReceiveRole', 'Tanya') | ||
| }) | ||
| function postMessage() { | ||
| unityContext.send('objectName', 'methodName', { | ||
| id: 'B0001', | ||
| name: 'Building#1', | ||
| location: [150, 75] | ||
| }) | ||
| } | ||
| function onUnload() { | ||
| unityContext.unload() | ||
| } | ||
| function onFullscreen() { | ||
| unityContext.setFullscreen(true) | ||
| } | ||
| </script> | ||
| ``` | ||
| You can also: | ||
| ```js | ||
| var unityContext = new UnityWebgl({ | ||
| loaderUrl: '/Build/unity.loader.js', | ||
| dataUrl: "/Build/unity.data", | ||
| frameworkUrl: "/Build/unity.framework.js", | ||
| codeUrl: "/Build/unity.wasm" | ||
| // 供unity 端调用 | ||
| unityContext.addUnityListener('gameStart', (msg) => { | ||
| console.log('from Unity : ', msg) | ||
| }) | ||
| unityContext.create(document.querySelector('#canvas')) | ||
| // window.dispatchUnityEvent('gameStart', '{score: 0}') | ||
| ``` | ||
| </details> | ||
| ### Vue | ||
| - [Vue@2.x Live](https://stackblitz.com/edit/unity-webgl-vue2-demo?file=src%2FApp.vue) | ||
| - [Vue@3.x Live](https://stackblitz.com/edit/unity-webgl-vue3-demo?file=src/App.vue) | ||
| <details> | ||
| <summary>Vue demo</summary> | ||
| <summary>Vue Demo</summary> | ||
| ```html | ||
| <script setup> | ||
| import UnityWebgl from 'unity-webgl'; | ||
| import VueUnity from 'unity-webgl/vue' | ||
| import UnityWebgl from 'unity-webgl' | ||
| import VueUnity from 'unity-webgl/vue' | ||
| const unityContext = new UnityWebgl({ | ||
| loaderUrl: '/Build/OUT_BIM.loader.js', | ||
| dataUrl: "/Build/OUT_BIM.data", | ||
| frameworkUrl: "/Build/OUT_BIM.framework.js", | ||
| codeUrl: "/Build/OUT_BIM.wasm", | ||
| }) | ||
| const unityContext = new UnityWebgl({ | ||
| loaderUrl: 'path/to/unity.loader.js', | ||
| dataUrl: 'path/to/unity.data', | ||
| frameworkUrl: 'path/to/unity.framework.js', | ||
| codeUrl: 'path/to/unity.code', | ||
| }) | ||
| unityContext.on('device', () => alert('click device ...')) | ||
| unityContext.addUnityListener('gameStart', (msg) => { | ||
| console.log('from Unity : ', msg) | ||
| }) | ||
| </script> | ||
| <template> | ||
| <VueUnity :unity="unityContext" width="800" height="600" /> | ||
| <VueUnity :unity="unityContext" width="800" height="600" /> | ||
| </template> | ||
| ``` | ||
| </details> | ||
| ## API | ||
| ### Constructor | ||
| ## API | ||
| ```typescript | ||
| unityContext = new UnityWebgl( | ||
| canvas: HTMLCanvasElement | string, | ||
| config: IUnityConfig, | ||
| bridge?: string | ||
| ) | ||
| ``` | ||
| 或 | ||
| ```typescript | ||
| // 1. 初始化 UnityWebgl | ||
| unityContext = new UnityWebgl( | ||
| config: IUnityConfig, | ||
| bridge?: string | ||
| ) | ||
| new UnityWebgl(canvas: HTMLCanvasElement | string, config?:UnityConfig) | ||
| // 2. 创建unity实例,并在canvas上渲染 | ||
| // or | ||
| const unityContext = new UnityWebgl(config: UnityConfig) | ||
| unityContext.create(canvas: HTMLCanvasElement | string) | ||
| ``` | ||
| > 备注: | ||
| > `unityContext` : 表示 `UnityWebgl`实例; | ||
| > `unityInstance` : 表示 Unity应用程序实例。 | ||
| - `canvas` : 渲染Unity的画布元素或选择器。 | ||
| - `config` : 初始化 Unity 应用程序的配置项。 | ||
| ### canvas | ||
| 渲染Unity的画布元素 | ||
| - type : `string | HTMLCanvasElement` | ||
| #### config | ||
| ### bridge | ||
| 与Unity通信的桥接名称。它挂载window上,用于收集已注册的方法供Unity调用。 | ||
| - type : `string` | ||
| - default : `__UnityLib__` | ||
| 初始化 Unity 应用程序的配置项。 | ||
| ### config | ||
| 初始化 Unity 应用程序的配置项。 | ||
| > 配置项必须包含最基本的四个属性`loaderUrl`, `dataUrl`, `frameworkUrl`, `codeUrl` ,这四个属性都是初始化 Unity 应用程序所需的资源文件。 | ||
| | Property | Type | Description | Required | | ||
| | ------------------------ | ------- | ------------------------------------------------------------------------------------- | -------- | | ||
| | `loaderUrl` | string | Unity 资源加载器文件 | ✅ | | ||
| | `dataUrl` | string | 包含资源数据和场景的文件 | ✅ | | ||
| | `frameworkUrl` | string | 包含运行时和插件代码的文件 | ✅ | | ||
| | `codeUrl` | string | 包含原生代码的 WebAssembly 二进制文件 | ✅ | | ||
| | `streamingAssetsUrl` | string | 流媒体资源的 URL | 可选 | | ||
| | `memoryUrl` | string | 生成的框架文件的 URL | 可选 | | ||
| | `symbolsUrl` | string | 生成的 Unity 代码文件的 URL | 可选 | | ||
| | `companyName` | string | 元数据:公司名称 | 可选 | | ||
| | `productName` | string | 元数据:产品名称 | 可选 | | ||
| | `productVersion` | string | 元数据:产品版本 | 可选 | | ||
| | `devicePixelRatio` | number | 画布设备像素比率. @see[devicePixelRatio][devicePixelRatio-url] | 可选 | | ||
| | `matchWebGLToCanvasSize` | boolean | 禁用 WebGL 画布大小自动同步. @see[matchWebGLToCanvasSize][matchWebGLToCanvasSize-url] | 可选 | | ||
| | `webglContextAttributes` | object | WebGL 渲染上下文选项. @see[WebGLRenderingContext][webglContextAttributes-url] | 可选 | | ||
| | Property | Type | Description | | ||
| | ---------------------- | ---- | ----------- | | ||
| | `loaderUrl` ⭐️ | string | Unity资源加载器文件 | | ||
| | `dataUrl` ⭐️ | string | 包含资源数据和场景的文件 | | ||
| | `frameworkUrl` ⭐️ | string | 包含运行时和插件代码的文件 | | ||
| | `codeUrl` ⭐️ | string | 包含本机代码的 Web Assembly 二进制文件 | | ||
| | `streamingAssetsUrl` | string | 可以找到流媒体资源的网址 | | ||
| | `memoryUrl` | string | 生成的框架文件的网址 | | ||
| | `symbolsUrl` | string | 生成的unity代码文件的网址 | | ||
| | `companyName` | string | 元数据: 公司名称 | | ||
| | `productName` | string | 元数据: 产品名称 | | ||
| | `productVersion` | string | 元数据: 产品版本 | | ||
| | `devicePixelRatio` | number | 设置画布的设备像素比率. @详见[MDN@devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) | | ||
| | `matchWebGLToCanvasSize` | boolean | 禁用WebGL画布的渲染尺寸自动同步标识。@详见[unity3d@matchWebGLToCanvasSize](https://issuetracker.unity3d.com/issues/webgl-builds-dont-allow-separate-control-on-canvas-render-buffer-size) | | ||
| | `webglContextAttributes` | object | 配置 WebGLRenderingContext 创建选项。@详见[MDN@WebGLRenderingContext](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getContextAttributes) | | ||
| [devicePixelRatio-url]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio | ||
| [matchWebGLToCanvasSize-url]: https://issuetracker.unity3d.com/issues/webgl-builds-dont-allow-separate-control-on-canvas-render-buffer-size | ||
| [webglContextAttributes-url]: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getContextAttributes | ||
| ### Methods | ||
| **Instance methods :** | ||
| ### Methods | ||
| UnityWebgl 实例方法 | ||
| #### ⭐️ `create(canvas: HTMLCanvasElement | string): void;` | ||
| #### `create(canvasElement: HTMLCanvasElement | string): void` | ||
| 创建Unity实例并在画布上渲染。 | ||
| - `canvasElement` : canvas画布元素 | ||
| 在指定画布上创建 Unity WebGL 实例。 | ||
| #### `unload(): Promise<void>` | ||
| 退出Unity实例并将其从内存中清除,以便从DOM中Unmount。此时也会删除所有已注册的方法。 | ||
| > 操作完成之后会触发 `unmounted` 事件 | ||
| - `canvas` : canvas画布元素 | ||
| #### `send(objectName: string, methodName: string, params?: any)` | ||
| ⭐️ 向Unity实例对象发送消息,调用一个公共方法。 | ||
| - `objectName`: Unity场景中对象的名称 | ||
| - `methodName`: Unity脚本中方法的名称 | ||
| - `params`: 传递的参数 | ||
| ```javascript | ||
| await unityContext.create('#canvas') | ||
| ``` | ||
| #### `on(eventName: string, eventListener: Function)` | ||
| ⭐️ 注册一个事件或方法,用于监听触发事件或供Unity脚本调用。 | ||
| #### ⭐️ `unload(): Promise<void>;` | ||
| #### `setFullscreen(enabled: boolean): void` | ||
| 启用或禁用 Unity 画布的全屏模式。 | ||
| 卸载 Unity WebGL 实例。 | ||
| #### `requestPointerLock(): void` | ||
| 允许您异步地请求将鼠标指针锁定在Unity应用的Canvas元素上。 | ||
| ```javascript | ||
| await unityContext.unload() | ||
| ``` | ||
| #### `takeScreenshot(dataType: 'image/png' | 'image/jpeg' | 'image/webp', quality?: number)` | ||
| 获取画布的屏幕截图并返回包含图像数据的数据 URL。 | ||
| - `dataType`: 图像数据的类型 | ||
| - `quality`: 图像的质量 | ||
| #### ⭐️ `sendMessage(objectName: string, methodName: string, value?: any): this;` | ||
| #### `once(eventName: string, eventListener: Function)` | ||
| 注册事件仅执行一次 | ||
| 向 `Unity` 场景中发送消息以调用公共方法。 | ||
| #### `off(eventName: string)` | ||
| 取消监听事件 | ||
| - `objectName`: Unity场景中对象名称 | ||
| - `methodName`: Unity脚本中方法名称 | ||
| - `value`: 传递的值 | ||
| #### `emit(eventName: string)` | ||
| 触发监听事件 | ||
| ```javascript | ||
| unityContext.sendMessage('GameObject', 'gameStart', { role: 'Tanya' }) | ||
| ``` | ||
| #### `requestPointerLock(): void;` | ||
| ### Events | ||
| Unity 实例从创建到销毁过程中触发的事件。 | ||
| 请求锁定 Unity 画布的指针。 | ||
| #### beforeMount | ||
| Unity 资源开始加载之前。(此时Unity实例还未创建) | ||
| ```js | ||
| unityContext.on('beforeMount', (unityContext) => {}) | ||
| ``` | ||
| #### `takeScreenshot(dataType?: string, quality?: any): string | undefined;` | ||
| #### progress | ||
| Unity 资源加载中。(显示加载进度) | ||
| ```js | ||
| unityContext.on('progress', (number) => {}) | ||
| ``` | ||
| 对 Unity 画布进行屏幕截图并返回包含图像数据的数据 URL。 | ||
| #### mounted | ||
| Unity 实例创建成功,并完成渲染。(此时webApp与Unity可以相互通信) | ||
| ```js | ||
| unityContext.on('mounted', (unityContext) => {}) | ||
| ``` | ||
| - `dataType`: 图像数据的类型 | ||
| - `quality`: 图像的质量 | ||
| #### beforeUnmount | ||
| Unity 实例退出之前。 | ||
| ```js | ||
| unityContext.on('beforeUnmount', (unityContext) => {}) | ||
| ```javascript | ||
| const screenshot = unityContext.takeScreenshot('image/jpeg', 0.92) | ||
| ``` | ||
| #### unmounted | ||
| Unity实例已退出并将其从内存中清除。 | ||
| ```js | ||
| unityContext.on('unmounted', () => {}) | ||
| ``` | ||
| #### `setFullscreen(enabled: boolean): void;` | ||
| #### error | ||
| Unity实例在创建过程中捕获的错误信息 | ||
| ```js | ||
| unityContext.on('error', (error) => {}) | ||
| 切换全屏模式。 | ||
| ```javascript | ||
| unityContext.setFullscreen(true) | ||
| ``` | ||
| **Event methods :** | ||
| #### `on(name: string, listener: EventListener, options?: { once?: boolean }): this;` | ||
| ## Vue component | ||
| Vue组件,兼容 `vue2.x` 和 `vue3.x` | ||
| 监听事件。 | ||
| ### props | ||
| - `unity` : UnityWebgl实例 | ||
| - `width` : canvas元素宽度, default: `100%` | ||
| - `height` : canvas元素高度, default: `100%` | ||
| - `tabindex` : 设置Canvas元素tabindex | ||
| ```javascript | ||
| unityContext.on('progress', (progress) => { | ||
| console.log('Progress:', progress) | ||
| }) | ||
| ``` | ||
| #### `off(name: string, listener?: EventListener): this;` | ||
| 移除事件监听器。 | ||
| ## Communication | ||
| ```javascript | ||
| unityContext.off('progress', listener) | ||
| ``` | ||
| * [Unity3d官方文档:**WebGL:与浏览器脚本交互**](https://docs.unity3d.com/cn/2020.3/Manual/webgl-interactingwithbrowserscripting.html) | ||
| **Unity Communication methods :** | ||
| ### 从 Unity 脚本调用 JavaScript 函数 | ||
| #### `addUnityListener(name: string, listener: EventListener, options?: { once?: boolean }): this;` | ||
| 1. 先在前端项目中通过 `Unity.on()` 注册 `showDialog` 方法,该方法会默认绑定在 `window['__UnityLib__']`对象上。 | ||
| 注册特定监听器供 Unity 端调用。 | ||
| ```js | ||
| // # in webApp | ||
| const unityContext = new UnityWebgl() | ||
| // Register functions | ||
| unityContext.on('showDialog', (data) => { | ||
| console.log(data) | ||
| $('#dialog').show() | ||
| ```javascript | ||
| unityContext.addUnityListener('GameStarted', (level) => { | ||
| console.log('Game started at level:', level) | ||
| }) | ||
| // you also can call function. | ||
| unityContext.emit('showDialog', data) | ||
| // then call it in Unity | ||
| window.dispatchUnityEvent('GameStarted', 3) | ||
| ``` | ||
| 2. 在Unity项目中,将注册的`showDialog`方法添加到项目中。 | ||
| 注意📢 :请使用 `.jslib` 扩展名将包含 JavaScript 代码的文件放置在 Assets 文件夹中的“Plugins”子文件夹下。插件文件需要有如下所示的语法: | ||
| #### `removeUnityListener(name: string, listener?: EventListener): this;` | ||
| ```js | ||
| // javascript_extend.jslib | ||
| 移除注册的监听器。 | ||
| mergeInto(LibraryManager.library, { | ||
| // this is you code | ||
| showDialog: function (str) { | ||
| // var data = Pointer_stringify(str); | ||
| var data = UTF8ToString(str); | ||
| // '__UnityLib__' is a global function collection. | ||
| __UnityLib__.showDialog(data); | ||
| }, | ||
| Hello: function () { | ||
| window.alert("Hello, world!"); | ||
| } | ||
| }); | ||
| ```javascript | ||
| unityContext.removeUnityListener('GameStarted', listener) | ||
| ``` | ||
| 然后你可以像这样从C#脚本中调用这些函数: | ||
| ### `window.dispatchUnityEvent(name: string, ...args: any[])` | ||
| ```c# | ||
| using UnityEngine; | ||
| using System.Runtime.InteropServices; | ||
| 在 Unity 端派发注册的监听器的方式。(在 unity 中调用 JS 的方法) | ||
| public class NewBehaviourScript : MonoBehaviour { | ||
| ```javascript | ||
| window.dispatchUnityEvent('GameStarted', 3) | ||
| ``` | ||
| [DllImport("__Internal")] | ||
| private static extern void Hello(); | ||
| ### Events | ||
| [DllImport("__Internal")] | ||
| private static extern void showDialog(string str); | ||
| Unity 实例从创建到销毁过程中触发的事件。 | ||
| void Start() { | ||
| Hello(); | ||
| showDialog("This is a string."); | ||
| } | ||
| } | ||
| ``` | ||
| | event name | description | | ||
| | ----------------------------- | ----------------------- | | ||
| | `beforeMount(unityContext)` | 创建 Unity 实例之前触发 | | ||
| | `mounted(unityContext)` | 创建 Unity 实例后触发 | | ||
| | `beforeUnmount(unityContext)` | 卸载 Unity 实例之前触发 | | ||
| | `unmounted()` | 卸载 Unity 实例后触发 | | ||
| | `progress(val: number)` | unity 资源加载进度更新 | | ||
| | `error(err: Event\|string)` | 发生错误 | | ||
| | `debug(msg: string)` | 来自 Unity 的调试消息 | | ||
| ### 使用 JavaScript 调用 Unity 脚本函数 | ||
| ## Unity-JavaScript Communication | ||
| ```js | ||
| const Unity = new UnityWebgl() | ||
| - [Unity官方文档:与浏览器脚本交互](https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html) | ||
| ### 1. Call Unity script functions from JavaScript | ||
| ```javascript | ||
| const unityContext = new UnityWebgl() | ||
| /** | ||
| * Sends a message to the UnityInstance to invoke a public method. | ||
| * @param {string} objectName Unity scene name. | ||
| * @param {string} objectName name of an object in your scene. | ||
| * @param {string} methodName public method name. | ||
| * @param {any} params an optional method parameter. | ||
| * @param {any} value send value. | ||
| */ | ||
| Unity.send(objectName, methodName, params) | ||
| unityContext.sendMessage('GameObject', 'StartGame', { role: 'Tanya' }) | ||
| ``` | ||
| // e.g. Initialize Building#001 data | ||
| Unity.send('mainScene', 'init', { | ||
| id: 'b001', | ||
| name: 'building#001', | ||
| length: 95, | ||
| width: 27, | ||
| height: 120 | ||
| ### 2. Call JavaScript functions from Unity scripts | ||
| 1. 首先在 web 端通过 `addUnityListener` 注册供 Unity 调用的监听器。 | ||
| ```javascript | ||
| unityContext.addUnityListener('gameStart', (level) => { | ||
| console.log('Game started at level:', level) | ||
| }) | ||
| ``` | ||
| 2. 在Unity项目中,将注册的 `gameStart` 方法添加到项目中。 | ||
| ```javascript | ||
| // javascript_extend.jslib | ||
| mergeInto(LibraryManager.library, { | ||
| Hello: function () { | ||
| window.alert('Hello, world!') | ||
| }, | ||
| ## ChangeLog | ||
| GameStart: function (level) { | ||
| //window.alert(UTF8ToString(str)); | ||
| window.dispatchUnityEvent('gameStart', UTF8ToString(level)) | ||
| }, | ||
| }) | ||
| ``` | ||
| ### v3.5.0 | ||
| #### 🚀 Features | ||
| - feat: 新增 `reload` 方法和事件 | ||
| - perf: 优化 `create` 和 `unload` 方法 | ||
| 3. 在 `C#` 脚本中调用这些函数: | ||
| ### v3.4.0 | ||
| #### 🚀 Features | ||
| - feat: 增加全局对象`bridge`的配置和更改 | ||
| - feat: 统一化Unity应用程序从创建到销毁的事件 | ||
| - 增加 `beforeMount`, `mounted`, `beforeUnmount`, `unmounted` 事件 | ||
| - 移除 `created`, `destroyed` 事件 | ||
| - perf: 简化内置事件监听器 | ||
| - perf: 优化内置vue组件 | ||
| - perf: 更新typescript types | ||
| - perf: 统一错误信息提示 | ||
| - docs: 优化使用文档 | ||
| ```csharp | ||
| using UnityEngine; | ||
| using System.Runtime.InteropServices; | ||
| #### 🐞 Bug Fixes | ||
| - fix: 修复单页应用unload报错 | ||
| public class WebGLPluginJS : MonoBehaviour | ||
| { | ||
| [DllImport("__Internal")] | ||
| public static extern void Hello(); | ||
| [DllImport("__Internal")] | ||
| public static extern void GameStart(string level); | ||
| ### v3.0.0 | ||
| #### 🚀 Features | ||
| - feat: 使用Typescript重写 | ||
| - feat: Vue组件兼容vue2.x和vue3.x | ||
| - perf: 按需引入vue component | ||
| void Start() | ||
| { | ||
| Hello(); | ||
| GameStart("2"); | ||
| } | ||
| } | ||
| ``` | ||
| #### 🐞 Bug Fixes | ||
| - fix: 修复createUnityInstance执行多次 | ||
| - fix: 修复vue组件width/height尺寸问题 | ||
| ## Issues | ||
| ### v2.x | ||
| - [v2.x文档](https://github.com/Meqn/UnityWebGL.js/blob/v2.x/README.md) | ||
| - [键盘输入和焦点处理](https://docs.unity3d.com/cn/2023.2/Manual/webgl-input.html) | ||
| - [调试 WebGL 构建并排除故障](https://docs.unity3d.com/cn/2023.2/Manual/webgl-debugging.html) | ||
| - [WebGL 性能考虑因素](https://docs.unity3d.com/cn/2023.2/Manual/webgl-performance.html) | ||
| ### v1.x | ||
| - [v1.x文档](https://github.com/Meqn/UnityWebGL.js/blob/v1.x/README.md) | ||
| ## License | ||
| MIT License | ||
| ## Contributing | ||
| Contributions are welcome! Please feel free to submit a [Pull Request](https://github.com/Marinerer/unity-webgl/pulls). | ||
| ## Support | ||
| For issues or questions, please file an issue on the [GitHub repository](https://github.com/Marinerer/unity-webgl). |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
0
-100%94532
-9.86%1311
-0.46%1
Infinity%341
-17.83%1
Infinity%