Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   BitmapData.draw для вывода покадровой анимации (http://www.flasher.ru/forum/showthread.php?t=133689)

Juster 10.12.2009 15:35

BitmapData.draw для вывода покадровой анимации
 
Здравствуйте!

Допустим, я пишу игру на Flex и у меня есть класс AnimatedObject, который не наследует от DisplayObject и не участвует в иерархии flash сцены. Грубо говоря, он должен выводить определенный кадр своей картинки в заданных координатах. Для этого я в менеджере объектов прохожу по всем объектам и вызываю onDraw, передавая в качестве аргумента backBuffer : BitmapData, в который каждый должен нарисовать себя.

Вот так метод был реализован:
Код AS3:

var frame : Number;
 
public function onDraw(backBuffer : BitmapData) : void
{
        var frameClipRect : Rectangle = new Rectangle(int(frame) * celWidth, 0, frameWidth, frameHeight);
 
        var matrix : Matrix = new Matrix();
        matrix.translate(-frameWidth / 2, -frameHeight / 2);
        if ( scale )
                matrix.scale(scale, scale);
        if ( angle )
                matrix.rotate(Math.PI * angle / 180.0);
        matrix.translate(frameWidth / 2, frameHeight / 2);
        matrix.translate(x, y);
 
        backBuffer.draw(bitmap, matrix, null, null, frameClipRect, true);
}

Проблема в отсечении. В документации сказано, что clipRect задает область из источника, которая будет отрисована на целевой BitmapData. Если не задавать clipRect, то объект выводится, но со всеми кадрами. НО Если задавать clipRect как я это делаю, то ничего вообще не выводится, потому что.... clipRect в моем случае задает область отсечения для backBuffer!!!
Что происходит? :)

Спасибо большое!

Волгоградец 10.12.2009 16:24

Для этой цели надо использовать copyPixels, т.к. clipRect обрезает изображение, но не двигает его. Т.е. если у вас конечная битмапа размером 100х100, а исходная 200х100 и вы к исходной применяете clipRect(100, 0, 100, 100), то ее видно не будет, т.к. она не попадает в размеры конечной битмапы.

Juster 10.12.2009 16:41

Проблема с copyPixels в том, что она не позволяет применять трансформации поворота и масштабирования, которые в моем случае обязательны.

Волгоградец 10.12.2009 16:46

Как это? Т.е. надо из исходной битмапы вырезать кусок, причем координаты этого куска ависят от скэйла и угла? Не могу представить для чего это нужно.

Juster 10.12.2009 18:41

Представьте, что у меня есть картинка, в которую последовательно врисованы 30 кадров анимации. Мне нужно вывести определенный кадр из этой анимации, причем вывести в позиции (x, y), повернутый на угол rotation, увеличенный на scale коэффициент.

Волгоградец 11.12.2009 11:16

Тогда я правильно говорил - copyPixels, затем экземпляру Bitmap задаете масштаб и поворот. Или создаете еще одну битмапДату, куда методом draw и с заданной матрицей рисуете скопированную методом copyPixels битмапДату.

cleptoman 11.12.2009 14:10

Matrix спасет мир)

Wolsh 11.12.2009 16:59

Набросал тут классик)
Код AS1/AS2:

package  
{
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.Sprite;
        import flash.events.TimerEvent;
        import flash.geom.Point;
        import flash.geom.Rectangle;
        import flash.utils.Timer;
        /**
        * ...
        * @author wolsh
        */

        public class FilmViewer extends Bitmap
        {
                private var _film:BitmapData;
                private var _frameRect:Rectangle;
                private var _fps:uint;
                private var _width:Number;
                private var _height:Number;
                private var _timer:Timer;
                private var _loop:uint;
                private var _loopCount:uint = 0;
                private var _position:Number;
                private var _frame:uint = 0;
 
                public function FilmViewer(screenWidth:Number, screenHeight:Number)
                {
                        _width = screenWidth;
                        _height = screenHeight;
                        bitmapData = new BitmapData(_width, _height);
                        super(bitmapData, "auto", true);
                }
                public function mount(film:BitmapData, cadrRect:Rectangle, fps:uint):void
                {
                        _film = film;
                        _frameRect = cadrRect;
                        _fps = Math.round(1000/fps);
                        bitmapData.copyPixels(_film, _frameRect, new Point());
                }
                public function demount():void
                {
                        _timer.stop();
                        _timer = null;
                        _film = null, _frameRect = null, _fps = 0;
                        bitmapData.dispose();
                        _frame = 0;
                        _loopCount = 0;
                }
                public function play(loop:uint = 1):void
                {
                        _loop = loop;
                        _loopCount = 0;
                        _position = _frameRect.x;
                        _timer = new Timer(_fps);
                        _timer.addEventListener(TimerEvent.TIMER, viewNextFrame);
                        _timer.start();
                }
                public function stop():void
                {
                        _timer.stop();
                }
                public function get currentFrame():uint
                {
                        return _frame;
                }
                private function viewNextFrame(event:TimerEvent):void
                {
                        if (_loopCount < _loop || _loop == 0)
                        {
                                var cadr:Rectangle = new Rectangle(_position, _frameRect.y, _frameRect.width, _frameRect.height);
                                bitmapData.copyPixels(_film, cadr, new Point());
                                _position += _frameRect.width;
                                _frame += 1;
                                if (_position > _film.width - _frameRect.width)
                                {
                                        _position = _frameRect.x;
                                        _loopCount += 1;
                                        _frame = 0;
                                }
                        }
                }
 
        }
}

Создаете экземпляр FilmViewer, монтируете вашу битмапДату, задаете размер кадра и отступы (Rectangle), фпс, и вперед - плей. Количество лупов указываете обязательно, если бесконечно - 0.
пример
Код AS1/AS2:

var projector:FilmViewer = new FilmViewer(122, 122);
addChild(projector);
projector.x = projector.y = 50;
var cadr:Rectangle = new Rectangle(0, 0, 122, 122);
var moveData:BitmapData = (new moveFilm() as Bitmap).bitmapData;
projector.mount(moveData, cadr, 12);
projector.rotation = 25;
projector.scaleX = projector.scaleY = 1.5;
projector.play(5);


Psycho Tiger 11.12.2009 18:18

MovieClipFactory у etc кстати ещё есть.

Juster 11.12.2009 18:38

Большое спасибо всем за ответы!

Wolsh, хотя ваш FilmViewer решает немного другие задачи и не показывает ту проблему, с которой я столкнулся, но вы мне подсказали кое-что интересное.

Вобщем, я решил свою задачу другим способом, но проблема все еще актуальна. Сведения в документации по параметру clipRect для метода BitmapData.draw не соответствуют действительности в моем случае. Пожалуйста, если кто-то может, сделайте пробный тест?


Часовой пояс GMT +4, время: 06:47.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.