Apr 12, 2012
Posted on Apr 12, 2012 in Hints and Tips | 10 comments
In this tutorial, I’ll follow the approach suggested by Richard Davey (Thanks, Richard!), and used by him and others, in detecting collisions between bitmaps with a subtle modification. I’ll also compare performance between various approaches of bitmap collision detection using Grant Skinner’s PerformanceTest harness.
Step 1: Overview
I describe this alternative approach in short here.
- Check whether there’s any overlap between the two bitmaps.
- If there is, proceed to #3. Otherwise, drop out.
- Check whether the overlap area has any opaque pixels overlapping.
- If so, the bitmaps overlap. Otherwise, drop out.
Step 2: Bounding Boxes
First, we check whether the two bitmaps’ bounding boxes are overlapping using Rectangle. The scripts are as below. First, the variables.
private var enemy1:Bitmap, myShip:Bitmap;
private var myShipSp:Sprite;
private var rec_e:Rectangle, rec_m:Rectangle;
private var intersec:Rectangle;
enemy1 = new E1 as Bitmap; addChild(enemy1);
myShip = new My as Bitmap;
myShipSp = new Sprite; addChild(myShipSp);
myShipSp.addChild(myShip);
enemy1.x = stage.stageWidth >> 1; myShipSp.x = stage.stageWidth >> 1;
enemy1.y = stage.stageHeight * 0.2; myShipSp.y = stage.stageHeight * 0.8;
//drawing boxes around the sprite
draw(enemy1.getBounds(stage), this, 0);
draw(myShipSp.getBounds(stage), this, 0);
Here we check for any overlapping area between the boxes. Check out DetectVisible.as in the source download for the full script
private function refresh(e:Event):void
{
//determining the bounding box of intersection area
rec_e = enemy1.getBounds(stage);
rec_m = myShipSp.getBounds(stage);
intersec = rec_e.intersection(rec_m);
//redraw the bounding box of both sprites
this.graphics.clear();
draw(enemy1.getBounds(stage), this, 0);
draw(myShipSp.getBounds(stage), this, 0);
//only draw bounding box of intersection area if there's one
if (!intersec.isEmpty()){
lines.graphics.clear();
draw(intersec, lines);
t.text ="Intersection area by red rectangle."
}
else {
t.text ="No intersection area."
}
}
Here’s a demo. Drag the smaller spaceship around.
(Don’t worry about the red box that gets “left behind” when the ship is dragged out of the other’s bounding box.)
Step 3: Drawing into the Intersection Area
So if there’s an intersecting box area, we proceed to check whether there are overlapping pixels in the area. However, let’s first try to draw bitmap into this intersection area. The full script’s in DetectVisible2.as
private function refresh(e:Event):void
{
//determining the bounding box of intersection area
rec_e = enemy1.getBounds(stage);
rec_m = myShipSp.getBounds(stage);
intersec = rec_e.intersection(rec_m);
//redraw the bounding box of both sprites
this.graphics.clear();
draw(enemy1.getBounds(stage), this, 0);
draw(myShipSp.getBounds(stage), this, 0);
//only draw bounding box of intersection area if there's one
if (!intersec.isEmpty()){
lines.graphics.clear();
draw(intersec, lines);
//to draw the intersection area and checking for overlapping of colored area
var eM:Matrix = enemy1.transform.matrix;
var myM:Matrix = myShipSp.transform.matrix;
bdt_intersec = new BitmapData(intersec.width, intersec.height, false, 0)
eM.tx -= intersec.x; eM.ty -= intersec.y
myM.tx -= intersec.x; myM.ty -= intersec.y
bdt_intersec.draw(enemy1, eM);
bdt_intersec.draw(myShip, myM);
bm_intersec.bitmapData = bdt_intersec;
bm_intersec.x = 10
bm_intersec.y = stage.stageHeight * 0.8 - bm_intersec.height;
t.text = "Intersection area by red rectangle.\n"
}
else {
t.text ="No intersection area."
}
}
Note that since we are drawing the area by the use of a matrix, any scaling, skewing and other transformations on both bitmaps are taken into account. Here’s a demo; check out the box in the bottom left corner.
Step 4: Check for Color in the Intersection Area
So how do we check for the right pixel? Well first of all, we give the color of this intersection box a shade of black (Red = 0, Green = 0, Blue = 0). Then, the shade of the smaller spaceship will painted into this dark box as green, with the blend mode of ADD. Similarly, the shade of the bigger stationary alien spaceship will be painted red.
So now, there will be areas of red and green for the spaceships, and black if there are no overlapping area. However, if there are pixels from these two bitmaps that overlap, these will be drawn in yellow (Red = 255, Green = 255, Blue = 0). We use the method Bitmapdata.getColorBoundsRect to check for the existance of this area.
Here’s the snippet in Main.as
//to draw the intersection area and checking for overlapping of colored area
var eM:Matrix = enemy1.transform.matrix;
var myM:Matrix = myShipSp.transform.matrix;
bdt_intersec = new BitmapData(intersec.width, intersec.height, false, 0)
eM.tx -= intersec.x; eM.ty -= intersec.y
myM.tx -= intersec.x; myM.ty -= intersec.y
//tweak color
bdt_intersec.draw(enemy1, eM, new ColorTransform(1,1,1,1,255,-255,-255), BlendMode.ADD);
bdt_intersec.draw(myShip, myM, new ColorTransform(1,1,1,1,-255,255,-255), BlendMode.ADD);
bm_intersec.bitmapData = bdt_intersec;
bm_intersec.x = 10
bm_intersec.y = stage.stageHeight * 0.8 - bm_intersec.height;
t.text = "Intersection area by red rectangle.\n"
//check for the existance of the right color
intersec_color = bdt_intersec.getColorBoundsRect(0xffffff, 0xffff00);
if (!intersec_color.isEmpty()) t.appendText("And there are interesecting pixels in the area.");
Note that we suppress the Red and Blue components in line 113 to max out Green for the small spaceship. On line 112 we do the same with the alien spaceship with the Blue and Green components.
Comparing Approaches
So after receiving comments on performance issues regarding collision detection, I decided to do some quick and dirty tests on these approaches. I created 20 enemy spaceships and one player spaceship and checked collision detection between that one player ship against the other 20. These sprites are packed into the same vicinity to force collision detection for all approaches to have a complete run.
The first approach is the simplest. BitmapData is captured on initiation and for each frame, collision detection is checked using BitmapData.hitTest(). For the second approach, BitmapData is updated each frame and collision detection is done based upon those BitmapData captured. The third one refers to the approach suggested by this tutorial.
So the result for one of the tests I’ve done is as below.
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
bitmapdata fixed (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
bitmapdata fixed 168 0.17
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
bitmapdata updates (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
bitmapdata updates 5003 5.00
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
custom method (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
custom method 4408 4.41
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
The PerformanceTest gives different results whenever I run test. So I ran it a few times and derived an average time. Conclusion: the fastest method is the first, followed by the third and then the second approach.
So storing away BitmapData for bitmaps when they are first introduced into stage and checking for hitTest every frame after is actually efficient, provided these sprites don’t perform any transformations other than translation (such as rotation, skewing and scaling) across time. Otherwise, you will be forced to adopt either the second or third approach, and the third one is more efficient as indicated by the image above.
You may check out Collisions.as and Results.as for the full script.
Searching for Expensive Methods
I embarked thereafter to search for the specific lines of code that took up more computation time. The second and third approach took more time, so I derived several functions from them, each breaking at different points. Check out one of the results below.
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
default hitTest (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
include bounds
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
default hitTest 189 0.19
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
default hitTest (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
include transform
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
default hitTest 357 0.36
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
default hitTest (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
include hittest
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
default hitTest 4427 4.43
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
custom method (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
inlcude bounds and transform
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
custom method 411 0.41
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
custom method (1000 iterations)
Player version: WIN 11,1,102,55 (debug)
include draw and bounds
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
method...................................................ttl ms...avg ms
custom method 3320 3.32
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
The first, second, and third times refer to the second approach at different breakpoints, and the fourth and fifth times refer to the third approach. Looking at the third and the fifth time results, BitmapData.draw seems to take a lot of computation time. And the time taken for drawing with the second approach seems to be more expensive in computation time, which leads me to think that the sizes for BitmapData.draw to operate on does matter. You may check out Collisions2.as and Results2.as for the full scripts.
One thing I find a little disturbing is the inconsistency of these tests – I always don’t get the same time results, although they almost follow the same ranking at all times. So, its good enough to do some simple comparison between functions.
Conclusion
Well, thanks for your time looking reading this little tip. Hope it has been useful. Do leave comments if you don’t agree with anything in this tutorial. I’d love to respond to feedback!



View full post on Activetuts+
Apr 12, 2012
Posted on Apr 12, 2012 in Hints and Tips | 10 comments
In this tutorial I will show you how to access the same saved data in separate Flash and JavaScript apps, by storing it in HTML5 LocalStorage and using ExternalInterface to reach it with AS3. We will create the same app in both JavaScript and Flash to demonstrate that it is platform agnostic.
Step 1: Examining Local Storage
Local Storage is an exciting part of HTML5 that allows you to do browser side storage that is persistent, meaning it lasts between browser sessions. It only disappears when the user clears their browser cache.
It is a very easy API to use, using simple key-value pairs to store data, and can be used in a few different ways. One way is to use localStorage.setItem('key','value'), and localStorage.getItem('key'). Another way is to use Object Notation: localStorage[key] = value to set a value, and theValue = localStorage[key] to retrieve it. And, if that wasn’t enough, there is yet a third way – Dot Notation: localStorage.key = value to set it, and theValue = localStorage.key to retrieve it.
I am opting for the third way in this tutorial, but if you prefer one of the other ways you can modify the code and it should work just fine. Local Storage does have a few other methods, but these are the only two methods we need: one to set a value and one to retrieve that value.
Step 2: Setting Up the JavaScript Project
We will create the JavaScript app first. You should develop both this and the Flash project on a live server, otherwise you will run into problems. I am using WAMP on my machine as a local hosting environment.
Create a folder to store your project in. Within this folder create two new folders. Name one of them “js” and the other “styles”.
Within the “styles” folder create a new file and name it “style.css”, and within the “js” folder create a new file and name it “externalinterface.js”. Finally, at the root of your project folder create a new file and name it “index.html”.
Step 3: The Index HTML Page
Enter the following code within the “index.html” file you created in the step above.
<!DOCTYPE html>
<html>
<head>
<title>Local Storage with external Interface</title>
<link rel="stylesheet" type="text/css" href="styles/style.css" />
<script type="text/javascript" src="js/externalinterface.js"></script>
</head>
<body>
<div id="wrapper">
<div id="scorewrapper">
<p id="scorediv"></p>
<p id="randomscorediv">Random Score is: </p>
<button type="button" id="scorebtn">Generate Score</button>
</div>
</div>
</body>
</html>
Here we set up the structure of our “index.html” file. We include the “style.css” and the “externalinterface.js” we created in the step above. The scorediv will be updated when we achieve a new high score, and the randomscorediv will be updated each time we generate a new score (click on the button to generate a random score).
Step 4: style.css
Enter the following within the “style.css” you created in the step above.
#wrapper{
width:400px;
height:400px;
margin: 0 auto;
}
#scorewrapper{
width:400px;
height:200px;
background-color:#FFFFFF;
}
#randomscorediv{
visibility: hidden;
}
body{
background: #f2f2f2;
text-align: center;
padding: 20px;
}
Here we set the app to be centered in the page, set the background-color of the scorewrapper div, and set the randomscorediv to initially be hidden (invisible). When we click on the button we will set the randomscorediv to visible.
Step 5: window.onload
Enter the following code within the “externalinterface.js” you created in the step above.
window.onload = function(){
alert("Window Loaded");
}
Whenever you need to tie into elements on your web page you should make sure the window has loaded first. Since we need to tie into the button, we use the window.onload function provided by JavaScript. Here we are just popping up an alert with the words “Window Loaded”. If you test the page you should see it is working.
Step 6: setScore()
In this step we will code the setScore() function that initially sets the score to 0. Enter the following code within the “externalinterface.js”.
window.onload = function(){
function setScore(){
if(!localStorage.score){
localStorage.score = 0;
}
}
}
Here we check whether the localStorage.score exists, and if it doesn’t we initialise its value to 0. When the user first runs the app, or after they clear their cache, this value would not exist – so we need to create it.
Now call this function immediately after you create it, and test by putting it in an alert.
window.onload = function(){
function setScore(){
if(!localStorage.score){
localStorage.score = 0;
}
}
setScore();
alert(localStorage.score);
}
Step 7: getScore()
We have a way to set our score, now we need a way to retrieve it. That is what the getScore() function will accomplish. Enter the following beneath the setScore() function you created in the step above.
function getScore(){
if(localStorage.score){
return(localStorage.score);
}
}
Here we check that localStorage.score does exist, and if it does we simply return the value it holds. Remove the alert from the previous step, and add the following alert beneath the getScore() function.
function getScore(){
if(localStorage.score){
return(localStorage.score);
}
}
alert(getScore());
}
If you test now you should see the alert again showing the score of “0″.
Step 8: updateScore()
Now that we have a way to set and get our score, we need a way to update it. That is exactly what the updateScore() function achieves. Add the following beneath the getScore() function you created in the step above.
function updateScore(newScore){
if(localStorage.score){
localStorage.score = newScore
}
}
Here we pass as a parameter a newScore; we then set the localStorage.score equal to this value. Remove the alert from the previous step, then add the following beneath the updateScore() function you just created.
function updateScore(newScore){
if(localStorage.score){
localStorage.score = newScore;
}
}
updateScore(10);
alert(getScore());
If you test now, you should see “10″ being alerted, since on line 6 we updated the score to 10.
Step 9: showScore()
Now that we have all our methods in place to manipulate the score, let’s get it showing. Enter the following beneath the updateScore() function you created in the step above.
function showScore(){
var scoreText = document.getElementById('scorediv');
scoreText.innerHTML = "Current High Score is "+getScore();
}
Here we get a reference to the scorediv, and alter its innerHTML property to show the current score.
Call this function immediately after you create it.
function showScore(){
var scoreText = document.getElementById('scorediv');
scoreText.innerHTML = "Current High Score is "+getScore();
}
showScore();
If you test the page now you should see the words “Current High Score is 10″.
Step 10: Getting a Reference to the Button
We want to run a function when the user click on the button. Add the following beneath the showScore() button you created in the step above.
var scoreBtn = document.getElementById('scorebtn');
scoreBtn.addEventListener('click',getRandomScore,false);
Here we get a reference to the button which we gave the ID scorebtn. We then add an EventListener of type click, which calls the getRandomScore() function that we will create in the next step.
Step 11: getRandomScore()
The getRandomScore() function is where the logic of this application takes place. Add the following beneath the line scoreBtn.addEventListener('click',getRandomScore,false); you entered in the step above.
function getRandomScore(){
var randScoreText = document.getElementById('randomscorediv');
randScoreText.style.visibility='visible';
var randScore = Math.floor(Math.random()* 200000);
var currentScore = Number(getScore());
randScoreText.innerHTML = "Random Score is "+randScore;
if(randScore > currentScore){
alert("New High Score!!");
updateScore(randScore);
showScore();
}
}
Here, we first get a reference to the randomscorediv and set it to be visible. We then generate a random score by calling Math.floor(Math.random()* 200000), which creates a number between 0 and 200,000. We use our getScore() function to set the variable currentScore (making sure we cast it to a Number), and set the innerHTML of the randScoreText to the randScore.
Lastly we check whether randScore is greater than currentScore, and if it is we show an alert("New High Score!!") and then update the localStorage.score by calling our updateScore() method and passing in the randomScore. We then use showScore() to show the new score.
This concludes the JavaScript application – you can test it here. In the next step we will start devloping the Flash version.
Step 12: Setting Up the Flash Project
In this step we will set up the Flash project.
Create a folder to store your project files in. Now inside this folder create a folder named “js”, and within this folder create a file and name it “externalinterface.js”. At the root of your project folder create a file named “index.html”. Lastly, create a new Flash Project and save it in the root folder, making sure you name it “externalInterface.fla”. Give it a white background, and set the size to 400x200px.
Step 13: Setting Up the Index Page
Add the following to the “index.html” file you created in the step above.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Tuts+ Premium: Demo</title>
<style>
body {background: #f2f2f2; text-align: center; padding: 20px}
</style>
<script type="text/javascript" src="js/externalinterface.js"></script>
</head>
<body>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="400" height="200" id="externalInterface" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="false" />
<param name="movie" value="externalInterface.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<embed src="externalInterface.swf" quality="high" bgcolor="#ffffff" width="400" height="200" name="externalInterface" align="middle" allowScriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>
</body>
</html>
Here we set up our “index.html” file. We include the “externalinterface.js” we created in the step above, and embed the SWF file inside the object tag. If you decided to name your FLA something different, it is important to place the correct value for the SWF where applicable.
Step 14: Setting Up externalinterface.js
Add the following to the “externalinterface.js” you created in the step above.
function setScore(){
if(!localStorage.score){
localStorage.score = 0;
}
}
function getScore(){
if(localStorage.score){
return localStorage.score;
}
}
function updateScore(newScore){
localStorage.score = newScore
}
These are the same functions we used in the JavaScript application, so I will not be explaining them here. It is important to note that I removed the window.onload, however.
Step 15: Setting Up the FLA
In this step we will setup the UI for the FLA you created in the steps above.
Select the Text tool and make sure the following properties are set under the “Character” panel.
Now drag a TextField out to the stage and give it the following properties.
- X: 102.00
- Y: 14.00
- W: 210.00
- H: 25.25
Give it the instance name “currentScore_txt” and make sure the type is set to “Classic Text” and “Dynamic Text” respectively.
Now, drag another TextField onto the stage and give it the following properties.
- X: 102.00
- Y: 49.00
- W: 210.00
- H: 25.25
Give it the instance name “randomScore_text”.
Go to the Components panel, and drag a button onto the stage. (You can get to the Components panel by going to Window > Components or just by pressing CTRL + F7.)
Give the button the following properties.
- X: 150.00
- Y: 110.00
- W: 100.00
- H: 22.00
Give it the instance name “scorebtn”.
Within the “Components Parameters” panel, change the label to “Generate Score”.
Select the Rectangle tool and give it a fill color of “#CCCCCC” and no stroke.
Now, drag a rectangle out on the stage. Click to select the rectangle and give it the following properties.
- X: 118.00
- Y: 50.00
- W: 173.00
- H: 82.00
Now, right-click on the rectangle and choose “Convert To Symbol”; give it the name “alertBox”.
Double click on the rectangle to go into editing mode. Open the Components panel and drag a Button into this MovieClip. Give the Button the following properties.
- X: 37.00
- Y: 52.00
- W: 100.00
- H: 22.00
Give it the instance name “alertBox_btn”, and change the label to read “OK”.
Drag a TextField into the MovieClip and give it the following properties.
- X: 29.00
- Y: 10.00
- W: 131.00
- H: 22.00
Type the words “New High Score!!” into the TextField, then close this MovieClip.
Step 16: Main.as
Create a new ActionScript file and save it as “Main.as”. Then, back in your FLA, set Main to be the Document Class.
Step 17: Package and Imports
Add the following within the “Main.as” file you created in the step above.
package {
import flash.display.Sprite;
import flash.events.*;
import flash.external.ExternalInterface;
public class Main extends Sprite {
public function Main() {
}
}
}
Here we import the classes we will need, and code our constructor function.
Step 18: ADDED_TO_STAGE
Add the following within Main().
public function Main() {
addEventListener(Event.ADDED_TO_STAGE,setup);
}
The ADDED_TO_STAGE event runs when the movie has fully loaded. Here it calls a setup function, which we will create next.
Step 19: The setup() Function
Add the following beneath the Main() constructor function.
private function setup(e:Event):void{
trace("MOVIE READY");
}
If you test now you’ll see that “MOVIE READY” is traced in the output panel.
Step 20: Hiding the Alert Box
You may have noticed the Alert Box we created was showing when the movie first starts; let’s hide it. Enter the following within the setup() function.
private function setup(e:Event):void{
alertBox.visible = false;
}
Here we set the alertbox to not be visible. Go ahead and test the movie.
Step 21: setScore()
In this step we will use the External Interface class to call our setScore() function that we set up in the JavaScript code. Enter the following beneath the setup() function you created in the steps above.
private function setScore():void {
ExternalInterface.call("setScore");
}
Here we use the call() method of the ExternalInterface class to run the setScore() function that is in our JavaScript code. The call() method takes as a parameter the name of the JavaScript function to run (as a string). If we had parameters in our setScore() function, we would have included them here too.
We want this function to run when the movie first starts, so add it to the setup() function.
private function setup(e:Event):void{
alertBox.visible = false;
setScore();
}
Step 22: getScore()
In this step we will get the score to show in our Flash movie. The JavaScript will be sending the score to Flash, and to do this we will use the External Interface method addCallback() to make the function accessible to it.
Add the following within the setup() function.
private function setup(e:Event):void{
alertBox.visible = false;
setScore();
ExternalInterface.addCallback("getScore", getScore);
}
The addCallback takes two parameters: the name of a function that you want to make accessible via JavaScript (as a string), and an AS3 function that this call will be linked to (as an AS3 function callback). Here we want to make the AS3 getScore() function available to our JavaScript code first; for simplicity’s sake we give it the name getScore() when accessed via JavaScript as well.
We will now code this getScore() AS3 function. Add the following beneath the setScore() function you created in the step above.
private function getScore(score:String):int{
var theScore:int = int(score);
return theScore;
}
Here we set up our getScore() function. Since we will be receiving a string back from the JavaScript, we set the parameter as a string, and we return an integer. Inside this function we set up a variable named theScore and cast it to an int; we then return theScore.
Step 23: showScore()
In this step we make the current score display in the Flash movie. Enter the following beneath the getScore() function you created in the step above.
private function showScore():void{
currentScore_txt.text = "Current High Score is: "+ExternalInterface.call("getScore");
}
Here we set the currentScore_txt.text to display the current score. We use ExternalInterface.call("getScore") to call the getScore function in the JavaScript code, which in turn triggers the getScore() function in our ActionScript code. Remember, this returns the score.
Now add the following within the setup() function.
private function setup(e:Event):void{
alertBox.visible = false;
ExternalInterface.addCallback("getScore", getScore);
setScore();
showScore();
}
If you test the movie now, you should see the score being shown.
Step 24: addButtonListeners()
We need a way to add some listeners to our buttons, so that when the user clicks on them they do something. Add the following beneath the showScore() method you created in the step above.
private function addButtonListeners():void{
scorebtn.addEventListener(MouseEvent.CLICK,getRandomScore);
alertBox.alertBox_btn.addEventListener(MouseEvent.CLICK,hideAlertBox);
}
Add the following highlighted line within the setup() function.
private function setup(e:Event):void{
alertBox.visible = false;
setScore();
ExternalInterface.addCallback("getScore", getScore);
showScore();
addButtonListeners();
}
Here we set up our scorebtn to call an AS3 function named getRandomScore(), and we set up the alertBox_btn that is within the alertBox to call an AS3 function named hideAlertBox(). Next we will add these functions.
Add the following beneath the addButtonListeners() function you just created.
private function getRandomScore(e:MouseEvent):void{
}
private function hideAlertBox(e:Event):void{
alertBox.visible = false;
}
We will finish the getRandomScore() function in the next step. All we do in the hideAlertBox() function is set the alertBox to not be visible. We will be making it visible when the user gets a new high score.
Step 25: getRandomScore()
In this step we will code the getRandomScore() function, where – just like in the JavaScript application we made – all the app’s logic takes place. Add the following within the getRandomScore() body you created in the step above.
private function getRandomScore(e:MouseEvent):void{
var randScore:int = Math.floor(Math.random()* 200000);
var currentScore:int = ExternalInterface.call("getScore");
randomScore_text.text = "Random Score is: "+ randScore.toString();
if(randScore > currentScore){
alertBox.visible = true;
ExternalInterface.call("updateScore",randScore);
showScore();
}
}
This works in a very similar way to the JavaScript version. We first generate a number between 0 and 200,000. Then we get the current score by using ExternalInterface.call("getScore"). We set randomScore_text to read out the random score. Lastly we check whether randScore is greater than currentScore, and if it is we show the Alert Box, update the score in Local Storage by using ExternalInterface.call("updateScore",randScore), and call our showScore() method to show the new score.
Check out the demo.
Conclusion
We have used External Interface to access the Local Storage API from HTML5. I hope you have found this tutorial useful and thanks for reading!



View full post on Activetuts+