Wonder wall case study

September 9th, 2011

Post in Actionscript 3.0

Everybody knows and loves Yugo Nakamura and this tha.jp company.
There are alot of “interpretations” on how Nakamura developed the http://wonder-wall.com website.

This is my interpretation of it in a series of tutorials. Hope you like it, comments are disabled.

Get Adobe Flash player



Get Adobe Flash player



Get Adobe Flash player



Over the time I created an easy way to get projects up and running without losing too much time in the logic.
There are a lot of frameworks that do this, and more, but I find that mine is very easy to work with, and I use it in all my projects. love™ isn´t exactly the best name, but its better the foo… right?!

For this post I decided to release a lighter version of the framework, not because I want to keep it a secret, but because there´s no need to complicate what I want to illustrate. Complete version of the framework will be released soon.

The Framework is divided in 3 parts.
-CORE (with events, settings, and logic)
-MEDIA (with custom buttons, animation engines, video players etc…)
-UTILS (with String validatores, math utilities, bitmap utilities, garbage collection, etc)

for this version i significant reduced the MEDIA folder, and the UTILS folder, leaving just the basic to understand and get you running on my framework.

Here is a quick example:

Get Adobe Flash player

You can download the source here.

Open your favorite actionscript editor and import the framework and the TweenMax engine used in this demo.

In your document class import StageDefinition.as and create a class (in this case called App.as that will extend Application.as

package 
{
	import flash.display.Sprite;
 
	import love.core.setup.StageDefinition;
	import pt.example.view.App;
 
	public class Main extends Sprite
	{
		public function Main()
		{
			var root:StageDefinition = StageDefinition.getInstance();
			root.start(this);
 
 
			addChild(new App());
		}
	}
}

So far, we have set the stage definitions, the custom right click menu (this can be override), and we added the App.as class to the stage.

The App.as is the visuals of your project.

package pt.example.view
{
	import flash.events.Event;
 
	import love.core.Application;
	import love.core.events.AppEvent;
	import love.core.setup.Structure;
	import love.media.button.Semi3D;
 
	import pt.example.view.page.Simple;
	import pt.example.view.sobre.Sobre;
 
	public class App extends Application
	{
		private var botao1:Semi3D;
		private var botao2:Semi3D;
		public function App()
		{
			var areas:Structure = Structure.getInstance();
			areas.addArea("about", pt.example.view.sobre.Sobre);
			areas.addArea("simple_page", pt.example.view.page.Simple);
 
			this.addEventListener(Event.ADDED_TO_STAGE, onAdded, false, 0, true);
		}
 
		public override function Navigation(id:String):void
		{
			switch(id)
			{
				case "about":
					botao1.enable(false);
					botao2.enable(true);
					break;
 
				default:
					botao1.enable(true);
					botao2.enable(false);
					break;
			}
		}
 
		private function onAdded(e:Event):void
		{
			this.removeEventListener(Event.ADDED_TO_STAGE, onAdded);
 
			botao1 = new Semi3D(click1);
			botao1.config("About the framework", null, 0xFFFFFF, 0xCCCCCC, 4, true);
			botao1.enable(true);
			botao1.x = 20;
			botao1.y = 20;
			addChild(botao1);
 
			botao2 = new Semi3D(click2);
			botao2.config("Simple Page", null, 0xFFFFFF, 0xCCCCCC, 4, true);
			botao2.enable(true);
			botao2.x = botao1.x + botao1.width + 10;
			botao2.y = botao1.y;
			addChild(botao2);
 
 
			dispatchEvent(new AppEvent(AppEvent.NAVIGATE, {area:"about"}));
		}
 
		private function click1():void
		{
			dispatchEvent(new AppEvent(AppEvent.NAVIGATE, {area:"about"}));
		}
 
		private function click2():void
		{
			dispatchEvent(new AppEvent(AppEvent.NAVIGATE, {area:"simple_page"}));
		}
	}
}

As you have noticed the App.as extends Application.as that handles the views and dispatches events throw the StageDefinition.STAGE (your stage) informing on AppEvent.Navigation type events.

In this example I´ve added 2 pages and 2 buttons.

Every page in a view, and it extends a Base.as class.

Base.as class handles the open and close methods, resize and remove methods, your can override all of this methods, to create custom open and close animations from page to page. In this example I use the default from Right to Left animation (using TweenMax).

The complete version of the framework has Papervision3D and SWFAddress support, custom debug tools, custom buttons, animation engine, and some great utilities to rapidly starting creating your website.

Cheers
André

Sometimes I like to pretend that in every website I do, I have and easter egg.
Sometimes I share it with friends and sometimes I dont. Its a kind of therapy that helps me keep excited about a project. Weird I know.

So, this is how I usually do it.

Somewhere in your Application, you should have this code

package
{	
	import flash.display.Sprite;
	import love.utils.Cheats;
 
	public class Main extends Sprite
	{
		public function Main()
		{		
			var cheats:Cheats = Cheats.getInstance();
			cheats.addWord("lorem ipsum", cheat1);
			cheats.addWord("user has no moustache", cheat2);
			cheats.enable(true);
		}
 
		public function cheat1():void
		{
			trace("do some shit");
		}	
 
		public function cheat2():void
		{
			trace("close website, user is lamme!");
		}
	}
}

So, if the user for some reason type in the sentence “LOREM IPSUM” it automatically call the cheat1 function. This adds a lot of creative possibilities.

package love.utils
{	
	import flash.events.KeyboardEvent;
 
	import love.core.debug.TheDebugger;//this class Is just for debugging, you can change the TheDebugger.lot() to trace().
	import love.core.setup.StageDefinition;//This class stores the stage reference, you can change the StageDefinition.STAGE to Stage.
 
	public class Cheats
	{
		protected static var instance:Cheats;
		private var words:Array = [];
		private var possible:Array = [];
		private var currentChar:uint = 0;
		public function Cheats()
		{
			if(instance != null)TheDebugger.error("Cheats Singleton already constructed!");
			instance = this;
		}
 
		public static function getInstance():Cheats 
		{
			if(instance == null)instance = new Cheats();
			return instance;
		}
 
		public function addWord(word:String, func:Function):void
		{
			var obj:Object	= new Object();
			obj.word	= word;
			obj.func	= func;
			words.push(obj);
		}
 
		public function enable(value:Boolean):void
		{
			if(value)
			{
				StageDefinition.STAGE.addEventListener(KeyboardEvent.KEY_DOWN, checkForSequence);
			}
		}
 
		private function checkForSequence(e:KeyboardEvent):void
		{
			var valid:Boolean = false;
			for(var i:uint = 0; i<words.length;++i)
			{
				if(checkLetterInWord(e.charCode, words[i].word))
				{
					possible.push(words[i]);
					valid = true;
				}
			}
 
			//var char:String = String.fromCharCode(e.charCode);
			checkValidWord(valid);
			possible =[];
		}
 
		private function checkValidWord(valid:Boolean):void
		{
			if(valid)
			{
				currentChar++;
 
				if(currentChar == possible[0].word.length)
				{
					possible[0].func();
					resetCharCount();
				}
			}
			else
			{
				resetCharCount()
			}
		}
 
		private function resetCharCount():void
		{
			currentChar = 0;
		}
 
 
		private function checkLetterInWord(code:Number, word:String):Boolean
		{
			return code == word.charCodeAt(currentChar) ? true : false;
		}
	}
}

Now, lets take this baby for a ride

Get Adobe Flash player

You can download the source here.

Calculating mouse speed

January 10th, 2011

Post in Actionscript 3.0

Usefull for game development.

package
{
	import flash.events.Event;
	import flash.text.TextField;
	public class Example
	{
		private var velocityInfo:TextField;
		private var prevX:Number = mouseX;
		private var prevY:Number = mouseY;
 		private var velX:Number = 0;
		private var velY:Number = 0;
		public function Example():void
		{
			velocityInfo = new TextField();
			velocityInfo.x = 20;
			velocityInfo.y = 20;
			addChild(velocityInfo);
 
 
			addEventListener(Event.ENTER_FRAME, onLoop);
 
			function onLoop(e:Event):void
			{
     				velX = mouseX - prevX;
				velY = mouseY - prevY;
 
				velocityInfo.text = velX + ", " + velY
				prevX = mouseX;
				prevY = mouseY;
			}
		}
	}
}

Its been a while since my last post… I´ve been working alot on new projects, and I haven´t had much time to update my blog. I´m sorry! ;)

It has been a big buzz about HTML5 for a while now, and is it or is it not going to “kill Flash”. I´ve worked with some people that believe Flash is going to be overrun by HTML5. And I was laughing in silence with sentences like:

No, we cannot use Flash Player 10, because its to damn recent and almost no one has it (including our clients).
mmmm, ok, but this was said yesterday (22nd, October 2010) and Flash Player 10 has been around since late 2008?

The same people told me:
Lets start learning HTML5 and do some works for our clients using this technology
mmmm, ok, but arent these clients the same clients from above? The ones who dont use Flash Player 10 because its to damn recent, and still use Internet Explorer 6 (released in 2001)? How will they manage to see (or even imagine) HTML5 using that?

Again:
Hey, I just bought this iPad abroad, lets start making apps for iPhone and iPad
mmmm, ok, I love programming in Cocoa, but is this app just for you and the client? Because you know, that iPad is still unavailable in Portugal, and only you, the client and well… me, can actually afford it. Shouldn´t we be doing apps for the clients target and not for the client itself?

Well, maybe in this last one I´m beeing just vicious. But this is just to illustrate the “fire at sight” policy that some people use and abuse, and how the sentence “Hey, Its new, let´s use it” can only apply with HTML5 or Cocoa. And in Flash Player 10 its more like “Hey, Its new, we can´t use it”.

First of all, I´m very excited about HTML5!!!

a) Do I fear for my job as a Flash Developer? No!
b) Am I learning HTML5 and Cocoa because I might fear for my Job subconscious? No!

I´m learning HTML5, Cocoa, Javascript, PHP, mySql, Arduino, Android, C++, etc, because I LOVE PROGRAMMING, and I LOVE TO CHALLENGE MYSELF.
Nothing gives me more pleasure then learning new stuff and after a while doing things I tough I could´t do before.

So, do I think Flash Player is going to be overrun by HTML5? No!

Flash Player will still grow and so will HTML5. They are different things, and none of them will crush the other.

Here´s some thoughts from Youtube on HTML5 vs Flash.
And Please check this and this HTML5 experiences. They are great!!!

Flash Developers, be in peace! I am!

In iPhone Development we use Objective C. Objective C was created in 1983 and it evolve from C and SmallTalk.
In 1988 Next licenced Objective C (for NextStep OS) and in 1996 Apple buys NeXT, and in the next few years they use Objective C in Developing OS X. So, this is why iPhone applications (and any other Apple apps) are build in Objective C.
Objective C is C but with other things added (not changed, added!).

In iPhone Development we also have Cocoa Touch. Cocoa Touch is a API build over Objective C.
In the beginning developers wrote some functions to handle various things like strings, dates, timezones, streams etc, and wrap it up, and they called it the Foundation Framework.
We´ll be programming for iPhone, so it will be useful to have some pre-written user interface elements, and thats been done in Objective C 2 called UIKit Framework, which contains hundreds of classes to building User Interfaces on the iPhone. And programmers kept adding on with things to building maps, games, and working with the address book, working with audio and graphics, hundreds of classes, undress of methods, all wrap up in and they called Cocoa Touch.

Calling a method in Java is different from calling in Objective C
in Java we call: myObject.someMethod();
in Objective C we call: [myObject someMethod];

How about if my method takes and argument?
in Java: myObject.someMethod(arg);
in Objective C: [myObject someMethod:arg];

How about methods that take multiple arguments?
in Java: myObject.someMethod(“this is a String”, 0);
in Objective C: [myObject someMethodText:@"this is a String" someMethodIndex:0];
notice that with multiple arguments the method name changes, and the method name defines what the 2, 3 or 4 methods are.
(note that in Objective C any String must be preceded by a @)

welcome to my 1st tutorial of iPhone Development.

This is a 4 step guide to program your first iPhone App.
1)

Open Xcode, create a new project by selecting New Project and the click on the icon labeled View-Based Application, this is the simplest of all templates. Save your project and you are ready to start.

2)

On the left, you have the Groups & Files Pannel, and in that, you will find the Classes Folder, the folder where you will spend much of your time. This is where most of the code that you write will go, since this is where all Objective-C classes belong, you are free to create subfolder under the Classes folder to help organize your code.

There is also a very important folder that is the Resources folder. Start by clicking on Hello_WorldViewController.xib and that will automaticly open the Interface Builder application.

3)

You can create a simple button either by instantiate and object of type UIButton (like this: UIButton *myButton = [[UIButton alloc] initWithFrame:aRect];)
or dragging a button from a palette of interface objects onto your application´s main window.

Scroll down through the list of objects in the Library paletter until you find one called Label. Drag it to the view pannel, and go back to Xcode, save your project and click on the Build and Run Button. Be amazed, your 1st Application was created. Using the iPhone Simulator, or your iPhone(if your a payed iPhone developer) you will notice that you application has a very bad looking icon. go ahead and open Photoshop and make a nice PNG at 57x57px

Dont worry about rounding edges, cause the iPhone OS will round the edges and give it that nice glassy appearance. Just create a normal flat, square image.

4)

After your masterpiece is done, drag it to the Resources folder in you Xcode Project. Next, we need to specify that this particular image should be used as our application´s icon. To do that, open the Info.plist file in your resources folder. In the Icon file property double click the empty value and type the name of your icon.

Save your project and click on the Build and Run button. While on iPhone Simulator click on the home button of the iPhone simulator, your will notice you now hava a awesome icon.

Congratulations, you got your first iPhone application, and you did note write a single line of code.

Here´s a simple loop to check every property in a object, just in case u dont know what you are getting.

var infoObject:Object = {info:"a string", name:"another String", data:["hello", "there","sir"], object:{}};
for (var propName:String in infoObject)
{
	trace(propName + " = " + infoObject[propName]);
}

While making a video stream project, I had to convert seconds to HH:MM:SS and vice versa, so I created this class.

/*
USAGE:
TimeUtils.encode(90);
TimeUtils.decode("00:01:30");
*/
package euro.utils
{
	public class TimeUtils
	{
		public function TimeUtils():void
		{
		}
 
		public static function encode(_seconds:int):String
		{
			var seg = _seconds %60;
			var min = _seconds/60 %60;
			var hor = _seconds/60 /60;
 
			return String(normalize(hor,2) + ":" +  normalize(min,2) + ":" + normalize(seg,2));
		}
 
		public static function decode(_string:String):Number
		{
			var parts:Array = _string.split(":");
 
			var seconds:Number	= parts[2];
			var minutes:Number	= parts[1];
			var hours:Number	= parts[0];
 
			return seconds + 60 * minutes + 60 * 60 * hours;
		}
 
		private static function normalize(_int:int, _size:int):String
		{
			var temp:String = String(_int)
 
			for (var i = 1; i < _size; i++)
			{
				if (_int < Math.pow(10,i))
				{
					temp = "0" + temp;
				}
			}
			return temp;	
		}
	}
}

I thought I could share a piece of code.
This is a work in progress, but I thought this could come in handy to someone out there.

Get Adobe Flash player



import av.events.SiteEvent;
import av.utils.LoadFont;
import av.effects.BackgroundText;
 
 
var font1:LoadFont = new LoadFont("fonts/AauxProBold.swf");
	font1.addEventListener(SiteEvent.LOAD_FONT_COMPLETE, loadComplete);
 
 
var style:TextFormat;
var texts:Array = [
					"Hello! I created this Class as an Example for Creating multiple lines using only one String.",
					"I added a background because as you know, the 'backgroundColor' property of a TextField() sucks!!!",
					"This was made for a very specific purpose, but I thought maybe this could be helpful to someone.",
					"This is just and experiment. It´s not ready for a public release yet, so feel free to download the source and use it as you like."
					];
 
var actual:Number;
 
 
 
function loadComplete(e:SiteEvent):void
{
	style= new TextFormat("AauxProBold", 16, 0xFFFFFF);
	style.letterSpacing = 0;
	style.kerning = true;
	style.align = "left";
 
	DemoSTART();
}
 
 
function DemoSTART():void
{
	actual = 0;
	var _title:BackgroundText = new BackgroundText();
		_title.y = 50;
		_title.addEventListener("ALL_DONE", DemoEND);
	addChild(_title)
 
 
	for(var i:uint=0;i<texts.length;++i)
	{
		_title.Config(texts[i], style, 150);
	}
 
	_title.animIN();
}
 
 
 
 
 
function DemoEND(e:Event):void
{
	trace("Acabou");
 
	var _over:Sprite = new Sprite();
		_over.addEventListener(MouseEvent.CLICK, doRestart);
		_over.buttonMode = true;
	addChild(_over);
	_over.graphics.clear();
	_over.graphics.beginFill(0,0)
	_over.graphics.drawRect(0,0,400,300)
	_over.graphics.endFill();
 
	var tf:TextField = new TextField();
		tf.text = " CLICK ANYWHERE TO RESTART";
		tf.autoSize = "left";
		tf.border = true;
		tf.borderColor = 0xFF0000;
		tf.selectable = false;
		tf.mouseEnabled = false;
		tf.embedFonts = true;
		tf.defaultTextFormat = style;
		tf.setTextFormat(style);
	_over.addChild(tf);
	tf.x = (400/2) - (tf.width/2);
	tf.y = (300/2) - (tf.height/2);
}
 
 
function doRestart(e:MouseEvent):void
{
	var total:uint =numChildren-1
	for(var i:uint = 0;i <total;++i)
	{
		removeChildAt(1);
	}
 
	DemoSTART();
}


package av.effects
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextLineMetrics;
	import flash.utils.setTimeout;
 
	import gs.TweenLite;
	import gs.easing.*;
 
	public class BackgroundText extends Sprite
	{
		private var dados:Array = [];
		private var currentTween:uint = 0;
		private var assets:Array = [];
		private var txt:TextField;
		private var tf:TextFormat;
 
		public function BackgroundText()
		{
			addEventListener("ANIM_IN_COMPLETE", checkForNewMessages);
			addEventListener("ANIM_OUT_COMPLETE", loadNextIfAny);
		}
 
		public function Config(_texto:String, _textFormat:TextFormat, _width:uint):void
		{
			tf = _textFormat;
 
			txt = new TextField();
			txt.width = _width;
			txt.wordWrap = true;
			txt.autoSize = "left";
			txt.text = _texto;
 
			var frases:Array = [];
			for(var i:uint = 0;i<txt.numLines;i++)
			{
				var OBJ:Object = new Object();
					OBJ.__text = txt.getLineText(i);
					OBJ.__x = 0;
					OBJ.__y = 22 * i;
					OBJ.__delay = .3 * i;
				frases.push(OBJ);
			}
			dados.push(frases);
		}
 
		private function checkForNewMessages(e:Event):void
		{
			//trace("IN complete");
			currentTween++
			if(currentTween<dados.length)
			{
				setTimeout(animOUT, 4000);
			}
			else
			{
				dispatchEvent(new Event("ALL_DONE"));
			}
		}
 
		private function loadNextIfAny(e:Event):void
		{
			//trace("OUT complete");
			if(currentTween<dados.length)
			{
				animIN()
			}
		}
 
		public function animIN():void
		{
			for(var i:uint = 0;i<dados[currentTween].length;i++)
			{
				setBackground(dados[currentTween][i].__text, dados[currentTween][i].__x, dados[currentTween][i].__y, dados[currentTween][i].__delay, i<dados[currentTween].length-1 ? false : true);
			}
		}
 
		private function setBackground(__texto:String, __x:int, __y:int, __delay:Number, _isLast:Boolean = false):void
		{
			var temp:Sprite = new Sprite();
			var tempBG:Sprite = new Sprite()
			var tempTXT:Sprite = new Sprite()
			var mascara:Sprite = new Sprite();
 
 
			addChild(temp);
			addChild(mascara);
 
			temp.addChild(tempBG);
			temp.addChild(tempTXT);
 
			temp.x = __x;
			temp.y = __y;
 
			mascara.x = __x;
			mascara.y = __y;
 
			tempBG.graphics.beginFill(0x6699cc);
			tempBG.graphics.drawRect(0, 0, 10, 10);
			tempBG.graphics.endFill()
 
			mascara.graphics.beginFill(0x000000,0);
			mascara.graphics.drawRect(0, 0, 10, 10);
			mascara.graphics.endFill()
 
			var txt:TextField = new TextField();
			txt.text = __texto;
			txt.textColor = 0xFFFFFF;
			txt.autoSize = "left";
			txt.selectable = false;
			txt.embedFonts = true;
			txt.defaultTextFormat = tf;
			txt.setTextFormat(tf);
			temp.addChild(txt);
			var tlm:TextLineMetrics = txt.getLineMetrics(0);
			tempBG.width = txt.width;
			tempBG.y = tlm.descent;
			tempBG.height = tlm.ascent + tlm.descent;
 
			temp.mask = mascara;
			mascara.width = 0;
			mascara.height = txt.height;
 
			assets.push(mascara);
			TweenLite.to(mascara, .5, {width: txt.width, delay:__delay,ease:Quad.easeInOut, onComplete:function():void
			{
				if(_isLast)dispatchEvent(new Event("ANIM_IN_COMPLETE"));
			}});
		}
 
		public function animOUT():void
		{
			assets.reverse();
			for(var i:int = 0;i<assets.length;++i)
			{
				if(i<assets.length-1)
				{
					TweenLite.to(assets[i], .5, {width: 0, delay:.3 * i, ease:Quad.easeInOut});
				}
				else
				{
					TweenLite.to(assets[i], .5, {width: 0, delay:.3 * i, ease:Quad.easeInOut, onComplete:function():void
					{
						var total:uint = numChildren;
						for(var i:uint = 0; i<numChildren;++i)
						{
							removeChildAt(0);
 
						}
						dispatchEvent(new Event("ANIM_OUT_COMPLETE"));
 
					}})
				}
			}
 
			assets = [];
 
		}
	}
}