Korchy (korchy) wrote,
Korchy
korchy

Category:

Вращение спрайта вокруг произвольной точки

Собственно классическое решение задачи поворота спрайта на заданный угол вокруг произвольной точки (чаще всего его центра) путем матричных преобразований описана в куче литературы и интернет-источниках и звучит следующим образом: перенос спрайта таким образом, чтобы точка совпадал с точкой 0.0,0.0 , поворот на заданный угол, перенос обратно.
Функция RotateAroundAxis представляет реализацию данного метода (Axis - ось или точка, вокруг которой будет повернут спрайт, Angle - угол поворота):

private function RotateAroundAxis(Axis:Vector2,Angle:Number):void {
      // Перенос в 0,0,0
      var MoveVector:Vector2 = new Vector2();
      Vector2.Vec2Subtract(Axis,new Vector2(0.0,0.0),MoveVector);
      var matrix:Matrix = new Matrix();
      matrix.identity();
      matrix.translate(MoveVector.x,MoveVector.y);
      CountWorldMatrix(matrix);
      // Поворот
      var RotAngle:Number = Angle*Math.PI/180.0;
      // Получить матрицу вращения
      var Rot:Matrix = new Matrix();
      Rot.identity();
      Rot.rotate(RotAngle);
      CountWorldMatrix(Rot);
      // Вернутся обратно
      matrix.identity();
      matrix.translate(Axis.x,Axis.y);
      CountWorldMatrix(matrix);
}

Вспомогательная функция CountWorldMatrix добавляет полученную матрицу трансформации к исходной матрице объекта, за счет чего и выполняется поворот:

private function CountWorldMatrix(M:Matrix):void {
      var w:Matrix = transform.matrix;
      if(M!=null) w.concat(M);
      transform.matrix = w;
}

При вызове функции RotateAroundAxis необходимо, чтобы координаты оси были заданны в той же самой системе координат, в которой находится сам поворачиваемый спрайт. Если не соблюдать это правило спрайт будет поворачиваться и убегать куда угодно, только не в ту точку, в которую его необходимо было поместить. Чаще же всего поворачивать спрайт удобнее всего вокруг точки, заданной в системе координат сцены, т.е. того контейнера в котором собираются все отображаемые спрайты. Поэтому, чтобы повернуть спрайт например вокруг центра экрана, сначала необходимо width/2 и height/2 перевести в систему координат спрайта.
Для этих целей служит функция globalToLocal, которая собственно умножает переданную в нее точку на обратную concatenated-матрицу объекта из которого вызывается. Однако же на практике ее использование оказалось достаточно своеобразным. Когда спрайт является чайлдом сцены - globalToLocal срабатывает правильно. Стоит же создать иерархию из 2-3 подчиненных уровней сцена -спрайт - чайлд спрайта - ... начинаются нестыковки. В случаях, если спрайт сначала повернуть, после чего добавить ему чайлда и если к спрайту добавить уже повернутого чайлда, функция срабатывает далеко не так, как нужно. Поэтому функцию приходится переопределять (заодно переопределяется тип входного параметра на Vector2 - переопределенный Point со статическими методами операций над двумерными векторами):

internal function GlobalToLocal(Vector:Vector2):Vector2 {
      var TransformedVector:Vector2 = new Vector2(Vector.x,Vector.y);
      var P:Point = globalToLocal(Point(TransformedVector));
      if(parent!=null) P = parent.globalToLocal(Point(TransformedVector));
      TransformedVector.x = P.x;
      TransformedVector.y = P.y;
      return TransformedVector;
}

Соответственно, делаем обертку над вызовом функции RotateAroundAxis:

internal function RotateAround(Axis:Vector2,Angle:Number):Boolean {
      var TransformedAxis:Vector2 = GlobalToLocal(Axis);
      return RotateAroundAxis(TransformedAxis,Angle);
}

Такое переопределение позволяет правильно вращать спрайт вокруг произвольной оси независимо от того, является он чьим-то чайлдом или нет.
Вращение спрайта вокруг центра сцены на 45 градусов будет выглядеть следующим образом:

RotateAround(new Vector2(width/2,height/2),45);
Tags: actionscript 3.0, progr, интерпланети
Subscribe

  • Аддон Blender: AniCam

    AniCam - Аддон для графического редактора Blender 3D позволяющий анимировать разрешение камеры. Читать дальше:…

  • Дискозанна

    Дискозанна от chanceLadder Все необычные Сюзанны Читать дальше: https://b3d.interplanety.org/diskozanna/

  • Переопределение контекста

    Некоторые операторы в Blender можно вызывать только в той рабочей области, для которой они предназначены. Если вызывать, например, оператор,…

Comments for this post were disabled by the author