A Flash Developer Resource Site

Results 1 to 10 of 10

Thread: Random Sliding Text from Array

Hybrid View

  1. #1
    Junior Member
    Join Date
    Nov 2009
    Posts
    8

    Random Sliding Text from Array

    Hi folks,

    This would seem on the surface to be a really simple effect to achieve, but as a noob to AS, it's got me totally baffled!

    All I want is to create multiple animated textboxes to slide horizontally from one side of the screen to the other and repeat indefinitely in a loop.

    Now the 'trick' is that I need the textbox contents to be selected at random from an array and for the speed, size and opacity to vary as well (to give a sense of depth, like the 'Parallax' effect).

    So, the final effect is multiple random strings of text sliding horizontally across the screen at the same time, some appearing closer than others.

    I'm positive I've seen this effect explained online before, but for the life of me I can't summon the right keywords to bring up a relevant article in my searches (keep getting lots of text scroller tutorials).

    If anyone knows of any tutorials out there to accomplish something like the above, I would be very grateful if you could put me out of my misery and throw me a link to check out.

    Cheers,

    Luke

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I think this is a great project to work on step by step to show the development process. The first step is to get your requirements down. You seem to have a fairly good idea of what you'd actually like to achieve, so that's just about done, but it couldn't hurt to write it down explicitly. We can always revise it later.

    Requirements:
    1. Create textboxes from array of strings.
    2. select text from array in a random fashion
    3. configure appearance of created textbox in a random fashion within parameters
    4. animate instances with a constrained random speed

    What your requirements don't cover is important. For instance, are the y positions of these textboxes random or specified? Should a box loop around once it traverses the entire screen? Is the direction random, right, or left? Where does the array of Strings come from?

    We will make some assumptions about these unanswered questions while building our prototype.

    The development process continues with the next post.

  3. #3
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    The next step is to break your project down into tasks. You will want to determine which tasks depend on other tasks and which can be done in parallel. If you have a team, then you can divide independent tasks and work on them at the same time, then put them together later.

    Tasks:
    1. Create and configure textboxes from an Array of Strings
    2. Animate instances.
    3. ?configure parameters from external data?
    4. Put it all together.

    It looks to me like 1 and 2 are independent. 3 may not be necessary for this project, and if it is we can come back and add it after the basics are working. 4 is necessary, but depends on both 1 and 2.

    So let's do task 1 and 2 in parallel, then 4, then evaluate whether 3 is necessary and do that.

    Since I'm only one person, I can't do 1 and 2 at the same time, but if you had a team, you could.

    Next, task 1, create and configure textboxes from an array of strings.

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Task 1, creating Textboxes from an Array of Strings.

    For the purposes of this task, I will assume the Array is already available, and the random parameters are too.

    Let's build a function which takes an Array of Strings, a number of boxes to create and builds that number of textboxes.

    Let's also build a function to create an individual textbox, given a String.

    Here's some code I built to do these things. This is all in the document class so far, we haven't made other classes yet.
    Code:
    package 
    {
    	import flash.display.DisplayObject;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFormat;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class Main extends Sprite 
    	{
    		
    		private var texts:Array;
    		private var boxes:Array;
    		private var minSize:int;
    		private var maxSize:int;
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			setup();
    			boxes = buildTextBoxes(texts, 4);
    			placeBoxes(boxes);
    		}
    		
    		private function setup():void {
    			texts = ["foo", "bar", "baz", "quux", "five", "tons", "of", "flax"];
    			minSize = 8;
    			maxSize = 50;
    		}
    		
    		private function buildTextBoxes(t:Array, howmany:int):Array {
    			var toreturn:Array = [];
    			for (var i:int = 0; i < howmany; i++) {
    				var randomText:String = t[Math.floor(Math.random() * t.length)];
    				toreturn.push(buildBox(randomText));
    			}
    			return toreturn;
    		}
    		
    		private function buildBox(s:String):TextField {
    			var tf:TextField = new TextField();
    			tf.autoSize = TextFieldAutoSize.LEFT;
    			var randomSize:int = Math.floor(Math.random() * (maxSize-minSize)) + minSize;
    			var format:TextFormat = new TextFormat(null, randomSize);
    			tf.defaultTextFormat = format;
    			tf.text = s;
    			return tf;
    		}
    		
    		private function placeBoxes(bs:Array):void {
    			for (var i:int = 0; i < bs.length; i++) {
    				var b:DisplayObject = bs[i];
    				b.x = Math.random() * stage.stageWidth;
    				b.y = Math.random() * stage.stageHeight;
    				addChild(b);
    			}
    		}
    		
    	}
    	
    }

  5. #5
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    For task 2, we need to animate these things. Again, we will make some assumptions. Namely, that the objects all move the same direction, and that they should wrap indefinitely. At this point, we should decide how we want to animate them. If we know we want a constant speed, we could just move them some amount each frame. But if we want easing, then we'd be better off with a tweening engine of some kind. I'll also assume that a given instance should maintain the same speed on each pass, so we want to associate that speed with the instance.

    Sounds like we want to make a class to hold that speed to make it easier to operate on. Let's do that first.

    Code:
    package  
    {
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFormat;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class MoveableTextField extends TextField 
    	{
    		
    		public var speed:Number;
    		
    		public function MoveableTextField(text:String, size:int, speed:Number) 
    		{
    			super();
    			this.speed = speed;
    			this.autoSize = TextFieldAutoSize.LEFT;
    			var format:TextFormat = new TextFormat(null, size);
    			this.defaultTextFormat = format;
    			this.text = text;
    		}
    		
    	}
    
    }
    Now, that does most of what our buildBox function did, so let's refactor Main.
    Code:
    package 
    {
    	import flash.display.DisplayObject;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFormat;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class Main extends Sprite 
    	{
    		
    		private var texts:Array;
    		private var boxes:Array;
    		private var minSize:int;
    		private var maxSize:int;
    		private var minSpeed:Number;
    		private var maxSpeed:Number;
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			setup();
    			boxes = buildTextBoxes(texts, 4);
    			placeBoxes(boxes);
    		}
    		
    		private function setup():void {
    			texts = ["foo", "bar", "baz", "quux", "five", "tons", "of", "flax"];
    			minSize = 8;
    			maxSize = 50;
    			minSpeed = 1;
    			maxSpeed = 15;
    		}
    		
    		private function buildTextBoxes(t:Array, howmany:int):Array {
    			var toreturn:Array = [];
    			for (var i:int = 0; i < howmany; i++) {
    				var randomText:String = t[Math.floor(Math.random() * t.length)];
    				var randomSize:int = Math.floor(Math.random() * (maxSize-minSize)) + minSize;
    				var randomSpeed:Number = Math.random() * (maxSpeed - minSpeed) + minSpeed;
    				toreturn.push(new MoveableTextField(randomText, randomSize, randomSpeed));
    			}
    			return toreturn;
    		}
    		
    		private function placeBoxes(bs:Array):void {
    			for (var i:int = 0; i < bs.length; i++) {
    				var b:DisplayObject = bs[i];
    				b.x = Math.random() * stage.stageWidth;
    				b.y = Math.random() * stage.stageHeight;
    				addChild(b);
    			}
    		}
    		
    	}
    	
    }
    That still doesn't move the textboxes though, so let's add that.
    Code:
    package  
    {
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFormat;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class MoveableTextField extends TextField 
    	{
    		
    		public var speed:Number;
    		
    		public function MoveableTextField(text:String, size:int, speed:Number) 
    		{
    			super();
    			this.speed = speed;
    			this.autoSize = TextFieldAutoSize.LEFT;
    			var format:TextFormat = new TextFormat(null, size);
    			this.defaultTextFormat = format;
    			this.text = text;
    			addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event):void {
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			addEventListener(Event.ENTER_FRAME, move);
    			addEventListener(Event.REMOVED_FROM_STAGE, stop);
    		}
    		
    		public function move(e:Event):void {
    			this.x += speed;
    			if (this.x > stage.stageWidth) {
    				this.x = -this.width;
    			}
    		}
    		
    		private function stop(e:Event):void{
    		  removeEventListener(Event.REMOVED_FROM_STAGE, stop);
    		  removeEventListener(Event.ENTER_FRAME, move);
    		  addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    	}
    
    }

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    At this point, you're left with adjusting the opacity, and parameters. If you want to load the parameters from an external source, you will need to replace the implementation of setup in Main.

    I'd suggest making the speed, size, and opacity all depend on another property, maybe something like "virtualdepth". You could have MoveableTextField implement a getter and setter for that which calculates those dependent values based on the apparent depth. Speed should decrease with depth (squared, I think), opacity should decrease probably, and size should definitely decrease (squared). That implies a maximum virtual depth, which you can probably just assume is a decently large number like 500.

  7. #7
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Okay, I felt like doing that too.
    Code:
    package  
    {
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFormat;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class MoveableTextField extends TextField 
    	{
    		
    		private var speed:Number;
    		private var _depth:Number;
    		public static const maxDepth:Number = 500;
    		
    		public static var minSize:int;
    		public static var maxSize:int;
    		public static var maxSpeed:Number;
    		
    		public function MoveableTextField(text:String, depth:Number) 
    		{
    			super();
    			this.depth = depth;
    			this.autoSize = TextFieldAutoSize.LEFT;
    			this.text = text;
    			addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event):void {
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			addEventListener(Event.ENTER_FRAME, move);
    			addEventListener(Event.REMOVED_FROM_STAGE, stop);
    		}
    		
    		public function move(e:Event):void {
    			this.x += speed;
    			if (this.x > stage.stageWidth) {
    				this.x = -this.width;
    			}
    		}
    		
    		private function stop(e:Event):void{
    		  removeEventListener(Event.REMOVED_FROM_STAGE, stop);
    		  removeEventListener(Event.ENTER_FRAME, move);
    		  addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		public function get depth():Number {
    			return _depth;
    		}
    		
    		public function set depth(d:Number):void {
    			if (d > maxDepth) {
    				d = maxDepth;
    			}
    			if (d < 1) {
    				d = 1;
    			}
    			_depth = d;
    			var ratio:Number = (_depth / maxDepth);
    			var reverseRatio:Number = 1 - ratio;
    			var size:int = Math.floor(reverseRatio * (maxSize - minSize) + minSize);
    			this.alpha = reverseRatio*(.8) + .2;
    			this.speed = reverseRatio * reverseRatio * maxSpeed;
    			var tf:TextFormat = new TextFormat(null, size);
    			this.defaultTextFormat = tf;
    		}
    	}
    
    }

  8. #8
    Junior Member
    Join Date
    Nov 2009
    Posts
    8
    WOW!!!

    This could be the most complete response I've ever received on any forum, ever!

    I'm so grateful for all the effort you've put in here.

    So, as I understand it, you have created two public classes in separate .as files:

    "Main" and "MoveableTextField"

    Do I link my Flash movie (In the Publish settings) to the "Main" .as file?

    Also, I was wondering how I could set the properties of the text (colour, font, etc) and constrain the area where the text can be generated (I need it to scroll acroll a particular area of my stage near the top)

    Thanks again for all your help, I really appreciate it!!

    Luke
    Last edited by Lukasx123; 11-25-2011 at 10:27 AM.

  9. #9
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Yes, there are two separate .as files. Main is intended to be the document class (and you will need to alter it further for your own purposes). You do not need to explicitly link MoveableTextField to any symbol, just make sure it's in your classpath. It should suffice to put it in the same directory as Main.as and your FLA. The reason that it doesn't need to be linked to any symbol is that it does not have any graphics that you would need to link. It's entirely code-based.

    To alter the font, color, etc of the text, you will want to set those properties on the TextFormat used in MoveableTextField. You could do that within MoveableTextField, or outside it since MoveableTextField is a subclass of TextField and has all the same methods and properties.

    To constrain the vertical position of your texts, just restrict the y positions that they are assigned in Main. If you need to constrain the horizontal range, it might be better to change MoveableTextField to take a Rectangle for bounds, or have it reference its display parent rather than the stage.

    By the way, I did not post the final Main.as, which had changes for using the depth getter/setter. Here it is:
    Code:
    package 
    {
    	import flash.display.DisplayObject;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFormat;
    	
    	/**
    	 * ...
    	 * @author srs
    	 */
    	public class Main extends Sprite 
    	{
    		
    		private var texts:Array;
    		private var boxes:Array;
    		private var minSize:int;
    		private var maxSize:int;
    		private var minSpeed:Number;
    		private var maxSpeed:Number;
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			setup();
    			boxes = buildTextBoxes(texts, 4);
    			placeBoxes(boxes);
    		}
    		
    		private function setup():void {
    			texts = ["foo", "bar", "baz", "quux", "five", "tons", "of", "flax"];
    			MoveableTextField.minSize = 8;
    			MoveableTextField.maxSize = 50;
    			MoveableTextField.maxSpeed = 15;
    		}
    		
    		private function buildTextBoxes(t:Array, howmany:int):Array {
    			var toreturn:Array = [];
    			for (var i:int = 0; i < howmany; i++) {
    				var randomText:String = t[Math.floor(Math.random() * t.length)];
    				var randomDepth:Number = Math.random() * MoveableTextField.maxDepth;
    				toreturn.push(new MoveableTextField(randomText, randomDepth));
    			}
    			return toreturn;
    		}
    		
    		private function placeBoxes(bs:Array):void {
    			for (var i:int = 0; i < bs.length; i++) {
    				var b:DisplayObject = bs[i];
    				b.x = Math.random() * stage.stageWidth;
    				b.y = Math.random() * stage.stageHeight;
    				addChild(b);
    			}
    		}
    		
    	}
    	
    }
    Last edited by 5TonsOfFlax; 11-25-2011 at 03:17 PM.

  10. #10
    Junior Member
    Join Date
    Nov 2009
    Posts
    8
    This works brilliantly!

    I am in your debt! Thanks so much for your help on this.

    If you're ever in the South of England, drinks are definitely on me!

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center