29 October 2010

Free Flash + AS3 + Flex Tutorials e-book

About two months ago I published my first e-book on Lulu. At first, idea was to create collection of better tutorials from this blog, which I'm writing for the past 3 and a half years. Initially, there was a small price under 5 bucks, but two months later I sold only 1 copy, so I decided to give it away for free. Actually, I wasn't selling the book, it was more like a small-donation-model to keep my blog running.

Right now, you can download the book from LULU pages or from Scribd.

As previously planned I'll update my e-book every 3-4 months with new tutorials and maybe few not available on this blog :)

*_*

19 October 2010

Custom Flex 4 HornLayout variation

Few days ago I presented custom Flex 4 TriangleLayout. Another variation of this layout would be when individual items are ordered from left to right, unlike in TrinagleLayout where items are placed top to bottom.



Code is almost the same, just a minor differences.

HornLayout.as


package com.flash2nd.layout {

// author: http://flanture.blogspot.com - www.flash2nd.com
// license: http://creativecommons.org/licenses/by/3.0/
// October 2010

import mx.core.ILayoutElement;
import mx.utils.ObjectUtil;

import spark.layouts.supportClasses.LayoutBase;

public class HornLayout extends LayoutBase {

public function HornLayout() {
super();
}

override public function measure():void {
super.measure();
}

override public function updateDisplayList(width:Number, height:Number):void {
super.updateDisplayList(width,height);

if(target){
var count:int = target.numElements;
var layoutElement:ILayoutElement;
var startX:Number = 0;
var startY:Number = target.height/2;
var shift:int = 1;

for(var i:int = 1; i < count+1; i++){
// find current level
var level:int = findLevel(i);

layoutElement = target.getElementAt(i-1);
layoutElement.setLayoutBoundsSize(NaN,NaN);

var elWidth:Number = layoutElement.getLayoutBoundsWidth();
var elHeight:Number = layoutElement.getLayoutBoundsHeight();

if (level !== findLevel(i-1)) {
shift = i;
}

var x:Number = startX + elWidth * (level - 1) * 2;
var y:Number = startY - elHeight * (level - 1) + (i % shift) * elHeight * 2;

layoutElement.setLayoutBoundsPosition(x,y);
}
}

}

private function findLevel(index:int):int {
var levelCounter:int = 1;
var sum:int = 1;
while (sum < index) {
sum += levelCounter;
if (sum <= index) {
levelCounter += 1;
}
}
return levelCounter;
}

}
}



HornLayoutTest.mxml


<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:layout="com.flash2nd.layout.*"
width="100%" height="100%">


<s:layout>
<layout:HornLayout/>
</s:layout>

<s:Button label="Button A"/>
<s:Button label="Button B"/>
<s:Button label="Button C"/>
<s:Button label="Button D"/>
<s:Button label="Button E"/>
<s:Button label="Button F"/>
<s:Button label="Button G"/>
<s:Button label="Button H"/>
<s:Button label="Button I"/>
<s:Button label="Button J"/>
<s:Button label="Button K"/>
<s:Button label="Button L"/>
<s:Button label="Button M"/>
<s:Button label="Button N"/>
<s:Button label="Button O"/>
<s:Button label="Button P"/>
<s:Button label="Button Q"/>
<s:Button label="Button R"/>

</s:Application>


sharing is caring :)
thanx.

*_*

16 October 2010

Discrete versus continual graphical AS3 Timer

Some Flash games require level timers. If mission is not complete when timer runs out, hero is dead. Usually you have two types of timers, numerical level timer and graphical timer.

On the other hand, graphical timer can be discrete or continual. Actually all graphical timers are discrete, when you think about it, just updates happen more frequently and user sees it like continual.

Here is how to create both discrete and continual graphic timers.

step 1.

First we set up some background color.


// background elements

var b1:Sprite = new Sprite();
b1.graphics.beginFill(0x33cc33);
b1.graphics.drawRect(0,0,stage.stageWidth,20);
addChild(b1);

var b2:Sprite = new Sprite();
b2.graphics.beginFill(0x33cc33);
b2.graphics.drawRect(0,25,stage.stageWidth,20);
addChild(b2);


step 2.

We write our discrete timer. Here is complete function.


function gTimer(seconds:int):void
{
var t:Timer = new Timer(1000, seconds);

var w:Number = stage.stageWidth;
var h:Number = 20;
var g:Sprite = new Sprite();
addChild(g);

t.addEventListener(TimerEvent.TIMER, onTimer);
function onTimer(evt:Event):void
{
var cc:int = evt.target.currentCount;
var gWidth:Number = (cc * w)/seconds;
g.graphics.beginFill(0x339933);
g.graphics.drawRect(0, 0, gWidth, h);
}
t.start();
}


Why this timer is 'discrete'? Because graphic update happens once every 1000 milliseconds. We see graphic change in distinct time intervals of one second.

Code is simple, only thing worth explanation is gWidth variable which is just proportion used to calculate current timer width.

step 3.

We write our continual timer. Here is complete function.


function cgTimer(seconds:int):void
{
var t:Timer = new Timer(50, seconds*20);

var w:Number = stage.stageWidth;
var h:Number = 20;
var g:Sprite = new Sprite();
addChild(g);

t.addEventListener(TimerEvent.TIMER, onTimer);
function onTimer(evt:Event):void
{
var cc:int = evt.target.currentCount;
var gWidth:Number = (cc * w)/(seconds * 20);
g.graphics.beginFill(0x339933);
g.graphics.drawRect(0, 25, gWidth, h);
}
t.start();
}


Code is exactly the same as in discrete graphical timer, with one minor change. Timer is called every 50 milliseconds and because those time intervals are so small, user sees this timer as continual one.

step 4.

We test our timers.

gTimer(24);
cgTimer(24);

Now, take your stopwatch and you will see that even both timers start in approximately the same time, discrete timer will finish first and both timers will finish after more than 24 seconds, discrete one in about 25,5 seconds and continual one almost 2 seconds later (at least on my computer).

This is not some error. Continual timer makes a lot more calculations than discrete one, hence difference. Just something you should be aware of when making games.

*_*

11 October 2010

Custom Flex 4 Spark TriangleLayout

Since Spark has separated layouts from components, now we have greater control of how final application will look like. Basic Flex 4 layouts are BasicLayout, HorizontalLayout, VerticalLayout and TileLayout.

However, one even more important feature is that you can create your own custom layouts by extendending LayoutBase class inside spark.layouts library or any of its subclasses.



TriangleLayout takes any given number of display elements and form triangle out of them, where first element is on top level, second and third on second level below, etc.

TriangleTest.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:layout="com.flash2nd.layout.*"
width="100%" height="100%">


<s:layout>
<layout:TriangleLayout/>
</s:layout>

<s:Button label="Button 1"/>
<s:Button label="Button 2"/>
<s:Button label="Button 3"/>
<s:Button label="Button 4"/>
<s:Button label="Button 5"/>
<s:Button label="Button 6"/>
<s:Button label="Button 7"/>
<s:Button label="Button 8"/>
<s:Button label="Button 9"/>
<s:Button label="Button 10"/>
<s:Button label="Button 11"/>
<s:Button label="Button 12"/>
<s:Button label="Button 13"/>
<s:Button label="Button 14"/>

</s:Application>


As mentioned before, TriangleLayout class extends LayoutBase class and overrides two methods: measure() and updateDisplayList(w,h).

I'm not going into details how code works, but if you need deeper understanding of it, feel free to email me with your questions.

TriangleLayout.as

package com.flash2nd.layout {

// author: http://flanture.blogspot.com - www.flash2nd.com
// license: http://creativecommons.org/licenses/by/3.0/
// October 2010

import mx.core.ILayoutElement;
import mx.utils.ObjectUtil;

import spark.layouts.supportClasses.LayoutBase;

public class TriangleLayout extends LayoutBase {

public function TriangleLayout() {
super();
}

override public function measure():void {
super.measure();
}

override public function updateDisplayList(width:Number, height:Number):void {
super.updateDisplayList(width,height);

if(target){
var count:int = target.numElements;
var layoutElement:ILayoutElement;
var startX:Number = target.width/2;
var startY:Number = 0;
var shift:int = 1;

for(var i:int = 1; i < count+1; i++){
// find current level
var level:int = findLevel(i);

layoutElement = target.getElementAt(i-1);
layoutElement.setLayoutBoundsSize(NaN,NaN);

var elWidth:Number = layoutElement.getLayoutBoundsWidth();
var elHeight:Number = layoutElement.getLayoutBoundsHeight();

if (level !== findLevel(i-1)) {
shift = i;
}
var x:Number = startX - elWidth * (level - 1) + (i % shift) * elWidth * 2;
var y:Number = startY + elHeight * level * 2;

layoutElement.setLayoutBoundsPosition(x,y);
}
}

}

private function findLevel(index:int):int {
var levelCounter:int = 1;
var sum:int = 1;
while (sum < index) {
sum += levelCounter;
if (sum <= index) {
levelCounter += 1;
}
}
return levelCounter;
}

}
}



You can also download TriangleLayout source code.

*_*

 

template by blogger templates