#javascript #internet-explorer #unity3d #unityscript
#javascript #internet-Explorer #unity-игровой движок #unityscript
Вопрос:
Я работаю над проектом, который имеет эти атрибуты:
- jQuery управляет страницей
- Unity 3d Player встроен в страницу с помощью jQuery и
unityobject.js
(согласно инструкции от Unity) - У Unity есть пользовательский курсор мыши, когда курсор пользователя находится внутри области холста Unity
Проблема: Unity фиксирует курсор мыши, но не выпускает его, когда веб-страница, содержащая его, становится неактивной. Это означает, что если пользователь переключается на другую вкладку (или открывает новое окно), курсор мыши исчезает, когда пользователь наводит курсор мыши на область, где должен был находиться Unity. Это ошибка unity, описанная здесь, на форуме Unity 3d: http://forum.unity3d.com/threads/4565-Unity-Web-player-issue-mouse-hidden-for-all-new-windows
И нет, это все еще не исправлено в последней версии веб-клиента Unity.
Чтобы смягчить проблему, мы решили заставить Unity прослушивать текущее состояние окна браузера с помощью Javascript и захватывать / отпускать пользовательский курсор мыши на основе получаемого им статуса. Но есть и другие проблемы:
Как Unity получает статус окна:
// GetUnity returns the Unity object in the DOM<br>
NAMESPACE.windowStatus = function( statusStr ) {
GetUnity().SendMessage( "_AppShell", "OnRecieveWindowStatusFromWebPage", statusStr );
}
Я пробовал следующие методы…
Способ 1: Привязка событий к объекту «window»
$( window ).live( 'focus', function() {
NAMESPACE.windowStatus( 'active' );
} );
$( window ).live( 'blur', function() {
NAMESPACE.windowStatus( 'inactive' );
} );
Проблема: в IE7 и IE8 новые вкладки браузера не считаются разными «окнами», поэтому код не влияет на Unity. Это работает только в том случае, если было открыто настоящее отдельное окно браузера.
Способ 2: Привязка событий к объекту «document»
Как такое: $( document ).live(...);
Проблема: $( document )
в jQuery фактически ничего не делает. Выяснил на собственном горьком опыте.
Источник: http://forum.jquery.com/topic/should-document-live-map-to-document-bind-window-too
Метод 3: Привязка событий к <body>
объекту
Как такое: $( 'body' ).live(...);
Проблема: каким-то образом IE не распознает, что объект Unity является частью DOM (несмотря на использование .live()
метода). Таким образом, каждый раз, когда пользователь нажимает на встроенный проигрыватель Unity, браузер отправляет blur
событие в Unity, и курсор мыши блокируется ( console.log()
распечатывается inactive
при нажатии на Unity). И в некоторых случаях он даже не отпускает курсор мыши, делая весь браузер невосприимчивым к событиям мыши; единственный способ освободить курсор — щелкнуть за пределами окна браузера и снова щелкнуть в браузере).
Другие вещи, которые я пробовал:
window.addEventListener( 'focus', function() {...} );
document.addEventListener( 'focus', function() {...} );
document.body.addEventListener( 'focus', function() {...} );
document.getElementsByTagName('body')[0].addEventListener( 'focus', function() {...} );
Проблема: .addEventListener()
метод вообще не поддерживается в IE для этих элементов! БОЖЕ!
Бонус:
Более наблюдательные из вас могут сказать: «Эй, почему бы не обнаружить событие щелчка мыши в самом объекте Unity и проигнорировать blur
событие, .live()
или .bind()
events». Пробовал это. IE это тоже не нравится. Он полностью игнорирует событие и говорит, что эти события недоступны для объекта.
Итак, мои коллеги-гуру Javascript. У меня закончились идеи о том, как наилучшим образом элегантно подойти к этой проблеме. Любые указания были бы оценены.
Ответ №1:
Проблема решена. Решение было предоставлено на форуме Unity3d, где-то спрятанном … http://forum.unity3d.com/threads/27516-Mouse-input-possible-from-different-tab
Суть этого такова: фреймворки не всегда являются ответом. Вернитесь к корням.
Я забыл, что .addEventListener()
не является родным для IE, .attachEvent()
есть. Итак, мой приведенный выше код сработал бы, если бы я просто заменил все прослушиватели событий специфичными для IE при обнаружении IE.
Итак, измененный код выглядит следующим образом:
if ( navigator.appName == 'Microsoft Internet Explorer' ) {
GetUnity().attachEvent( 'onmouseover', onFocus, false );
GetUnity().attachEvent( 'onfocusin', onFocus, false );
GetUnity().attachEvent( 'onmouseout', onBlur, false );
} else {
// Netscape, Firefox, Mozilla, Chrome and Safari.
GetUnity().addEventListener( 'mouseover', onFocus, false );
GetUnity().addEventListener( 'focus', onFocus, false );
GetUnity().addEventListener( 'mouseout', onBlur, false );
}
function onFocus() {
NAMESPACE.WindowStatus( 'active' );
}
function onBlur() {
NAMESPACE.WindowStatus( 'inactive' );
}
Чтобы это действительно сработало, вам пришлось бы создавать вложения событий в функции обратного вызова unityobject.embedUnity()
метода. Если вы попытаетесь прикрепить события до загрузки Unity, браузер будет жаловаться, что GetUnity()
это null
или undefined
.
Надеюсь, это поможет кому-то, кто ломает голову над теми же проблемами.