color me brad предпринял хорошую попытку - и это заставило меня задуматься о проблеме.
Переопределить BitmapRenderer, чтобы разрешить тайлинг, сложно, потому что изменения, вносимые компонентом рендеринга, выполняются с матрицами.Я написал класс, который игнорирует масштабирование и вместо этого создает новое растровое изображение с большими физическими размерами по мере необходимости.
Приведенное ниже решение имеет некоторые небольшие ограничения: мне пришлось округлять изменения масштабирования и проверять измененияс точностью до 1 знака после запятой (тестирование доказывает, что иногда это необходимо для тел с определенными коэффициентами масштаба).
Во-вторых, поскольку мы перерисовываем каждый раз, когда изменяется масштаб, он может быть не так хорошо оптимизирован, как если бы мы просто обновлялиматричная шкала.
Тем не менее - она все еще очень быстрая, соответствует «философии» PBE, и сейчас я успешно использую ее в играх.
package render
{
import com.pblabs.engine.PBUtil;
import com.pblabs.rendering2D.BitmapRenderer;
import com.pblabs.rendering2D.SpriteRenderer;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.Vector3D;
/**
* Creates a tiles bitmap. The tile is identified as the first bitmap parameter set when this component is created.
*/
public class TileRenderer extends BitmapRenderer
{
public function TileRenderer()
{
super();
}
protected var lastScaleX:Number = undefined;
protected var lastScaleY:Number = undefined;
// the original bitmap contains the single tile we will reuse to fill out the bitmap
protected var originalBitmapData:BitmapData;
/**
* Just set this to the tile you want to reuse. It will automatically figure out tile width and height.
*/
override public function set bitmapData(value:BitmapData):void{
if (value === bitmapData)
return;
originalBitmapData = value;
bitmap.bitmapData = advanceRender(value.width, value.height);
// Due to a bug, this has to be reset after setting bitmapData.
smoothing = _smoothing;
// set registration point to get spritesheet-component-style centering
registrationPoint = new Point(value.width/2,value.height/2);
_transformDirty = true;
}
/**
* tile the original bitmap across a new bitmap area
* the following is adapted from http://stackoverflow.com/users/102373/colour-me-brad:
*/
protected function advanceRender(targetWidth:Number, targetHeight:Number):BitmapData{
var target:BitmapData = new BitmapData(targetWidth,targetHeight, true,0x00000000);
var cx:int = Math.ceil(target.width/originalBitmapData.width);
var cy:int = Math.ceil(target.height/originalBitmapData.height);
target = new BitmapData(target.width, target.height, true, 0x000000);
// fill the bitmapData object with all display info with the provided bitmap
for (var ix:int = 0; ix<cx; ix++) {
for (var iy:int = 0; iy<cy; iy++)
target.copyPixels(originalBitmapData,originalBitmapData.rect, new Point(ix*originalBitmapData.width,iy*originalBitmapData.height));
}
return target;
}
/**
* heavily override this function to avoid changing scale. We instead redraw the
* bitmap to the correct width and height.
*/
override public function updateTransform(updateProps:Boolean = false):void
{
if(!displayObject)
return;
if(updateProps)
updateProperties();
// If size is active, it always takes precedence over scale.
var tmpScaleX:Number = _scale.x;
var tmpScaleY:Number = _scale.y;
if(_size)
{
var localDimensions:Rectangle = displayObject.getBounds(displayObject);
tmpScaleX = _scale.x * (_size.x / localDimensions.width);
tmpScaleY = _scale.y * (_size.y / localDimensions.height);
}
_transformMatrix.identity();
//_transformMatrix.scale(tmpScaleX, tmpScaleY);
_transformMatrix.translate(-_registrationPoint.x * tmpScaleX, -_registrationPoint.y * tmpScaleY);
_transformMatrix.rotate(PBUtil.getRadiansFromDegrees(_rotation) + _rotationOffset);
_transformMatrix.translate(_position.x + _positionOffset.x, _position.y + _positionOffset.y);
if (getRoundDecimal(tmpScaleX,1) != 1 || getRoundDecimal(tmpScaleY,1) != 1) {
bitmap.bitmapData = advanceRender(originalBitmapData.width*tmpScaleX, originalBitmapData.height * tmpScaleY);
smoothing = _smoothing;
// set registration point to get spritesheet-component-style centering
registrationPoint = new Point(bitmap.bitmapData.width/2,bitmap.bitmapData.height/2);
}
displayObject.transform.matrix = _transformMatrix;
displayObject.alpha = _alpha;
displayObject.blendMode = _blendMode;
displayObject.visible = (alpha > 0);
_transformDirty = false;
}
/**
* taken from: http://swordfish1987.wordpress.com/2009/07/10/decimal-rounding-in-actionscript-3/
*/
public static function getRoundDecimal(num:Number, precision:int):Number{
var decimal:Number = Math.pow(10, precision);
return Math.round(decimal* num) / decimal;
}
override protected function onRemove():void{
originalBitmapData = null;
super.onRemove();
}
}
}