Showing posts with label interactive media. Show all posts
Showing posts with label interactive media. Show all posts

Monday, 22 October 2012

Mouse Wheel Animation Control with Easing

The previous post gives a simple ActionScript 2 solution for using the mouse wheel to control forward and backward play along the Flash timeline.

This example extends that to introduce an element of easing. When the user stops scrolling the mouse wheel, instead of coming to an immediate halt, the animation gently glides to a stop.

var damping = 0.95;
var accelerator = 0; //equivalent to movieclip frames per framerate frame

//detect mouse scroll
var mouseListener:Object = new Object();
mouseListener.onMouseWheel = function(delta)
{
accelerator += delta/3;
};
Mouse.addListener(mouseListener);

//manage the animation
onEnterFrame = function ()
{
accelerator = accelerator*damping;
framespeed = Math.round(accelerator);
moveframe = clip_mc._currentframe + framespeed;
clip_mc.gotoAndStop(moveframe);
};


And there you have it. Play a MovieClip animation with speed and direction determined by the direction the user scrolls the mouse wheel. And when the mouse wheel is released the animation slowly comes to a halt.

Happy days.

Controlling Flash Animation Frame, Direction and Speed with Mouse Scroll

Most animations just play, you set their frame rate, your press play, and away they go. But I have an interactive item that I want users to be able to play forwards, or backwards, at the speed they scroll their mouse.

I am using ActionScript 2 for this, and the code is blissfully simple:
var mouseListener:Object = new Object();
mouseListener.onMouseWheel = function(delta) {
     frame = (clip_mc._currentframe + delta);
     clip_mc.gotoAndStop(frame);
}
Mouse.addListener(mouseListener);

As you can see you just create a mouseListener object and then build a function that acts on the onMouseWheel event.

When the mouse is rolled the 'delta' (or the value of the mouse scroll, forward or backwards) is used to calculate a new position in a MovieClip's timeline based on the current frame. The function then moves the play head using gotoAndStop to that new position in the timeline.

And you're done... This can be used to control the speed and direction of animation play within a MovieClip. I have a few creative applications of this technique in mind for the future - I hope you find it helpful. Happy scrolling.

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.

Friday, 7 August 2009

Manipulating Colour in Flash - #4 - Building an Interactive Colour Mixer

Now we are beginning to see the end result of all my experiments with manipulating colour using Actionscript. Using the techniques from my previous posts, and a few others to get a working interface, this post explains how to make a simple RGB colour mixer that gives a preview of the colour and the hexadecimal value in a form that can be copy and pasted.

Demo SWF







The Interface

While it is very tempting for those with a graphics background to want to start by designing a groovy interface (including me), it is sometimes a good idea to get just a basic prototype working so you can get the bugs out of the code - and that's what you see here.

The demo above shows my basic interface. Before we can go much further you will need to lay out something similar on your stage. The items in the demo above are labelled, check the key below:

KEY:

A = MovieClip, instance name 'colourspot_mc'
B = Input Text, instance name 'red_txt', variable 'red'
C = Input Text, instance name 'green_txt', variable 'green'
D = Input Text, instance name 'blue_txt', variable 'blue'
E = Dynamic Text, variable 'displayhex'
F = MoveiClip, instance name 'redpointer_mc'
G = MovieClip, instance name 'redclicker_mc'
H = MoveiClip, instance name 'greenpointer_mc'
I = MovieClip, instance name 'greenclicker_mc'

J = MoveiClip, instance name 'bluepointer_mc'
K = MovieClip, instance name 'blueclicker_mc'


Once you have set up your objects on the stage as above, you are ready to start coding.

The Code

I won't go into long and drawn out explanations of everything this time. The colour manipulation is explained in previous posts on this blog, and other things are explained within the code as comments.

NOTE: For some reason blogger is not treating this code very well. When you dump it into Flash make sure you hit the 'Format' button so it looks as it should.



/* set default values for R, G and B */
var red = 0;
var green = 0;
var blue = 0;
/* Create colour object to control colourspot_mc */
var my_color:Color = new Color(colourspot_mc);
/* Button triggers conversion of RGB into hex, then applies it to the colour object */
onEnterFrame = function() { /*This enables colour to be constantly updated */
/* ensures that only values between 0 and 255 can be used for red */
if (red>255) {
red = 255;
}
if (red<0) {
red = 0;
}
/* convert red decimal into hex */
var decred = new Number(red);
hexred = decred.toString(16);
if (decred<=15) {
hexredfinal = "0"+hexred;
} else {
hexredfinal = hexred;
}
/* ensures that only values between 0 and 255 can be used for green */
if (green>255) {
green = 255;
}
if (green<0) {
green = 0;
}
/* convert green decimal into hex */
var decgreen = new Number(green);
hexgreen = decgreen.toString(16);
if (decgreen<=15) {
hexgreenfinal = "0"+hexgreen;
} else {
hexgreenfinal = hexgreen;
}
/* ensures that only values between 0 and 255 can be used for blue */
if (blue>255) {
blue = 255;
}
if (blue<0) {
blue = 0;
}
/* convert blue decimal into hex */
var decblue = new Number(blue);
hexblue = decblue.toString(16);
if (decblue<=15) {
hexbluefinal = "0"+hexblue;
} else {
hexbluefinal = hexblue;
}
/* build the final 6 digit hex figure and prepend with 0x as needed by Flash */
hex = "0x"+hexredfinal+hexgreenfinal+hexbluefinal;
/* build the final 6 digit hex figure and prepend with # as needed by HTML */
displayhex = "#"+hexredfinal+hexgreenfinal+hexbluefinal;
/* set the colour property of the colour object controlling the MovieClip */
my_color.setRGB(hex);
/* Update the location of the pointers */
_root.redpointer_mc._x = ((_root.redclicker_mc._width/256)*red)+_root.redclicker_mc._x;
_root.greenpointer_mc._x = ((_root.greenclicker_mc._width/256)*green)+_root.greenclicker_mc._x;
_root.bluepointer_mc._x = ((_root.blueclicker_mc._width/256)*blue)+_root.blueclicker_mc._x;
};
/* Set the red decimal value with a clicker */
_root.redclicker_mc.onPress = function () {
redleft = _root.redclicker_mc._x;
clickpos = _xmouse;
clickval = clickpos-redleft;
clickprop = (clickval/_root.redclicker_mc._width)*256;
red = Math.floor(clickprop);
/*moving the pointer
_root.redpointer_mc._x = clickpos;
}
/* Set the green decimal value with a clicker */
_root.greenclicker_mc.onPress = function () {
redleft = _root.greenclicker_mc._x;
clickpos = _xmouse;
clickval = clickpos-redleft;
clickprop = (clickval/_root.greenclicker_mc._width)*256;
green = Math.floor(clickprop);
/*moving the pointer */
_root.greenpointer_mc._x = clickpos;
}
/* Set the blue decimal value with a clicker */
_root.blueclicker_mc.onPress = function () {
/*Getting the zero point on the clicker bar */
redleft = _root.blueclicker_mc._x;
/*Capturing the location of the click on the clicker bar */
clickpos = _xmouse;
/*Calculating how far along the clicker bar the click was made */
clickval = clickpos-redleft;
/*Calculating the proportional distance along the bar at which the click was made as a figure between 0 and 1, then converting that into a value between 0 and 256. */
clickprop = (clickval/_root.blueclicker_mc._width)*256;
/*Converting the figure to an integer by rounding DOWN to the nearest whole number. Rounding DOWN ensures we can get 0 at the bottom and 255 rather than 256 at the top. */
blue = Math.floor(clickprop);
/*moving the pointer object to the position clicked on the clicker bar */
_root.bluepointer_mc._x = clickpos;
}


And there we have it.

Solving Issues as You Go

It is always interesting to solve some issues as you go. For instance, I hadn't quite decided whether I wanted users to be able to type RGB values, or just limit them to using the colour bars.

When I decided that some users might want to be able to type them (as it might be easier and faster in some situations) I realised that some users might enter a value greater than 255 - which would then give inaccurate results. So, at the last minute I included the code that converts any number higher than 255 into 255 and any number lower than 0 into 0. Like I say, always interesting.

Another implication was with the pointers on the colour bars (items F, H and J in my diagram). Making the RGB numbers updatem depending on where the user clicked, and moving the pointers to the place the user clicked was one thing. But now we had to also work it the other way, and get the pointers to move to the place on the colour bar representing the value the user typed. It wasn't difficult, just a case of working the equation the other way, but it needed doing.

Sometimes seemingly small decisions about user experience can have a significant impact on our code. That doesn't mean we shouldn't put the user first, but it does mean we should be prepared to modify our code when needed. After all, our interactive applications need to actually do what the user wants, if we want any users to use them.

Saturday, 3 January 2009

More Coding for Fun (while still solving the design problem)

Well, as usual I take the opportunity in the holidays to practice and develop my Interactive Media skills. Last time I made a Ukulele Tuner, this time, prompted by a relatives' purchase of a OO gauge railway for Christmas (and my own love of making things and building models) I put together a program to speed up scale calculations to make it easier for me when (and if) I find time to make scale model buildings for my relatives' railway.

Here it is produced in Flash with ActionScript, graphics produced in Fireworks and exported as PNG 32. Ultimately I will compile it into a windows executable using Zinc or Flash Studio once it has been thoroughly tested:








The model railway community on the Model Rail Forum, the New Railway Modellers forum and the Model Railway Forum were very helpful. Although I like to make models when I have time, I am by no means an OO or even a model railway expert at this point in time, so input from the potential user base was absolutely vital.

I guess the lesson I would want my students to take from this is that you don't have to be an expert in a field to successfully design for it. But you do have to do thorough research and be genuinely interested in learning about the field and learning about what is important to your client/the user. If you haven't learned to be interested you may find that what you produce meets the needs of precisely no-one - and you won't even get paid.

This lesson was summed up nicely by a designer who has influenced my approach to creative practice, Ivan Chermayeff. In a long time ago interview with ID magazine (I think it was ID), in an article called "Design: Another Reconsideration", Ivan simply states that "designers should be interested in everything" (para).

I think he is right. Almost the one industry a designer will not design for is his or her own industry. They will be employed to design for a variety of other industries throughout their career however, so an interest in other people's area of expertise is vital. After all, design is about problem solving (another lesson from Chermayeff), so designers need to be interested in the problems and get inside them, because as Ivan once described - solutions come directly out of an understanding of the problems (para).

That's why my research took me directly to the community of model railway enthusiasts. Because in talking to them (here, here and here) I would come to correctly understand the problem (the issues surrounding calculating scale conversions for model railways, the scales themselves, what the user needs it to do etc.) Once I understood the problem, the solution was pretty much obvious, all I had to do was apply my new understanding to the interface, visual appearance and make it work.

And the result? The community feedback was positive about the current version, so I know I have been successful. While a few suggestions for even further development have since been made, for now I have a working product that actually meets my own needs, and the needs of real live users.

Only possible, because the users were consulted about the design problem, and their input turned into a solution. Problem solved.

Thursday, 14 August 2008

Flash Projects - #3 - Custom FLV Player

Back in February I posted a tutorial to make a video player in Flash that played external SWF files. I promised then to post another tutorial that showed how to make a video player in Flash that played external FLV files. I wrote the program ages ago but finally got round to writing it up for my blog.

Although both programs are fine, FLV is much the up-to-date way of showing video in Flash so I hope you find this useful. feel free to leave comments or questions.

Getting Started

To keep things organised I like wherever possible to keep all my code in one place. All the ActionScript in this tutorial should be attached to the first key frame in your movie.

Unlike the version of the video player that played SWF movies, we cannot use loadmovie to simply show a movie within a movie. FLV files require us to use NetConnection and then NetStream to stream the FLV file from its location.

First off then we need to create a new NetConnection called "myConnection_nc":

var myConnection_nc:NetConnection = new NetConnection();
myConnection_nc.connect(null);


Now we need to create a NetStream called "video_ns" that will stream through the NetConnection you made above:

var video_ns:NetStream = new NetStream(myConnection_nc);

Now we have created a NetConnection and a NetStream through which we will stream the FLV file, we need to create a video object on the stage through which the FLV will be displayed.

First, you need to create a new Embedded Video object in the library. To do this, click the little menu in the corner at the top of the Library and select the "New Video" option. It should appear in the Library as "Embedded Video 1". Then drag an instance of the Embedded Video 1 onto the stage and give it the instance name of "my_video".

Now we are ready to attach the NetStream created above to the video object you just placed on the stage called "my_video":

my_video.attachVideo(video_ns);

Now we need to do two things. First, we need to find out how long the FLV file is (its duration), second we need to set the value of the duration variable equal to the property of the duration object. This will allow us to control the playback of the FLV later on.

To do this we first use prototype.OnMetaData to find the duration of the video - this only works with FLV 1.1 files and later, earlier versions do not include duration in metadata.

Unfortunately there is no other way of finding the duration of an FLV file (you can't use the _totalframes method like you can in SWF files).

Then we can set the value of the duration variable to be equal to the duration property of the FLV file as defined in the FLV's MetaData. Here goes:

NetStream.prototype.onMetaData = function(obj){
var duration = obj.duration;
}


Video Selector

Now for the playback controls. The simplest control is the video selector. This allows the user to choose which video they want to watch.

First create a button in the Library, then drag two instances of the button onto the stage. Give the buttons the following instance names - "m1_btn" and "m2_btn".

Because we are playing FLV files and not SWF files, we cannot use the loadMovie method. Instead we need to tell the NetStream object we created earlier, to play and tell it which FLV file to play. We create code for each of the buttons we created earlier, so that when each is clicked, the NetStream object we created streams a different FLV file to the video object:

_root.m1_btn.onRelease = function () {
video_ns.play("video2.flv");
currentvid = "video2.flv";
}

_root.m2_btn.onRelease = function () {
video_ns.play("video1.flv");
currentvid = "video1.flv";
}


The code above does two things when the button is released. First, it tells the NetStream object called "video_ns" to play a specified FLV file. Secondly it sets the value of a variable called currentvid to be the same as the name of the FLV file - this helps us later on when we are programming the playback controls.

Rewind Button

Dead easy. Create a button in the Library that looks like a rewind icon. Drag an instance of the button onto the stage and give it the instance name of "rw_btn". Then add the following code to the first key frame with the rest:

_root.rw_btn.onRelease = function () {
playpos = video_ns.time;
if (playpos > 10)
{
video_ns.seek(playpos-10);
}
else
{
video_ns.seek(0);
}
}


The code above makes the video jump back 10 seconds when the rewind button is clicked. It might seem pretty complex considering that all we want to do is rewind a bit. What it actually does first is check how far into the video we have progressed and the reason for this is that we don't want to jump back to a point before the video starts, that would be impossible. Depending on how far the video has played the code then does one of two things. If the video has played more than 10 seconds, then it tells the NetStream object to jump back 10 seconds in the FLV, if the video has not yet been playing for more than 10 seconds it tells the NetStream object to go back to the beginning of the FLV.

I found that in practice, with large FLV files, the rewind is not always reliable, and can get "stuck" at points, refusing to rewind past them. I suspect this is something to do with the FLV itself, rather than the coding - however, I have also included the option of clicking on the progress bar to jump to any point in the video, which so far has proved very reliable - this is explained later in the tutorial.

NOTE: If you made the previous video player that used SWF instead of FLV files, you will notice that we are using a lot of different methods. Most significant is that with FLV we cannot gotoAndPlay specific frames as we can with SWF files. Instead we use the seek method, and it is the NetStream object called "video_ns" that we are instructing to seek, not the video instance on the stage.

Forward-wind

This is much more straightforward. As before, create a button in the Library that looks like a forward-wind icon. Drag an instance of the button onto the stage and give it the instance name of "fw_btn". Then add the following code to the first key frame with the rest:

_root.fw_btn.onRelease = function () {
playpos = video_ns.time;
video_ns.seek(playpos+10);
}

This isn't nearly as complex. When the forward-wind button is released the code sets the value of a variable playpos to the current time position of the movie using video_ns.time. It then simply uses the seek method to tell the NetStream object to jump forward 10 seconds from the current time position in the FLV.

Play and Pause Button

Now we get more complex. For my player I opted to have the Play and Pause buttons be the same button, but have the icon on the button change depending on whether the movie is playing or not. If the movie is playing, the pause icon is visible, telling the user they can click to pause. If the movie is paused, the play icon is visible, telling the user they can click to play.

To accomplish this the play/pause button is not a button at all - it is a movie clip. The movie clip has two frames, one frame with the play icon, the other with the pause icon. The frames are then given labels - "pauseon" and "pauseoff". This allows us to dynamically change which frame is currently visible, and therefore the appearance of the play/pause button. Create a movie clip that does all that, then drag an instance of it to the stage and give it the instance name of "pause_mc". Then add the following code to the first key frame in the root timeline with the rest:

video_ns.onStatus = function() {
if (video_ns.time >= duration-1){
playstatus = 2;
_root.pause_mc.gotoAndStop("pauseon");
}
else
{
playstatus = 1;
_root.pause_mc.gotoAndStop("pauseoff");
}
}

The code above uses a change in the NetStream status to trigger a check. The code checks whether the current position within the FLV file is greater than or equal to 1 second from the end of the file. If so it sets the value of the playstatus variable to "2" (we use this later), and tells the play/pause button to move to the frame labelled "pauseon", so the button shows the pause icon, telling the user they can click to pause.

If the current position within the FLV file shows there is more than 1 second of the movie left to play, then the code sets the value of the playstatus variable to "1", and tells the play/pause button to show the frame labelled "pauseoff", so the button shows the play icon, telling the user they can click to play.

the above code just sets the playstatus variable, and changes the visual appearance of the play/pause button. Now we need to enter the code that actually controls the playing and the pausing. Add the following code to the first key frame in the root timeline with the rest:

_root.pause_mc.onRelease = function () {
if (playstatus == 1)
{
video_ns.pause();
_root.pause_mc.gotoAndStop("pauseoff");
}
else if (playstatus == 2)
{
video_ns.play(currentvid);
}
}


This is where lots of the variables we have been setting earlier, with no visible purpose, suddenly become useful. The code above runs whenever the play/pause button is released.

First it checks the value of the playstatus variable. If the value of playstatus is "1" (which means the FLV file has more than 1 second left to play - see above), then it tells the NetStream object called "video_ns" to pause, and tells the play/pause button to show the frame labelled "pauseoff", so the button shows the play icon, telling the user they can click to play again.

If the value of playstatus is "2" (which means the FLV file is in its last second of playback - see above), then it tells the NetStream object called "video_ns" to play the FLV file again, and uses thevalue of the currentvid variable, which was set when the user click the button to select which video they wanted to see, to tell it which FLV file that was. This currentvid reminder is needed because we are playing FLV files and so must use NetStream and not loadmovie as we would if we were playing SWF files. With loadmovie the SWF file remains loaded into memory and so the program does not need reminding which movie to play because it still has it, with NetStream the file is streamed from its location and not kept in memory - this is why the currentvid variable was needed, to remind the program which FLV to play, without the user having to select it again using one of the video selector buttons we created right at the beginning. This is all about making it work more smoothly for the user - trying to make it work how they expect, rather than expecting them to learn the quirks of how your's works.

Progress Bar

No video player is complete without a progress bar telling the user how quickly the video is progressing, where they are in the video timewise, and how long is left.

To create the progress bar graphics, draw a rectangle on the stage to represent the video progress bar. Make sure the rectangle has a fill and a stroke. Then select the filled area only, press F8 and convert it into a movieclip called progbar. Make sure you set the registration point of the symbol to be top left. Then select the stroke that outlined the rectangle, again press F8 and convert it into a movieclip called progbarframe. Again make sure you set the registration point of the symbol to be top left. Give each an instance names "progbar_mc" and
"progbarframe_mc".

Add the following code to the first key frame in the root timeline with the rest:

onEnterFrame = function() {
comppc = video_ns.time / duration;
_root.progbar_mc._width = _root.progbarframe_mc._width*comppc;
}


The above code sets a variable called comppc with a value that comes out of dividing the current position of the FLV movie in seconds with the duration of the movie in seconds. This gives comppc a a value between 0 and 1. A value of 0.5 would mean the movie was half way through. We then multiply the maximum width of the progress bar (based on the width of the progbarframe_mc) by the value of comppc to set the current width of the progress bar. By using onEnterFrame the progress bar updates several times per second as the movie plays, thus giving an accurate graphical representation of how far the movie has to go.

Progress Bar Jumper

Now we want to make it so the user can click anywhere on the progress bar and jump to that part of the movie. Add the following code to the first key frame in the root timeline with the rest:

_root.progbarframe_MC.onRelease = function() {
barleft = _root.progbarframe_MC._x;
jumppos = (_xmouse-barleft)/_root.progbarframe_MC._width;
if (playstatus == 1)
{
video_ns.seek(Math.round(jumppos*duration));
}
else if (playstatus == 2)
{
video_ns.play(currentvid);
video_ns.seek(Math.round(jumppos*duration));
}
}


The above code is probably the most complex part of the whole program. Funny how the luxuries, the "optional extras", that provide the least functionality are often the most complicated parts of the program.

First we define a variable for the left side of theprogress bar called barleft. This gives us a zero point against which to measure the location of the user's click on the progress bar. Then we define a variable that represents the users click on the progress bar called jumppos.

The value of jumppos is defined by getting the X coordinate of the mouse when the bar is clicked and then subtracting from that the value of barleft (the X coordinate of the the start of the bar). This tells us how far along the bar the user clicked. This number is then divided by the total width of the bar to give a number that represents how far along the bar the user clicked as a value between 0 and 1. A result of 0.5 would mean the user clicked in the middle of the bar.

We then tell the NetStream object to seek to the point in the movie corresponding to where the user clicked on the bar. This is calculated by multiplying the value of jumppos (where on the bar the user clicked) by the value of the duration of the FLV file in seconds. However, I have also used Math.round to convert the result into an integer (by rounding up or down to the nearest whole number). This just helps keep things tidy and means the FLV will jump to a whole second, rather than a fraction of a second which may not exist.

If the value of playstatus is "1" then we just attempt to seek straight to the relevant point in the FLV file. However if the playstatus is "2" this means there is only 1 second or less of the movie to go, so to make sure it works and we get no glitches, we tell the NetStream object to play the currentvid from the beginning and then seek to the relevant point in the FLV file. We have to do this because, as mentioned before, with NetStream the video is not stored in memory, and so if there is less than 1 second left in the video, the streaming might be over before Flash has a chance to seek to another part of the movie. By telling the video to start again using the currentvid variable to remind it which video, and then seek to the relevant point, we can get a smoother operation.

Converting Video to FLV Format

Of course, for this player to be any use, you need to be able to convert your video to FLV format.

One programme that has worked for me without trouble is Free Video to Flash Converter.

It is completely freeware and can convert video into SWF or FLV. You can even export video with its own player interface - and, while this defeats the object for my use of it, since I wanted a custom interface of my own design, some people may find this feature helpful.

The program is pretty self explanatory, all you need to do is remember to export the movie as a FLV and save it with the name you programmed into your player and in the same directory as the player.

The End

And there we have it. Export your player as a SWF into the same directory as the FLV files you linked to and it should just work. Any problems, leave a comment and I will try to help.

Playing Sound with your Computer Keyboard - Flash

I had a chat with one of my old Multimedia students on Facebook today. I pointed him to my Ukulele Tuner and he told me that he was currently building a Flash based interactive drum kit (he is a drummer after all).

He had already produced a prototype that worked by clicking each drum with the mouse, but was not happy with the inability to play the drums properly on it. To play drums you need to be able to switch instrument quickly and at times strike two instruments at the same time. You can't do this with a single mouse and clicking on each drum. It's like playing the drums with one stick.

He had the idea of allowing the user to play the drums using the keys on their computer keyboard, but was unsure how to proceed. Unable to leave teacher mode with a challenge like this I put together the following code.

Stage 1

Create a new AS2 Flash file and insert the following code into the first keyframe:

//This attaches the sound for drum 1, make sure you did the linkage thing in the library

var sound1:Sound = new Sound();
sound1.attachSound("drum_1");

//This attaches the sound for drum 2, make sure you did the linkage thing in the library

var sound2:Sound = new Sound();
sound2.attachSound("drum_2");

//This code listens out for the user to press a key, then, depending on which key is pressed will trigger one of the sounds attached above.

var myDrumKeyListener:Object = new Object();
myDrumKeyListener.onKeyDown = function () {
if (Key.getCode()==65) {
sound1.start();
} else if (Key.getCode()==66) {
sound2.start();
}
}
Key.addListener(myDrumKeyListener);

Stage 2

You will notice a bit where it says:

(Key.getCode()==

and then there is a number, this number is the keycode for the key that plays the sound. You can find a list of keycodes online here:

http://livedocs.adobe.com/flash/mx2004/main_7_2/wwhelp/wwhimpl/common/html/wwhelp.htm?context=Flash_MX_2004&file=00001113.html

Stage 3

Now you need to add the actual sound files. Do this by importing the sounds into the Library. Then right click the first sound and choose "Linkage" from the menu. Select the "Export for Actionscript" and "Export in First Frame" options. Then make sure you give the sound an identifier. This is the name by which the sound will be referenced in the actionscript above. I called the sound for the first drum "drum_1". Then in the actionscript it is referenced as follows:

var sound1:Sound = new Sound();
sound1.attachSound("drum_1");

If you put a different name as the identifier, make sure you also change it in the actionscript.

Once that's all done you can press "OK". Then just repeat Stage 3 for each sound in the library.

And that is about it.

The challenge for my ex-student then, is to modify the code to include more drums and have them respond to an appropriate range of keys on the keyboard.

Have jolly fun.

Demo SWF





Saturday, 26 July 2008

Uke Tuner - Flash Based Ukulele Tuning Application



Now that I teach interactive media, rather than practice commercially for a living, I sometimes get fidgety, wanting to do more of my own but never having the time.

Finally the holiday's arrived and I was able to get inspired, on account of my wife buying a Ukulele. She was using an online tuning system, but it wasn't as helpful as it could have been. The problem with the online tuning system, was that it only gave audio samples of a Ukulele string being plucked. However it is much easier to tune an instrument to a continuous tone. In Uke Tuner I gave the option, plucked note, or continuous tone, so the user can choose their preferred method. Then of course I went overboard on graphics and interactivity - just for the fun of it.

You can download Uke Tuner 0.92 (Beta) here free >

For the more technically minded, graphics were produced in Fireworks then exported as PNG 32 to preserve alpha channels or SWF, for use in Flash. Audio was recorded from a Yamaha PSR-240 keyboard via a line-in cable from the keyboard's headphone socket. Sound was recorded and processed with Audacity then exported as WAV 32-bit for use in Flash. Interactivity was produced in Flash, with ActionScript 2. Flash Audio settings were set to export sound at 22Khz stereo and 128kbps. Playback speed is 30 fps to make it animate more smoothly. The application was compiled with MDM Flash Studio because it has a faster projector engine than the Flash Standalone Player, extends the ActionScript classes available in Flash with some additional functionality, and allows the creator to tweak the display options (such as turning off the blue bar at the top).

Friday, 2 November 2007

Interactive Media of Note - Narnia.com

Sometimes you come across a piece of interactive media that you just wish you had been a part of producing. Narnia.com is one of my favourites.

What I love about this particular piece of interactive media is the richness of the experience it provides. You know the designers have been allowed to go to town, and they really have. For a start they really know how to set the scene and they use visuals (static and animated) along with sound to do it. You can hear the wind buffeting the attic room with the wardrobe, you feel cold as the icy wind of Lantern Wood blasts you and you feel warm as you wander through Aslan's Camp.

Beyond the ambience it is really nice to just explore the world they have created. You can look around by moving the mouse in any direction and click on objects. Selecting the Globe reveals a map allowing you to change your location. There are even games built in to test a level of wits.

I really appreciate the attention to detail. These designers have gone much further. At the beginning, instead of the standard loading bar, you see the door handle of the attic room turning. The same "alternative" approach to the loading bar has been taken throughout, as you watch emblems of the various factions from the story slowly appear instead. Details such as giving the lamp in the wood a flickering flame have not been missed.

Truly this is a feast for the senses, and a great example of what multimedia can be made to do if you have the imagination, and the client is willing to pay for the time.