Memory Effecient Text with border


(Crofty) #1

Hello. I’m working on my first project with Flash / Flashpunk. I had created a pop-up text (the kind you see for damage or heal on a creature). I have an embedded font, but I want a 2px border around it to make it more legible.

By combining multiple tutorials online, I managed to do this. First by creating a text field and a text format for it. Then I draw it on a bitmap data with a glow filter. Finally I put the bitmap data into an image. I also used this same method for more permanent text like HP, etc. However, they’re changing every update (regen) which means a new bitmap data and a new image on every update.

From what I can tell, each pop-up text takes up 70kb of memory. This seems very costly memory wise to me. What is a better way to do this? Is 70kb too much or is it okay? Thanks in advance.


(rostok) #2

Here’s my static class for fast font rendering. I have a habit to overload render methods and do a lot of gfx in realtime. Quite a different approach but maybe you will find it useful. The idea is to create all the images for each char.

package rostok 
{
	import flash.display.BitmapData;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import net.flashpunk.FP;
	import net.flashpunk.Graphic;
	import net.flashpunk.graphics.Image;
	import net.flashpunk.graphics.Text;
	import net.flashpunk.utils.Draw;

	/**
	 * very fast text rendering class
	 * 2013-09-01 22:37
	 * @author rostok
	 */
	public class FastFont 
	{
		private static var _matrix:Matrix = null;
		private static var _colorTransform:ColorTransform = null;
		private static var _characters:Dictionary = null;
		private static var _size:int = 8;
		private static var _font:String = "default";
		
		public function FastFont() 
		{
			
		}
		
		/**
		 * initializes class (prepares font characters)
		 */
		public static function init():void 
		{
			var i:int = 0;
			_matrix = new Matrix();
			_colorTransform = new ColorTransform();
			_characters = new Dictionary();
			var allchars:String;
			for (i = 0; i < 255; i++) allchars += String.fromCharCode(i);

			for (i = 0; i < allchars.length; i++)
			{
				var s:String = allchars.charAt(i);
				
				var txt:Text = new Text( s.substr(0, 1) , 0, 0, { font:_font, size:_size, color:0xFFFFFF } ); // change for sth completly different
				//if (s.length>1) txt.getSource().draw((new Text( s.substr(1, 10), 0, 0, { font:_font, size:_size, color:0xFFFFFF } )).getSource());
				_characters[allchars.charAt(i)] = txt;
			}
		}
		
		/**
		 * returns text width
		 * @param	text
		 */
		public static function width(text:String, special:Boolean=false):int 
		{
			// remove it and initialize manually for even higher speed
			if (_characters == null) init();
			var w:int = 0;
			for (var i:int = 0; i < text.length; i++) 
			{ 
				var letter:Image = _characters[text.charAt(i)];
				if (!letter) continue;
				var src:BitmapData = letter.getSource();
				
				w += src.width - 4;
				if (special) switch (text.charAt(i)) 
				{
					case "\n":
					case "\r":
								w = 0;
								break;
					case "\t":
								w += Image(_characters['A']).width*8;
								break;
					default:
				}
			}		
			return w;
		}
		
		/**
		 * draws text 
		 * @param	text	text to be drawn
		 * @param	x		x position
		 * @param	y		y position
		 * @param	color	colour, alpha is omitted
		 * @param	target	destination bitmapdata of FP's screen if null
		 * @param   special	if true special chars (newline, CR, tab) are not ignored
		 */
		public static function print(text:String, ox:int, oy:int, color:int=0xFFFFFF, target:BitmapData = null, special:Boolean = false):void 
		{
			// remove it and initialize manually for even higher speed
			if (_characters == null) init();
			
			_colorTransform.redMultiplier = (color >> 16 & 0xFF) / 255.0;
			_colorTransform.greenMultiplier = (color >> 8 & 0xFF) / 255.0;
			_colorTransform.blueMultiplier = (color & 0xFF) / 255.0;
				
			var x:int = ox;
			var y:int = oy;
			if (!target) target = FP.buffer;
			x -= FP.camera.x;
			y -= FP.camera.y;
			for (var i:int = 0; i < text.length; i++) 
			{ 
				var letter:Image = _characters[text.charAt(i)];
				if (!letter) continue;
				var src:BitmapData = letter.getSource();
				
				_matrix.tx = x;
				_matrix.ty = y;
				target.draw(src, _matrix, _colorTransform);
				//target.draw(src, null, null);
				//target.copyPixels(src, src.rect, new Point(x, y), src, src.rect.topLeft, true);
				x += src.width - 4;
				if (special) switch (text.charAt(i)) 
				{
					case "\n":
					case "\r":
								x = ox;
								y += Image(_characters['A']).height;
								break;
					case "\t":
								x += Image(_characters['A']).width*8;
								break;
					default:
				}
			}		
		}
	}
}

Faster text rendering
(azrafe7) #3

See this post on the forums for basic ideas.

And if you’re familiar with FlashPunk’s Text class you should also look into this diff on github, which shows an implementation of FlashPunk’s Text class with additional support for outlines/borders (via GlowFilter) by @AbelToy.

The latter is somewhat old, in the sense that the official code of the Text class may have changed slightly, but once you get where the neccesary additions are being made, then it should be fairly trivial to add them to your custom Text.as.

EDIT: Ooohh…I didn’t see @rostok had already published his post while I was editing mine. Is there a way to get a warning when things like this happen (or I’m missing something?! o.O).


(Crofty) #4

I think I understand what your code is doing. Correct me if I’m wrong, but you’re storing the individual letters into an array and then reading the string to type it one character at a time (like a typewriter). Or at least what I started building after looking at your code. However, I noticed a problem: the font I want to use is not mono-spaced. How do you deal with the kerning?


(rostok) #5

That’s exactly right - first store, then paste each letter. But every character has its own width that depends on the font face you are using. So for example ‘I’ will be narrower than ‘A’, provided, of course, the font isn’t monospaced. Check out this line w += src.width - 4;