Remove .svn folders

This commit is contained in:
Pyogenics
2024-10-05 14:02:34 +01:00
parent 51adb7f3ad
commit 1548517cf6
4897 changed files with 3 additions and 709425 deletions

View File

@@ -1,29 +0,0 @@
K 25
svn:wc:ra_dav:version-url
V 103
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/controllers
END
FlyController.as
K 25
svn:wc:ra_dav:version-url
V 120
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/controllers/FlyController.as
END
WalkController.as
K 25
svn:wc:ra_dav:version-url
V 121
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/controllers/WalkController.as
END
ObjectController.as
K 25
svn:wc:ra_dav:version-url
V 123
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/controllers/ObjectController.as
END
CameraController.as
K 25
svn:wc:ra_dav:version-url
V 123
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/controllers/CameraController.as
END

View File

@@ -1,76 +0,0 @@
8
dir
46043
http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/controllers
http://svndev.alternativaplatform.com
2008-09-08T06:50:26.103978Z
468
mike
svn:special svn:externals svn:needs-lock
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
FlyController.as
file
2010-10-28T04:31:16.000000Z
819162f5f890b890eca280272d1c4dd8
2008-08-29T11:41:21.451513Z
304
wolf
WalkController.as
file
2010-10-28T04:31:16.000000Z
67cb497ffc9a536d65065dacb16a99be
2008-09-08T06:50:26.103978Z
468
mike
ObjectController.as
file
2010-10-28T04:31:16.000000Z
20fdfabe14732c8fb81c041f142da4a4
2008-08-29T11:41:21.451513Z
304
wolf
CameraController.as
file
2010-10-28T04:31:16.000000Z
cc1c7ecdc58c115dcdab53d2ea0ef1d9
2008-08-29T11:41:21.451513Z
304
wolf

View File

@@ -1,889 +0,0 @@
package alternativa.engine3d.controllers {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.physics.EllipsoidCollider;
import alternativa.types.Map;
import alternativa.types.Matrix3D;
import alternativa.types.Point3D;
import alternativa.types.Set;
import alternativa.utils.KeyboardUtils;
import alternativa.utils.MathUtils;
import flash.display.DisplayObject;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.utils.getTimer;
use namespace alternativa3d;
/**
* Контроллер камеры. Контроллер обеспечивает управление движением и поворотами камеры с использованием
* клавиатуры и мыши, а также предоставляет простую проверку столкновений камеры с объектами сцены.
*/
public class CameraController {
/**
* Имя действия для привязки клавиш движения вперёд.
*/
public static const ACTION_FORWARD:String = "ACTION_FORWARD";
/**
* Имя действия для привязки клавиш движения назад.
*/
public static const ACTION_BACK:String = "ACTION_BACK";
/**
* Имя действия для привязки клавиш движения влево.
*/
public static const ACTION_LEFT:String = "ACTION_LEFT";
/**
* Имя действия для привязки клавиш движения вправо.
*/
public static const ACTION_RIGHT:String = "ACTION_RIGHT";
/**
* Имя действия для привязки клавиш движения вверх.
*/
public static const ACTION_UP:String = "ACTION_UP";
/**
* Имя действия для привязки клавиш движения вниз.
*/
public static const ACTION_DOWN:String = "ACTION_DOWN";
// public static const ACTION_ROLL_LEFT:String = "ACTION_ROLL_LEFT";
// public static const ACTION_ROLL_RIGHT:String = "ACTION_ROLL_RIGHT";
/**
* Имя действия для привязки клавиш увеличения угла тангажа.
*/
public static const ACTION_PITCH_UP:String = "ACTION_PITCH_UP";
/**
* Имя действия для привязки клавиш уменьшения угла тангажа.
*/
public static const ACTION_PITCH_DOWN:String = "ACTION_PITCH_DOWN";
/**
* Имя действия для привязки клавиш уменьшения угла рысканья (поворота налево).
*/
public static const ACTION_YAW_LEFT:String = "ACTION_YAW_LEFT";
/**
* Имя действия для привязки клавиш увеличения угла рысканья (поворота направо).
*/
public static const ACTION_YAW_RIGHT:String = "ACTION_YAW_RIGHT";
/**
* Имя действия для привязки клавиш увеличения скорости.
*/
public static const ACTION_ACCELERATE:String = "ACTION_ACCELERATE";
// флаги действий
private var _forward:Boolean;
private var _back:Boolean;
private var _left:Boolean;
private var _right:Boolean;
private var _up:Boolean;
private var _down:Boolean;
private var _pitchUp:Boolean;
private var _pitchDown:Boolean;
private var _yawLeft:Boolean;
private var _yawRight:Boolean;
private var _accelerate:Boolean;
private var _moveLocal:Boolean = true;
// Флаг включения управления камерой
private var _controlsEnabled:Boolean = false;
// Значение таймера в начале прошлого кадра
private var lastFrameTime:uint;
// Чувствительность обзора мышью. Коэффициент умножения базовых коэффициентов поворотов.
private var _mouseSensitivity:Number = 1;
// Коэффициент поворота камеры по тангажу. Значение угла в радианах на один пиксель перемещения мыши по вертикали.
private var _mousePitch:Number = Math.PI / 360;
// Результирующий коэффициент поворота камеры мышью по тангажу
private var _mousePitchCoeff:Number = _mouseSensitivity * _mousePitch;
// Коэффициент поворота камеры по рысканью. Значение угла в радианах на один пиксель перемещения мыши по горизонтали.
private var _mouseYaw:Number = Math.PI / 360;
// Результирующий коэффициент поворота камеры мышью по расканью
private var _mouseYawCoeff:Number = _mouseSensitivity * _mouseYaw;
// Вспомогательные переменные для обзора мышью
private var mouseLookActive:Boolean;
private var startDragCoords:Point = new Point();
private var currentDragCoords:Point = new Point();
private var prevDragCoords:Point = new Point();
private var startRotX:Number;
private var startRotZ:Number;
// Скорость изменения тангажа в радианах за секунду при управлении с клавиатуры
private var _pitchSpeed:Number = 1;
// Скорость изменения рысканья в радианах за секунду при управлении с клавиатуры
private var _yawSpeed:Number = 1;
// Скорость изменения крена в радианах за секунду при управлении с клавиатуры
// public var bankSpeed:Number = 2;
// private var bankMatrix:Matrix3D = new Matrix3D();
// Скорость поступательного движения в единицах за секунду
private var _speed:Number = 100;
// Коэффициент увеличения скорости при соответствующей нажатой клавише
private var _speedMultiplier:Number = 2;
private var velocity:Point3D = new Point3D();
private var destination:Point3D = new Point3D();
private var _fovStep:Number = Math.PI / 180;
private var _zoomMultiplier:Number = 0.1;
// Привязка клавиш к действиям
private var keyBindings:Map = new Map();
// Привязка действий к обработчикам
private var actionBindings:Map = new Map();
// Источник событий клавиатуры и мыши
private var _eventsSource:DisplayObject;
// Управляемая камера
private var _camera:Camera3D;
// Класс реализации определния столкновений
private var _collider:EllipsoidCollider;
// Флаг необходимости проверки столкновений
private var _checkCollisions:Boolean;
// Радиус сферы для определения столкновений
private var _collisionRadius:Number = 0;
// Набор исключаемых из проверки столкновений объектов
private var _collisionIgnoreSet:Set = new Set(true);
// Флаг движения
private var _isMoving:Boolean;
private var _onStartMoving:Function;
private var _onStopMoving:Function;
/**
* Создание экземпляра контроллера.
*
* @param eventsSourceObject объект, используемый для получения событий мыши и клавиатуры
*/
public function CameraController(eventsSourceObject:DisplayObject) {
if (eventsSourceObject == null) {
throw new ArgumentError("CameraController: eventsSource is null");
}
_eventsSource = eventsSourceObject;
actionBindings[ACTION_FORWARD] = forward;
actionBindings[ACTION_BACK] = back;
actionBindings[ACTION_LEFT] = left;
actionBindings[ACTION_RIGHT] = right;
actionBindings[ACTION_UP] = up;
actionBindings[ACTION_DOWN] = down;
actionBindings[ACTION_PITCH_UP] = pitchUp;
actionBindings[ACTION_PITCH_DOWN] = pitchDown;
actionBindings[ACTION_YAW_LEFT] = yawLeft;
actionBindings[ACTION_YAW_RIGHT] = yawRight;
actionBindings[ACTION_ACCELERATE] = accelerate;
}
/**
* Установка привязки клавиш по умолчанию. Данный метод очищает все существующие привязки клавиш и устанавливает следующие:
* <table border="1" style="border-collapse: collapse">
* <tr><th>Клавиша</th><th>Действие</th></tr>
* <tr><td>W</td><td>ACTION_FORWARD</td></tr>
* <tr><td>S</td><td>ACTION_BACK</td></tr>
* <tr><td>A</td><td>ACTION_LEFT</td></tr>
* <tr><td>D</td><td>ACTION_RIGHT</td></tr>
* <tr><td>SPACE</td><td>ACTION_UP</td></tr>
* <tr><td>CONTROL</td><td>ACTION_DOWN</td></tr>
* <tr><td>SHIFT</td><td>ACTION_ACCELERATE</td></tr>
* <tr><td>UP</td><td>ACTION_PITCH_UP</td></tr>
* <tr><td>DOWN</td><td>ACTION_PITCH_DOWN</td></tr>
* <tr><td>LEFT</td><td>ACTION_YAW_LEFT</td></tr>
* <tr><td>RIGHT</td><td>ACTION_YAW_RIGHT</td></tr>
* </table>
*/
public function setDefaultBindings():void {
unbindAll();
bindKey(KeyboardUtils.W, ACTION_FORWARD);
bindKey(KeyboardUtils.S, ACTION_BACK);
bindKey(KeyboardUtils.A, ACTION_LEFT);
bindKey(KeyboardUtils.D, ACTION_RIGHT);
bindKey(KeyboardUtils.SPACE, ACTION_UP);
bindKey(KeyboardUtils.CONTROL, ACTION_DOWN);
bindKey(KeyboardUtils.UP, ACTION_PITCH_UP);
bindKey(KeyboardUtils.DOWN, ACTION_PITCH_DOWN);
bindKey(KeyboardUtils.LEFT, ACTION_YAW_LEFT);
bindKey(KeyboardUtils.RIGHT, ACTION_YAW_RIGHT);
bindKey(KeyboardUtils.SHIFT, ACTION_ACCELERATE);
}
/**
* Направление камеры на точку.
*
* @param point координаты точки направления камеры
*/
public function lookAt(point:Point3D):void {
if (_camera == null) {
return;
}
var dx:Number = point.x - _camera.x;
var dy:Number = point.y - _camera.y;
var dz:Number = point.z - _camera.z;
_camera.rotationZ = -Math.atan2(dx, dy);
_camera.rotationX = Math.atan2(dz, Math.sqrt(dx * dx + dy * dy)) - MathUtils.DEG90;
}
/**
* Callback-функция, вызываемая при начале движения камеры.
*/
public function get onStartMoving():Function {
return _onStartMoving;
}
/**
* @private
*/
public function set onStartMoving(value:Function):void {
_onStartMoving = value;
}
/**
* Callback-функция, вызываемая при прекращении движения камеры.
*/
public function get onStopMoving():Function {
return _onStopMoving;
}
/**
* @private
*/
public function set onStopMoving(value:Function):void {
_onStopMoving = value;
}
/**
* Набор объектов, исключаемых из проверки столкновений.
*/
public function get collisionIgnoreSet():Set {
return _collisionIgnoreSet;
}
/**
* Источник событий клавиатуры и мыши.
*/
public function get eventsSource():DisplayObject {
return _eventsSource;
}
/**
* @private
*/
public function set eventsSource(value:DisplayObject):void {
if (_eventsSource != value) {
if (value == null) {
throw new ArgumentError("CameraController: eventsSource is null");
}
if (_controlsEnabled) {
unregisterEventsListeners();
}
_eventsSource = value;
if (_controlsEnabled) {
registerEventListeners();
}
}
}
/**
* Ассоциированная камера.
*/
public function get camera():Camera3D {
return _camera;
}
/**
* @private
*/
public function set camera(value:Camera3D):void {
if (_camera != value) {
_camera = value;
if (value == null) {
controlsEnabled = false;
} else {
createCollider();
}
}
}
/**
* Режим движения камеры. Если значение равно <code>true</code>, то перемещения камеры происходят относительно
* локальной системы координат, иначе относительно глобальной.
*
* @default true
*/
public function get moveLocal():Boolean {
return _moveLocal;
}
/**
* @private
*/
public function set moveLocal(value:Boolean):void {
_moveLocal = value;
}
/**
* Включение режима проверки столкновений.
*/
public function get checkCollisions():Boolean {
return _checkCollisions;
}
/**
* @private
*/
public function set checkCollisions(value:Boolean):void {
_checkCollisions = value;
}
/**
* Радиус сферы для определения столкновений.
*
* @default 0
*/
public function get collisionRadius():Number {
return _collisionRadius;
}
/**
* @private
*/
public function set collisionRadius(value:Number):void {
_collisionRadius = value;
if (_collider != null) {
_collider.radiusX = _collisionRadius;
_collider.radiusY = _collisionRadius;
_collider.radiusZ = _collisionRadius;
}
}
/**
* Привязка клавиши к действию.
*
* @param keyCode код клавиши
* @param action наименование действия
*/
public function bindKey(keyCode:uint, action:String):void {
var method:Function = actionBindings[action];
if (method != null) {
keyBindings[keyCode] = method;
}
}
/**
* Очистка привязки клавиши.
*
* @param keyCode код клавиши
*/
public function unbindKey(keyCode:uint):void {
keyBindings.remove(keyCode);
}
/**
* Очистка привязки всех клавиш.
*/
public function unbindAll():void {
keyBindings.clear();
}
/**
* Активация движения камеры вперёд.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function forward(value:Boolean):void {
_forward = value;
}
/**
* Активация движения камеры назад.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function back(value:Boolean):void {
_back = value;
}
/**
* Активация движения камеры влево.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function left(value:Boolean):void {
_left = value;
}
/**
* Активация движения камеры вправо.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function right(value:Boolean):void {
_right = value;
}
/**
* Активация движения камеры вверх.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function up(value:Boolean):void {
_up = value;
}
/**
* Активация движения камеры вниз.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function down(value:Boolean):void {
_down = value;
}
/**
* Активация поворота камеры вверх.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function pitchUp(value:Boolean):void {
_pitchUp = value;
}
/**
* Активация поворота камеры вниз.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function pitchDown(value:Boolean):void {
_pitchDown = value;
}
/**
* Активация поворота камеры влево.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function yawLeft(value:Boolean):void {
_yawLeft = value;
}
/**
* Активация поворота камеры вправо.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function yawRight(value:Boolean):void {
_yawRight = value;
}
/**
* Активация режима увеличенной скорости.
*
* @param value <code>true</code> для включения ускорения, <code>false</code> для выключения
*/
public function accelerate(value:Boolean):void {
_accelerate = value;
}
/**
* @private
*/
private function createCollider():void {
_collider = new EllipsoidCollider(_camera.scene, _collisionRadius);
_collider.offsetThreshold = 0.01;
_collider.collisionSet = _collisionIgnoreSet;
}
/**
* Чувствительность мыши &mdash; коэффициент умножения <code>mousePitch</code> и <code>mouseYaw</code>.
*
* @default 1
*
* @see #mousePitch()
* @see #mouseYaw()
*/
public function get mouseSensitivity():Number {
return _mouseSensitivity;
}
/**
* @private
*/
public function set mouseSensitivity(sensitivity:Number):void {
_mouseSensitivity = sensitivity;
_mousePitchCoeff = _mouseSensitivity * _mousePitch;
_mouseYawCoeff = _mouseSensitivity * _mouseYaw;
}
/**
* Скорость изменения угла тангажа при управлении мышью (радианы на пиксель).
*
* @default Math.PI / 360
*/
public function get mousePitch():Number {
return _mousePitch;
}
/**
* @private
*/
public function set mousePitch(pitch:Number):void {
_mousePitch = pitch;
_mousePitchCoeff = _mouseSensitivity * _mousePitch;
}
/**
* Скорость изменения угла рысканья при управлении мышью (радианы на пиксель).
*
* @default Math.PI / 360
*/
public function get mouseYaw():Number {
return _mouseYaw;
}
/**
* @private
*/
public function set mouseYaw(yaw:Number):void {
_mouseYaw = yaw;
_mouseYawCoeff = _mouseSensitivity * _mouseYaw;
}
/**
* Угловая скорость по тангажу при управлении с клавиатуры (радианы в секунду).
*
* @default 1
*/
public function get pitchSpeed():Number {
return _pitchSpeed;
}
/**
* @private
*/
public function set pitchSpeed(spd:Number):void {
_pitchSpeed = spd;
}
/**
* Угловая скорость по рысканью при управлении с клавиатуры (радианы в секунду).
*
* @default 1
*/
public function get yawSpeed():Number {
return _yawSpeed;
}
/**
* @private
*/
public function set yawSpeed(spd:Number):void {
_yawSpeed = spd;
}
/**
* Скорость поступательного движения (единицы в секунду).
*/
public function get speed():Number {
return _speed;
}
/**
* @private
*/
public function set speed(spd:Number):void {
_speed = spd;
}
/**
* Коэффициент увеличения скорости при активном действии <code>ACTION_ACCELERATE</code>.
*
* @default 2
*/
public function get speedMultiplier():Number {
return _speedMultiplier;
}
/**
* @private
*/
public function set speedMultiplier(value:Number):void {
_speedMultiplier = value;
}
/**
* Активность управления камеры.
*
* @default false
*/
public function get controlsEnabled():Boolean {
return _controlsEnabled;
}
/**
* @private
*/
public function set controlsEnabled(value:Boolean):void {
if (_camera == null || _controlsEnabled == value) return;
if (value) {
lastFrameTime = getTimer();
registerEventListeners();
}
else {
unregisterEventsListeners();
}
_controlsEnabled = value;
}
/**
* Базовый шаг изменения угла зрения в радианах. Реальный шаг получаеся умножением этого значения на величину
* <code>MouseEvent.delta</code>.
*
* @default Math.PI / 180
*/
public function get fovStep():Number {
return _fovStep;
}
/**
* @private
*/
public function set fovStep(value:Number):void {
_fovStep = value;
}
/**
* Множитель при изменении коэффициента увеличения. Закон изменения коэффициента увеличения описывается формулой:<br>
* <code>zoom (1 + MouseEvent.delta zoomMultiplier)</code>.
*
* @default 0.1
*/
public function get zoomMultiplier():Number {
return _zoomMultiplier;
}
/**
* @private
*/
public function set zoomMultiplier(value:Number):void {
_zoomMultiplier = value;
}
/**
* @private
*/
private function registerEventListeners():void {
_eventsSource.addEventListener(KeyboardEvent.KEY_DOWN, onKey);
_eventsSource.addEventListener(KeyboardEvent.KEY_UP, onKey);
_eventsSource.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_eventsSource.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
}
/**
* @private
*/
private function unregisterEventsListeners():void {
_eventsSource.removeEventListener(KeyboardEvent.KEY_DOWN, onKey);
_eventsSource.removeEventListener(KeyboardEvent.KEY_UP, onKey);
_eventsSource.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_eventsSource.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
_eventsSource.removeEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
}
/**
* @private
* @param e
*/
private function onKey(e:KeyboardEvent):void {
var method:Function = keyBindings[e.keyCode];
if (method != null) {
method.call(this, e.type == KeyboardEvent.KEY_DOWN);
}
}
/**
* @private
* @param e
*/
private function onMouseDown(e:MouseEvent):void {
mouseLookActive = true;
currentDragCoords.x = startDragCoords.x = _eventsSource.stage.mouseX;
currentDragCoords.y = startDragCoords.y = _eventsSource.stage.mouseY;
startRotX = _camera.rotationX;
startRotZ = _camera.rotationZ;
_eventsSource.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
/**
* @private
* @param e
*/
private function onMouseUp(e:MouseEvent):void {
mouseLookActive = false;
_eventsSource.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
/**
* @private
* @param e
*/
private function onMouseWheel(e:MouseEvent):void {
if (_camera.orthographic) {
_camera.zoom = _camera.zoom * (1 + e.delta * _zoomMultiplier);
} else {
_camera.fov -= _fovStep * e.delta;
}
}
/**
* Обработка управляющих воздействий.
* Метод должен вызываться каждый кадр перед вызовом <code>Scene3D.calculate()</code>.
*
* @see alternativa.engine3d.core.Scene3D#calculate()
*/
public function processInput(): void {
if (!_controlsEnabled || _camera == null) return;
// Время в секундах от начала предыдущего кадра
var frameTime:Number = getTimer() - lastFrameTime;
lastFrameTime += frameTime;
frameTime /= 1000;
// Обработка mouselook
if (mouseLookActive) {
prevDragCoords.x = currentDragCoords.x;
prevDragCoords.y = currentDragCoords.y;
currentDragCoords.x = _eventsSource.stage.mouseX;
currentDragCoords.y = _eventsSource.stage.mouseY;
if (!prevDragCoords.equals(currentDragCoords)) {
_camera.rotationZ = startRotZ + (startDragCoords.x - currentDragCoords.x) * _mouseYawCoeff;
var rotX:Number = startRotX + (startDragCoords.y - currentDragCoords.y) * _mousePitchCoeff;
_camera.rotationX = (rotX > 0) ? 0 : (rotX < -MathUtils.DEG180) ? -MathUtils.DEG180 : rotX;
}
}
// Поворот относительно вертикальной оси (рысканье, yaw)
if (_yawLeft) {
_camera.rotationZ += _yawSpeed * frameTime;
} else if (_yawRight) {
_camera.rotationZ -= _yawSpeed * frameTime;
}
// Поворот относительно поперечной оси (тангаж, pitch)
if (_pitchUp) {
rotX = _camera.rotationX + _pitchSpeed * frameTime;
_camera.rotationX = (rotX > 0) ? 0 : (rotX < -MathUtils.DEG180) ? -MathUtils.DEG180 : rotX;
} else if (_pitchDown) {
rotX = _camera.rotationX - _pitchSpeed * frameTime;
_camera.rotationX = (rotX > 0) ? 0 : (rotX < -MathUtils.DEG180) ? -MathUtils.DEG180 : rotX;
}
// TODO: Поворот относительно продольной оси (крен, roll)
var frameDistance:Number = _speed * frameTime;
if (_accelerate) {
frameDistance *= _speedMultiplier;
}
velocity.x = 0;
velocity.y = 0;
velocity.z = 0;
var transformation:Matrix3D = _camera.transformation;
if (_moveLocal) {
// Режим относительных пермещений
// Движение вперед-назад
if (_forward) {
velocity.x += frameDistance * transformation.c;
velocity.y += frameDistance * transformation.g;
velocity.z += frameDistance * transformation.k;
} else if (_back) {
velocity.x -= frameDistance * transformation.c;
velocity.y -= frameDistance * transformation.g;
velocity.z -= frameDistance * transformation.k;
}
// Движение влево-вправо
if (_left) {
velocity.x -= frameDistance * transformation.a;
velocity.y -= frameDistance * transformation.e;
velocity.z -= frameDistance * transformation.i;
} else if (_right) {
velocity.x += frameDistance * transformation.a;
velocity.y += frameDistance * transformation.e;
velocity.z += frameDistance * transformation.i;
}
// Движение вверх-вниз
if (_up) {
velocity.x -= frameDistance * transformation.b;
velocity.y -= frameDistance * transformation.f;
velocity.z -= frameDistance * transformation.j;
} else if (_down) {
velocity.x += frameDistance * transformation.b;
velocity.y += frameDistance * transformation.f;
velocity.z += frameDistance * transformation.j;
}
}
else {
// Режим глобальных перемещений
var cosZ:Number = Math.cos(_camera.rotationZ);
var sinZ:Number = Math.sin(_camera.rotationZ);
// Движение вперед-назад
if (_forward) {
velocity.x -= frameDistance * sinZ;
velocity.y += frameDistance * cosZ;
} else if (_back) {
velocity.x += frameDistance * sinZ;
velocity.y -= frameDistance * cosZ;
}
// Движение влево-вправо
if (_left) {
velocity.x -= frameDistance * cosZ;
velocity.y -= frameDistance * sinZ;
} else if (_right) {
velocity.x += frameDistance * cosZ;
velocity.y += frameDistance * sinZ;
}
// Движение вверх-вниз
if (_up) {
velocity.z += frameDistance;
} else if (_down) {
velocity.z -= frameDistance;
}
}
// Коррекция модуля вектора скорости
if (velocity.x != 0 || velocity.y != 0 || velocity.z != 0) {
velocity.length = frameDistance;
}
// Проверка столкновений
if (_checkCollisions) {
_collider.calculateDestination(_camera.coords, velocity, destination);
_camera.x = destination.x;
_camera.y = destination.y;
_camera.z = destination.z;
} else {
_camera.x += velocity.x;
_camera.y += velocity.y;
_camera.z += velocity.z;
}
// Обработка начала/окончания движения
if (_camera.changeRotationOrScaleOperation.queued || _camera.changeCoordsOperation.queued) {
if (!_isMoving) {
_isMoving = true;
if (_onStartMoving != null) {
_onStartMoving.call(this);
}
}
} else {
if (_isMoving) {
_isMoving = false;
if (_onStopMoving != null) {
_onStopMoving.call(this);
}
}
}
}
}
}

View File

@@ -1,450 +0,0 @@
package alternativa.engine3d.controllers {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Camera3D;
import alternativa.types.Matrix3D;
import alternativa.types.Point3D;
import alternativa.utils.KeyboardUtils;
import alternativa.utils.MathUtils;
import flash.display.DisplayObject;
use namespace alternativa3d;
/**
* Контроллер, реализующий управление, подобное управлению летательным аппаратом для объекта, находящегося в системе
* координат корневого объекта сцены. Повороты выполняются вокруг локальных осей объекта, собственные ускорения
* действуют вдоль локальных осей.
*
* <p>Соответствия локальных осей для объектов, не являющихся камерой:
* <table border="1" style="border-collapse: collapse">
* <tr>
* <th>Ось</th><th>Направление</th><th>Поворот</th>
* </tr>
* <tr>
* <td>X</td><td>Вправо</td><td>Тангаж</td>
* </tr>
* <tr>
* <td>Y</td><td>Вперёд</td><td>Крен</td>
* </tr>
* <tr>
* <td>Z</td><td>Вверх</td><td>Рысканье</td>
* </tr>
* </table>
*
* <p>Соответствия локальных осей для объектов, являющихся камерой:
* <table border="1" style="border-collapse: collapse">
* <tr>
* <th>Ось</th><th>Направление</th><th>Поворот</th>
* </tr>
* <tr>
* <td>X</td><td>Вправо</td><td>Тангаж</td>
* </tr>
* <tr>
* <td>Y</td><td>Вниз</td><td>Рысканье</td>
* </tr>
* <tr>
* <td>Z</td><td>Вперёд</td><td>Крен</td>
* </tr>
* </table>
*
* Поворот мышью реализован следующим образом: в момент активации режима поворота (нажата левая кнопка мыши или
* соответствующая кнопка на клавиатуре) текущее положение курсора становится точкой, относительно которой определяются
* дальнейшие отклонения. Отклонение курсора по вертикали в пикселях, умноженное на коэффициент чувствительности мыши
* по вертикали даёт угловую скорость по тангажу. Отклонение курсора по горизонтали в пикселях, умноженное на коэффициент
* чувствительности мыши по горизонтали даёт угловую скорость по крену.
*/
public class FlyController extends ObjectController {
/**
* Имя действия для привязки клавиш поворота по крену влево.
*/
public static const ACTION_ROLL_LEFT:String = "ACTION_ROLL_LEFT";
/**
* Имя действия для привязки клавиш поворота по крену вправо.
*/
public static const ACTION_ROLL_RIGHT:String = "ACTION_ROLL_RIGHT";
private var _rollLeft:Boolean;
private var _rollRight:Boolean;
private var _rollSpeed:Number = 1;
private var rotations:Point3D;
private var rollMatrix:Matrix3D = new Matrix3D();
private var transformation:Matrix3D = new Matrix3D();
private var axis:Point3D = new Point3D();
private var velocity:Point3D = new Point3D();
private var displacement:Point3D = new Point3D();
private var destination:Point3D = new Point3D();
private var deltaVelocity:Point3D = new Point3D();
private var accelerationVector:Point3D = new Point3D();
private var currentTransform:Matrix3D = new Matrix3D();
private var _currentSpeed:Number = 1;
/**
* Текущие координаты мышиного курсора в режиме mouse look.
*/
private var currentMouseCoords:Point3D = new Point3D();
/**
* Модуль вектора ускорния, получаемого от команд движения.
*/
public var acceleration:Number = 1000;
/**
* Модуль вектора замедляющего ускорения.
*/
public var deceleration:Number = 50;
/**
* Погрешность определения скорости. Скорость приравнивается к нулю, если её модуль не превышает заданного значения.
*/
public var speedThreshold:Number = 1;
/**
* Переключение инерционного режима. В инерционном режиме отсутствует замедляющее ускорение, в результате чего вектор
* скорости объекта остаётся постоянным, если нет управляющих воздействий. При выключенном инерционном режиме к объекту
* прикладывается замедляющее ускорение.
*/
public var inertialMode:Boolean;
/**
* @inheritDoc
*/
public function FlyController(eventsSourceObject:DisplayObject) {
super(eventsSourceObject);
actionBindings[ACTION_ROLL_LEFT] = rollLeft;
actionBindings[ACTION_ROLL_RIGHT] = rollRight;
}
/**
* Текущая скорость движения.
*/
public function get currentSpeed():Number {
return _currentSpeed;
}
/**
* Активация вращения по крену влево.
*/
public function rollLeft(value:Boolean):void {
_rollLeft = value;
}
/**
* Активация вращения по крену вправо.
*/
public function rollRight(value:Boolean):void {
_rollRight = value;
}
/**
* Установка привязки клавиш по умолчанию. Данный метод очищает все существующие привязки клавиш и устанавливает следующие:
* <table border="1" style="border-collapse: collapse">
* <tr><th>Клавиша</th><th>Действие</th></tr>
* <tr><td>W</td><td>ACTION_FORWARD</td></tr>
* <tr><td>S</td><td>ACTION_BACK</td></tr>
* <tr><td>A</td><td>ACTION_LEFT</td></tr>
* <tr><td>D</td><td>ACTION_RIGHT</td></tr>
* <tr><td>SPACE</td><td>ACTION_UP</td></tr>
* <tr><td>CONTROL</td><td>ACTION_DOWN</td></tr>
* <tr><td>UP</td><td>ACTION_PITCH_UP</td></tr>
* <tr><td>DOWN</td><td>ACTION_PITCH_DOWN</td></tr>
* <tr><td>LEFT</td><td>ACTION_ROLL_LEFT</td></tr>
* <tr><td>RIGHT</td><td>ACTION_ROLL_RIGHT</td></tr>
* <tr><td>Q</td><td>ACTION_YAW_LEFT</td></tr>
* <tr><td>E</td><td>ACTION_YAW_RIGHT</td></tr>
* <tr><td>M</td><td>ACTION_MOUSE_LOOK</td></tr>
* </table>
*/
override public function setDefaultBindings():void {
unbindAll();
bindKey(KeyboardUtils.W, ACTION_FORWARD);
bindKey(KeyboardUtils.S, ACTION_BACK);
bindKey(KeyboardUtils.A, ACTION_LEFT);
bindKey(KeyboardUtils.D, ACTION_RIGHT);
bindKey(KeyboardUtils.SPACE, ACTION_UP);
bindKey(KeyboardUtils.CONTROL, ACTION_DOWN);
bindKey(KeyboardUtils.UP, ACTION_PITCH_UP);
bindKey(KeyboardUtils.DOWN, ACTION_PITCH_DOWN);
bindKey(KeyboardUtils.LEFT, ACTION_ROLL_LEFT);
bindKey(KeyboardUtils.RIGHT, ACTION_ROLL_RIGHT);
bindKey(KeyboardUtils.Q, ACTION_YAW_LEFT);
bindKey(KeyboardUtils.E, ACTION_YAW_RIGHT);
bindKey(KeyboardUtils.M, ACTION_MOUSE_LOOK);
}
/**
* Метод выполняет поворот объекта относительно локальных осей в соответствии с имеющимися воздействиями.
*
* @param frameTime длительность текущего кадра в секундах
*/
override protected function rotateObject(frameTime:Number):void {
var transformation:Matrix3D = _object.transformation;
if (_mouseLookActive) {
currentMouseCoords.x = _eventsSource.stage.mouseX;
currentMouseCoords.y = _eventsSource.stage.mouseY;
if (!currentMouseCoords.equals(startMouseCoords)) {
var deltaYaw:Number = (currentMouseCoords.x - startMouseCoords.x) * _mouseCoefficientX;
if (_object is Camera3D) {
axis.x = transformation.c;
axis.y = transformation.g;
axis.z = transformation.k;
} else {
axis.x = transformation.b;
axis.y = transformation.f;
axis.z = transformation.j;
}
rotateObjectAroundAxis(axis, deltaYaw * frameTime);
currentTransform.toTransform(0, 0, 0, _object.rotationX, _object.rotationY, _object.rotationZ, 1, 1, 1);
var deltaPitch:Number = (startMouseCoords.y - currentMouseCoords.y) * _mouseCoefficientY;
axis.x = currentTransform.a;
axis.y = currentTransform.e;
axis.z = currentTransform.i;
rotateObjectAroundAxis(axis, deltaPitch * frameTime);
}
}
// Поворот относительно продольной оси (крен, roll)
if (_rollLeft) {
if (_object is Camera3D) {
axis.x = transformation.c;
axis.y = transformation.g;
axis.z = transformation.k;
} else {
axis.x = transformation.b;
axis.y = transformation.f;
axis.z = transformation.j;
}
rotateObjectAroundAxis(axis, -_rollSpeed * frameTime);
} else if (_rollRight) {
if (_object is Camera3D) {
axis.x = transformation.c;
axis.y = transformation.g;
axis.z = transformation.k;
} else {
axis.x = transformation.b;
axis.y = transformation.f;
axis.z = transformation.j;
}
rotateObjectAroundAxis(axis, _rollSpeed * frameTime);
}
// Поворот относительно поперечной оси (тангаж, pitch)
if (_pitchUp) {
axis.x = transformation.a;
axis.y = transformation.e;
axis.z = transformation.i;
rotateObjectAroundAxis(axis, _pitchSpeed * frameTime);
} else if (_pitchDown) {
axis.x = transformation.a;
axis.y = transformation.e;
axis.z = transformation.i;
rotateObjectAroundAxis(axis, -_pitchSpeed * frameTime);
}
// Поворот относительно вертикальной оси (рысканье, yaw)
if (_yawRight) {
if (_object is Camera3D) {
axis.x = transformation.b;
axis.y = transformation.f;
axis.z = transformation.j;
rotateObjectAroundAxis(axis, _yawSpeed * frameTime);
} else {
axis.x = transformation.c;
axis.y = transformation.g;
axis.z = transformation.k;
rotateObjectAroundAxis(axis, -_yawSpeed * frameTime);
}
} else if (_yawLeft) {
if (_object is Camera3D) {
axis.x = transformation.b;
axis.y = transformation.f;
axis.z = transformation.j;
rotateObjectAroundAxis(axis, -_yawSpeed * frameTime);
} else {
axis.x = transformation.c;
axis.y = transformation.g;
axis.z = transformation.k;
rotateObjectAroundAxis(axis, _yawSpeed * frameTime);
}
}
}
/**
* Метод вычисляет вектор потенциального смещения эллипсоида.
*
* @param frameTime длительность текущего кадра в секундах
* @param displacement в эту переменную записывается вычисленное потенциальное смещение объекта
*/
override protected function getDisplacement(frameTime:Number, displacement:Point3D):void {
// Движение вперед-назад
accelerationVector.x = 0;
accelerationVector.y = 0;
accelerationVector.z = 0;
if (_forward) {
accelerationVector.y = 1;
} else if (_back) {
accelerationVector.y = -1;
}
// Движение влево-вправо
if (_right) {
accelerationVector.x = 1;
} else if (_left) {
accelerationVector.x = -1;
}
// Движение ввверх-вниз
if (_up) {
accelerationVector.z = 1;
} else if (_down) {
accelerationVector.z = -1;
}
var speedLoss:Number;
var len:Number;
if (accelerationVector.x != 0 || accelerationVector.y != 0 || accelerationVector.z != 0) {
// Управление активно
if (_object is Camera3D) {
var tmp:Number = accelerationVector.z;
accelerationVector.z = accelerationVector.y;
accelerationVector.y = -tmp;
}
accelerationVector.normalize();
accelerationVector.x *= acceleration;
accelerationVector.y *= acceleration;
accelerationVector.z *= acceleration;
currentTransform.toTransform(0, 0, 0, _object.rotationX, _object.rotationY, _object.rotationZ, 1, 1, 1);
accelerationVector.transform(currentTransform);
deltaVelocity.x = accelerationVector.x;
deltaVelocity.y = accelerationVector.y;
deltaVelocity.z = accelerationVector.z;
deltaVelocity.x *= frameTime;
deltaVelocity.y *= frameTime;
deltaVelocity.z *= frameTime;
if (!inertialMode) {
speedLoss = deceleration * frameTime;
var dot:Number = Point3D.dot(velocity, accelerationVector);
if (dot > 0) {
len = accelerationVector.length;
var x:Number = accelerationVector.x / len;
var y:Number = accelerationVector.y / len;
var z:Number = accelerationVector.z / len;
len = dot / len;
x = velocity.x - len * x;
y = velocity.y - len * y;
z = velocity.z - len * z;
len = Math.sqrt(x*x + y*y + z*z);
if (len > speedLoss) {
x *= speedLoss / len;
y *= speedLoss / len;
z *= speedLoss / len;
}
velocity.x -= x;
velocity.y -= y;
velocity.z -= z;
} else {
len = velocity.length;
velocity.length = (len > speedLoss) ? (len - speedLoss) : 0;
}
}
velocity.x += deltaVelocity.x;
velocity.y += deltaVelocity.y;
velocity.z += deltaVelocity.z;
if (velocity.length > _speed) {
velocity.length = _speed;
}
} else {
// Управление неактивно
if (!inertialMode) {
speedLoss = deceleration * frameTime;
len = velocity.length;
velocity.length = (len > speedLoss) ? (len - speedLoss) : 0;
}
}
displacement.x = velocity.x * frameTime;
displacement.y = velocity.y * frameTime;
displacement.z = velocity.z * frameTime;
}
/**
* Метод применяет потенциальный вектор смещения к эллипсоиду с учётом столкновений с геометрией сцены, если включён
* соотвествующий режим.
*
* @param frameTime время кадра в секундах
* @param displacement векотр потенциального смещения эллипсоида
*/
override protected function applyDisplacement(frameTime:Number, displacement:Point3D):void {
if (checkCollisions) {
_collider.calculateDestination(_coords, displacement, destination);
displacement.x = destination.x - _coords.x;
displacement.y = destination.y - _coords.y;
displacement.z = destination.z - _coords.z;
} else {
destination.x = _coords.x + displacement.x;
destination.y = _coords.y + displacement.y;
destination.z = _coords.z + displacement.z;
}
velocity.x = displacement.x / frameTime;
velocity.y = displacement.y / frameTime;
velocity.z = displacement.z / frameTime;
_coords.x = destination.x;
_coords.y = destination.y;
_coords.z = destination.z;
setObjectCoords();
var len:Number = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
if (len < speedThreshold) {
velocity.x = 0;
velocity.y = 0;
velocity.z = 0;
_currentSpeed = 0;
} else {
_currentSpeed = len;
}
}
/**
* Поворот объекта вокруг заданной оси.
*
* @param axis
* @param angle
*/
private function rotateObjectAroundAxis(axis:Point3D, angle:Number):void {
transformation.toTransform(0, 0, 0, _object.rotationX, _object.rotationY, _object.rotationZ, 1, 1, 1);
rollMatrix.fromAxisAngle(axis, angle);
rollMatrix.inverseCombine(transformation);
rotations = rollMatrix.getRotations(rotations);
_object.rotationX = rotations.x;
_object.rotationY = rotations.y;
_object.rotationZ = rotations.z;
}
/**
* Направление объекта на точку. В результате работы метода локальная ось объекта, соответствующая направлению "вперёд"
* будет направлена на указанную точку, а угол поворота вокруг этой оси будет равен нулю.
*
* @param point координаты точки, на которую должен быть направлен объект
*/
public function lookAt(point:Point3D):void {
if (_object == null) {
return;
}
var dx:Number = point.x - _object.x;
var dy:Number = point.y - _object.y;
var dz:Number = point.z - _object.z;
_object.rotationX = Math.atan2(dz, Math.sqrt(dx * dx + dy * dy)) - (_object is Camera3D ? MathUtils.DEG90 : 0);
_object.rotationY = 0;
_object.rotationZ = -Math.atan2(dx, dy);
}
}
}

View File

@@ -1,839 +0,0 @@
package alternativa.engine3d.controllers {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.physics.EllipsoidCollider;
import alternativa.types.Map;
import alternativa.types.Point3D;
import alternativa.utils.MathUtils;
import alternativa.utils.ObjectUtils;
import flash.display.DisplayObject;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.utils.getTimer;
use namespace alternativa3d;
/**
* Базовый контроллер для изменения ориентации и положения объекта в сцене с помощью клавиатуры и мыши. В классе
* реализована поддержка назначения обработчиков клавиатурных команд, а также обработчики для основных команд
* перемещения.
*/
public class ObjectController {
/**
* Имя действия для привязки клавиш движения вперёд.
*/
public static const ACTION_FORWARD:String = "ACTION_FORWARD";
/**
* Имя действия для привязки клавиш движения назад.
*/
public static const ACTION_BACK:String = "ACTION_BACK";
/**
* Имя действия для привязки клавиш движения влево.
*/
public static const ACTION_LEFT:String = "ACTION_LEFT";
/**
* Имя действия для привязки клавиш движения вправо.
*/
public static const ACTION_RIGHT:String = "ACTION_RIGHT";
/**
* Имя действия для привязки клавиш движения вверх.
*/
public static const ACTION_UP:String = "ACTION_UP";
/**
* Имя действия для привязки клавиш движения вниз.
*/
public static const ACTION_DOWN:String = "ACTION_DOWN";
/**
* Имя действия для привязки клавиш поворота вверх.
*/
public static const ACTION_PITCH_UP:String = "ACTION_PITCH_UP";
/**
* Имя действия для привязки клавиш поворота вниз.
*/
public static const ACTION_PITCH_DOWN:String = "ACTION_PITCH_DOWN";
/**
* Имя действия для привязки клавиш поворота налево.
*/
public static const ACTION_YAW_LEFT:String = "ACTION_YAW_LEFT";
/**
* Имя действия для привязки клавиш поворота направо.
*/
public static const ACTION_YAW_RIGHT:String = "ACTION_YAW_RIGHT";
/**
* Имя действия для привязки клавиш увеличения скорости.
*/
public static const ACTION_ACCELERATE:String = "ACTION_ACCELERATE";
/**
* Имя действия для привязки клавиш активации обзора мышью.
*/
public static const ACTION_MOUSE_LOOK:String = "ACTION_MOUSE_LOOK";
/**
* Флаг движения вперёд.
*/
protected var _forward:Boolean;
/**
* Флаг движения назад.
*/
protected var _back:Boolean;
/**
* Флаг движения влево.
*/
protected var _left:Boolean;
/**
* Флаг движения вправо.
*/
protected var _right:Boolean;
/**
* Флаг движения вверх.
*/
protected var _up:Boolean;
/**
* Флаг движения вниз.
*/
protected var _down:Boolean;
/**
* Флаг поворота относительно оси X в положительном направлении (взгляд вверх).
*/
protected var _pitchUp:Boolean;
/**
* Флаг поворота относительно оси X в отрицательном направлении (взгляд вниз).
*/
protected var _pitchDown:Boolean;
/**
* Флаг поворота относительно оси Z в положительном направлении (взгляд налево).
*/
protected var _yawLeft:Boolean;
/**
* Флаг активности поворота относительно оси Z в отрицательном направлении (взгляд направо).
*/
protected var _yawRight:Boolean;
/**
* Флаг активности режима ускорения.
*/
protected var _accelerate:Boolean;
/**
* Флаг активности режима поворотов мышью.
*/
protected var _mouseLookActive:Boolean;
/**
* Начальные координаты мышиного курсора в режиме mouse look.
*/
protected var startMouseCoords:Point3D = new Point3D();
/**
* Флаг активности контроллера.
*/
protected var _enabled:Boolean = true;
/**
* Источник событий клавиатуры и мыши
*/
protected var _eventsSource:DisplayObject;
/**
* Ассоциативный массив, связывающий коды клавиатурных клавиш с именами команд.
*/
protected var keyBindings:Map = new Map();
/**
* Ассоциативный массив, связывающий имена команд с реализующими их функциями. Функции должны иметь вид
* function(value:Boolean):void. Значение параметра <code>value</code> указывает, нажата или отпущена соответсвующая команде
* клавиша.
*/
protected var actionBindings:Map = new Map();
/**
* Флаг активности клавиатуры.
*/
protected var _keyboardEnabled:Boolean;
/**
* Флаг активности мыши.
*/
protected var _mouseEnabled:Boolean;
/**
* Общая чувствительность мыши. Коэффициент умножения чувствительности по вертикали и горизонтали.
*/
protected var _mouseSensitivity:Number = 1;
/**
* Коэффициент чувствительности мыши по вертикали. Значение угла в радианах на один пиксель перемещения мыши по вертикали.
*/
protected var _mouseSensitivityY:Number = Math.PI / 360;
/**
* Коэффициент чувствительности мыши по горизонтали. Значение угла в радианах на один пиксель перемещения мыши по горизонтали.
*/
protected var _mouseSensitivityX:Number = Math.PI / 360;
/**
* Результирующий коэффициент чувствительности мыши по вертикали. Значение угла в радианах на один пиксель перемещения мыши по вертикали.
*/
protected var _mouseCoefficientY:Number = _mouseSensitivity * _mouseSensitivityY;
/**
* Результирующий коэффициент чувствительности мыши по горизонтали. Значение угла в радианах на один пиксель перемещения мыши по горизонтали.
*/
protected var _mouseCoefficientX:Number = _mouseSensitivity * _mouseSensitivityX;
/**
* Угловая скорость поворота вокруг поперечной оси в радианах за секунду.
*/
protected var _pitchSpeed:Number = 1;
/**
* Угловая скорость поворота вокруг вертикальной оси в радианах за секунду.
*/
protected var _yawSpeed:Number = 1;
/**
* Скорость поступательного движения в единицах за секунду.
*/
protected var _speed:Number = 100;
/**
* Коэффициент увеличения скорости при соответствующей активной команде.
*/
protected var _speedMultiplier:Number = 2;
/**
* Управляемый объект.
*/
protected var _object:Object3D;
/**
* Время в секундах, прошедшее с последнего вызова метода processInput (обычно с последнего кадра).
*/
protected var lastFrameTime:uint;
/**
* Текущие координаты контроллера.
*/
protected var _coords:Point3D = new Point3D();
/**
* Индикатор движения объекта (перемещения или поворота) в текущем кадре.
*/
protected var _isMoving:Boolean;
/**
* Объект для определения столкновений.
*/
protected var _collider:EllipsoidCollider = new EllipsoidCollider();
/**
* Включение и выключение режима проверки столкновений.
*/
public var checkCollisions:Boolean;
/**
* Функция вида <code>function():void</code>, вызываемая при начале движения объекта. Под движением
* понимается изменение координат или ориентации.
*/
public var onStartMoving:Function;
/**
* Функция вида <code>function():void</code>, вызываемая при прекращении движения объекта. Под движением
* понимается изменение координат или ориентации.
*/
public var onStopMoving:Function;
// Вектор смещения
private var _displacement:Point3D = new Point3D();
/**
* Создаёт новый экземпляр контролллера.
*
* @param eventsSourceObject источник событий клавиатуры и мыши
*/
public function ObjectController(eventsSourceObject:DisplayObject) {
if (eventsSourceObject == null) {
throw new ArgumentError(ObjectUtils.getClassName(this) + ": eventsSourceObject is null");
}
_eventsSource = eventsSourceObject;
actionBindings[ACTION_FORWARD] = moveForward;
actionBindings[ACTION_BACK] = moveBack;
actionBindings[ACTION_LEFT] = moveLeft;
actionBindings[ACTION_RIGHT] = moveRight;
actionBindings[ACTION_UP] = moveUp;
actionBindings[ACTION_DOWN] = moveDown;
actionBindings[ACTION_PITCH_UP] = pitchUp;
actionBindings[ACTION_PITCH_DOWN] = pitchDown;
actionBindings[ACTION_YAW_LEFT] = yawLeft;
actionBindings[ACTION_YAW_RIGHT] = yawRight;
actionBindings[ACTION_ACCELERATE] = accelerate;
actionBindings[ACTION_MOUSE_LOOK] = setMouseLook;
keyboardEnabled = true;
mouseEnabled = true;
}
/**
* Включение и выключение контроллера. Выключенный контроллер пропускает выполнение метода <code>processInput()</code>.
*
* @default true
*
* @see #processInput()
*/
public function get enabled():Boolean {
return _enabled;
}
/**
* @private
*/
public function set enabled(value:Boolean):void {
_enabled = value;
}
/**
* Координаты контроллера. Координаты совпадают с координатами центра эллипсоида, используемого для определения
* столкновений. Координаты управляемого объекта могут не совпадать с координатами контроллера.
*
* @see #setObjectCoords()
*/
public function get coords():Point3D {
return _coords.clone();
}
/**
* @private
*/
public function set coords(value:Point3D):void {
_coords.copy(value);
setObjectCoords();
}
/**
* Чтение координат контроллера в заданную переменную.
*
* @param point переменная, в которую записываются координаты контроллера
*/
public function readCoords(point:Point3D):void {
point.copy(_coords);
}
/**
* Управляемый объект.
*/
public function get object():Object3D {
return _object;
}
/**
* @private
* При установке объекта устанавливается сцена для коллайдера.
*/
public function set object(value:Object3D):void {
_object = value;
_collider.scene = _object == null ? null : _object.scene;
}
/**
* Объект, реализующий проверку столкновений для эллипсоида.
*/
public function get collider():EllipsoidCollider {
return _collider;
}
/**
* Активация движения вперёд.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function moveForward(value:Boolean):void {
_forward = value;
}
/**
* Активация движения назад.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function moveBack(value:Boolean):void {
_back = value;
}
/**
* Активация движения влево.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function moveLeft(value:Boolean):void {
_left = value;
}
/**
* Активация движения вправо.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function moveRight(value:Boolean):void {
_right = value;
}
/**
* Активация движения вверх.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function moveUp(value:Boolean):void {
_up = value;
}
/**
* Активация движения вниз.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function moveDown(value:Boolean):void {
_down = value;
}
/**
* Активация поворота вверх.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function pitchUp(value:Boolean):void {
_pitchUp = value;
}
/**
* Активация поворота вниз.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function pitchDown(value:Boolean):void {
_pitchDown = value;
}
/**
* Активация поворота влево.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function yawLeft(value:Boolean):void {
_yawLeft = value;
}
/**
* Активация поворота вправо.
*
* @param value <code>true</code> для начала движения, <code>false</code> для окончания
*/
public function yawRight(value:Boolean):void {
_yawRight = value;
}
/**
* Активация режима увеличенной скорости.
*
* @param value <code>true</code> для включения ускорения, <code>false</code> для выключения
*/
public function accelerate(value:Boolean):void {
_accelerate = value;
}
/**
* Угловая скорость поворота вокруг поперечной оси (радианы в секунду).
*
* @default 1
*/
public function get pitchSpeed():Number {
return _pitchSpeed;
}
/**
* @private
*/
public function set pitchSpeed(spd:Number):void {
_pitchSpeed = spd;
}
/**
* Угловая скорость поворота вокруг вертикальной оси (радианы в секунду).
*
* @default 1
*/
public function get yawSpeed():Number {
return _yawSpeed;
}
/**
* @private
*/
public function set yawSpeed(spd:Number):void {
_yawSpeed = spd;
}
/**
* Скорость движения в единицах за секунду. При установке отрицательного значения берётся модуль.
*
* @default 100
*/
public function get speed():Number {
return _speed;
}
/**
* @private
*/
public function set speed(value:Number):void {
_speed = value < 0 ? -value : value;
}
/**
* Коэффициент увеличения скорости при активном действии <code>ACTION_ACCELERATE</code>.
*
* @default 2
*/
public function get speedMultiplier():Number {
return _speedMultiplier;
}
/**
* @private
*/
public function set speedMultiplier(value:Number):void {
_speedMultiplier = value;
}
/**
* Чувствительность мыши &mdash; коэффициент умножения <code>mouseSensitivityX</code> и <code>mouseSensitivityY</code>.
*
* @default 1
*
* @see #mouseSensitivityY()
* @see #mouseSensitivityX()
*/
public function get mouseSensitivity():Number {
return _mouseSensitivity;
}
/**
* @private
*/
public function set mouseSensitivity(sensitivity:Number):void {
_mouseSensitivity = sensitivity;
_mouseCoefficientY = _mouseSensitivity * _mouseSensitivityY;
_mouseCoefficientX = _mouseSensitivity * _mouseSensitivityX;
}
/**
* Чувтсвительность мыши по вертикали.
*
* @default Math.PI / 360
*
* @see #mouseSensitivity()
* @see #mouseSensitivityX()
*/
public function get mouseSensitivityY():Number {
return _mouseSensitivityY;
}
/**
* @private
*/
public function set mouseSensitivityY(value:Number):void {
_mouseSensitivityY = value;
_mouseCoefficientY = _mouseSensitivity * _mouseSensitivityY;
}
/**
* Чувтсвительность мыши по горизонтали.
*
* @default Math.PI / 360
*
* @see #mouseSensitivity()
* @see #mouseSensitivityY()
*/
public function get mouseSensitivityX():Number {
return _mouseSensitivityX;
}
/**
* @private
*/
public function set mouseSensitivityX(value:Number):void {
_mouseSensitivityX = value;
_mouseCoefficientX = _mouseSensitivity * _mouseSensitivityX;
}
/**
* Включение/выключение режима вращения объекта мышью. При включении режима вполняется метод <code>startMouseLook()</code>,
* при выключении &mdash; <code>stoptMouseLook()</code>.
*
* @see #startMouseLook()
* @see #stopMouseLook()
*/
public function setMouseLook(value:Boolean):void {
if (_mouseLookActive != value) {
_mouseLookActive = value;
if (_mouseLookActive) {
startMouseLook();
} else {
stopMouseLook();
}
}
}
/**
* Метод выполняет необходимые действия при включении режима вращения объекта мышью.
* Реализация по умолчанию записывает начальные глобальные координаты курсора мыши в переменную <code>startMouseCoords</code>.
*
* @see #startMouseCoords
* @see #setMouseLook()
* @see #stopMouseLook()
*/
protected function startMouseLook():void {
startMouseCoords.x = _eventsSource.stage.mouseX;
startMouseCoords.y = _eventsSource.stage.mouseY;
}
/**
* Метод выполняет необходимые действия при выключении вращения объекта мышью. Реализация по умолчанию не делает
* ничего.
*
* @see #setMouseLook()
* @see #startMouseLook()
*/
protected function stopMouseLook():void {
}
/**
* Метод выполняет обработку всех воздействий на объект. Если объект не установлен или свойство <code>enabled</code>
* равно <code>false</code>, метод не выполняется.
* <p>
* Алгоритм работы метода следующий:
* <ul>
* <li> Вычисляется время в секундах, прошедшее с последнего вызова метода (с последнего кадра). Это время считается
* длительностью текущего кадра;
* <li> Вызывается метод rotateObject(), который изменяет ориентацию объекта в соответствии с воздействиями;
* <li> Вызывается метод getDisplacement(), который вычисляет потенциальное перемещение объекта;
* <li> Вызывается метод applyDisplacement(), которому передаётся вектор перемещения, полученный на предыдущем шаге.
* Задачей метода является применение заданного вектора перемещения;
* <li> При необходимости вызываются обработчики начала и прекращения движения управляемого объекта;
* </ul>
*/
public function processInput():void {
if (!_enabled || _object == null) {
return;
}
var frameTime:Number = getTimer() - lastFrameTime;
lastFrameTime += frameTime;
if (frameTime > 100) {
frameTime = 100;
}
frameTime /= 1000;
rotateObject(frameTime);
getDisplacement(frameTime, _displacement);
applyDisplacement(frameTime, _displacement);
// Обработка начала/окончания движения
if (_object.changeRotationOrScaleOperation.queued || _object.changeCoordsOperation.queued) {
if (!_isMoving) {
_isMoving = true;
if (onStartMoving != null) {
onStartMoving.call(this);
}
}
} else {
if (_isMoving) {
_isMoving = false;
if (onStopMoving != null) {
onStopMoving.call(this);
}
}
}
}
/**
* Метод выполняет поворот объекта в соответствии с имеющимися воздействиями. Реализация по умолчанию не делает ничего.
*
* @param frameTime длительность текущего кадра в секундах
*/
protected function rotateObject(frameTime:Number):void {
}
/**
* Метод вычисляет потенциальное смещение объекта за кадр. Реализация по умолчанию не делает ничего.
*
* @param frameTime длительность текущего кадра в секундах
* @param displacement в эту переменную записывается вычисленное потенциальное смещение объекта
*/
protected function getDisplacement(frameTime:Number, displacement:Point3D):void {
}
/**
* Метод применяет потенциальное смещение объекта. Реализация по умолчанию не делает ничего.
*
* @param frameTime длительность текущего кадра в секундах
* @param displacement смещение объекта, которое нужно обработать
*/
protected function applyDisplacement(frameTime:Number, displacement:Point3D):void {
}
/**
* Метод выполняет привязку клавиши к действию. Одной клавише может быть назначено только одно действие.
*
* @param keyCode код клавиши
* @param action наименование действия
*
* @see #unbindKey()
* @see #unbindAll()
*/
public function bindKey(keyCode:uint, action:String):void {
var method:Function = actionBindings[action];
if (method != null) {
keyBindings[keyCode] = method;
}
}
/**
* Очистка привязки клавиши.
*
* @param keyCode код клавиши
*
* @see #bindKey()
* @see #unbindAll()
*/
public function unbindKey(keyCode:uint):void {
keyBindings.remove(keyCode);
}
/**
* Очистка привязки всех клавиш.
*
* @see #bindKey()
* @see #unbindKey()
*/
public function unbindAll():void {
keyBindings.clear();
}
/**
* Метод устанавливает привязки клавиш по умолчанию. Реализация по умолчанию не делает ничего.
*
* @see #bindKey()
* @see #unbindKey()
* @see #unbindAll()
*/
public function setDefaultBindings():void {
}
/**
* Включение и выключение обработки клавиатурных событий. При включении выполняется метод <code>registerKeyboardListeners</code>,
* при выключении &mdash; <code>unregisterKeyboardListeners</code>.
*
* @see #registerKeyboardListeners()
* @see #unregisterKeyboardListeners()
*/
public function get keyboardEnabled():Boolean {
return _keyboardEnabled;
}
/**
* @private
*/
public function set keyboardEnabled(value:Boolean):void {
if (_keyboardEnabled != value) {
_keyboardEnabled = value;
if (_keyboardEnabled) {
registerKeyboardListeners();
} else {
unregisterKeyboardListeners();
}
}
}
/**
* @private
* Запуск обработчиков клавиатурных команд.
*/
private function onKeyboardEvent(e:KeyboardEvent):void {
var method:Function = keyBindings[e.keyCode];
if (method != null) {
method.call(this, e.type == KeyboardEvent.KEY_DOWN);
}
}
/**
* Регистрация необходимых обработчиков при включении обработки клавиатурных событий.
*
* @see #unregisterKeyboardListeners()
*/
protected function registerKeyboardListeners():void {
_eventsSource.addEventListener(KeyboardEvent.KEY_DOWN, onKeyboardEvent);
_eventsSource.addEventListener(KeyboardEvent.KEY_UP, onKeyboardEvent);
}
/**
* Удаление обработчиков при выключении обработки клавиатурных событий.
*
* @see #registerKeyboardListeners()
*/
protected function unregisterKeyboardListeners():void {
_eventsSource.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyboardEvent);
_eventsSource.removeEventListener(KeyboardEvent.KEY_UP, onKeyboardEvent);
}
/**
* Включение и выключение обработки мышиных событий. При включении выполняется метод <code>registerMouseListeners</code>,
* при выключении &mdash; <code>unregisterMouseListeners</code>.
*
* @see #registerMouseListeners()
* @see #unregisterMouseListeners()
*/
public function get mouseEnabled():Boolean {
return _mouseEnabled;
}
/**
* @private
*/
public function set mouseEnabled(value:Boolean):void {
if (_mouseEnabled != value) {
_mouseEnabled = value;
if (_mouseEnabled) {
registerMouseListeners();
} else {
unregisterMouseListeners();
}
}
}
/**
* Регистрация необходимых обработчиков при включении обработки мышиных событий.
*
* @see #unregisterMouseListeners()
*/
protected function registerMouseListeners():void {
_eventsSource.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
/**
* Удаление используемых обработчиков при выключении обработки мышиных событий.
*
* @see #registerMouseListeners()
*/
protected function unregisterMouseListeners():void {
_eventsSource.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_eventsSource.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
/**
* Активация mouselook
*/
private function onMouseDown(e:MouseEvent):void {
setMouseLook(true);
_eventsSource.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
/**
* Отключение mouselook
*/
private function onMouseUp(e:MouseEvent):void {
setMouseLook(false);
_eventsSource.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
/**
* Установка координат управляемого объекта в зависимости от текущих координат контроллера.
*/
protected function setObjectCoords():void {
_object.coords = _coords;
}
/**
* Индикатор режима увеличенной скорости.
*/
public function get accelerated():Boolean {
return _accelerate;
}
}
}

View File

@@ -1,508 +0,0 @@
package alternativa.engine3d.controllers {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.Mesh;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.physics.Collision;
import alternativa.types.Matrix3D;
import alternativa.types.Point3D;
import alternativa.utils.KeyboardUtils;
import alternativa.utils.MathUtils;
import flash.display.DisplayObject;
use namespace alternativa3d;
/**
* Контроллер, реализующий управление движением объекта, находящегося в системе координат корневого объекта сцены.
*
* <p>Контроллер предоставляет два режима движения: режим ходьбы с учётом силы тяжести и режим полёта, в котором сила
* тяжести не учитывается. В обоих режимах может быть включена проверка столкновений с объектами сцены. Если проверка
* столкновений отключена, то в режиме ходьбы сила тяжести также игнорируется и дополнительно появляется возможность
* движения по вертикали.
*
* <p>Для всех объектов, за исключением <code>Camera3D</code>, направлением "вперёд" считается направление его оси
* <code>Y</code>, направлением "вверх" &mdash; направление оси <code>Z</code>. Для объектов класса
* <code>Camera3D</code> направление "вперёд" совпадает с направлением локальной оси <code>Z</code>, а направление
* "вверх" противоположно направлению локальной оси <code>Y</code>.
*
* <p>Вне зависимости от того, включена проверка столкновений или нет, координаты при перемещении расчитываются для
* эллипсоида, параметры которого устанавливаются через свойство <code>collider</code>. Координаты управляемого
* объекта вычисляются исходя из положения центра эллипсоида и положения объекта на вертикальной оси эллипсоида,
* задаваемого параметром <code>objectZPosition</code>.
*
* <p>Команда <code>ACTION_UP</code> в режиме ходьбы при ненулевой гравитации вызывает прыжок, в остальных случаях
* происходит движение вверх.
*/
public class WalkController extends ObjectController {
/**
* Величина ускорения свободного падения. При положительном значении сила тяжести направлена против оси Z,
* при отрицательном &mdash; по оси Z.
*/
public var gravity:Number = 0;
/**
* Вертикальная скорость прыжка.
*/
public var jumpSpeed:Number = 0;
/**
* Объект, на котором стоит эллипсоид при ненулевой гравитации.
*/
private var _groundMesh:Mesh;
/**
* Погрешность определения скорости. В режиме полёта или в режиме ходьбы при нахождении на поверхности
* скорость приравнивается к нулю, если её модуль не превышает заданного значения.
*/
public var speedThreshold:Number = 1;
// Коэффициент эффективности управления перемещением при нахождении в воздухе в режиме ходьбы и нулевой гравитации.
private var _airControlCoefficient:Number = 1;
private var _currentSpeed:Number = 0;
private var minGroundCos:Number = Math.cos(MathUtils.toRadian(70));
private var destination:Point3D = new Point3D();
private var collision:Collision = new Collision();
private var _objectZPosition:Number = 0.5;
private var _flyMode:Boolean;
private var _onGround:Boolean;
private var velocity:Point3D = new Point3D();
private var tmpVelocity:Point3D = new Point3D();
private var controlsActive:Boolean;
private var inJump:Boolean;
private var startRotX:Number;
private var startRotZ:Number;
// Координаты мышиного курсора в режиме mouse look в предыдущем кадре.
private var prevMouseCoords:Point3D = new Point3D();
// Текущие координаты мышиного курсора в режиме mouse look.
private var currentMouseCoords:Point3D = new Point3D();
/**
* @inheritDoc
*/
public function WalkController(eventSourceObject:DisplayObject) {
super(eventSourceObject);
}
/**
* Объект, на котором стоит эллипсоид при ненулевой гравитации.
*/
public function get groundMesh():Mesh {
return _groundMesh;
}
/**
* Направление объекта на точку. В результате работы метода локальная ось объекта, соответствующая направлению "вперёд"
* будет направлена на указанную точку, а угол поворота вокруг этой оси будет равен нулю.
*
* @param point координаты точки, на которую должен быть направлен объект
*/
public function lookAt(point:Point3D):void {
if (_object == null) {
return;
}
var dx:Number = point.x - _object.x;
var dy:Number = point.y - _object.y;
var dz:Number = point.z - _object.z;
_object.rotationX = Math.atan2(dz, Math.sqrt(dx * dx + dy * dy)) - (_object is Camera3D ? MathUtils.DEG90 : 0);
_object.rotationY = 0;
_object.rotationZ = -Math.atan2(dx, dy);
}
/**
* Коэффициент эффективности управления перемещением в режиме ходьбы при нахождении в воздухе и ненулевой гравитации.
* Значение 0 обозначает полное отсутствие контроля, значение 1 указывает, что управление так же эффективно, как при
* нахождении на поверхности.
*
* @default 1
*/
public function get airControlCoefficient():Number {
return _airControlCoefficient;
}
/**
* @private
*/
public function set airControlCoefficient(value:Number):void {
_airControlCoefficient = value > 0 ? value : -value;
}
/**
* Максимальный угол наклона поверхности в радианах, на которой возможен прыжок и на которой объект стоит на месте
* в отсутствие управляющих воздействий. Если угол наклона поверхности превышает заданное значение, свойство
* <code>onGround</code> будет иметь значение <code>false</code>.
*
* @see #onGround
*/
public function get maxGroundAngle():Number {
return Math.acos(minGroundCos);
}
/**
* @private
*/
public function set maxGroundAngle(value:Number):void {
minGroundCos = Math.cos(value);
}
/**
* Положение управляемого объекта на оси Z эллипсоида. Значение 0 указывает положение в нижней точке эллипсоида,
* значение 1 -- положение в верхней точке эллипсоида.
*/
public function get objectZPosition():Number {
return _objectZPosition;
}
/**
* @private
*/
public function set objectZPosition(value:Number):void {
_objectZPosition = value;
setObjectCoords();
}
/**
* Включене и выключение режима полёта.
*
* @default false
*/
public function get flyMode():Boolean {
return _flyMode;
}
/**
* @private
*/
public function set flyMode(value:Boolean):void {
_flyMode = value;
}
/**
* Индикатор положения эллипсоида на поверхности в режиме ходьбы. Считается, что эллипсоид находится на поверхности,
* если угол наклона поверхности под ним не превышает заданного свойством <code>maxGroundAngle</code> значения.
*
* @see #maxGroundAngle
*/
public function get onGround():Boolean {
return _onGround;
}
/**
* Модуль текущей скорости.
*/
public function get currentSpeed():Number {
return _currentSpeed;
}
/**
* Установка привязки клавиш по умолчанию. Данный метод очищает все существующие привязки клавиш и устанавливает следующие:
* <table border="1" style="border-collapse: collapse">
* <tr><th>Клавиша</th><th>Действие</th></tr>
* <tr><td>W</td><td>ACTION_FORWARD</td></tr>
* <tr><td>S</td><td>ACTION_BACK</td></tr>
* <tr><td>A</td><td>ACTION_LEFT</td></tr>
* <tr><td>D</td><td>ACTION_RIGHT</td></tr>
* <tr><td>SPACE</td><td>ACTION_UP</td></tr>
* <tr><td>CONTROL</td><td>ACTION_DOWN</td></tr>
* <tr><td>SHIFT</td><td>ACTION_ACCELERATE</td></tr>
* <tr><td>UP</td><td>ACTION_PITCH_UP</td></tr>
* <tr><td>DOWN</td><td>ACTION_PITCH_DOWN</td></tr>
* <tr><td>LEFT</td><td>ACTION_YAW_LEFT</td></tr>
* <tr><td>RIGHT</td><td>ACTION_YAW_RIGHT</td></tr>
* <tr><td>M</td><td>ACTION_MOUSE_LOOK</td></tr>
* </table>
*/
override public function setDefaultBindings():void {
unbindAll();
bindKey(KeyboardUtils.W, ACTION_FORWARD);
bindKey(KeyboardUtils.S, ACTION_BACK);
bindKey(KeyboardUtils.A, ACTION_LEFT);
bindKey(KeyboardUtils.D, ACTION_RIGHT);
bindKey(KeyboardUtils.SPACE, ACTION_UP);
bindKey(KeyboardUtils.CONTROL, ACTION_DOWN);
bindKey(KeyboardUtils.UP, ACTION_PITCH_UP);
bindKey(KeyboardUtils.DOWN, ACTION_PITCH_DOWN);
bindKey(KeyboardUtils.LEFT, ACTION_YAW_LEFT);
bindKey(KeyboardUtils.RIGHT, ACTION_YAW_RIGHT);
bindKey(KeyboardUtils.SHIFT, ACTION_ACCELERATE);
bindKey(KeyboardUtils.M, ACTION_MOUSE_LOOK);
}
/**
* Метод выполняет поворот объекта в соответствии с имеющимися воздействиями. Взгляд вверх и вниз ограничен
* отклонением в 90 градусов от горизонтали.
*
* @param frameTime длительность текущего кадра в секундах
*/
override protected function rotateObject(frameTime:Number):void {
// Mouse look
var rotX:Number;
if (_mouseLookActive) {
prevMouseCoords.copy(currentMouseCoords);
currentMouseCoords.x = _eventsSource.stage.mouseX;
currentMouseCoords.y = _eventsSource.stage.mouseY;
if (!prevMouseCoords.equals(currentMouseCoords)) {
_object.rotationZ = startRotZ + (startMouseCoords.x - currentMouseCoords.x) * _mouseCoefficientX;
rotX = startRotX + (startMouseCoords.y - currentMouseCoords.y) * _mouseCoefficientY;
if (_object is Camera3D) {
// Коррекция поворота для камеры
_object.rotationX = (rotX > MathUtils.DEG90) ? 0 : (rotX < -MathUtils.DEG90) ? -Math.PI : rotX - MathUtils.DEG90;
} else {
_object.rotationX = (rotX > MathUtils.DEG90) ? MathUtils.DEG90 : (rotX < -MathUtils.DEG90) ? -MathUtils.DEG90 : rotX;
}
}
}
// Повороты влево-вправо
if (_yawLeft) {
_object.rotationZ += _yawSpeed * frameTime;
} else if (_yawRight) {
_object.rotationZ -= _yawSpeed * frameTime;
}
// Взгляд вверх-вниз
rotX = NaN;
if (_pitchUp) {
rotX = _object.rotationX + _pitchSpeed * frameTime;
} else if (_pitchDown) {
rotX = _object.rotationX - _pitchSpeed * frameTime;
}
if (!isNaN(rotX)) {
if (_object is Camera3D) {
// Коррекция поворота для камеры
_object.rotationX = (rotX > 0) ? 0 : (rotX < -Math.PI) ? -Math.PI : rotX;
} else {
_object.rotationX = (rotX > MathUtils.DEG90) ? MathUtils.DEG90 : (rotX < -MathUtils.DEG90) ? -MathUtils.DEG90 : rotX;
}
}
}
/**
* Метод вычисляет вектор потенциального смещения эллипсоида, учитывая режим перемещения, команды перемещения и силу тяжести.
*
* @param frameTime длительность текущего кадра в секундах
* @param displacement в эту переменную записывается вычисленное потенциальное смещение объекта
*/
override protected function getDisplacement(frameTime:Number, displacement:Point3D):void {
var cos:Number = 0;
if (checkCollisions && !_flyMode) {
// Проверка наличия под ногами поверхности
displacement.x = 0;
displacement.y = 0;
displacement.z = - 0.5 * gravity * frameTime * frameTime;
if (_collider.getCollision(_coords, displacement, collision)) {
cos = collision.normal.z;
_groundMesh = collision.face._mesh;
} else {
_groundMesh = null;
}
}
_onGround = cos > minGroundCos;
if (_onGround && inJump) {
inJump = false;
}
var len:Number;
var x:Number;
var y:Number;
var z:Number;
// При наличии управляющих воздействий расчитывается приращение скорости
controlsActive = _forward || _back || _right || _left || _up || _down;
if (controlsActive) {
if (_flyMode) {
tmpVelocity.x = 0;
tmpVelocity.y = 0;
tmpVelocity.z = 0;
// Режим полёта, ускорения направлены вдоль локальных осей
// Ускорение вперёд-назад
if (_forward) {
tmpVelocity.y = 1;
} else if (_back) {
tmpVelocity.y = -1;
}
// Ускорение влево-вправо
if (_right) {
tmpVelocity.x = 1;
} else if (_left) {
tmpVelocity.x = -1;
}
// Ускорение вверх-вниз
if (_up) {
tmpVelocity.z = 1;
} else if (_down) {
tmpVelocity.z = -1;
}
var matrix:Matrix3D = _object.transformation;
x = tmpVelocity.x;
if (_object is Camera3D) {
y = -tmpVelocity.z;
z = tmpVelocity.y;
} else {
y = tmpVelocity.y;
z = tmpVelocity.z;
}
// Поворот вектора из локальной системы координат объекта в глобальную
velocity.x += (x * matrix.a + y * matrix.b + z * matrix.c) * _speed;
velocity.y += (x * matrix.e + y * matrix.f + z * matrix.g) * _speed;
velocity.z += (x * matrix.i + y * matrix.j + z * matrix.k) * _speed;
} else {
// Режим хождения, ускорения вперёд-назад-влево-вправо лежат в глобальной плоскости XY, вверх-вниз направлены вдоль глобальной оси Z
var heading:Number = _object.rotationZ;
var headingCos:Number = Math.cos(heading);
var headingSin:Number = Math.sin(heading);
var spd:Number = _speed;
if (gravity != 0 && !_onGround) {
spd *= _airControlCoefficient;
}
// Вперёд-назад
if (_forward) {
velocity.x -= spd * headingSin;
velocity.y += spd * headingCos;
} else if (_back) {
velocity.x += spd * headingSin;
velocity.y -= spd * headingCos;
}
// Влево-вправо
if (_right) {
velocity.x += spd * headingCos;
velocity.y += spd * headingSin;
} else if (_left) {
velocity.x -= spd * headingCos;
velocity.y -= spd * headingSin;
}
if (gravity == 0) {
// Ускорение вверх-вниз
if (_up) {
velocity.z += _speed;
} else if (_down) {
velocity.z -= _speed;
}
}
}
} else {
// Управление неактивно, замедление движения
len = 1 / Math.pow(3, frameTime * 10);
if (_flyMode || gravity == 0) {
velocity.x *= len;
velocity.y *= len;
velocity.z *= len;
} else {
if (_onGround) {
velocity.x *= len;
velocity.y *= len;
if (velocity.z < 0) {
velocity.z *= len;
}
} else {
if (cos > 0 && velocity.z > 0) {
velocity.z = 0;
}
}
}
}
// Прыжок
if (_onGround && _up && !inJump) {
velocity.z = jumpSpeed;
inJump = true;
_onGround = false;
cos = 0;
}
// В режиме ходьбы добавляется ускорение свободного падения, если находимся не на ровной поверхности
if (!(_flyMode || _onGround)) {
velocity.z -= gravity * frameTime;
}
// Ограничение скорости
var max:Number = _accelerate ? _speed * _speedMultiplier : _speed;
if (_flyMode || gravity == 0) {
len = velocity.length;
if (len > max) {
velocity.length = max;
}
} else {
len = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y);
if (len > max) {
velocity.x *= max / len;
velocity.y *= max / len;
}
if (cos > 0 && velocity.z > 0) {
velocity.z = 0;
}
}
// Cмещение за кадр
displacement.x = velocity.x * frameTime;
displacement.y = velocity.y * frameTime;
displacement.z = velocity.z * frameTime;
}
/**
* Метод применяет потенциальный вектор смещения к эллипсоиду с учётом столкновений с геометрией сцены, если включён
* соотвествующий режим.
*
* @param frameTime время кадра в секундах
* @param displacement векотр потенциального смещения эллипсоида
*/
override protected function applyDisplacement(frameTime:Number, displacement:Point3D):void {
if (checkCollisions) {
_collider.calculateDestination(_coords, displacement, destination);
displacement.x = destination.x - _coords.x;
displacement.y = destination.y - _coords.y;
displacement.z = destination.z - _coords.z;
} else {
destination.x = _coords.x + displacement.x;
destination.y = _coords.y + displacement.y;
destination.z = _coords.z + displacement.z;
}
velocity.x = displacement.x / frameTime;
velocity.y = displacement.y / frameTime;
velocity.z = displacement.z / frameTime;
_coords.x = destination.x;
_coords.y = destination.y;
_coords.z = destination.z;
setObjectCoords();
var len:Number = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
if (len < speedThreshold) {
velocity.x = 0;
velocity.y = 0;
velocity.z = 0;
_currentSpeed = 0;
} else {
_currentSpeed = len;
}
}
/**
* Метод устанавливает координаты управляемого объекта в зависимости от параметра <code>objectZPosition</code>.
*
* @see #objectZPosition
*/
override protected function setObjectCoords():void {
_object.x = _coords.x;
_object.y = _coords.y;
_object.z = _coords.z + (2 * _objectZPosition - 1) * _collider.radiusZ;
}
/**
* Метод выполняет необходимые действия при включении вращения объекта мышью.
*/
override protected function startMouseLook():void {
super.startMouseLook();
startRotX = _object is Camera3D ? _object.rotationX + MathUtils.DEG90 : _object.rotationX;
startRotZ = _object.rotationZ;
}
}
}