Tutorial: Making a Frog Generator with Adobe Animate (HTML5 & CreateJS)

Share Button

You can VIEW the end result here: http://frogs.alienmelon.com/html5/
You can DOWNLOAD the sourcefiles here: http://nathalielawhead.com/sourcefiles/Weird_Alien_Frogs/

This tutorial will walk you through using Animate to make a procedural frog generator. It will cover all the basics of using the HTML5 Canvas output, as well as timeline scripting for the functionality.

For those that are interested I also have a tutorial for making a game with CreateJS + the canvas in Flash/Animate here.
It’s a bit older, and some of the issues (and resulting workarounds) I mention there no longer apply. Although the tutorial itself is still fairly relevant.

It’s also interesting to note that it’s easy to run into minor weird bugs or issues working with the canvas. I do frequently. While creating the tutorial I ran into one “hard to explain one”.
Also, there are some things this doesn’t support that makes using this for games difficult. For example, at the moment InputText is not supported. Working with (fancier fontier) text can be very hard. Selectable text isn’t supported either. The filters (like glow, etc) aren’t supported… These are things that keep me up at night. Hoping… Waiting…
Then again, for a while .width & .height where not supported which made collision detection (and other things) hard. Now there’s getBounds() and getTransformedBounds(), and setBounds(), or object.nominalBounds.width. Good things come to those that wait… but you know… it’s good to keep in mind that there’s always a workaround.

Moving on…

This tutorial is based on my original frog generator. The original was ActionScript based, but I ported it to HTML5 Canvas (createJS) so I can write a fun tutorial about generating frogs with something javascript! Yay!
I also figure a Javascript tutorial is probably more interesting to people.
I’m under the impression that ActionScript programmers do not need tutorials because they already know what they are doing.

Also, on the note of frog generating tutorials, G.P. Lackey gave a pretty kick ass presentation where he built a frog generator with Construct 2. Video is here. It’s also something you can follow along to make your own frog generator. His end result is playable here. http://mousefountain.itch.io/fantastic-frogs-forever

Ok. Let’s begin…

PAGE SETUP

Like I said… This will be using timeline scripting. Timeline scripting is usually looked down on, and controversial among self-respecting programmers. I’m neither of these things and think it’s one of the greatest things that ever happened. So I use timeline scripting.

Add a top layer called “JS”. Keep this layer at the top, and only scripts go here.

In the first frame add the following page setup:

//PAGE SETUP//

var page_body = document.getElementsByTagName("body")[0];
page_body.style.backgroundColor = "black";
page_body.style.overflow = "hidden";//hide scrollbars
page_body.style.position = "fixed";//no scroll. ever.
//
var page_canvas = document.getElementsByTagName("canvas")[0];
//these two variables are important
stageWidth = page_canvas.width;
stageHeight = page_canvas.height;
//
document.documentElement.style.cursor = 'url("images/CURSOR_FROG_3.gif"), auto';
//
function onResize()
{
	stage.width = window.innerWidth;
	stage.height = window.innerHeight;
	page_canvas.style.height = window.innerHeight + "px";
	page_canvas.style.width = window.innerWidth + "px";
}
//
window.onresize = function()
{
     onResize();
}
//
onResize();

Of course you could add this to the HTML page in a script tag, or in a separate js file, or however you want it. I add it like this because it’s convenient.

Basically, it makes the canvas/stage stretch to fit the window (so it’s sort of fullscreen). There are a lot of ways of sizing the canvas to fit the screen. You can also keep it proportionate, but I like it this way. However you prefer.

It also changes the mouse cursor to Kermit, because Kermit is a pretty awesome frog. So this is fitting.

SOUNDS

Sounds that you want to play/stop have to be loaded in first. As far as I know (and from last time I checked) linkage identifiers don’t work (loading in from the library).
I cover sounds very extensively in this tutorial: http://www.nathalielawhead.com/candybox/tutorial-building-a-game-with-flash-html5-canvas-createjs-haxatron-2000
so there is no need to repeat myself.

The code is as follows…

//REFERENCES (GLOBAL)//

_stage = this;//stage
//save width/height
_stage.width = 1366;
_stage.height = 768;

//AUDIO//

//http://createjs.com/docs/soundjs/classes/Sound.html
var assetsPath = "sounds/";
var snd_manifest = [
	{id:"snd_title_start", src:"AUD_START.mp3"},
	{id:"snd_title_credits", src:"AUD_CREDITS.mp3"},
	{id:"snd_transition", src:"AUD_TRANSITION_01.mp3"},
	{id:"snd_evnt01", src:"AUD_EVNT01.mp3"},
	{id:"snd_evnt02", src:"AUD_EVNT02.mp3"},
	{id:"snd_evnt03", src:"AUD_EVNT03.mp3"},
	{id:"snd_evnt04", src:"AUD_EVNT04.mp3"},
	{id:"snd_evnt05", src:"AUD_EVNT05.mp3"},
	{id:"snd_mountains", src:"AUD_SCENE_MOUNTAIN.mp3"},
	{id:"snd_stream", src:"AUD_SCENE_STREAM.mp3"},
	{id:"snd_space", src:"AUD_SCENE_SPACE.mp3"},
	{id:"snd_frog01", src:"AUD_LOOP_FROG01.mp3"},
	{id:"snd_frog02", src:"AUD_LOOP_FROG02.mp3"},
	{id:"snd_frog03", src:"AUD_LOOP_FROG03.mp3"},
	{id:"snd_camera", src:"AUD_CAMERASHUTTER01.mp3"}
];
	
var queue = new createjs.LoadQueue(true, assetsPath);
//See: http://www.createjs.com/Docs/SoundJS/classes/Sound.html#property_alternateExtensions
createjs.Sound.alternateExtensions = ["mp3", "wav"];
queue.installPlugin(createjs.Sound);
//load is complete, and the other to display the load progress
queue.addEventListener("complete", handleComplete);
queue.addEventListener("progress",handleProgress);
//load manifest is to load multiple sounds/a set of them
queue.loadManifest(snd_manifest);
//to load an individual file:
//queue.loadFile({id:"snd_title_start", src:"AUD_START.mp3"});
	
function handleComplete(evt) {
	console.log("all sounds loaded.");
	playSound("snd_title_start");
	_stage.gotoAndStop("mainmenu");
}
function handleProgress(evt) {
	//console.log("Event Loading: " + (queue.progress.toFixed(2) * 100) + "%");
}

//manage playing and stopping of sounds
//to play a sound pass it the string name
playSound = function(name) {
	return createjs.Sound.play(name);
}
playSoundLoop = function(name, loops){
	return createjs.Sound.play(name, {loop:loops});
};
//play a random sound from one of the arrays
playArrSound = function(arr){
	var arr_element = arr[Math.ceil(Math.random()*arr.length)-1];
	return createjs.Sound.play(arr_element);
}
stopSound = function(name){
	return createjs.Sound.stop(name);
}
stopAllSounds = function(){
	createjs.Sound.stop();
}

//sound arrays
//for randomly playing a sound
arr_snd_events = ["snd_evnt01", "snd_evnt02", "snd_evnt03", "snd_evnt04", "snd_evnt05"];
//frog 'singing'
arr_frog_sound = ["snd_frog01", "snd_frog02", "snd_frog03"];

//various event functions (random sounds)
//on key down, and other
playEvntSound = function(){
	playArrSound(arr_snd_events);
}

So you see they are queued, and there are two formats I offer (mp3 or wav).
There are a bunch of functions for controlling audio. These should be pretty self-explanatory, and cover all cases.
To play one you call the function and pass it the name (as a string).
Sounds that I want to play at random are kept in an array, and the playArrSound function handles that playback.

Once loading is completed, we proceed to the “mainmenu” and play the Main Menu music ("snd_title_start")…

INPUT TEXT

Like I said, there are some things createjs (Animate’s HTML5 canvas output) doesn’t support that really starts to get hard if you’re making games. In this case input text is not supported.

I mean, yes it sort of is, but not really. You have to add a DOM element if you want real input text. I don’t like that. It gets messy really fast, especially if you want to use your own fonts.

For the sake of this tutorial I’ll try to do something different while using what is supported.

I’ll capture keypresses (document.onkeydown = event_keydown) and += them to the dynamic text field. Some basic logic is there. It will allow for deleting, and adding new characters. This is enough for me.

The name of the dynamic “input” text field is “txt_namefield“.

This is what we will use:

str_startmsg = "START TYPING YOUR NAME";
str_name = "";//the frogname (yourname)

//keyboard
function setKeyboard(){
	//
	document.onkeydown = event_keydown;
	//
};

The actual event looks like this. The comments should be pretty self explanatory…

function event_keydown(e){
	if(!e){ var e = window.event; }
	//get the charcdoe
	var num_char = e.keyCode;
	console.log(num_char);
	//get the letter
	var str_letter = String.fromCharCode(e.keyCode);
	//regex to allow only for letters (no numbers or puncuation)
	var regex_letters = /^[A-Za-z\s]+$/; // /^[A-Za-z\s]*$/;
	//clear text field if nothing entered yet
	if(_stage.txt_namefield.text == str_startmsg){
		_stage.txt_namefield.text = "";
	}
	//if "enter" is hit (same as selecting manually)
	if(num_char == 13 && _stage.txt_namefield.text.length > 0 && _stage.txt_namefield.text != str_startmsg){
		mainmenu_refresh();
	}else if(num_char == 8 || num_char == 46){
		//if backspace or delete
		//trim off the last character
		//start with saving the contents of the text field into a string
		var str_textfield = _stage.txt_namefield.text;
		//now trim it
		str_textfield = str_textfield.substring(0, str_textfield.length - 1);
		//set the text field to the new value
		_stage.txt_namefield.text = str_textfield;
	}else if(_stage.txt_namefield.text.length < 25 && str_letter.match(regex_letters)){
		//if not backspace or delete
		//and if only letter (no numbers or punctuation)
		//and if under 25 characters long
		//populate text field with:
		_stage.txt_namefield.text += str_letter;
		str_yourname = _stage.txt_namefield.text;
	};
	//show or hide btn_refresh (if text is actually input, and not the default string)
	if(_stage.txt_namefield.text.length > 0 && _stage.txt_namefield.text != str_startmsg){
		_stage.btn_refresh.visible = true;
	}else{
		_stage.btn_refresh.visible = false;
	}
	//play event sound (frog ribbit)
	playEvntSound();
}

The variables at the top get the keycode and the letter from that keycode.
The regular expression makes sure you can only enter letters. Numbers and punctuation is not allowed. I apologize if you have a fancy name.
The first condition is just so we can get rid of the "START TYPING YOUR NAME" text. The only downside of this is if there is a person who is actually named “START TYPING YOUR NAME”, but I doubt it.
The second condition takes care of text input. Enter key takes precedence (same as selecting the “start button” manually), then deleting and backspace, and then whatever is entered (with the condition of under 25 and regex_letters).
Also make sure to show or hide the button that generates the frog. This button is what makes the magic happen. Alternatively you can just press ENTER to make the magic happen. All cases are covered.
Play ribbit sound!

Also, for those who are interested. A couple useful links for understanding js char codes and keys:
http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
http://www.quirksmode.org/js/keys.html

That’s it!

The biggest downside of this is that it will not work on mobile. If we where so inclined we could create an alternative for these users, but for the sake of simplicity we’ll leave that for later. Some other time.

Minor issue here is that you can’t select (to edit) wherever you want in the text field. I mean, if you worked on it you could probably get it to work. It doesn’t really mater to me. It’s probably a good idea that they don’t put in long names anyway. :)

MAIN MENU

The “main menu” is really simple. It’s basically just the title with giant rotating lines (like light rays), to give it a little motion.

There’s a credits screen. The visibility of it is set to false, unless you click the “credits” button to see it.
To read more about buttons I suggest checking this out: http://www.createjs.com/docs/easeljs/classes/ButtonHelper.html
You may also find this helpful: http://www.createjs.com/tutorials/Mouse%20Interaction/
You could use the ButtonHelper Class to take care of over, out, etc… but (for convenience sake) I just “create new symbol” of type Button.

Here you will also put in your name so it can be turned into a frog, and you can meet your frogself. I covered this functionality above.

Also there are two transitions (on their own “Transitions”) layer. These provide a little “flashy” animation for transitioning to the next area (like game, or opening the credits screen). A small audio “hit” plays for the larger one.
The “flashy” colors here are a series of frames. The playhead is sent to a random frame for the funky flashy static effect.

Like so:

gotoAndStopRandom = function(clip){
	clip.gotoAndStop(Math.ceil(Math.random()*clip.timeline.duration));
};
gotoAndPlayRandom = function(clip){
	clip.gotoAndPlay(Math.ceil(Math.random()*clip.timeline.duration));
};

To play the transition you would call the following function

//Transitions
//play transitions   
play_transition = function(clip){
	//chan_title.stop();
	clip.gotoAndPlay(2);
}

There is one difficult thing working with the HTML5 Canvas Document you will encounter often… make sure to keep scope in mind when referencing things.
Local scope isn’t implicit in HTML canvas timelines. You have to be explicit.

For example JUST calling stop(); to stop your animation will not work because that’s the global scope (same as saying window.stop();)
this.stop(); will work. That’s the current timeline.

It’s probably a good idea to save a reference to your “stage” by using something like (on a separate “JS” layer):

_stage = this;//stage

Then always reference _stage.whatever to get access to anything on the stage.

You may already know this, but…

If you want to make symbols (Buttons, MovieClips, Sprites) on your stage accessible to code be sure to always assign it a name in the Properties panel. Like so:

Then to access it you can “_stage.mc_title...

So, what we will have in the main menu is:

//UNIVERAL (GLOBAL)//

//Timelines
gotoAndStopRandom = function(clip){
	clip.gotoAndStop(Math.ceil(Math.random()*clip.timeline.duration));
};
gotoAndPlayRandom = function(clip){
	clip.gotoAndPlay(Math.ceil(Math.random()*clip.timeline.duration));
};

//Transitions
//play transitions   
play_transition = function(clip){
	stopAllSounds();
	clip.gotoAndPlay(2);
}

//MENU SETUP//

//strings

str_startmsg = "START TYPING YOUR NAME";
str_yourname = "";//your name before frogification
str_name = "";//the name for frogification

These are the more “global” functions and setup. The strings you know from the textfield + keyboard input part.
The transition function is important.

Then there is:

//width & height of things that are hard to get the width/height for

_stage.txt_namefield.width = 1146;
_stage.txt_namefield.height = 42;

//seting up clips

set_small_ribbon = function(){
	//
	_stage.mc_ribbon.gotoAndStop("small");
	_stage.mc_ribbon.x = Math.ceil(_stage.width/2);
	_stage.txt_namefield.x = (_stage.mc_ribbon.x-_stage.mc_ribbon.nominalBounds.width/2+50) + _stage.txt_namefield.width/2;
}

set_large_ribbon = function(){
	_stage.mc_ribbon.gotoAndStop("large");
	_stage.mc_ribbon.x = Math.ceil(_stage.width/2);
	_stage.txt_namefield.x = (_stage.mc_ribbon.x-_stage.mc_ribbon.nominalBounds.width/2+50) + _stage.txt_namefield.width/2;
	_stage.txt_namefield.y = 518.9;
	_stage.mc_ribbon.y = 513.2;
	_stage.mc_ribbon.x = 682.85;
	_stage.btn_refresh.x = 1214;
	_stage.btn_refresh.y = 505;
}

I “record” the width/height of text fields because that’s sort of harder to get.
The ribbons (that’s the backdrop to the text) gets moved up and down a lot. So that’s here too.
The UI generally will get shuffled around a lot for all the different states. For example, when you take a picture of your frog, the UI changes to make that look nicer.

After that we have our keyboard input portion (above), and then this final bit:

//credits
function event_credits_open(event){
	stopSound("snd_title_start");
	playSound("snd_title_credits");
	//
	play_transition(_stage.mc_transition_bottom);
	play_transition(_stage.mc_transition_top);
	_stage.mc_credits.visible = true;
}
function event_credits_close(event){
	stopSound("snd_title_credits");
	playSound("snd_title_start");
	//
	play_transition(_stage.mc_transition_bottom);
	play_transition(_stage.mc_transition_top);
	_stage.mc_credits.visible = false;
}
//credits (url)
function event_credits_twitter(event){
	window.open("http://twitter.com/alienmelon", "_blank");
}
function event_credits_moreabout(event){
	window.open("http://www.allaboutfrogs.org/weird/weird.html", "_blank");
}

//function for "refresh", enter key and refresh button use this
function mainmenu_refresh(){
	event_clearmenu();
	stopSound("snd_title_credits");
	stopSound("snd_title_start");
	//
	play_transition(_stage.mc_transition_bottom);
	play_transition(_stage.mc_transition_top);
	//
	_stage.gotoAndPlay("froggen");
}

//go to the froggen screen (start)
//clear everything, stop everything, and play the transition
function event_mainmenu_refresh(event){
	mainmenu_refresh();
}

//clear everything (all events)
function event_clearmenu(){
	_stage.btn_credits.removeEventListener("click", event_credits_open);
	_stage.mc_credits.btn_close.removeEventListener("click", event_credits_close);
	_stage.mc_credits.btn_link01.removeEventListener("click", event_credits_twitter);
	_stage.mc_credits.btn_link02.removeEventListener("click", event_credits_moreabout);
	_stage.btn_refresh.removeEventListener("click", event_mainmenu_refresh);
	//
	document.onkeydown = null;
}
 
//add events
setKeyboard();
_stage.btn_credits.addEventListener("click", event_credits_open);
_stage.mc_credits.btn_close.addEventListener("click", event_credits_close);
_stage.mc_credits.btn_link01.addEventListener("click", event_credits_twitter);
_stage.mc_credits.btn_link02.addEventListener("click", event_credits_moreabout);
_stage.btn_refresh.addEventListener("click", event_mainmenu_refresh);
//setup clips
set_small_ribbon();
_stage.txt_namefield.text = str_startmsg;
//
_stage.mc_credits.visible = false;
_stage.mc_ui_back.visible = false;
_stage.btn_save.visible = false;
_stage.btn_refresh.visible = false;

These are the various button events, and menu setup.
The comments should make this pretty self explanatory.

Simple! That’s all there is to the menu.

Now for the actual frog generator…

THE GENERATOR

We’ll begin with the frogification of the name entered.
The idea of this generator is that you enter your name, and it generates a frog. This is your frogself. You get to know yourself if you where a frog.

Make sure that “Multiframe bounds” is selected in the Publish Settings. That’s under the Advanced tab.

Reason is probably given here: http://blog.createjs.com/update-width-height-in-easeljs/#comment-798
You can’t just check against .width or .height. You have to be more specific. In this case we’ll be doing a lot of mc_body.frameBounds[mc_body.currentFrame].height or clip.getTransformedBounds().width and the like… I’m very certain that there’s a better way of doing it. Sorry. This is how I did it.
To make life easier it’s in a function that returns:

function return_bounds(clip){
	//return clip.frameBounds[clip.currentFrame]; //you can do this
	return clip.getTransformedBounds(); //or this
}

and then use it like so:

return_bounds(mc_body).height or return_bounds(mc_body).width

You can read more about this here: http://blog.createjs.com/update-width-height-in-easeljs/

For starters we will turn the name entered into a frog version, and provide a little description of the personality.
It’s random, and takes place by splicing, slicing, and looping, and a bunch of arrays with tons of stuff randomly combined.

The arrays…

//description (about your frog)
var adj_aka = ["The humans call you", "Also commonly known as", "Also known as", "Often referred to as", "Someone once called you"];

var adj_very = ["very", "quite", "fully", "perfectly", "really", "thoroughly", "totally", "truly","rather"];
var arr_personality = ["an adventurous", "one "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" cool", "a kick-ass", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" small but formidable", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" formidable"," a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" calm", "a composed", "a calm and "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" composed", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" rowdy, and unruly", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" great", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" busy", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" successful", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" fortunate", "an outstanding", "a strong and stout", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" stout", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" strong", "a frog ahead of its game at being a", "a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" lucky","an all in all","an extraordinary","a notable","an undefeated","an undefeated frog at being a","a reigning","a champion","a boss","a choice","a top-notch","a world class","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" distinguished","an outstanding","a prime","a superior","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" audacious","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" bold","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" courageous","a risk-taker","an enterprising","a daredevil","a critically acclaimed","a distinguished frog at being a","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" distinguished","an eminent","an esteemed","a famed","a notable","a reputable","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" loved","a beloved","an admired","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" popular","an adventurous","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" audacious","a gallant","a gusty","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" heroic","a resolute","a spirited","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" stout","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" forward thinking","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" chivalrous","a gritty","an unblenching","a formidable","a redoubtable","a daunted","a frog aghast at all that is","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" alarmed","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" anxious","a suspicious","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" timid","an easily frightened","a frog in awe at all that is","a nervous","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" perplexed","a perturbed","an easily startled","an artistic","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" creative","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" dramatic","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" musical","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" idealistic","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" harmonious","a "+adj_very[Math.ceil(Math.random()*adj_very.length)-1]+" rhythmical","a sensitive","a stylish","a tasteful","an extravagant","an ample","a decided","a strong-minded","a responsible","an honest","a positive","an adaptable","a self-driven","a self-motivated","a patient","a kind","an all around good"];
//
var arr_01 = [", and have so many of them", ", and have such a large family", ", and love your family", ", and love everything about everyone"];
var arr_02 = [". You just escaped after being held captive in an aquarium for years", ". No one can capture you", ". It's so warm and titillating here, you love everyone"];
var arr_03 = [". Your genus has settled all the difficult places", ". You're proud to be part of such a widespread species", ". You fear nothing, not even the dog"];
var arr_04 = [", even if you're the last of your kind after a city grew over your natural habitat", ". You just know everything will work out, even if your natural habitat is disappearing", ". Your self esteem is a force to be reckoned with"];
var arr_05 = [". If you where human you know you would rule the world as an ungainly frogtyrant", ". You have better things to do than to be boring", ". You have a punchline for every predator, even your mom"];
var arr_06 = [". All frogs can count on you, you are the frogcount", ". You've waited days for that bug to crawl out of its hole", ". You can literally wait all winter for a ray of sunshine"];
var arr_07 = ["... although everyone knows you're cold-blooded, duh", "... although frogs are cold-blooded, duh", ". If you had fur you would be a cuddle cat"];
var arr_08 = [". Once you put your mind to something you never change it", ". Sometimes you like to sit in something that's too hot just to see how long you can do it", ". Sometimes you like to sit in hot water just to test yourself"];
var arr_09 = [". You know what's good. That's good. Yes", ". You like to play it safe and that's smart", ". You rather do the eating than to be eaten"];
var arr_10 = [". There's no climate too harsh for you", ". What some call climate change you call a nice challenge. Yes", ". Your genus evolves gracefully"];
var arr_11 = [". You love to sing and keep everyone awake", ". You once kept an entire neighborhood awake with your musical talents", ". You like to sit in high places and make noise"];
var arr_12 = [". You love the sound of your own croaks", ". You love to listen to the sounds you make", ". You're pretty certain that if you spoke english humans would call the sound of your voice poetry"];
var arr_13 = [". You just escaped after being held captive in an aquarium for years", ". Nothing can stop you, not even that cat", ". You're never too old, especially with a face like that"];
var arr_14 = [". You have all the answers to all the questions", ". If you where a human you would be the ungainly frogdictator of the world", ". You're pretty sure you're a smart frog no matter what the stinky humans say"];
var arr_15 = [". You're not afraid to show your soft side, which is everywhere", ". You've got a squishy center and just as squishy skin", ". You're pretty soft, all over"];
var arr_16 = [". You like to sit here and daydream for hours", ". You're a beautiful daydreamer. Actually, you're pretty sure you're dreaming right now", ". You've got all sorts of ideas about all sorts of frogs"];
var arr_17 = [". Good looks like yours only happen once", ", like that one time... but you rather not talk about it", ". You could brag, but that would be rude"];
var arr_18 = ["... in the vernacular. Everyone knows you're coldblooded", "... although frogs like you are coldblooded, but you appreciate the colloquialism", "... although your appreciate the colloquialism, frogs are coldblooded"];
var arr_19 = [". There's so much to do and so little time", ". You're so happy to have evolved this way", "... amphibians are the best, even bester than reptiles"];
var arr_20 = [". You pride yourself in being open-minded, but only in a manner of speaking", ". Although you're a small frog you're big on the inside", ". You keep growing. If you keep it up you'll be a frogbeast in no time"];
var arr_21 = [". Your bonds last for life! That's how strong love is. YOUR love", ". Your bonds last a life-time, maybe two, or three", ". Once a frogfriend, always a frogfriend. It's what your frogdaddy taught you"];
var arr_22 = ["... There's no need to brag, we're all frogs", ". You're pretty good at what you do, and that's being a frog. No need to brag", ". You know, you're just a small frog, and that's a pretty big deal, in a small way"];
var arr_23 = [". Any frog can count on you to get the job done right", ". You can be counted on. You are a frog", ". You are a hardworking frogcitizen and anyone can count on that"];
var arr_24 = [". You love to work hard and play harder", "... it's like they always say work hard and frog harder. That is not a pun. It's a frogsaying", ". Your ancestors came to this land with nothing and now populate everything"];
var arr_25 = [". Your ability to find warm water is unrivaled", ". You understand your surroundings perfectly and that's why you eat so well", ". They call you the frogwhisperer because you're so frog"];
var arr_26 = [". You're pretty sure that's a good thing", "... which is not bad for a frog", ". You've got class, and that's all a frog can ask... rhyme intended"];
var arr_27 = [". You have so much offspring as a result", ". All the frogs love you and love to love you. So much love", ". You're a lovable amphibian and that is good"];
var arr_28 = [". Everyone wants to be your neighbor", ". Everyone loves being near you. As a result it's a heavily populated area", ". You'll get around to it, but friends come first"];
var arr_29 = [". Strong opinions are what keep this place running", ". You break up fights, but that's what frogfriends are for", "... all's good that frogs well, and frog is what you're all about"];
var arr_30 = [". You'll get it done, no matter what", ". You'll move a mountain if you have to. Even if that means evolving into a bigger scarier species first", "... as a result you're constantly growing into god knows what"];
var arr_31 = [". You've got a squishy center, and squishy surface. All around squishy", ". You have a strong feeling that squishy is good", ". You have a big heart... literally. That thing is HUGE"];
var arr_32 = [". It's good to care! You're a frog", ". You throw yourself into anything 100%. You're a good jumper", ". You're a strong frog for all that you've been through"];
var arr_33 = [". Everyone loves you and wants to love you", ". You swallowed a magnet once, and now everything chases you", "... ever since you swallowed that magnet everything seems drawn to you"];
var arr_34 = [". You believe in the better good of frogs, they'll never catch you", ". Your best friend was used in a middle school dissection you try to stay positive to honor him", ". You escaped that aquarium and now intend to live life to the fullest"];
var arr_35 = [". You always sound like you're laughing. It's because of a genetic defect, but that's ok", ". You can turn the darkest situations into a joke", ". You can see the humor in everything and everyone"];
var arr_36 = [". You're a frog they can count on", ". You're blunt and that's a good thing, especially for a frog", ". They can count on your opinions. You are a frog"];
var arr_37 = [". You enjoy the deeper conversations, but not too deep. You're not that great of a jumper", "... it's because of your big head. You can store lots of big ideas", ". There are so many things to talk about. You are a smart frog"];
var arr_38 = [". You work hard and get frogthings done", ". There's always more frog that needs frogging and you frog hard", ". There are so many frogthings to get done"]; 
var arr_39 = [". You've got a goal and nofrog can stop you now", ". You can accomplish anything you put your froghead to", ". You're a hardworking frog, and good at it too"];
var arr_40 = [". You've lived here a long time despite all the natural predators", ". You would rather eat than be eaten and that's why you're so fat", ". Despite all the natural predators you're growing quite old"];
var arr_41 = [". You're hilarious when you get going", ". You take it easy and laugh a lot. This is good for a frog", ". Your sense of humor is not bad for a frog. It's impressive"];
var arr_42 = ["... everyone can count on you", ". Every frog can count on you to be a frog", ". Every frog can count on you! You are a frog"];
var arr_43 = [". You never lie even if that involves telling the truth", "... even if you have to tell the truth you'll never lie", ". You're a frog other frogs can count on to be a true frog"];
var arr_44 = [". You dig your own holes, and catch your own meals", ". You catch your own food. No handouts", ". You dig your own holes, and even use tools"];
var arr_45 = [". You come up with all sorts of applicable ideas", ". No one can catch you! You are a smart frog", ". They'll never catch you. You are a cunning frog"];
var arr_46 = [". It's obvious from looking at your gooey surface", ". Everyone can tell from your gooey surface that you have a soft center", ". You have a soft center and even softer surface"];
var arr_47 = [". You donate your bugs to the hungry", ". You regularly feed hungry fish your freshly caught butterflies", ". You like to help others, and help yourself in the process. This is good frogging"];
var arr_48 = [". You are probably an alien but you live among the frogs", ". You don't think about yourself much, even if others think you're an alien", ". Sometimes you wonder if you're an alien, but you try not to think about yourself too much"];
var arr_49 = [". You know what's up even when you don't know why just yet", ". You've got feelings. So many", ". You can understand the struggle of being a frog and help other frogs to frog better"];
//
var arr_aboutyou = ["great with the tadpoles"+arr_01[Math.ceil(Math.random()*arr_01.length)-1],"adventurous and energetic" + arr_02[Math.ceil(Math.random()*arr_02.length)-1],"pioneering and courageous" + arr_03[Math.ceil(Math.random()*arr_03.length)-1],"enthusiastic and confident" + arr_04[Math.ceil(Math.random()*arr_04.length)-1],"dynamic and quick witted"+arr_05[Math.ceil(Math.random()*arr_05.length)-1],"patient and reliable" + arr_06[Math.ceil(Math.random()*arr_06.length)-1],"warmhearted and loving" + arr_07[Math.ceil(Math.random()*arr_07.length)-1],"persistent and determined" + arr_08[Math.ceil(Math.random()*arr_08.length)-1],"placid and security loving" + arr_09[Math.ceil(Math.random()*arr_09.length)-1],"adaptable and versatile" + arr_10[Math.ceil(Math.random()*arr_10.length)-1],"communicative and witty" + arr_11[Math.ceil(Math.random()*arr_11.length)-1],"intellectual and eloquent" + arr_12[Math.ceil(Math.random()*arr_12.length)-1],"youthful and lively" + arr_13[Math.ceil(Math.random()*arr_13.length)-1],"cunning and inquisitive" + arr_14[Math.ceil(Math.random()*arr_14.length)-1],"emotional and loving" + arr_15[Math.ceil(Math.random()*arr_15.length)-1],"intuitive and imaginative" + arr_16[Math.ceil(Math.random()*arr_16.length)-1],"protective and sympathetic" + arr_17[Math.ceil(Math.random()*arr_17.length)-1],"generous and warmhearted" + arr_18[Math.ceil(Math.random()*arr_18.length)-1],"creative and enthusiastic" + arr_19[Math.ceil(Math.random()*arr_19.length)-1],"broad-minded and expansive" + arr_20[Math.ceil(Math.random()*arr_20.length)-1],"faithful and loving" + arr_21[Math.ceil(Math.random()*arr_21.length)-1],"modest and shy" + arr_22[Math.ceil(Math.random()*arr_22.length)-1],"meticulous and reliable" + arr_23[Math.ceil(Math.random()*arr_23.length)-1],"practical and diligent" + arr_24[Math.ceil(Math.random()*arr_24.length)-1],"intelligent and analytical" + arr_25[Math.ceil(Math.random()*arr_25.length)-1],"diplomatic and urbane" + arr_26[Math.ceil(Math.random()*arr_26.length)-1],"romantic and charming" + arr_27[Math.ceil(Math.random()*arr_27.length)-1],"easygoing and sociable" + arr_28[Math.ceil(Math.random()*arr_28.length)-1],"idealistic and peaceable" + arr_29[Math.ceil(Math.random()*arr_29.length)-1],"determined and forceful" + arr_30[Math.ceil(Math.random()*arr_30.length)-1],"emotional and intuitive" + arr_31[Math.ceil(Math.random()*arr_31.length)-1],"powerful and passionate" + arr_32[Math.ceil(Math.random()*arr_32.length)-1],"exciting and magnetic" + arr_33[Math.ceil(Math.random()*arr_33.length)-1],"optimistic and freedom-loving" + arr_34[Math.ceil(Math.random()*arr_34.length)-1],"jovial and good-humored" + arr_35[Math.ceil(Math.random()*arr_35.length)-1],"honest and straightforward" + arr_36[Math.ceil(Math.random()*arr_36.length)-1],"intellectual and philosophical" + arr_37[Math.ceil(Math.random()*arr_37.length)-1],"practical and prudent" + arr_38[Math.ceil(Math.random()*arr_38.length)-1],"ambitious and disciplined" + arr_39[Math.ceil(Math.random()*arr_39.length)-1],"patient and careful" + arr_40[Math.ceil(Math.random()*arr_40.length)-1], "humorous and reserved" + arr_41[Math.ceil(Math.random()*arr_41.length)-1],"friendly and frogitarian" + arr_42[Math.ceil(Math.random()*arr_42.length)-1], "honest and loyal" + arr_43[Math.ceil(Math.random()*arr_43.length)-1], "original and inventive" + arr_44[Math.ceil(Math.random()*arr_44.length)-1], "independent and intellectual" + arr_45[Math.ceil(Math.random()*arr_45.length)-1], "imaginative and sensitive" + arr_46[Math.ceil(Math.random()*arr_46.length)-1], "compassionate and kind" + arr_47[Math.ceil(Math.random()*arr_47.length)-1], "selfless and unworldly" + arr_48[Math.ceil(Math.random()*arr_48.length)-1], "intuitive and sympathetic" + arr_49[Math.ceil(Math.random()*arr_49.length)-1]];
var arr_punctuation = ["!", "."];

Ok, that’s a lot. This is the meat of the written content.

Then we have the actual function that makes the frogification magic happen. It looks like this:

//make the frog name
//frogification of names. this is the future of naming conventions.
function generate_frogname(){
	//frog arrays
	var arr_frogvariant = ["Frog", "Froglet", "Toad", "Frog", "Tadpole", "Amphibian"];
	var arr_frogplaces = ["pond", "lake", "swamp", "marsh", "woods", "underbrush", "creek", "tree", "canopy", "forest", "woods", "waters", "stream", "brook"];
	var arr_title = ["duke","marquis","earl","viscount","baron","baronet","knight","lord"];
	var arr_akafrogs = ["Abs", "Agnus", "Al-gea", "Amphibulus", "Scrubby", "Crusty", "Bouncer", "Bouncy", "Blinky", "Booboo the Bloatoad", "Bobo", "Booboo", "Bob", "Boo", "Boogy", "Bubba", "Bubble", "Buds", "Buddy", "Buggy", "Bumpy", "Chicky", "Chops", "Chubby", "Fats", "Fatso", "Chubber", "Flubber", "Chubbs", "Chunk", "Chunky", "Chunko", "Copper", "Conan", "Cool Frog", "Croaker", "Croaks", "Croaky", "Crunchy", "Cups", "Curmet", "Kermits", "Darty", "Dars", "Doc", "Dots", "Frogzilla", "Peppers", "Ducky", "Ducks", "Dumbell", "Dumpy", "Dumby", "Edgar", "Mimi", "Fatso", "Fatty", "Fatter Frog", "Fattest", "Fattest Frog", "Fatty Arbuckles", "Fearless Froglet", "Fergie", "Fibby", "Fiddles", "Fillmore", "Filbert", "Ferdinand", "Figaro", "Flibbit", "Flips", "Floatie", "Flubbers", "Francis", "Freaky Frog", "Freaky", "Froggens", "Froggins", "Froglestew", "Freckle", "Fugie", "Glossy", "Gobble", "Gobbles", "Gomez", "Gooey", "Gordon", "Gorf", "Gorf", "Gordito", "Greenie", "Gregan", "Grinner", "Grog", "Guacamole", "Guacky", "Gub-gub", "Gumball", "Gus", "Gus Gus", "Hogie", "Hoogie", "Hoogy", "Howie", "Hecktor", "Gerby", "Herby", "Hippyfrog", "Hopkins", "Hopper", "Hoppy", "Hoppity", "Hoppity-Hop", "Hop-Hop", "Hopps-alot", "Hopson", "Hopston", "Hot Frog", "Hot-Toad", "Hugo-a-go-go", "Hugo", "Ichabod", "Iggy", "Ivan", "Jabba", "Jabba the Jumpy", "Jumpy", "Jeremiah", "Jimmy da toad", "Joey", "Jorg", "Yurg", "Jumpiter", "Kermit", "Kermit Klein", "Ketchup", "Kilroy", "Kirby", "King Kirby", "Klack", "Kokomo", "Krebbit", "Kroppy", "Leaper", "Leapy", "Leafy", "Legs", "Leroy", "Little Guy", "Leggy", "Louie", "Lumpy", "Lumps", "Man-o Frog", "Marina", "Mark McGwire", "Max", "Maxter", "Mermin", "Merms", "Germs", "Mr.Croak", "Mr. Frog", "Mr. Fribble", "Mr. Skinny", "Mr. Mouth", "Mister Mac", "Mr. Red Bottom", "Mr. Moco", "Mog", "Moe Moe", "Munky", "Murdock", "Nanotoad", "Noodles", "Nozy", "Frogy-Wan", "Patches", "Peabody", "Peanut", "Peeps", "Squeeks", "Pekkle", "Pickles", "Pickle", "Floyd", "Pip", "Phyto-P", "Plop", "Plopps", "Po", "Poegy", "Pogo", "Pookee", "Crackers", "Popcorn", "Prince Soggy Bottom", "Puddles", "Pug Pug", "Punkins", "Pudgetta", "Quigley", "Quiggle", "Quibbit", "Quigleys", "Quiggles", "Giggles", "Quiglly", "Raisin", "Ruperts", "Crumbs", "Shamrockfrog", "Sir Croaks alot", "Skippy", "Skippydippy", "Skittles", "Slappy", "Slims", "Slimmy", "Slinky", "Slippy", "Slick", "Slub", "Sluggs", "Sluggo", "Soupy", "Smeaglet", "Smiles", "Smiley", "Springer", "Sprocket", "Sprog", "Sproing", "Spud", "Spuds", "Squiggly", "Squirt", "Sticky", "Stinky", "Stomper", "Stone Cold", "Stoney", "Stubby", "Stumper", "Stud", "Studs", "Squishy", "Squeeky", "Squirmy", "Squirms", "Tater", "Tomato", "Taters", "Tamoto", "El Tamoto", "Tapioca", "Tiggle", "Tiggles", "Tibbir", "Ribbits", "Tommy the Toad", "Tricky", "Tubby", "Tubs", "Tuffy", "Twiggles", "Watermelonbaby", "Webby", "Webs", "Wet Willy", "Wembley", "Wiggles", "Giggles", "Winky", "Wiggletins", "Whopper", "Xorcon", "Yggorf", "Zenon", "Zippity", "Zippy", "Zips", "Zookey", "Zucchini"];
	//get starting values
	str_name = str_yourname;
	//aka sentence
	str_aka = arr_akafrogs[Math.ceil(Math.random()*arr_akafrogs.length)-1];
	var arr_aka_sentence = [adj_aka[Math.ceil(Math.random()*adj_aka.length)-1]+" "+str_aka, str_aka+" "+"for short"];
	//
	arr_originalname = [];
	arr_originalname = (str_name).split(" ");
	arr_fullname = (str_name).split(" ");
	//clear
	str_name = "";
	//start
	for(var i=0; i<arr_fullname.length; ++i){
		if(arr_fullname[i].length>4){
			arr_fullname[i] = "Frog"+(arr_fullname[i].slice(4,arr_fullname[i].length));
		}else if(Math.random()*100>50){
			var randTitle = arr_frogvariant[Math.ceil(Math.random()*arr_frogvariant.length)-1]+arr_title[Math.ceil(Math.random()*arr_title.length)-1];
			arr_fullname[i] = randTitle+" of "+arr_fullname[i]+"frog";
		}
		if((i==arr_fullname.length-1 && Math.random()*100>50) && arr_fullname.length>1){
			arr_fullname[i] = "of the "+ arr_frogplaces[Math.ceil(Math.random()*arr_frogplaces.length)-1] +" of "+arr_fullname[i];
		}
		//set to this
		str_name+=arr_fullname[i]+" ";
	}
	_stage.txt_aboutfrog.text = ("Your frogname is: "+str_name+". "+ arr_aka_sentence[Math.ceil(Math.random()*arr_aka_sentence.length)-1] +", "+arr_personality[Math.ceil(Math.random()*arr_personality.length)-1]+" frog. You are known for being "+arr_aboutyou[Math.ceil(Math.random()*arr_aboutyou.length)-1]+arr_punctuation[Math.ceil(Math.random()*arr_punctuation.length)-1]);
};

It sends the value to the _stage.txt_aboutfrog text field.

The important thing about making a good generator is how you place all the body parts. Depending on how you build it, you will most likely have a lot of random pieces, of varying shapes and sizes.
Getting them all to place on each-other, or relative to each-other, is the key to making something look good (and hopefully goofy).
So registration points here are important, and nesting things right (if you decide to nest things, which works very well in many cases).

We have the following structure:

//paths
var mc_frog = _stage.mc_frog;
var mc_head = _stage.mc_frog.mc_face.mc_head;
var mc_body = _stage.mc_frog.mc_body;
var mc_arm_left = _stage.mc_frog.mc_arm_left;
var mc_arm_right = _stage.mc_frog.mc_arm_right;
var mc_arm_back_left = _stage.mc_frog.mc_arm_back_left;
var mc_arm_back_right = _stage.mc_frog.mc_arm_back_right;
var mc_eye_left = _stage.mc_frog.mc_face.mc_eyes.mc_eye_left;
var mc_eye_right = _stage.mc_frog.mc_face.mc_eyes.mc_eye_right;
var mc_mouth = _stage.mc_frog.mc_face.mc_mouth;
var mc_eyes = _stage.mc_frog.mc_face.mc_eyes;

All clips need a proper registration point to where they connect to their appropriate body part, or body.
For example, the head’s registration point is at the bottom middle. Like a neck. It connects to the body.

Arms are somewhere top left (for left arm) and top right (for right arm).

The body is at the bottom middle, because it will be sitting on the ground.

You notice from the “paths” above that things are grouped within their appropriate body part. For example, the “FACE” holds the head, eyes, and mouth. This is so, after all the placing, moving it is easier.

The most busily grouped thing is the face. The rest is just inside of FROG.

Of course there are many ways of doing this, but if you’ll watch G.P. Lackey’s presentation where he makes a frog generator on stage, he does it in a similar way. Creates many graphics, scales them, colors them, and places them.
I think this approach is more intuitively to visual people. It also offers the most control over the resulting character’s style.

I found that, if the approach leaned more in the programming direction, I would have had to spend too much time programming the blobs to work as body parts and (although cooler) it would end up being pretty much the same thing in the end, but much more work. This way is faster.

For creating the actual body parts, you make a ton of them. The starting groups act like “types”, then you can optionally “morph” them together in varying combinations to get even more types.
These are all on frames inside the body part.

The generator then takes care of placing, and choosing them appropriately. Some parts that require a similar body part will choose from the same random frame. Sometimes it’s totally random so, for example, there are two different arms and the frog looks like it’s making some sort of gesture.
Eyes are usually the same eye type. There is “tiny”, “slanted”, and “round”.

In the very end, a minor amount of movement is applied to all the parts. To give it some life.

The movement functionality looks like this:

var arr_movement = [];//refferneces to clips that move go here, ticker loops through it

//movement for the frog
function start_randomMovement(clip, mcProp, maxVal, minVal, decay, decimal) {
	//starting values
	clip.ymoveval = 0;
	clip.yPos = 0;
	clip.yTarget = 0;
	clip.yval = 0;
	clip.rVar = 0;
	clip.fVar = 0;
	clip.yVar = 0;
	//
	clip.mcProp = mcProp;
	clip.maxVal = maxVal;
	clip.minVal = minVal;
	clip.decay = decay;
	clip.decimal = decimal;
	//
	arr_movement.push(clip);
}

//random movement's listener
function evnt_randomMovement(event) {
	//
	for(var i = 0; i<arr_movement.length; ++i){
		var clip = arr_movement[i];
		//
		if (clip.ymoveval < 0.1 && clip.ymoveval > -0.1) {
			clip.rVar = ((Math.ceil(Math.random() * 4) + 4) / 100);
			clip.fVar = ((Math.ceil(Math.random() * 4) + 4) / 10);
			clip.yVar = (Math.random() * (clip.maxVal - clip.minVal)) + clip.minVal;
		}
		//           
		clip.yPos = (clip.yPos * clip.fVar) + ((clip.yVar - clip.yTarget) * clip.rVar);
		clip.yTarget = clip.yTarget + clip.yPos;
		clip.ymoveval = (clip.yTarget - clip.yval) * clip.decimal + (clip.ymoveval * clip.decay);
		clip.yval = clip.yval + clip.ymoveval;
		clip[clip.mcProp] = clip.yval;
	};
}

//scale, y, and rotation mostly
start_randomMovement(mc_mouth, "scaleY", .5, 0, 1, 0.9);
start_randomMovement(mc_frog.mc_face, "y", mc_frog.mc_face.y, mc_frog.mc_face.y-8, 0.1, 0.05);
start_randomMovement(mc_body, "rotation", 3, -3, 0.1, 0.05);//breathing
start_randomMovement(mc_arm_left, "rotation", 5, -5, 0.1, 0.05);
start_randomMovement(mc_arm_right, "rotation", 5, -5, 0.1, 0.05);
start_randomMovement(mc_head, "rotation", -3, 3, 0.1, 0.05);
start_randomMovement(mc_eye_left, "y", mc_eye_left.y,mc_eye_left.y-10, 0.1, 0.07);
start_randomMovement(mc_eye_right, "y", mc_eye_right.y,mc_eye_right.y-10, 0.1, 0.07);
//ticker for movement
createjs.Ticker.addEventListener("tick", evnt_randomMovement);

Whatever part you wish to move is pushed to the arr_movement array. You give it some values because all parts move different. For example, the mouth (if there is one) is very erratic.
The rest is fairly self explanatory.

In the original ActionScript version there where also lines being drawn to the eyes.
Example of that, so you know what I mean:

function evnt_drawEyeline(event:Event){
	if(bool_drawEyeLine){
		mc_eyes.graphics.clear();
		var point_start:Point = mc_eyes.globalToLocal(mc_eye_left.localToGlobal(new Point()));
		var point_end:Point = mc_eyes.globalToLocal(mc_head.localToGlobal(new Point()));
		mc_eyes.graphics.lineStyle(15, calc_hexTint(col_frog,0.7));
		mc_eyes.graphics.moveTo(point_start.x-2,point_start.y);
		mc_eyes.graphics.lineTo(point_end.x-mc_head.width/4,point_end.y-mc_head.height/2);
		//
		point_start = mc_eyes.globalToLocal(mc_eye_right.localToGlobal(new Point()));
		point_end = mc_eyes.globalToLocal(mc_head.localToGlobal(new Point()));
		mc_eyes.graphics.lineStyle(15, calc_hexTint(col_frog,0.7));
		mc_eyes.graphics.moveTo(point_start.x-2,point_start.y);
		mc_eyes.graphics.lineTo(point_end.x+mc_head.width/4,point_end.y-mc_head.height/2);
		//graphics.clear();//in case of on enter and must follow around keep drawing (in event)
	}else{
		mc_eyes.graphics.clear();
	}
}

This was so that the eyes always stay attached to their bodies. Sometimes the eyes hover just a bit above the head. I was testing it again in this version and decided I will not do this, because they look sort of adorable with the eyes doing that.
If you like you can incorporate that yourself. bool_drawEyeLine is handled in the generateFrog() function I will be describing shortly.

The original ActionScript version was a bit more complicated. It did more. This is simplified for the sake of a readable tutorial.

The backgrounds…

There are three different backgrounds. Space, Mountains, and Stream. They all have their own ambient soundtrack playing. Space is super rare. Space is for the super rare Spacefrogs.
The function that sets the background, and takes care of the associating soundtrack is as follows:

//set a background
function set_background(){
	//stop the sounds first (if curr_background has a value)
	if(curr_background != ""){
		stopSound("snd_"+curr_background);
	};
	//
	var arr_backgrounds = ["space", "mountains", "stream", "mountains", "stream", "mountains", "stream", "mountains", "stream", "mountains", "stream"];
	curr_background = arr_backgrounds[Math.ceil(Math.random()*arr_backgrounds.length)-1];
	_stage.mc_foreground.gotoAndStop(curr_background);
	_stage.mc_background.gotoAndStop(curr_background);
	//set soundscape
	if(curr_background == "space"){
		playSoundLoop("snd_space", 999);
	}
	if(curr_background == "stream"){
		playSoundLoop("snd_stream", 999);
	}
	if(curr_background == "mountains"){
		playSoundLoop("snd_mountains", 999);
	}
}

_stage.mc_foreground is the foreground clip that contains foreground details like rocks and grass.
_stage.mc_background is the large scene in the back.

These two clips have frame labels named "space", "mountains", "stream". It’s very simple.
The sound is then handled. Sound ID’s for these areas look like this:

{id:"snd_mountains", src:"AUD_SCENE_MOUNTAIN.mp3"},
{id:"snd_stream", src:"AUD_SCENE_STREAM.mp3"},
{id:"snd_space", src:"AUD_SCENE_SPACE.mp3"},

So that’s why the ("snd_"+curr_background)… If you stop a sound that doesn’t exist things break. You have to be specific.

Now on to the generateFrog() function…

The generateFrog() function is the big thing where all the magic happens. It looks like this:

//generate the frog (triggered by the 'refresh' button)
function generateFrog(){
	//
	stopAllSounds();
	//
	play_transition(_stage.mc_transition_bottom);
	play_transition(_stage.mc_transition_top);
	mc_frog.visible = true;
	_stage.btn_save.visible = true;//only appears after frogs start coming in
	_stage.mc_ui_back.visible = true;
	_stage.txt_aboutfrog.visible = true;
	set_large_ribbon();
	set_background();
	//
	generate_frogname();
	//random head and body
	gotoAndStopRandom(mc_head);
	gotoAndStopRandom(mc_body);
	//get a random arm (frame number)
	var num_arm_frame = (Math.ceil(Math.random()*mc_arm_left.timeline.duration)); //same frame for both arms
	if(Math.random()*100>50){//50 chance of both arms being same frame
		mc_arm_left.gotoAndStop(num_arm_frame);
		mc_arm_right.gotoAndStop(num_arm_frame);
	}else{
		//random gesture
		gotoAndStopRandom(mc_arm_left);
		gotoAndStopRandom(mc_arm_right);	
	}
	//eyes and legs
	var num_arm_back_frame = (Math.ceil(Math.random()*mc_arm_back_left.timeline.duration));
	mc_arm_back_left.gotoAndStop(num_arm_back_frame);
	mc_arm_back_right.gotoAndStop(num_arm_back_frame);
	var num_eye_frame = (Math.ceil(Math.random()*mc_eye_left.timeline.duration));
	mc_eye_left.gotoAndStop(num_eye_frame);
	mc_eye_right.gotoAndStop(num_eye_frame);
	//does it have a mouth? show or hide it...
	//if it has a mouth, frog must sing
	if (Math.random()*100>50){
		playFrogSound();
		mc_mouth.visible = true
	}else{
		stopFrogSound()
		mc_mouth.visible = false;	
	}
	//
	//size the body parts. frogs come in many shapes and sizes
	var num_sizeoffset = Math.ceil(Math.random()*10);
	mc_head.width = mc_body.width+num_sizeoffset;
	mc_arm_left.width = num_arm_left_width+num_sizeoffset;
	mc_arm_left.height = num_arm_left_height+num_sizeoffset;
	mc_arm_right.width = num_arm_left_width+num_sizeoffset;
	mc_arm_right.height = num_arm_left_height+num_sizeoffset;
	//eyes (reset size first for eyes) - eyes must have an if else that determines if both are different size or same size (circles only both different size)
	//reset
	mc_eye_left.width = mc_eye_right.width = num_eye_left_width;
	mc_eye_left.height = mc_eye_right.height = num_eye_left_height;
	//if round allow random size, else no (uniform size)
	//mc_eye_right.frameBounds[mc_eye_right.currentFrame].width
	if(eye_type=="round"){
		mc_eye_left.height = mc_eye_left.width = Math.ceil(number_randomRange(return_bounds(mc_eye_right).width, return_bounds(mc_eye_right).width*8));
		mc_eye_right.height = mc_eye_right.width = Math.ceil(number_randomRange(return_bounds(mc_eye_right).width, return_bounds(mc_eye_right).width*8));
	}else if(eye_type=="slanted"){
		mc_eye_left.height = mc_eye_right.height = Math.ceil(number_randomRange(return_bounds(mc_eye_right).height, return_bounds(mc_eye_right).height*2));
		mc_eye_left.width = mc_eye_right.width = Math.ceil(number_randomRange(return_bounds(mc_eye_right).width, return_bounds(mc_eye_right).width*8));
	}else{//tiny or other
		mc_eye_left.height = mc_eye_left.width = number_randomRange(2, 7);
		mc_eye_right.height = mc_eye_right.width = number_randomRange(2, 7);
	}
	mc_mouth.width = number_randomRange(20, mc_head.width-5);//-width of line
	mc_mouth.height = number_randomRange(10, 85);
	num_mouth_height = mc_mouth.height;//max value to tweak
	
	//place
	var num_placeoffset = Math.ceil(number_randomRange(20, 30));
	mc_head.y = (mc_body.y-return_bounds(mc_body).height)+(num_placeoffset);//offset could be random
	
	mc_arm_left.x = mc_body.x-return_bounds(mc_body).width/2+3;
	mc_arm_left.y = mc_body.y-return_bounds(mc_body).height/2;
	mc_arm_right.x = mc_body.x+return_bounds(mc_body).width/2-3;
	mc_arm_right.y = mc_body.y-return_bounds(mc_body).height/2;
	
	var num_arm_back_placeoffset = Math.ceil(number_randomRange(-10,10));
	mc_arm_back_left.x = mc_body.x-return_bounds(mc_body).width/2+10;
	mc_arm_back_left.y = mc_body.y-return_bounds(mc_body).height/2+num_arm_back_placeoffset;

	mc_arm_back_right.x = mc_body.x+return_bounds(mc_body).width/2-10;
	mc_arm_back_right.y = mc_body.y-return_bounds(mc_body).height/2+num_arm_back_placeoffset;
	
	mc_eyes.x = mc_head.x;
	mc_eyes.y = mc_head.y - (return_bounds(mc_head).height/2) + number_randomRange(-10,10);
	
	//minimum is -20 for left 20 for right
	var num_eyes_place = number_randomRange(20, return_bounds(mc_head).width/2 + (return_bounds(mc_eye_left).width) - return_bounds(mc_head).width/8);// - one fourth of the head
	mc_eye_left.x = -num_eyes_place;//left eye on left side of head + width of eye to keep it on the head
	mc_eye_right.x = num_eyes_place;//
	
	//
	mc_mouth.x = mc_head.x;
	mc_mouth.y = mc_head.y;
	
	//draw lines to eyes to connect to body
	//this is handled in an event (constant timer because movement updates)
	if(eye_type == "round" || eye_type == "slanted"){
		bool_drawEyeLine = true;
	}else{
		bool_drawEyeLine = false;
	}
	
	//flip body parts
	//for added randomness
	if(Math.random()*100>50){
		mc_head.scaleX *= -1;
	}
	if(Math.random()*100>50){
		mc_body.scaleX *= -1;
	}
}

The beginning takes care of the new scene and sounds. Also setting visibility of the UI incase it’s hidden.
Then the frogname is generated.
The rest is all body and placement of the body.
The comments should make sense of the mess.

As you can see, the:

//returns a random number range
//eye calc: eye1 = random number in from 0, eye2 = width of head - random number in...
function number_randomRange(min, max){
	return min + (max - min) * Math.random();
}

function return_bounds(clip){
	return clip.getTransformedBounds();
}

Are being heavily used.

At the end this is all called in the handler for the refresh button:

function evnt_refresh(event){
	generateFrog();
	playEvntSound();
}

And that’s it for the meat of it!

SAVING THE FROG

The idea here is that once you found your perfect frog. Your frog soulmate, or frog spirit guide. You can save it as a pretty picture. We’ll do this as .png.

There are a few ways to save a canvas to image. Most notably canvas.toDataURL.
If I remember right:

var canvas = document.getElementsByTagName("canvas")[0];
var dataURL = canvas.toDataURL('image/png');
window.open(dataURL);

There are also many libraries, resources, and tutorials for doing this. To name some:

https://github.com/gillyb/reimg
https://github.com/hongru/canvas2image
http://greenethumb.com/article/1429/user-friendly-image-saving-from-the-canvas/
https://github.com/eligrey/FileSaver.js/
https://github.com/aaccurso/canvas-image-saver
http://stackoverflow.com/questions/923885/capture-html-canvas-as-gif-jpg-png-pdf

Also, in the original ActionScript version you could save as both .png or record your frog and save it as an animated .gif. You can easily accomplish both of these things with javascript. There are a few solutions for recording canvas to animated .gif. Most notably:

https://github.com/aaccurso/canvas-image-saver
http://antimatter15.com/wp/2010/07/javascript-to-animated-gif/
https://github.com/jnordberg/gif.js

So at the moment, to keep things simple, I’ll just do this:

//called at the end of the camera shutter animation
saveFrog = function(){
	var canvas = document.getElementsByTagName("canvas")[0];
	var dataURL = canvas.toDataURL('image/png');
    window.open(dataURL);
	//put it back the way it was
	set_large_ribbon();
	_stage.btn_refresh.visible = true;
	_stage.btn_save.visible = true;
}

//button event for downloading the frog (save as image)
function event_saveFrog(event){
	//hide UI and make it look nice for the picture
	set_small_ribbon();
	_stage.btn_refresh.visible = false;
	_stage.btn_save.visible = false;
	//camera shutter
	_stage.mc_camera.play();
	playSound("snd_camera");
}

This can be made fancy some other time.
The important thing here is to re-arrange the UI so it’s nice for the picture (get rid of the buttons, and center the banner again). Then play a little camera shutter animation.
When that’s done, save the frog. Put everything back the way it was.

The picture will open in a new browser window, where you can save it yourself.

By the way if you run this (save the picture part) locally you may get “Tainted canvases may not be exported.”. It’s explained here: http://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported

Conclusion

That’s about it! Frog generators are tons of fun. :)
Again, here are the download links to the sourcefiles and end result:

PLAY it here: http://frogs.alienmelon.com/html5/

DOWNLOAD sourcefiles: http://nathalielawhead.com/sourcefiles/Weird_Alien_Frogs/

Posted in Games, Web/Game Dev: Tutorials & Sourcecode | Leave a /b/romment

Beerme: