Создание камеры HoverCamera3D

Материал из AlternativaPlatform Wiki

Перейти к: навигация, поиск

Часто поведение нативного контроллера Альтернативы SimpleObjectController не удовлетворяет потребностям. Давайте создадим один из стандартных обработчиков событий мыши — камеру, реагирующую на положение мыши пользователя в сцене. Подобное поведение очень удобно для радиального просмотра единичных объектов, потому как камера движется вокруг объекта. Правда в одной плоскости. Но расширить пример будет достаточно просто впоследствии.


Итак, давайте наследуем стандартную камеру Альтернативы — Camera3D.
public class HoverCamera3D extends Camera3D {}

Чтобы реагировать на события мыши на сцене передадим в конструктор ссылку на объект stage, ведь без реагирования на события мыши наша задумка не будет иметь смысла, а снимать эти события мы будем именно со сцены. Также, для того, чтобы определить положение камеры будем считать, что камера всегда смотрит в одну точку. Настроить эту точку мы дадим возможность пользователю также через конструктор, передав в него расстояние до камеры от точки наблюдения и саму эту точку. В конструкторе нашей камеры после выполнения конструктора родительского класса выполняем действия по настройке камеры:

super();
if (!stage)
    throw new Error("HoverCamera3D must have link on stage object in passing parameters of constructor!");
_stage = stage;
_cameraTarget = target || new Vector3D(0, 0, 0);
_distance = distance;

Далее, будем помнить, что пользователь может изменить размер сцены и тогда наши данные о ней будут не актуальны, поэтому подпишемся на событие изменения размеров сцены

addEventListener(Event.RESIZE, resizeListener);

и будем контролировать горизонтальный максимум смещения в слушателе события resizeListener

_maxX = _stage.stageWidth >> 1;

Далее в конструкторе настраиваем положение камеры, согласно наших исходных данных:

var m:Matrix3D = matrix;
m.appendTranslation(0, 0, _distance);
m.appendRotation(-_tiltAngle, new Vector3D(1, 0, 0), _cameraTarget);
m.appendRotation(-_panAngle, new Vector3D(0, 1, 0), _cameraTarget);
matrix = m;

Также нужно создать геттеры и сеттеры для параметров камеры, чтобы пользователь мог их менять по необходимости:

Для удобства управления камерой также создадим два дополнительных метода: changeTiltAngle (меняет угол наклона камеры вверх-вниз, в градусах), changePanAngle (меняет угол поворота камеры влево-вправо, в градусах).

Все подготовительные действия совершены. Теперь переходим к самому интересному — переопределим метод render камеры. Так как он должен вызываться в каждом кадре приложения, в нем мы и будем анимировать камеру в зависимости от положения мыши. Для этого определим величину на которую мышь отклонена от центра:

var dx:Number = _stage.mouseX - _maxX;

На основании этой величины при условии, что она лежит вне "мертвой зоны", мы будем менять положение нашей камеры:

if (Math.abs(dx) - _limit > .001) {
    var m:Matrix3D = matrix;
    m.appendRotation(dx * _factor, new Vector3D(0, 1, 0), _cameraTarget);
    matrix = m;
}

Не забываем о логике родительского класса:

super.render();

Наш простой контроллер камеры, интегрированный в саму камеру для удобства готов. Вот код всего класса:

package
{
    import alternativa.engine3d.core.Camera3D;
    import flash.display.Stage;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import flash.events.Event;
 
 
    public class HoverCamera3D extends Camera3D {
 
        private var _stage:Stage = null;
        private var _distance:Number = -200;
        private var _factor:Number = .005;
        private var _limit:Number = 50.;
        private var _maxX:Number = 0;
        private var _cameraTarget:Vector3D = new Vector3D(0, 0, 0);
 
        public function HoverCamera3D (stage:Stage, tiltAngle:Number = 30, panAngle:Number = 0, distance:Number = -200, target:Vector3D = null) {
            super();
            if (!stage)
                throw new Error("HoverCamera3D must have link on stage object in passing parameters of constructor!");
            _stage = stage;
            _cameraTarget = target || new Vector3D(0, 0, 0);
            _distance = distance;
 
            resizeListener(null);
            addEventListener(Event.RESIZE, resizeListener);
            var m:Matrix3D = matrix;
            m.appendTranslation(0, 0, _distance);
            m.appendRotation(-tiltAngle, new Vector3D(1, 0, 0), _cameraTarget);
            m.appendRotation(panAngle, new Vector3D(0, 1, 0), _cameraTarget);
            matrix = m;
        }
 
        public override function render():void {
            var dx:Number = _stage.mouseX - _maxX;
            if (Math.abs(dx) - _limit > .001) {
                var m:Matrix3D = matrix;
                m.appendRotation(dx * _factor, new Vector3D(0, 1, 0), _cameraTarget);
                matrix = m;
            }
 
            super.render();
        }
 
        public function set factor (n:Number):void {
            _factor = n;
        }
 
        public function get factor ():Number {
            return _factor;
        }
 
        public function set limit (n:Number):void {
            _limit = n;
        }
 
        public function get limit ():Number {
            return _limit;
        }
 
        public function changeTiltAngle (n:Number):void {
            var m:Matrix3D = matrix;
            m.appendRotation(-n, new Vector3D(1, 0, 0), _cameraTarget);
            matrix = m;
        }
 
        public function changePanAngle (n:Number):void {
            var m:Matrix3D = matrix;
            m.appendRotation(n, new Vector3D(0, 1, 0), _cameraTarget);
            matrix = m;
        }
 
        private function resizeListener (e:Event):void {
            _maxX = _stage.stageWidth >> 1;
        }
 
    }
 
}

Далее для работы нашей камеры можете её размещать в любом проекте Альтернативы 7 вместо стандартной камеры Camera3D. Контроллер SimpleObjectController в этом случае не нужен.

Вопрос оптимизации производительности данного примера оставлю открытым.

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

Код урока можно загрузить отсюда.

Личные инструменты
Пространства имён
Варианты
Действия
Навигация
Category
Инструменты
На других языках