Thursday, 26 August 2010

Link Flash Buttons to Web Pages

This is simple stuff compared to doodling apps and platform games, but no less vital if that's what the job requires. Here I give a brief intro to making Flash link to external URLs.

We can often think of Flash as creating standalone apps that talk only internally, but sometimes there is a need for your Flash work to link to external web pages, either because you are making a Flash menu for a website, or because you want your Flash based CD ROM interface to link to your website.

Whatever the reason, it's really simple.

Example

In this example I have 2 simple buttons that link to other websites.



Make some buttons

In this example I have a simple button symbol in the Library. I drag 2 instances of the button onto the stage and give each the following instance names: "google_btn" and "bbc_btn".


Then I add the following ActionScript.

The Code

This ActionScript is added to the first keyframe on the root timeline:


_root.bbc_btn.onPress = function () {
    getURL("http://www.bbc.co.uk/","
_blank");
}
_root.google_btn.onPress = function () {
    getURL("http://www.google.co.uk/","_blank");
}


How does it work?

Nothing could be simpler. We use a simple onPress event handler, so as soon as the button is pressed the action happens. The action is very easy to follow - we are using getURL and then specifying the URL and the target window.

getURL("http://URL_GOES_HERE","_TARGET_WINDOW_HERE");

And that's a wrap.

Wednesday, 25 August 2010

Simple Platform Game Engine in Flash

This year my students will be learning about game engines. For 3D they will most likely use the Unreal Development Kit, along with 3DS Max/Carrara 8 Pro for content creation. But that's all 3D - what about the 2D games? Well, for 2D, my platform of choice is Flash.

Problem is, that unlike the UDK, or Unity, or even the FPSC, Flash is not a game engine - and that means, not only creating and scripting content for 2D games, but also scripting the whole engine.

It's something I have been meaning to do for a while. And while I know that many talented developers have posted Platform game solutions online, there is something about working through the problem yourself that I really like. Besides, I don't always get on well with other people's code - and if I am to teach my students to code their own, I need a solution I have worked out so I know it inside out and backwards and can really explain it to them.

Many of you will want the code now, but I am still fine tuning it. Meanwhile, here is version 4d as a peep of how it is going so far (I am currently on version 4f).

Controls:
JetPack = SPACE

Left = LEFT ARROW
Right = RIGHT ARROW
Climb Ladder = UP/DOWN ARROW




When it is finished I will post the code and an explanation.

Friday, 20 August 2010

Controlling Sounds

The basic way of including sound in your Flash movies is to add them to keyframes in the timeline. And this is fine for sounds that must coincide with animated events, or simple audio feedback on button rollovers. But if you want more sophisticated control over sounds, like starting and stopping them individually, or changing their volume, then you need to use ActionScript.

Preparing sound for ActionScript control

In Flash you can either load an external sound, or you can export sounds in your document Library for ActionScript. If you want to learn more about loading external sounds read my post on making an MP3 player in Flash. In this post I am going to just look at exporting sounds from the Library.

First off then you need to import all the sounds you need into your document Library of your .fla file. To do this click File > Import > Import to Library. Then browse for the sound file you need and click "OK". The sound will be imported into your Library. If you can't see your Library click CTRL+L (Cmd+L on the Mac).

Repeat this import step as often as you need to for every sound you need to appear in the Library.

Once they are imported you need to change their linkage settings to you can access the sounds with ActionScript. To do this right-click one of the sounds in the Library and choose linkage. When the Linkage Properties box opens tick the Export for ActionScript option, the Export in first frame will automatically be selected, this is fine. Then you need to give the sound an Identifier. By default the Identifier will be the same as the sound's original filename, but I find it helpful to give it an Identifier that makes it easy to remember what it is e.g. "backgroundmusic" or "whizzysound". Once you have given it a new Identifier you can click the "OK" button.

Repeat this step for every sound in the Library that you want to control with ActionScript.

Controlling sound with ActionScript

All this code should be added to the first frame of your Flash movie. I like to create a separate layer called "Actions" just for the code to keep it separate from other layers and so I know where all my code is when I want to edit it.

So far you have set some sounds in the Library to export for use with ActionScript and given those sounds Identifiers. Now we write the code to make use of those sounds.

Creating a sounds object and attaching a sound
First you create a sound object for each of the sounds you want to use, and then attach those library sounds to the objects. In this example let's pretend we have just one sound in the library with the identifier "backgroundloopsound". Here's how you create the sound object, and then attach "backgroundloopsound":


/* create a sound object */
var sound1_snd:Sound = new Sound(sound1_mc);

/* attach a sound from the library to the sound object */
sound1_snd.attachSound("backgroundloopsound");


In the above code I have created a sound object called "sound1_snd". I have given the object a target of sound1_mc which will allow me to control the sound independent of other sounds - but for this to work I must also add an empty MovieClip to the stage called "sound1_mc". I do this by creating a new MovieClip symbol in the library with nothing in it. Then I drag this symbol to the stage and give it the instance name "sound1_mc".

Then I have used "attachSound" to attach "backgroundloopsound".

Controlling the sound through the sound object

Now that we have a sound object with a sound attached, we can control the sound by controlling the object. Here are some examples.

Starting Sound

/* to make it play automatically, just put it in your code near the top */
sound1_snd.start(0, 100);


In the code above, the first 0 in the parenthesis means that the sound should be started at the beginning. If you have a 20 second sound, and you want to start it from 10 seconds in, then you should write sound1_snd.start(10, 100). The 100 in the parenthesis tells Flash how many times to loop the sound, when setting this, think about how long someone might stay on the scene and make sure you have enough loops or the sound will stop before they leave.

The previous start sound code starts the sound as soon as the frame loads in the flash movie. If you only want a sound to start when the user clicks a button, you need to first make the button and give it an instance name such as startSoundButton_btn, and you need to surround it by an event handler such as onPress:

_root.startSoundButton_btn.onPress = function () {
sound1_snd.start(0, 100);
}


Other ways of controlling sound

You can stop the sound:


sound1_snd.stop();


You can change the volume of the sound:


/* 0 = no volume, 100 = full volume, 50 = half volume etc... */
sound1_snd.setVolume(50);


If you want any of these to work when the user clicks a button, once again, you need to make a button and an event handler.

Here's an example



For this example I have 2 sounds in the library, one is a recording of me saying the word 'background" once. The other is a recording of me saying the word 'button' once. These were saved as WAVs and imported into the stage.

Then I right-clicked the 'background' WAV in the Library and chose "Linkage" and I set it to export for actionscript and gave it the handler "backgroundsound".

Then I right-clicked the 'button' WAV in the Library and chose "Linkage" and I set it to export for actionscript and gave it the handler "buttonsound".

Then I made an empty MovieClip by creating a new MovieClip symbol in the Library with nothing in it.

Then I dragged an instance of the empty MovieClip onto the stage and gave it the instance name "bgsound_mc".

Then I dragged another instance of the empty MovieClip onto the stage and gave it the instance name "buttonsound_mc".

Then I made a button symbol in the Library and dragged 4 instances onto the stage. The buttons were given the instance names: "button_btn", "bgmute_btn", "allmute_btn" and "unmute_btn".

I then added static text by each button to remind me which was which.

Once all that was done it was time to add the code.


/* create a sound object for the background sound */
var background_snd:Sound = new Sound (bgsound_mc);
/* attach a sound from the library to the sound object */
background_snd.attachSound ("backgroundsound");
/* create a sound object for the button sound */
var button_snd:Sound = new Sound (buttonsound_mc);
/* attach a sound from the library to the sound object */
button_snd.attachSound ("buttonsound");
/* start the background sound loop and set it to mute as default */
background_snd.start (0, 1000000);
background_snd.setVolume (0);
/* set the button sound to play on button roll-over */
_root.button_btn.onRollOver = function () {
    button_snd.start (0, 1);
};
/* making the mute background button work */
_root.bgmute_btn.onPress = function () {
    background_snd.setVolume (0);
};
/* making the mute every sound button work */
_root.allmute_btn.onPress = function () {
    background_snd.setVolume (0);
    button_snd.setVolume (0);
};
/* making the un-mute button work */
_root.unmute_btn.onPress = function () {
    background_snd.setVolume (100);
    button_snd.setVolume (100);
};


That's it

That's the basics. You can of course use different event handlers such as onRollOver, onRollOut, onDragOver to trigger the sounds or change their volume. You can of course use event handlers to trigger more than one sound, or more than one action, you might start one sound while changing the volume of another at the same time for instance.

It's up to you to be creative, now you know the basics.

Thursday, 19 August 2010

Slider Input With a Difference

Slider or sliding inputs for user interfaces are not new, we get them in desktop software and on the web. But this one is slightly different. Instead of sliding the handle along a bar, the handle stays still and the bar moves. This is helpful when the bar contains measurements that are too big to fit on the screen.

In this example we are pretending to measure height. Just click and drag the pointer to measure.



As you can see the code that prevents the ruler dropping off the end is a bit clunky, but it will do for now.

How to make it

Make a MovieClip of a ruler, with the scale spaced evenly along its entire length - set the registration point to be the bottom-left of the MovieClip. Then make another MovieClip for the ruler pointer - set the registration point to be the bottom-left of the MovieClip too.

Place both MovieClips onto the stage and scale them so that the fit together nicely, but also so the ruler is much much longer than the stage is high.

Give the ruler the instance name 'ruler_mc' and the pointer the instance name 'pointer_mc'.

Then insert the following code onto the first frame of the movie.

The code

The comments will give you some idea of what does what:

var damping:Number = 20;
/*the higher the number the slower the ruler will move*/
var rulerdivisions:Number = 20;
/*this helps us work out the how far the along the ruler you are*/
/*make the rule move when the pointer is dragged on*/
moveruler = function () {
    if (_root.ruler_mc._y >= _root.pointer_mc._y && (_root.ruler_mc._y - _root.ruler_mc._height) <= _root.pointer_mc._y) {
        movefactor = (clickstart - _ymouse) / damping;
        _root.ruler_mc._y += movefactor;
    } else if (_root.ruler_mc._y <= _root.pointer_mc._y) {
        _root.ruler_mc._y = _root.pointer_mc._y;
    } else if (_root.ruler_mc._y - _root.ruler_mc._height) {
        _root.ruler_mc._y = (_root.pointer_mc._y + _root.ruler_mc._height);
    }
    measure = Math.floor ((_root.ruler_mc._y - _root.pointer_mc._y) / (_root.ruler_mc._height / rulerdivisions));
    measure_txt.text = measure+" cm";
};
/*check when the pointer is dragged*/
_root.pointer_mc.onPress = function () {
    clickstart = _ymouse;
    moveRulerInterval = setInterval (moveruler, 15);
};
/*check when the dragging stops*/
_root.pointer_mc.onRelease = function () {
    clearInterval (moveRulerInterval);
};
_root.pointer_mc.onReleaseOutside = function () {
    clearInterval (moveRulerInterval);
};


And that's all there is to it. If you have a neater way of stopping the ruler from dropping off either end, feel free to post your solution as a comment.

Making it useful

If you want to use the input of this interface for something useful, perhaps to base other calculations on it, simply use the 'measure' variable within your formula, to represent the user's input.

Thursday, 5 August 2010

Doodling Program in Flash AS2

Inspired by Dragon's Den this week, when 2 guys demonstrated a fun drawing program they had made, I decided to learn some more about Flash's drawing API to make a very much simpler doodling application in Flash.

Try It



It might look complex, but the hardest bit is only 26 lines of ActionScript, including comments. What makes me laugh the most, is that the whole application comes out as less than 2Kb.

The Code

It's getting late in my time zone, so I won't dissect the code in this post. But enjoy the code, and I'll explain it another time:


//Code from http://dansinteractive.blogspot.com
//default settings
var layernum = 0;
var curcolour:String = "0x000000";
var curlineweight = 5;
//draw the line
drawline = function () {
["layer"+layernum+"_mc"]lineStyle(curlineweight, curcolour, 100);
["layer"+layernum+"_mc"]lineTo(_xmouse, _ymouse);
};
//start drawing on mouse press
_root.paper_mc.onPress = function() {
layernum += 1;
startx = _xmouse;
starty = _ymouse;
createEmptyMovieClip("layer"+layernum+"_mc", this.getNextHighestDepth());
["layer"+layernum+"_mc"]moveTo(startx, starty);
drawlineInterval = setInterval(drawline, 10);
};
//stop drawing on mouse release
_root.paper_mc.onRelease = function() {
clearInterval(drawlineInterval);
}
_root.paper_mc.onReleaseOutside = function() {
clearInterval(drawlineInterval);
}
//colour selector
_root.black_mc.onPress = function () {
curcolour = "0x000000";
}
_root.blue_mc.onPress = function () {
curcolour = "0x0000FF";
}
_root.cyan_mc.onPress = function () {
curcolour = "0x00FFFF";
}
_root.green_mc.onPress = function () {
curcolour = "0x00FF00";
}
_root.magenta_mc.onPress = function () {
curcolour = "0xFF00FF";
}
_root.red_mc.onPress = function () {
curcolour = "0xFF0000";
}
_root.white_mc.onPress = function () {
curcolour = "0xFFFFFF";
}
_root.yellow_mc.onPress = function () {
curcolour = "0xFFFF00";
}
//line thickness selector
_root.line1_mc.onPress = function () {
curlineweight = 1;
}
_root.line3_mc.onPress = function () {
curlineweight = 3;
}
_root.line5_mc.onPress = function () {
curlineweight = 5;
}
_root.line10_mc.onPress = function () {
curlineweight = 10;
}


Happy doodling.

Monday, 2 August 2010

Simpler Click and Drag Rotation in Flash AS2

Although this is more lines of code, the code is easier to follow.

The last example used trigonometry to calculate the angle of rotation and gave a realistic simulation of dragging an object in a circle. This is much more basic, and sets the rotation of the object based on a horizontal drag only.

The Script

/* sets the starting point for the maths that follows */
var objectnewdeg = 0;
var objectdeg = 0;
var mindeg = 0;
var maxdeg = 300;
/* this function rotates the object live as the user drags */
rotateobject = function () {
/* this checks whether the user is rotating within the max and min rotation factors defined in the variables above, it only allows rotation if it is within the set limits, otherwise the object won't move */
if (objectnewdeg>=mindeg && objectnewdeg<=maxdeg) {
curpoint = _xmouse;
objectnewdeg = objectdeg+(curpoint-objectstartdeg);
_root.object_mc._rotation = objectnewdeg;
}
}; 

/* This starts the object rotation function and sets the starting point of the user's click - all rotation is then based on the difference between where the user first clicks and where they drag to */
_root.object_mc.onPress = function() {
objectstartdeg = _xmouse;
objectrotInterval = setInterval(rotateobject, 10);
}; 

/* This stops the rotation as soon as the user let's go. It also checks that the user has not been able to drag further than the min or max limits before the code could correct them, and if they have, adjusts the rotation to fit within the limit boundaries */
_root.object_mc.onRelease = function() {
clearInterval(objectrotInterval);
if (objectnewdegmaxdeg) {
_root.object_mc._rotation=maxdeg;
objectnewdeg = maxdeg;
}
objectdeg = objectnewdeg;
};

/* This is the same as the function above, but executes if the user has drifted off the object when they stop dragging */
_root.object_mc.onReleaseOutside = function() {
clearInterval(objectrotInterval);
if (objectnewdegmaxdeg) {
_root.object_mc._rotation=maxdeg;
objectnewdeg = maxdeg;
}
objectdeg = objectnewdeg;
};


While this code may have more lines, it's much simpler to follow. In addition it also allows you to set a maximum and minimum rotation factor, so you can set how far you want the user to be allowed to rotate the object in either direction.

To use it, simply paste it into frame 1, and create and MovieClip on the stage with the instance name 'object_mc'.

Try It



Making it Useful

Let's say you wanted to use this to make a user input for a program. The user rotates the object (say a dial or a volume knob) and you want to use the numerical value of the object's rotation for something. Nothing could be simpler.

If you want the numerical value only once the user has stopped dragging then base your program on the variable objectdeg.

If you want the numerical value to constantly update as the user drags, then base your program on the variable objectnewdeg.

Click and drag rotation in Flash AS2

In Flash I often find that some things which seem hard, are easy, and some things which ought to be easy are hard. Making things rotate when you click and drag them is, for me, one of the latter. It doesn't take much code, but figuring the code out hurt my brain.

You'd think this would be easier - you'd think there would be a class already in existence for this. But as there isn't here's an ActionScript 2 solution.

The Script With Comments

The comments explain how it works:

/*sets starting points for the maths that comes later*/
var objectnewdeg = 0;
var objectdeg = 0;
/* This is the Rotate Object function, it updates the rotation of the object continuously as the user drags */
rotateobject = function () {
    curpoint = (Math.atan2(_root._ymouse-_root.object_mc._y, _root._xmouse-_root.object_mc._x)/Math.PI)*180;
    objectnewdeg = objectdeg+(curpoint-objectstartdeg);
    _root.object_mc._rotation = objectnewdeg;
};
/* This initiates the
Rotate Object function when the user clicks on the object */
_root.object_mc.onPress = function() {
    /* This finds the position around the object that is first clicked in degrees and sets it as a variable that is used in the function above */
    objectstartdeg = (Math.atan2(_root._ymouse-_root.object_mc._y, _root._xmouse-_root.object_mc._x)/Math.PI)*180;
    /* starts the function above and sets the repeat frequency as 10 */
    objectrotInterval = setInterval(rotateobject, 10);
};
/* This stops the
Rotate Object function when the user releases the object, so it stays where the user left it, then records the new rotation of the object as objectdeg ready for when it is rotated again. */
_root.object_mc.onRelease = function() {
    /* stops the function above */
    clearInterval(objectrotInterval);
    /*records the new rotation of the object as set by the user's drag as variable objectdeg, ready for next time they drag */
    objectdeg = objectnewdeg;
};
/* This is almost a repeat of the release code above, but takes account of the fact the user might drift off the object when they drag it, hence onReleaseOutside. */
_root.object_mc.onReleaseOutside = function() {
    /* stops the function above */
    clearInterval(objectrotInterval);
    /* records the new rotation of the object as set by the user's drag as variable objectdeg, ready for next time they drag */
    objectdeg = objectnewdeg;
};



The Script Without Comments

And if that code above looks scary, it's not so bad without comments - only 19 lines.

var objectnewdeg = 0;
var objectdeg = 0;
rotateobject = function () {
curpoint = (Math.atan2(_root._ymouse-_root.object_mc._y, _root._xmouse-_root.object_mc._x)/Math.PI)*180;
objectnewdeg = objectdeg+(curpoint-objectstartdeg);
_root.object_mc._rotation = objectnewdeg;
};
_root.object_mc.onPress = function() {
objectstartdeg = (Math.atan2(_root._ymouse-_root.object_mc._y, _root._xmouse-_root.object_mc._x)/Math.PI)*180;
objectrotInterval = setInterval(rotateobject, 10);
};
_root.object_mc.onRelease = function() {
clearInterval(objectrotInterval);
objectdeg = objectnewdeg;
};
_root.object_mc.onReleaseOutside = function() {
clearInterval(objectrotInterval);
objectdeg = objectnewdeg;
};


Copy and paste the code into the first frame. Then place a MovieClip on the stage and give it the instance name 'object_mc'.

Test the movie and you should be able to click the object anywhere and drag it to rotate it.

The centre of rotation is the Registration point that you set when you made the object into a MovieClip.

If you want to re-use the code yourself, just replace every instance of the name object_mc with the instance name of your object.

Try It



Applying it to something useful

I originally developed this for use with my VirtualCompass teaching aid This uses drag rotation to allow the user to position several different elements on the screen.

Design: Another Reconsideration - Ivan Chermayeff, 1969

When, as a young college design student, I discovered the existence of Ivan Chermayeff I felt I had found the one professional graphic designer that really understood the purpose and role of his vocation. His approach resonated with me as being honest, open and direct - and as such was a refreshing change from what can seem to be a rat race of mimicking styles and trends at speed without pause for genuineness or genius. Chermayeff's own philosophy has had a massive impact on my own thinking about my role as a designer, and the ideals I hold about how I should apply my craft.

Years later, when studying at University I came across an article originally written by Chermayeff in 1969 (and if memory serves correctly re-published in Idea: Special Issue: Chermayeff & Geismar, 1981) entitled "Design: Another Reconsideration". I drank in every word, photocopied it, and used it to fuel part of my dissertation. Since then I have often wanted to read it again, but never found it re-printed or archived anywhere on the Internet.

Yesterday, when visiting my parents, I took a look in their attic and found some of my old college work. Stuffed into one of my essays I was suprised and pleased to find the photocopy I must have made over 10 years ago.

I wouldn't know how to get hold of it now, so I have attempted to transcribe the article from my photocopy.  If Ivan Chermayeff or IP owners of Idea magazine object, I will gladly take this down.

But in my opinion, this is too good to miss.

Design: Another Reconsideration

Every few years, or is it months – on some days it seems like minutes – I ask myself, as I'm quite sure most other designers do, what is it I do every day. What is design anyway? And whatever it is, do I personally really want to do any more of it? Is it of any importance? To society? To communications? Even to clients?
It is easier to begin answering these questions by sneaking up on them; by deciding what design is not.
Design is not what a considerable number of self-described designers think it is.
Design is not art.
Design is not terribly significant.
Design is not always better than nothing.
Design is the solution to problems, real, important or unimportant. The problems of design are not designer problems, they are client problems. Design must therefore grow out of a reasonable understanding of these problems, and their goals and aspirations.
If design solutions do not come directly out of the problems they face, then they will not be design solutions, but be arbitrary, and will probably lean heavily on current fads of typographic or illustrational style. Such designs will also be no good, or to put it another way, will not be design. Truman Capote when asked what he thought of the writing in some best seller, a few years back, replied, “That's not writing, that's typing.” The same thing applies to design. If it's not an answer to a problem, it's not design, it's layout.
I suppose I should backtrack and make clear that “design” refers to Graphic Design or other predominantly visually oriented areas of activity. It include the shell of the typewriter but not the guts.
Because design is concerned with symbols rather than structures, looks of machines rather than their works, typefaces rather than words, a concerned designer can get frustrated.
In order to design a good symbol the designer must understand what it will represent and the more he investigates, presuming a highly cynical, objective, and unbiased questioning attitude, the more likely the designer will want to influence the structure, to change it for the better, or quit.
Every problem of every client is different, and every client is different. (You can argue that they are all the same, but that would be a confession the design is a waste of time and money.) Under these circumstances the only way to keep up or reach a high level of design (in no way synonymous with successful) is to maintain a continuous and unrelenting interest in what the problem at hand really is. It is an old adage that once a problem is truly described, the solution comes along with the description.
Herein lies one fundamental problem with design as a viable activity.
Simply put:
Design problems are more interesting than design solutions.
It seems more challenging to design a new concept, than to design an ad about it. Talking about problems, visually or in print, is not as rewarding or interesting as dealing with them intimately.
All this, of course, is only true if the problems are interesting. Not all problems are either interesting, valid or worth working on or thinking about for a second, unless it's a matter of survival.
I feel it is extremely important for designers to be more interested in areas outside their own. Design is a service operation. Thinking about and developing solutions to other people's problems.
Designers usually don't write very well.
Designers don't usually even communicate very well, even thought communication, or one form of it, is their life's work.
Designers should read.
Designers should make themselves aware of everything.
Designers must be selective.
Designers must think.
Ivan Chermayeff
New York, May 1969
(Source believed to be: Chermayeff, I. (1981). Design: Another Reconsideration. Idea Special Issue: Chermayeff & Geismar. Unknown (1), Unknown.)