A Flash Developer Resource Site

Results 1 to 15 of 15

Thread: How would I go about making this work?

  1. #1
    Senior Member
    Join Date
    Nov 2004
    Posts
    110

    How would I go about making this work?

    Hi

    I'm in the stages of brainstorming ideas for a web site for a new font that is coming out. For one of the ideas I wanted to make something interactive and sort of experimental. Basically I want to have each character of the font be represented by a tiny circle; all the circles will then be randomly placed on stage. On roll over each circle a small blobby window opens up next to it showing which character it represents. Until now, no problem, but here's where I need help:

    I want to have a dynamic text field where the user can insert text and click a button to preview it on stage. When that button is clicked I want the circles corresponding to the input characters to be placed in position and reveal the word. Basically make the circles move from their random location on stage to a centered location and reveal their letters, and in doing so revealing the word the user input.

    What I'm trying to understand is how I would go about doing this. I know all the characters on stage will be inside an array. I know that when the user inputs the text I have to create a for loop, having as limit the number of characters keyed in including spaces; but I don't know how to relate a keyed in letter in a dynamic text field with the array of objects on my stage.

    I'm not looking for actual code or anything, just help with know what the best course of action to achieve this would be.

    Thanks!

  2. #2
    rabid_Delineator AttackRabbit's Avatar
    Join Date
    Dec 2003
    Location
    Orlando, Florida
    Posts
    481
    You are pretty much already there. I would make sure i add each , tiny circle , as a child to the same sprite , lets call it , circleHolder. Then on submit you could say
    Code:
    private function onSubmit() : void {
         for( var i : int = 0 , i < inputText.text.length ; i ++ ) {
              var inputChar : String = String( inputText.text.charAt );
              for( var j : int = 0 ; j < circleHolder.numChildren ; j ++ ) {
                   var targ : YourTextCircleClass = YourTextCircleClass( circleHolder.getChildAt( i ) );
                   if( inputChar == String( targ.txt.text ) ) {                    
                       targ.x = someFixedValue + ( ( targ.txt.textWidth + gutter ) * i );
                       targ.y = someOtherFixedValue;
                   };
              };
         };
    };
    Now of course you can refactor this , replace the x , y assignments with tweens , you could add support function , or even public function in your text circle class to return string , basically you could get this loop down even smaller.
    Last edited by AttackRabbit; 02-19-2010 at 10:07 AM.

  3. #3
    Senior Member
    Join Date
    Nov 2004
    Posts
    110
    Thanks! Your code got me thinking.
    What do you think of this:

    PHP Code:
    var total_glyphs:String = new String("ABCDEFGHIJKLMNOPQRSTUVXWZabcdefghijklmnopqrstuvxwz");
    var 
    array_glyphs:Array = new Array();
    var 
    array_circles:Array = new Array();

    for (var 
    g=0total_glyphs.lengthg++)
    {
        
    array_glyphs[g] = total_glyphs.charAt(g);
        
        var 
    circle:NewCircle = new NewCircle(); // Here I'm creating a new instance of NewCircle out of a class where I'll build the circles
                                                // Question: Is there a way to include the value of "g" onto the instance name of each circle?
                                                // Or better yet, the current value of array_glyphs[g].
                                                // Just so I can keep track of whatever circle it is. Like circle_A or circle_b. Is there a way?
                                                
        
    addChild(circle);
        
    circle.randomX;
        
    circle.randomY;
        
        
    array_circles.push(circle);
    }

    var 
    input_word:String = new String(tf_input.text);
    var 
    input_array:Array = new Array();
    var 
    used_glyphs_array:Array = new Array();

    for (var 
    i=0i<input_word.length i++)
    {
        
    input_array[i] = input_word.charAt(i);
        
        for (var 
    p=0p<array_glyphs.lengthp++)
        {
            if ( 
    input_array[i] == array_glyphs[p] )
            {
                
    used_glyphs_array.push(array_circles[g]); // This stores all the circles that represent the used glyphs on this array.
                                                          // Is this correct?
            
    }
        }

    Am I on something here?

  4. #4
    rabid_Delineator AttackRabbit's Avatar
    Join Date
    Dec 2003
    Location
    Orlando, Florida
    Posts
    481
    Well one thing about as3 which is nice , which you are not really taking advantage of , is direct access to the display list. You really don't need to create all these arrays. You really only need the one total glyphs string , and you dont need both 'cases' ie , A , and , a ,. You can use a case conversion operator later on if you need both to be on stage. I would declare a sprite , call it circleHolder for the sake of this coversation , so your declarations would look like this :

    Code:
    var glyphs : String = "abcdefghijklmnopqrstuvxwz"; 
    var circleHolder : Sprite = new Sprite();
    addChild( circleHolder );
    notice you dont have to say new String. Just assign it a literal like above.

    then in your loop just create your circle objects , im assuming NewCircle is a class you wrote , with a textfield in it.



    Code:
    var isUpperCase : Boolean = false;
    for ( var g : int = 0; g < glyphs.length; g++ ) {
         var targetGlyph : String;
         if( !isUpperCase ) {
              targetGlyph = String( glyphs.charAt( g ) );
         }else {
              targetGlyph = String( glyphs.charAt( g ) ).toUpperCase();
         };
         var circle : NewCircle = new NewCircle( targetGlyph  );                
         circleHolder.addChild( circle );
         circle.x = randomX;
         circle.y = randomY;
         if( g == glyphs.length ) {
              g = 0;
              isUpperCase = true;
         };
    };
    So here , you basically grab a character , and pass it into the constructor of your NewCircle class , so you can add it to the textfield inside. We've also added some logic to run your loop twice completely , to compensate for both uppercase and lowercase.

    so then on input or sumbit , or whenever you want to run this thing ,

    Code:
    for( var i : int = 0 ; i < input_text.length ; i ++ ) {
        var inputGlyph : String ( inputText.charAt( i ) );
        for( var j : int = 0 ; j < circleHolder.numChildren ; j ++ ) {
             var circleItem : NewCircle = NewCircle( circleHolder.getChildAt( j ) );
             if( String( circleItem.txt.text ) == inputGlyph ) matchFound( circleItem );
        };
    };
    
    function matchFound( _item : NewCircle ) : void {
    // do some positioning or animation here
    };
    So here we take advantage of circleHolder, and it display list , numChildren , etc. We don't need all those arrays. The , i wrote a little support function to move your stuff.

  5. #5
    Senior Member
    Join Date
    Nov 2004
    Posts
    110
    Very nice! I actually got mine to work when I cleaned and actually tested out my code, but yours is tremendously cleaner and way more simple.

    For the sake of saving us time I would invite you to use my code, and fla file, on the attached archive, for the next set of issues I just ran into. Again you don't need to actually code it out (although that would be fantastic) but just an insight on how I should go about doing it would be great!

    As you can see on the attached code (Main.as) I was actually able to make the corresponding circle do something, in this case change color and scale up. But if you remember correctly what I really need is for them to move out of their current position, be placed side by side in the order of the word and display the letters. Right now I don't need them to display the letters yet, what I'm really having trouble discerning is how I will duplicate the circles that have been input more than once. Say for example if the user inputs "Hello". The circle H, e, l and o will move out of the grid and into a separate location, be placed centered horizontally on stage and evenly spaced out (something like "H" "e" "l" "" "o") but only have 4 circles where there should be 5, being that the "l" circle should be duplicated. Same with, say, Alameda (3 "a"s) and so on and so forth.

    So basically, on submit, how do I move them out of the grid onto a location that evenly spaces them out (regardless of the length of the input text) and centers them horizontally on stage, and most importantly after that, have the circles duplicate if need be? Any ideas on how to achieve this?

    Thanks so much for all your help, this is getting exciting!
    Attached Files Attached Files

  6. #6
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    You're going to have to generate new instances; so it would make sense store the extra letters into an array of "temporary" sprites, so you can loop through that array and fade them out, then remove them from stage when the dots go back to normal.

    As far as centering on stage, it's basically just a matter of figuring out the total width+total spacing of the letters being arranged, then subtracting half of that from half of the stage.stageWidth and adding x value to each based on its position in the word times the width of one letter plus spacing. In pseudo-code:

    lsw = letterwidth+spacing;
    letter.x = ((stage.stageWidth/2)-((lsw*wordlength)/2))+(letter.position*lsw);

    Then all you need to know is the length of the word typed in and the position of this particular letter in that word. To my mind, the easiest way to do that is to hold input text as a set of objects within an array, like this:

    [{value:"a",sprite:letterSprite},{value:"b",sprite: letterSprite}]

    pushing new objects into it as the user types. That way you can write a function that goes through each activated sprite and figures out which position it is in the array, and spaces it from there.

  7. #7
    Senior Member
    Join Date
    Nov 2004
    Posts
    110
    Thanks joshstrike

    Here's the code I have to make them move to center: ( _input:Array is the Array that contains all the used/input characters )

    PHP Code:
    private function animateSelected_input:Array ):void
            
    {
                
    kerning 25;
                
    _delay 0.5;
                var 
    newy 480;
                
                for ( var 
    i=0_input.lengthi++ )
                {
                    var 
    newx = ((stage.stageWidth/2) + (kerning i)) - ((kerning _input.length)/2);
                    var 
    delay _delay i;
                    
    trace(delay);
                    
    TweenLite.to_input[i], 1, { x:newxy:newydelay:delay } );
                }
            } 
    It works!

    Now, as far as creating several hidden instances of each letter goes I have my doubts. Imagine some sneaky bastard enters: "Heeeeeeeeeeeeeeeeeeeeeelloooooooooooooooooooooooo oooo" just for the heck of it. Do I need to have that many hidden instances of EACH letter just to be safe? Wouldn't that bring up cpu and ram issues? (Maybe not)

    Isn't there a simpler way to just duplicate, literally, a movieclip if it's entered more than once? Isn't there a dynamic constructor to duplicate movieclips in AS3?

    Thanks again!

  8. #8
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    AS3 does not allow you to exactly duplicate an instance of a movieclip, although you can certainly generate more of the originals out of the Library or out of a code class that extends MovieClip. Duplicating an already existing, on-stage movieclip would imply copying its current frame and everything that might have happened to it up until that point, and AS3 is not up to that task.

    I don't think it's necessary, though. Nor do you need to create an almost-endless supply of instances prior to the user typing in letters. The best way to go about it would be to write a function that takes a letter string and returns a new movieclip on command for that letter, then pushes the movieclip into an array specifically for temporary clips. Then add it to the stage and treat it like all the other letters; you can hold a reference to it in the main array of letters and in the temporary array, since these are just references to the actual instance, which is a movieclip that you're placing on the stage. When the user's typing is released, you can loop through your temporary array list to find which instances should be discarded.

    This touches on the way Flash deals with MovieClips in memory, and I don't know if this interests you, but in its simplest form, a MovieClip is a class instance and if it's created inside a function and not added to a display chain or to another object of some kind (like a class-level or global array) outside the scope of the function that created it, Flash considers it to be dead and you cannot reference it anymore. Once you place it on-stage OR add it to an array that exists outside the function creating it, Flash will keep it alive until it is removed from the stage and/or detached from any arrays holding it. So the trickiest thing here is to minimize the number of actual instances you have at any one time, and try to get rid of them as quickly as possible when you don't need them. The cleanest way to do this is to create these new movieclips in a function, when they're needed, and add them (a). to a class-level or global (root level) array, and (b). to the display chain (as a child of another clip or of the stage). When you're ready to dispose of them, you use the array to find them and remove them from the stage, and then empty out the array (set it to new Array() or [])... and then the references are all gone, and Flash will garbage-collect the instances and clear up the memory. Otherwise, you're likely to have problems over time with this, as more and more instances pile up and Flash starts to slow down.

  9. #9
    Senior Member
    Join Date
    Nov 2004
    Posts
    110
    I do believe I get your point and thanks for the thorough explanation. The thought of creating more originals out of the code class that extends the tiny circles' movieclip had come to mind but I just figured there might be an easier way to do it, by duplicating movieclips, but guess I was wrong.

    So now what comes to mind is creating a for loop that goes through the whole input text characters, and an if statement inside that finds whether or not a character is used more than once. If it is I just create a new instance of that code class that extends the circles with the character being the one that is used more than once.

    Any ideas as to how I'll go through the whole set of characters and find duplicates? Can't seem to get my head around that.

  10. #10
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    Some people use the Dictionary class for this kind of thing, but I've never been a big fan... I think the best structure would be this:

    Have 3 arrays.
    (1). an array of the permanent letters on the screen. It's important that this include not just the movieclip of the letter, but what the letter actually is as a string, and whether we're using it yet for a word. So make it an array of objects, {str:"a",mc:letterMovieClip,used:false}
    (2). an array which holds any temporary letters created by the user's typing, which should be in the same format as the first array, and basically works as above; if for some reason you need to manipulate all letters at the same time, this and array #1 can both hold references to the same actual movieclips, but it's important to keep this array as a list so you know what to discard when the typing is finished. You don't need a used: parameter in these, since we're going to assume that if they were generated, they are being used.
    (3). an array based on what the user has typed. You can generate this by taking the text of the textfield and splitting it with nothing... inputField.text.split(); will return an array of letter strings...then go through and create an object of each of those [{str:"a",mc:null}];

    Then you go through array #3, the user input letters, and for each that has a null MC reference you loop through array #1. If the letter found in array #1 has used==false, then use that one and set used=true. Otherwise, create a new letter for it and add it to the temporary array (#2). Either way, set the mc: for that letter in array #3 as a reference to whatever one you used. There is no serious penalty for making more references to the same instance.

    Basically now you have 3 arrays that hold references to a finite set of instances. The first array holds all the ordinary letters. The second holds the ones temporarily created. The third holds a subset derived from each of those, based upon whatever the player typed. Backspace and typing into the center of a string will be your next big issue. If you want to get really fancy, you will probably have to look at the caret position for the textfield and write a function to figure out whether the letter before it has changed, then splice the new one into array #3. Depending on how fluid you want this system to be, it can get pretty dicey at that point; but theoretically, even if you flushed the 3rd array after every text input change and created a new one, the letters would move to the correct positions if you just stop all their tweens and create a new set of tweens with every change.

    Above all, I'd recommend you create a class for the letters extending MovieClip, which can also have a public array to hold its own tweens, because this will be crucial if you want smooth animation. Tweens created on the fly inside of a local function stop as soon as the function stops running. Creating a ton of them on the timeline or in the document class has some negative effects; mainly, as long as a tween is still running on an object, it is not garbage collected. So putting the tweens inside the objects is essential. And when you make them a class, give them a destruction function that first stops the tweens, fades them out, waits for the fade, then dispatches an event that's listened for to remove them from the root.

    Maybe that's going too fast, I don't know. The memory management with lots of separate sprites adding and removing from lists is where it gets really dicey, so I'd say if you keep even half these things in mind as you go forward, you'll be ahead of the curve on that score. But make those letters a class.

  11. #11
    Senior Member
    Join Date
    Nov 2004
    Posts
    110
    I got it to work!
    www.tiagocabaco.com/other/type_test/
    Pink circles represent new instances of duplicated characters.
    All I need to do now is add the mouse over effects that will show the characters. As well as have the input characters pop out of the circles when submited, but that I believe to be pretty simple so I'll leave it to later.
    Hard part is done I believe!

    Thanks for everyone's help!

  12. #12
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    Excellent! You seem to have a good grasp of this.
    I think there's an extra item being carried over in your typing array; inputting a three-letter word the second time causes four dots to show up. Besides that, looks like you got a handle on it. Bravo!

  13. #13
    rabid_Delineator AttackRabbit's Avatar
    Join Date
    Dec 2003
    Location
    Orlando, Florida
    Posts
    481
    nice work , post the finished app when you swap out all the debug elements.

  14. #14
    Senior Member
    Join Date
    Nov 2004
    Posts
    110
    Thanks!
    When I start incorporating the design elements I'm sure I'll run into other issues, and I'll be sure to post them here as well as the finished project, most definitely.

    Actually, come to think of it, I do have one tiny(?) question. Right now all the circles are in a simple grid I did, but I really wanted them to show up on random x and y positions everytime the user re-opens the app. I've thought deep about it and I also don't want them to be too close to each other. Having this said, is there a way to display the circles on random locations throughout the whole Width and Height of the app and still keep a minimum distance between each other?

    @joshstrike: I just tested many times typing in 3 letter words and I didn't catch that bug. Can you be more specific? What word/combination did you use? Thanks!

  15. #15
    rabid_Delineator AttackRabbit's Avatar
    Join Date
    Dec 2003
    Location
    Orlando, Florida
    Posts
    481
    when you place an object on stage , you would need call a support function that recursively loops through either your array of circle object or the display list to which they are added. It would need to run a collision check , or hit test , on the new object , and each old object , or at least until it found a collision. If it finds a collision it would need to adjust , or pad the randomly generated x , y of the new circle , and then run the collision check again , so on and so on. Now as a warning , if you have loads and loads of object , which i know you wont because its just the alphabet , but if you did , this can get real choppy. Your app can chug because of the amount of calculations. In that case you could do a proximity check , to try to limit the number of objects you are checking against. Another route would be to have a predefined vector, of x and y positions that appear random, store those in an array , and randomly generates index's of to pull from. Which actually might be the best way to go , because honestly, completely random lay outs often look terrible, simply because you have no control of where the objects will end up. Its better to have something appear random , but look the way you intend it to.
    Last edited by AttackRabbit; 02-22-2010 at 12:22 AM.

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