матричные преобразования на смежных спрайтах, вызывающие субпиксельные промежутки - PullRequest
4 голосов
/ 23 апреля 2009

У меня есть три спрайта, сложенных друг на друга.

Я изменяю их transform.matrix, чтобы создать впечатление, что они растут в унисон.

Однако между плитками иногда появляются небольшие трещины в зависимости от коэффициента масштабирования.

трещины между спрайтами http://img21.imageshack.us/img21/7518/cracks.png

Мне интересно, как это исправить.

Я знаю, что текстовые объекты в AS3 имеют опции для субпиксельного рендеринга . Может быть, похожая настройка существует для всех AS3? Другие идеи?

Тактика, которая не работает: cacheAsBitmap.

package
{

import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;

import mx.core.UIComponent;

public class tmpa extends UIComponent
{

    private var _scale:Number;

    private var _s1:Sprite;
    private var _s2:Sprite;
    private var _s3:Sprite;

    private var _s1Pt:Point;
    private var _s2Pt:Point;
    private var _s3Pt:Point;

    private var _tileDim:int;


    public function tmpa( ):void
    {
        _scale = 1;
        _tileDim = 100;

        _s1 = new Sprite();
        _s2 = new Sprite();
        _s3 = new Sprite();

        paintSprite( _s1, _tileDim );
        paintSprite( _s2, _tileDim );
        paintSprite( _s3, _tileDim );

        _s1Pt = new Point( 100, _tileDim );
        _s1.x = _s1Pt.x;
        _s1.y = _s1Pt.y;
        _s2Pt = new Point( 100, _tileDim*2 );
        _s2.x = _s2Pt.x;
        _s2.y = _s2Pt.y;
        _s3Pt = new Point( 100, _tileDim*3 );
        _s3.x = _s3Pt.x;
        _s3.y = _s3Pt.y;

        addChild( _s1 );
        addChild( _s2 );
        addChild( _s3 );

        scale = 1.0394; //cracks
        //scale = 1.0306; // nocracks
    }

    private function paintSprite( s:Sprite, dim:int, color:int=0xFF0000 ):void
    {   s.graphics.beginFill( color, .5 );
        s.graphics.drawRect( 0, 0, dim, dim );
        s.graphics.endFill( );
    }


    public function set scale( s:Number ):void
    {   _scale = s;

        var scaleFromPt:Point = new Point( 20, 20 );
        updateSpriteMatrix( _s1, _s1.globalToLocal(scaleFromPt), _s1Pt );
        updateSpriteMatrix( _s2, _s2.globalToLocal(scaleFromPt), _s2Pt );
        updateSpriteMatrix( _s3, _s3.globalToLocal(scaleFromPt), _s3Pt );
    }

    public function get scale( ):Number
    {   return _scale;
    }

    private function updateSpriteMatrix( t:Sprite, ctrPt:Point, regPt:Point ):void
    {   var mx:Matrix = t.transform.matrix;
        mx.identity();
        mx.scale( _scale, _scale );
        mx.translate( ctrPt.x*(1-_scale), ctrPt.y*(1-_scale));
        mx.translate( regPt.x, regPt.y );
        t.transform.matrix = mx;
    }

}
}

И mxml:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            xmlns:a="*"
            width="100%" height="100%"
            paddingTop="0" paddingBottom="0" paddingLeft="0" paddingRight="0"
            backgroundColor="0x000000"
            backgroundGradientAlphas="undefined">
    <a:tmpa id="t" width="100%" height="100%" x="0" y="0" left="0" top="0"/>
</mx:Application>

1 Ответ

7 голосов
/ 23 апреля 2009

Причина, по которой существуют пропуски, связана с ошибками округления. Flash может размещать элементы только с точностью до 1 двадцатого пикселя (твип). Вы устанавливали позиции у на

  • +3,152000000000008
  • +7,092000000000018
  • 11,032000000000028

соответственно. Очевидно, что это намного точнее, чем двадцатое, поэтому происходит округление. Когда происходит округление, вы подвержены ошибкам.

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

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

package
{

import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;

import mx.core.UIComponent;

public class tmpa extends UIComponent
{

        private var _scale:Number;

        private var _s1:Sprite;
        private var _s2:Sprite;
        private var _s3:Sprite;

        private var _s1Pt:Point;
        private var _s2Pt:Point;
        private var _s3Pt:Point;

        private var _tileDim:int;


        public function tmpa( ):void
        {
                _scale = 1;
                _tileDim = 100;

                _s1 = new Sprite();
                _s2 = new Sprite();
                _s3 = new Sprite();

                paintSprite( _s1, _tileDim );
                paintSprite( _s2, _tileDim );
                paintSprite( _s3, _tileDim );

                _s1Pt = new Point( 100, _tileDim );
                _s1.x = _s1Pt.x;
                _s1.y = _s1Pt.y;
                _s2Pt = new Point( 100, _tileDim*2 );
                _s2.x = _s2Pt.x;
                _s2.y = _s2Pt.y;
                _s3Pt = new Point( 100, _tileDim*3 );
                _s3.x = _s3Pt.x;
                _s3.y = _s3Pt.y;

                _s1.transform.matrix = new Matrix();
                _s2.transform.matrix = new Matrix();
                _s3.transform.matrix = new Matrix();

                addChild( _s1 );
                addChild( _s2 );
                addChild( _s3 );

                scale = 1.0394; //cracks
                //scale = 1.0306; // nocracks
        }

        private function paintSprite( s:Sprite, dim:int, color:int=0xFF0000 ):void
        {       s.graphics.beginFill( color, .5 );
                s.graphics.drawRect( 0, 0, dim, dim );
                s.graphics.endFill( );
        }

        public function set scale( s:Number ):void
        {       _scale = s;

                scaleSpriteMatrix( _s1 );
                scaleSpriteMatrix( _s2 );
                scaleSpriteMatrix( _s3 );

                translateSprite(_s2, _s1);
                translateSprite(_s3, _s2);
        }

        public function get scale( ):Number
        {       return _scale;
        }

        private function scaleSpriteMatrix( targetSprite:Sprite):void
        {       var mx:Matrix = targetSprite.transform.matrix;
                mx.scale( _scale, _scale );
                targetSprite.transform.matrix = mx;
        }

        private function translateSprite( targetSprite:Sprite, basedOnSprite:Sprite):void
        {       var mx:Matrix = targetSprite.transform.matrix;
                mx.translate( basedOnSprite.x, basedOnSprite.y + basedOnSprite.height);
                targetSprite.transform.matrix = mx;
        }

}
}

Надеюсь, это поможет

Джеймс

...