Thursday, 6 August 2009
Manipulating Colour in Flash - #3 - Successfully Converting Decimal to Hexadecimal Using the toString Method (even with user defined variables)
Teething Trouble
But as I work towards harnessing these techniques to make a simple colour mixer in Flash I suddenly ran into difficulty converting decimal to hexadecimal when the user defines the decimal values in text input fields.
I must confess that to begin with I spent a while being stumped by this. As I Googled around for a solution there were similar questions, but no answers. Anyway, I am happy to say, there is a solution.
No doubt some of you will have a similar problem, so let me talk you through the problem I experienced and then the solution (I hope it helps).
The Problem
In my tests the toString method easily converted a decimal defined as a variable in a keyframe to a hexadecimal as follows:
/* This works */
var R = 255;
mybutton_but.onPress = function () {
hex = R.toString(16);
trace(hex); //Returns FF
}
However, when the value of R was defined by the user through a text input box it suddenly stopped working, as follows:
/* This DOESN'T work */
/* value of R is defined as 255 in a text input field by the user */
mybutton_but.onPress = function () {
hex = R.toString(16);
trace(hex); //Returns 255
}
For some reason, when the value of R was defined in the keyframe the toString method successfully converted the decimal value 255 and returned FF, but when the value of R was defined in a text input field the toString method failed to perform any conversion on the decimal value 255 and returned 255.
Preparing to Find a Solution
When I struggle with solving these niggly little problems I often find that taking some time out and doing something else gives the mind time to unwind (and also mull over the problem without having to try out every idea instantly). The brain is a fantastic problem solver, if it is given the right conditions. As a college lecturer I know that the ideal conditions come when an individual is relaxed but alert. So, if needed, take a break, unwind, get some sleep or remove distractions. I spent the morning cutting the grass and sorting out the chickens, then in the afternoon found the solution.
The Solution
As I said before, none of my Googling revealed an answer to my problem, but as I hunted around for anything I could find that might give me a hint, or prompt an idea I came across this snippet on WikiBooks.org:
var i = new Number(555);
trace(i.toString());
I must have seen several similar examples yesterday evening and got nothing from them (too tired no doubt). But having taken a break from the problem since then, and relaxed, my brain was ready to spot the significant detail that was the solution:
var i = new Number(555);
And there it was, staring out at me. Something I had not yet tried. So I modified my code as follows:
/* This DOES work */
/* value of R is defined as 255 in a text input field by the user */
mybutton_but.onPress = function () {
var decimalred = new Number(R);
hexred = decimalred.toString(16);
trace(hexred); //Returns FF
}
Why it Works
So why didn't it work before, and what's the big difference that makes it work this time?
I suspect that the reason it did not work before was because the user defined variable 'R' was already being treated by Flash as a string and so using the toString method to convert to a string did nothing, because it was already a string to start with.
Result: 255 (string) in, 255 (string) out.
The solution is really hidden within the problem (as are so many design solutions). We are converting a decimal value (representing a colour channel intensity) into its hexadecimal equivalent. We want to do this using the toString method. However, the toString method is for datatype conversion. This means converting one datatype to another datatype, in this case a non-string into a string. For this to work we need to force Flash to treat the user input 'R' as a number so that we can use toString to convert it into a string in hex format.
The script above does this by passing the user defined decimal value 'R' to a new variable 'decimalred' - with 'decimalred' specifically defined as being a new Number. This forces Flash to treat the user defined value as a number datatype thereby allowing toString to work as expected and convert the decimal number value to a hexadecimal string.
Result: 255 (number) in, FF (string) out.
And that's a wrap.
It is precisely this kind of problem that I see as being the drawback of having come to Flash and Actionscript from a graphic design, rather than a programming background. Nevertheless, I hope that by posting my solution I have helped at least one other poor designer get to grips with with one small area of Actionscript. If my Googling is anything to go by, this may well be the only explanation of this problem on the web (at time of posting of course).
Happy coding.
Tuesday, 4 August 2009
Manipulating Colour in Flash - #2 - Dynamically Changing MovieClip Colour
One of the inconsistent(?), and certainly annoying things about Flash is the way you modify the colour of a MovieClip with Actionscript. We already know you can modify various attributes of a MovieClip such as _height, _width, _x, _y, _rotation... but there is no attribute for colour.
The Colour Object
What you have to do instead is create a create a colour Object which in turn controls the colour of the MovieClip. It's not difficult, take this as an example:
var my_color:Color = new Color(MovieClipName_mc);
In this code we call the object 'my_color' and in the parenthesis we specify the instance name of the MovieClip the colour object will be controlling the colour of, in this case a MovieClip called 'MovieClipName_mc' - you can of course name your MovieClip differently, provided you specify its name in the parenthesis as above.
Changing the Colour
We know the name of the colour object - 'my_color' - so now we can tell Flash the colour value of that object in hexadecimal (just as we would specify a colour in HTML). Here's the code:
my_color.setRGB(0xFFFFFF);
In HTML we prefix a hexadecimal colour value with '#' as in '#FFFFFF'. In Actionscript we prefix with '0x' as above '0xFFFFFF'.
FFFFFF of course represents the colour White (if white is a colour), if you change this value in the script above the MovieClip specified in the colour object will adopt the same colour.
Practical Use
That explains the principles of how we can use a colour object to control the colour of a MovieClip, but how about a practical example...
1. Create an object on the stage, select it and hit F8 to turn it into a MovieClip. Give the MovieClip the instance name of 'colourthing_mc'.
2. Create a new layer, name it 'Actions', then select the first frame of the layer.
3. Now create a Dynamic Text Box of the Input variety on the stage. In the properties panel set the variable to be '_root.usercolour', the reason for this will be explained in my comments below.
4. Now create a Button on the stage and give it the instance name 'calc_but'.
And that's the easy bit, now for the easy code:
/* This is one of those really silly things about Flash. Instead of having a colour attribute like they have _width and _height attributes, you have to create a colour Object which in turn controls the colour of a specified MovieClip. Here's how you do it: */
var my_color:Color = new Color(colourthing_mc);
/* This next step sets up for allowing the user to specify the colour of the MovieClip. */
/* First we create the user controlled variable */
var usercolour = "000000";
/* Then we create another variable that is the result of formatting 'usercolour' as required for Flash to understand it as a hexadecimal value by pre-pending it with '0x' */
var hexusercolour = "0x"+usercolour;
/* Then we setRGB of 'my_color' to that hexadecimal value */
my_color.setRGB(hexusercolour);
/* All that remains is to create a dynamic text box that allows the user to input their own hex value for the 'usercolour' variable and a button that will update the 'my_color' value with the user value from the text box, whenever it is clicked.
The important thing to remember when setting up the text input box, is to se the variable very precisely. If the variable it is updating is in the root timeline, then you must define the variable in the text box as '_root.variablename' not simply 'variablename'. In this case the variable for the text box must be '_root.usercolour'. */
/* This code then makes the button update the colour object with the user specified value. */
_root.calc_but.onPress = function () {
var hexusercolour = "0x"+usercolour;
my_color.setRGB(hexusercolour);
}
And that should be it.
Now we have been able to change the colour of an object through user input of the hex value. This could be developed further to allow the user to change the value by using sliders. This will require us to change 0-255 values into hex values on the fly. But knowing what we know from my previous post, this shouldn't be too hard.
Monday, 3 August 2009
Manipulating Colour in Flash - #1
This experiment looks at how we can convert decimal RGB values into hexadecimal using Actionscript.
It's very simple...
The Code
/* First we set the RGB values as decimal integers (whole numbers) from 0-255, as you would see them defined in any graphics program. This example would reproduce white, but you can change the values to be anything you like between 0-255. */
var R = 255;
var G = 255;
var B = 255;
/* Then we convert the RGB decimals to their hexadecimal equivalents. The toString method is the easiest way I have found of doing it (thanks to Colin Moock). This script takes the value of each of the variables and converts the datatype from a numeric value (in this case 255) into a string using '16' as the radix argument of the method. As a result 255 becomes FF, the hexadecimal equivalent. The code below then simply stitches the converted values of the R, G and B variables together to form a 6 digit hex number for the colour. */
trace(R.toString(16)+G.toString(16)+B.toString(16)); //Returns FFFFFF
What I like about this method is its simplicity. It would form the basis of a very simple colour mixer program, since the R, G and B values could easily be set by sliders, or the user keying in decimal values for each of the channels.
Over to you... meanwhile, I play with colour some more.
Thoughts on Colour
I have since learned that as a child I was playing with subtractive colour, the mixing of pigments to subtract from white and make black. Meanwhile your computer monitor uses additive colour, mixing light to add to black and make white.
It gets even more interesting when you introduce colour wheels and start to notice the relationships between primary, secondary and tertiary colours. Or the difference between tint, hue and shade, or complementary colours and colours in common.
16 Million +
Computers make mixing colours so easy, in fact, with the right tools it becomes less about art or aesthetics and more about mathematics. Did you know for instance that the 16 million or so colours your monitor can display are made up of just 3 colours, red, green and blue? Each of these is called a channel, a red channel, a green channel and a blue channel. In fact your computer can display 256 increments (levels of colour strength) on each channel and by mixing those colours in different amounts you get all the colours available to your monitor.
Just think about it, 3 colour channels, 256 increments of each to mix:
256 x 256 x 256 = 16,777,216 possible colours
Decimal v. Hexadecimal
In decimal we count from 0 to 9 before starting over, giving us 10 increments. like so:
0 1 2 3 4 5 6 7 8 9
Using decimal to define colour we start with 0 as the lowest colour value, and end with 255 as the highest, giving 256 increments.
However, HTML (and at times Flash) prefers hexadecimal which differs from decimal in that we count from 0 to 15 before starting over, giving us 16 increments. Like so:
0 1 2 3 4 5 6 7 8 9 A B C D E F
Using hexadecimal to define colour we start with 00 as the lowest colour value, and end with FF as the highest, giving 256 increments also.
We can say that a decimal 255 and a hexadecimal FF are of equal value. They represent the same number. Likewise a decimal 0 and a hexadecimal 00 are also equal.
Defining Colour Values Numerically
A present we are looking at specifying RGB colour, that is colour defined by the amounts of Red, Green and Blue in their makeup.
When defining RGB colour numerically, it is vital to remember the order of the colour channels. It is always Red, then Green, then Blue. Take the following decimal example:
255,192,128
Knowing the order of the colour channels means we can understand that this means the Red channel is on full blast at 255, the green channel is at three-quarter strength at 192 and the blue channel is at about half strength at 128.
Using hexadecimal we would write the same colour as:
FFC080
The first 2 digits are the red channel, the second 2 digits the green channel and the last 2 digits the blue channel.
Fascinating stuff.
Anyway, as a result of my interest in digital colour, I have decided to take the plunge and see how Flash can be used to manipulate colour. From my initial reading an understanding of the above will be vital to colour manipulation with Actionscript.
Monday, 27 July 2009
Sliding-Page Effect - Navigation in Flash
Fuel Fugitives utilises a nice idea I have seen a few times. Instead of simply changing to another "page" or screen, you slide gracefully from one place to another, as though all the "pages" are actually on the same sheet, you just change which part of the sheet you are looking at.
Well, unable to resist the challenge I decided to work out a way of getting the same effect myself, using Flash and AS2.
Let's get started
1. Create a new Actionscript 2 document and set the frame rate to 30fps.
2. Create an object on the stage, hit F8 and convert it into a MovieClip, with the registration set to the middle.
3. Create 3 more instances of the MovieClip (for a total of 4), space them out, and give them the instance names object1_mc, object2_mc, object3_mc, and object4_mc.
4. Select (using SHIFT) all of the instances of the MovieClip on the stage, then hit F8 and convert the group into a MovieClip with the registration set to the top left. This new MovieClip should contain all the other clips on the stage. Give this new MovieClip the instance name objholder_mc.
Once that's done it's time for the Actionscript.
The Actionscript
/* First we set a variable called currobj. This will store the name (or in this case number) of the movieclip we want centred on the stage. We will use it later to centre that movieclip if it is not already centred. */var currobj = 1;
/* Now we need some easing to give the slide animation a bit of style */
var easing = 6;
/* Then we set variables to define the centrepoint we want to centre movieclips to. */
var hmiddle = Stage.width/2;
var vmiddle = Stage.height/2;
/* Then we create the function that moves the current movieclip (defined by currobj) to the centre (defined by hmiddle and vmiddle). */
onEnterFrame = function () {
/* Finding the difference between the object holder x and y and the centre x and y */
objh_v = _root.objholder_mc._y;
objh_h = _root.objholder_mc._x;
vdiff = vmiddle-objh_v;
hdiff = hmiddle-objh_h;
/* Finding the object x and y within object holder. By using the ["object"+currobj+"_mc"] the code works for every object, all we need to do is update the value of the currobj variable. This means that we can keep our code small and reusable. */
obj_h = _root.objholder_mc["object"+currobj+"_mc"]._x;
obj_v = _root.objholder_mc["object"+currobj+"_mc"]._y;
/* Finding the difference between the current object (currobj) x and y and the centre x and y */
finalvdiff = vdiff-obj_v;
finalhdiff = hdiff-obj_h;
/* Finally we get onto the animation. This basically tells the objholder x and y to move so that the currobj MovieClip inside objholder is centred. All the calculations up to now allowed us to find out exactly where objholder needed to move to for this to happen. So that we get the easing effect on the animation, objholder only moves just under half the actual distance to its destination on each frame (this is controlled by the easing variable). */
_root.objholder_mc._y += finalvdiff/easing;
_root.objholder_mc._x += finalhdiff/easing;
};
/* Making the objects act as links to the next object. I am working on a way to write this code only once for any number of objects, on the basis of telling Flash the total number of objects, but not there yet. meanwhile we need a function for each object manually telling it to go to the next by setting the currobj value to the next object. */
_root.objholder_mc.object1_mc.onPress = function () {
currobj = 2;
};
_root.objholder_mc.object2_mc.onPress = function () {
currobj = 3;
};
_root.objholder_mc.object3_mc.onPress = function () {
currobj = 4;
};
_root.objholder_mc.object4_mc.onPress = function () {
currobj = 1;
};
Over to you...
As you can see, the code is fairly straightforward (hopefully the comments explain how it works). But so far all we have is the mechanics, to be really effective you need to have good graphics to go with it. A good idea!
That's what Fuel Fugitives has, now over to you.
Controling Flash Navigation through the URL
This is useful because it means you can bookmark or "add to favourites" a specific part of the Flash Movie. It also means you can use your browser back button to return to a previous part of the same movie (normally with Flash this would result in you leaving the page containing the embedded movie).
So how did they do it?
I'm still looking into that, but a quick view of the source code indicates that some cool javascript is the answer. Will investigate more later... meanwhile - gardening.
Having cleared nigh on 168 square feet of garden (and finding bricks, carpet, bags of clothes and all manner of rubbish buried there by previous owners) with the help of a brother, I have come back to find the answer, and after a bit of searching found if not the solution, a solution...
And the answer is...
http://www.asual.com/swfaddress/
To quote the website:
SWFAddress is a small, but powerful library that provides deep linking for
Flash and Ajax. It's a developer tool, allowing creation of unique virtual URLs
that can point to a website section or an application state. SWFAddress enables
a number of important capabilities which are missing in today's rich web
technologies including:
- Bookmarking in a browser or social website
- Sending links via email or instant messenger
- Finding specific content with the major search engines
- Utilizing browser history and reload buttons
There are some cool little demos too so you can see it in action, and sure enough, seems to be pretty much what I saw on http://www.fuelfugitives.co.uk/, the site that started me looking in the first place.
So that seems to be it. One more thing to add to my todo list, but I fully intend to put this to good use this holiday. I hope you find it useful as well.
Friday, 24 July 2009
Drag n' Drop (with momentum) in Flash
A few weeks ago I had the opportunity to attend a JISC e-learning event. A fair number of educational technology vendors were present promoting their latest products and services, but for a brief moment one thing caught my eye. The SMART Technologies SMART Table.
It wasn't so much the idea of the SMART Table that intrigued me but the interactivity it offered. The e-learning game running on the table at the time was a diagram of the human body on which the students would have to correctly identify the different body parts by dragging labels onto them from the edge of the screen. As they were dragged the labels would turn as though being pulled by little strings, then when released would continue on to a gentle stop as though they had their own momentum.
I thought that idea of dragging and dropping labels that had weight and momentum was really cool, and I immediately realised that you could do a similar thing using flash.
Well, now that the first evening of my holiday is here I have begun work and have a basic solution for the momentum part of it (I will add the turning and following part another day when that is done).
So here it is, drag and drop, with momentum, in Flash:
Here's it is
If you are not yet an AS3 whizz or using an older version of Flash, don't worry, this one uses AS2.
Let's get going.
1. Create a new AS2 document.
2. Create a shape on the stage, select it and hit F8, then turn it into a MovieClip
3. Give the new MovieClip the instance name of object_mc in the Properties panel.
And that's the easy bit done. Now for the ActionScript.
4. Create a new layer in the timeline and give it the name Actions.
5. Select the first frame of the Actions layer, then hit F9 to open the Actions panel.
5. Input the following code into the Actions panel (hopefully my comments will explain everything, if not, leave a comment):
/* set some variables we will use later */
var posBh = 0;
var posBv = 0;
var posAh = 0;
var posAv = 0;
var trajh = 0;
var trajv = 0;
var drag = 0;
/* sets the level of friction, the higher the number, the more friction.*/
var friction = 1.35;
/*We make the object draggable, and set the drag value to 1*/
object_mc.onPress = function() {
this.startDrag();
drag = 1;
};
/*We stop dragging and set the drag value to 0*/
object_mc.onRelease = function() {
this.stopDrag();
drag = 0;
};
/*This part controls the momentum of the drag on stopDrag()*/
onEnterFrame = function () {
/*If we are dragging the object (and we can tell we are because drag == 1) then we gather information on the trajectory of the drag for ready for when we stop drag. We do this by comparing the X and Y position of the object between frames and so finding out its X and Y velocity. This is stored in the variables trajh and trajv.*/
if (drag == 1) {
/* Calculate Y trajectory/velocity*/
posBv = posAv;
posAv = _ymouse;
trajv = posBv-posAv;
/* Calculate X trajectory/velocity*/
posBh = posAh;
posAh = _xmouse;
trajh = posBh-posAh;
}
/*If the object has stopped being dragged (and we can tell because drag == 0) we then apply some momentum so the object keeps moving after it is let go. We do this by telling the X and Y position of the object to keep moving each frame with the value of the X and Y velocity as stored in the variables trajh and trajv. However we also apply some friction by reducing the value of trajh and trajv a little on each frame. We do this by dividing the variables trajh and trajv by the friction value on every frame and then setting trajh and trajv to have this new value.*/
if (drag == 0) {
trajh = (trajh/friction);
trajv = (trajv/friction);
_root.object_mc._x -= (trajh);
_root.object_mc._y -= (trajv);
}
};
And that's your lot.
CTRL ENTER to test your movie. You will find you can click and drag the object on the stage and if you let go while moving it will carry on with momentum but come to a gradual halt.
You can increase or reduce the amount of friction the object encounters on release by changing the value of the friction variable. Remember, the more friction the quick it slows, the less friction further it travels (like on ice). Have fun experimenting.
Summary
Although this was inspired by my experience of the SMART Table, it won't ever be that versatile because while the SMART table can handle several kids all working at once, Flash will always be limited by the number of "mouse" type inputs your computer supports at once. Usually one.
But we interactive media types don't care for such trifling limitations. Inspiration is one thing, and application is another. I don't have to make a SMART Table clone.
I can still use my flash experiment in a variety of ways to spice up my interactive applications, so the inspiration and the experiment was worth it.