Calculations to Find an Angle in a Right Triangle (Flash)
by aMartinez on Jan.24, 2012, under Software
Recently I worked on a project that involved finding the angle of a right triangle in the Flash environment. The Google results I found had explained several equations related to the right triangle but the equations were incomplete for someone coding this type of math in the Flash environment.
The Angle variable in the image above (Image #1) is the variable I was initially looking to solve. I planned to use that value to rotate a MovieClip object using the rotation property. The trigonometry equation used to solve for this angle in a written form would be like this:
inverse tangent = opposite / adjacent
Flash doesn’t have an inverse tangent property but instead we can use the Math.atan() property to calculate the equation. This is how you would code it in Flash:
angleRadians = Math.atan( opposite / adjacent );
When tracing the final value for angleRadians you will notice that the returned value doesn’t quite seem like a number in degrees. In order to transform this radian value into degrees you would have to perform this additional equation::
angleDegrees = angleRadians / (Math.PI / 180);
Now we can use this new value for angleDegrees to rotate a MovieClip like this:
mc.rotation = angleDegrees;
We’re Hiring Again. Technology Jobs In the Museum Industry
by Charles on Jul.01, 2011, under Miscellaneous, Software
We recently posted two new positions in the interactive development department at BPI. The first position is targeted at an experienced developer. The second, support developer opportunity focuses on someone potentially just starting their career or transitioning industries.
The work that you will do at BPI is without a doubt going to be challenging, but with that challenge comes the potential to make a lasting impression for generations of visitors to the venues you will help create. All the work we do is used by the general public throughout the U.S. You’ll have the opportunity to harness cutting edge technologies to convey your creative spirit. You’ll also become a part of a supportive team that will challenge and encourage your own understanding of technology. Growing an original concept from prototype to polished product will become a routine skill in your arsenal.
Check out the full job descriptions and instructions for applying:
Debugging and Error Logging in Deployed Adobe Flash/AIR Applications
by Jake on Feb.23, 2011, under Software
It can be extremely difficult to fix issues in AIR applications that have been deployed to environments like museums. Because end users are often limited in their knowledge of effective bug reporting techniques, the summaries we get are usually quite vague. Deployed AIR applications throw exceptions silently, so the nature of the reports tend to be “it just stopped working” or something similar.
In the past I have created logging frameworks to catch such errors, along with application state information, and record them to text files. The main problem with this approach is that it only works if the application has been explicitly told to report a specific error. As far as I know, there is no way to globally catch all errors thrown at runtime (if there is I’d love to know about it). This works fine for things like asset loading, where it’s pretty easy to handle errors and redirect their output to the log, but becomes trickier if the bug is more elusive.
After a bit of research I found an alternate to this approach which will log all errors thrown at runtime. The best part is that this can be done to any existing deployed application and requires no additional code or recompiling! There are a few steps involved, but for the most part the process is pretty straightforward.
- Locate the “META-INF\AIR” folder inside the the folder in which the AIR application is installed.
- Place an empty file (an empty text file will work) named “debug” into this folder. This file should not have a file extension. This allows errors to be shown in the standard Flash Player dialog window when they occur, despite the application being installed as a release version.
- Locate the “mm.cfg” file on your system. On Windows 7 systems this should be located in “C:\Users\username”. Refer to this page for a full list of paths to this file on different operating systems:
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7fc9.htmlThis is a config file for the debug version of the Flash Player which allows numerous options to be turned on and off. It’s worth checking out the full list as it is quite extensive. It can be found in the Flash Player Admin Guide on this page:
http://www.adobe.com/devnet/flashplayer/articles/flash_player_admin_guide.html.
Some of the more interesting options are outlined here:
http://jpauclair.net/2010/02/10/mmcfg-treasure/ - The log file is named “flashlog.txt” and can be found in various locations depending on your operating system. On Windows 7 systems it is in “C:\Users\username\AppData\Roaming\Macromedia\Flash Player\Logs”. For other operating systems refer to this page:
http://help.adobe.com/en_US/flex/using/WSda78ed3a750d6b8f-4867184d1239f9d0558-8000.html
For our purposes, we want the file to look like this:
ErrorReportingEnable=1
MaxWarnings=1000
SuppressDebuggerExceptionDialogs=1
These settings tell the player to write any errors to a log file and suppress the debug dialog window (which was just enabled by creating the empty “debug” file) so that the user does not see it. Essentially we have created an environment where the released application will behave like a debug version, but its debug output will be written to a log file instead displayed in a window. Another interesting mm.cfg option not used here, but worth noting, is “TraceOutputFileEnable”, which allows trace messages to be sent to the same log file.
These steps allow errors to be silently logged in released AIR applications. In many cases there is still one more issue presented by this approach: each time that the application runs the log file is overwritten, deleting any old errors (this is a global log file for the Flash Player, not one specific application). This is not very helpful if you have an application that is only encountering issues occasionally, after which it is reset and continues running. (There is a “PolicyFileLogAppend” option that can go in the mm.cfg file, however as far as I can tell this only works for a separate policy file log and there is no equivalent for the flashlog.txt file.)
To get around this issue I wrote a small Java application that maintains another text file called “flashlog_archive.txt”. I run this before the AIR application starts in order to collect any errors that may have been logged during the last execution. It checks the last modification date of the flashlog.txt file and compares it to the last date stamped on the content in the archive file; if the last modification date is newer then the contents of the flashlog.txt file are appended to flashlog_archive.txt and stamped with a date and time. This results in a log history that is sorted chronologically.
To ensure that the logs are collected before the AIR application runs I created a Windows batch file that starts the Java application, waits for its execution to finish, then launches the AIR app. Here’s what the first line of that batch file looks like (the one that launches the Java app and waits for it to finish):
start /wait java LogArchiver “C:/users/Jake Frederick/AppData/Roaming/Macromedia/Flash Player/Logs/”
By default the application looks in it’s own current folder to find flashlog.txt. The argument passed in the example points it to a different folder. The flashlog_archive.txt file is automatically created in the same location if it doesn’t exist.
You can download the compiled Java class here:
LogArchiver.class
I have also created a JAR file which does not require the command line to run, but doesn’t provide any console output about it’s current activity:
LogArchiver.jar
The Java source is here for anyone interested:
LogArchiver.java
Selling Your Green Screen Shots to Your Audience in Videomaker Magazine
by Charles on Feb.04, 2011, under Uncategorized
Mike Sullivan, one of our senior editors at BPI wrote an article that just appeared in the current issue of Videomaker Magazine. He covers the complex aspects of creating a good green screen experience. You can check out the full article at Videomaker Magazine under “Selling Your Green Screen Shots to Your Audience”.
ECHO Science Center Voices For the Lake Projects Added
by Charles on Jan.21, 2011, under Hardware, Software, Web
We have added project descriptions for the multimedia experiences that we worked on in collaboration with the talented folks at the ECHO Lake Aquarium and Science Center in Burlington, VT on beautiful lake Champlain. The Voices For the Lake project uses many exciting social media components to allow media creation from online visitors and those at the science center. You can check out the full project listing on the exhibit key page.
If you want to check out the most recently submitted media, or contribute your own to the exhibit, head over to voicesforthelake.org
Adobe Flash/AIR Debugging and Testing Tips
by Bruce on Dec.14, 2010, under Software
I don’t pretend to be a master as3 programmer. There are many folks out there, three of which are on my staff, that are better at application development. I am, however, pragmatic when it comes to programming and testing. The applications we build here go out onto the floor of a museum or other venue, and often you can’t just push out an update if there’s a problem. So, they have to be solid from day 1. I have a few things that I do when writing applications, that help me test rapidly and optimize my development time. These are not just applicable to Flash applications, but since that’s what I do, I am tailoring this to that.
Keyboard Shortcuts
I build in a keyboard shortcut system to all programs that I do. It helps me not have to wait for timers, animations to stop, etc. I’ll always add one to hide and show the mouse pointer, immediately go to the attract loop, etc. This saves a lot of time when testing out pieces of the program.
Jump to the end of videos.
We often have video pieces built into our programs. Since we mash up video, audio, etc. we’ll find ourselves playing back FLVs or h264 files much of the time. One of the keyboard shortcuts that I use is to make one that jumps to 95% of the duration of the video. This helps me move through linear pieces quicker. You still have to spend some time letting the whole video play when you’re doing final QC, but this is good for much of development, when you’re not working on the video timing specifically and just want to move to different areas of the program quickly.
Reload XML on the fly.
This is really great, but can also be challenging to implement. If you’re dealing with an application with a lot of variables and externally loaded configurable options, this can really save a lot of time. If the program only loads it’s config info, which I always put in an XML document, when it starts, then you’re going to have stop and start that program repeatedly to test out different options. If you built in a method, triggered by a keystroke, that reloads that data and repopulates your variables, then a ton of time can be saved.
Use short timeout settings in your XML during testing.
All of our programs have a timeout built into them to take some action when nobody has hit a key or touched the screen or whatever. When building the timeouts, I always make it really short, like 5 seconds, so that I can check if it’s working properly. It’s like building in the video shortcut.
Set Up the Real Thing
I can’t stress this enough. Unless you’re testing on the actual hardware, with the actual configuration, you’re not getting accurate information about whether the program is going to work. This doesn’t apply to web development as much when talking about hardare, although you can make sure you use all the browsers you can find and see how it performs from a software perspective. This is about setting up the real screens, computers, extenders, connectors, etc. that will actually be on the exhibit floor, and running it. Not for a few hours, but for days.
Although some of these things above entail shortcuts, it’s important that when you’re doing your final QC, that you don’t use all these tricks. The actual program, with it’s actual timeouts, videos playing, and animations triggering needs to be observed. These aren’t meant to replace the stress testing you’re going to need to do on your programs, but to speed up development of parts of it.
Solving Problems With AMFPHP 1.9 and PHP 5.3 With an Updated Debuggateway.php File
by Charles on Nov.19, 2010, under Uncategorized
AMFPHP is an awesome technology that allows Flash Player to communicate with PHP using the AMF protocol. So you can use Netconnection.call in flash to call server side php functions.
I recently setup AMFPHP 1.9 on Windows XP using XAMPP with PHP 5.3 and ran into a few days of trouble that I wanted to elaborate on.
The main issue was that I had not set a default timezone in php.ini, so PHP was outputting an error message which was getting mixed into the AMF return and causing errors. I think this constant warning is new to PHP 5.3.
date.timezone = America/New_York
In order to understand why you can’t see the errors occurring in AMFPHP during a setup, you need to understand the AMF protocol. It’s tough to get messages out of it, because it is a binary protocol. So for instance, if you have ever loaded an image in a web browser or unknown document type, it may show up as a bunch of encoded junk that is just a bunch of symbols and nonsense. Getting an AMF message to or from PHP is just like getting an image, so without decoding that message some how, you have no way of seeing the errors occurring inside it!
In order to see errors occurring during setup you need to route the AMFPHP calls through an additional php file that can detect errors and decode them for you.
The old documentation for AMFPHP always talks about a debuggateway.php file which doesn’t exist in any of the recent versions of AMFPHP since it was re-designed. I got so frustrated trying to debug amfphp that I re-wrote the old debuggateway.php file to work with the newest version of AMFPHP using the newer architecture. The file is a mess, but it will intercept and write out the errors to a file in the same directory called “amfPHPOutput.txt”. The following is the contents of the new debuggateway file.
/*
* The debug gateway is a simple gateway that calls the real gateway and then checks if
* the outgoing message is correctly formatted. If not, it wraps the message into a correctly
* formatted message, so that even fatal errors are caught. It is highly recommended
* the the real gateway be called directly for production use.
*
* This gateway requires CURL to work properly
*/
//Enabling sessions may result in lowered performance and computers being set on fire
//use at your own risk
define("ENABLE_SESSIONS", true);
//Guess gateway location (you may change this manually)
$gatewayUrl = 'http://' . $_SERVER['HTTP_HOST'] . str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])) . '/gateway.php';
$gatewayUrl = str_replace('//gateway', '/gateway', $gatewayUrl);
$sessionName = ini_get('session.name');
if(isset($_GET[$sessionName]))
{
//Add session id
$gatewayUrl .= '?' . $sessionName . '=' . $_GET[$sessionName];
}
include "globals.php";
define("AMFPHP_BASE", realpath(dirname(__FILE__)) . "/core/");
define("AMFPHP_CONTENT_TYPE", 'Content-type: application/x-amf');
/**
* required classes for the application
*/
require_once(AMFPHP_BASE . "shared/app/Constants.php");
require_once(AMFPHP_BASE . "shared/app/Globals.php");
if(AMFPHP_PHP5)
{
require_once(AMFPHP_BASE . "shared/util/CompatPhp5.php");
//Set gloriously nice error handling
include_once(AMFPHP_BASE . "shared/app/php5Executive.php");
include_once(AMFPHP_BASE . "shared/exception/php5Exception.php");
}
else
{
require_once(AMFPHP_BASE . "shared/util/CompatPhp4.php");
//Cry
include_once(AMFPHP_BASE . "shared/app/php4Executive.php");
include_once(AMFPHP_BASE . "shared/exception/php4Exception.php");
}
require_once(AMFPHP_BASE . "shared/util/CharsetHandler.php");
require_once(AMFPHP_BASE . "shared/util/NetDebug.php");
require_once(AMFPHP_BASE . "shared/util/Headers.php");
require_once(AMFPHP_BASE . "shared/exception/MessageException.php");
require_once(AMFPHP_BASE . "shared/app/BasicActions.php");
require_once(AMFPHP_BASE . "amf/util/AMFObject.php");
require_once(AMFPHP_BASE . "amf/util/WrapperClasses.php");
require_once(AMFPHP_BASE . "amf/app/Filters.php");
require_once(AMFPHP_BASE . "amf/app/Actions.php");
// Variables needed for debugging
$filters = array();
$actions = array();
$exec = new Executive();
registerFilterChain();
registerActionChain();
$GLOBALS['amfphp']['actions'] = $actions;
// Pulled out of the AMFPHP 1.9 core io gateway updated 2/2010
if (!isset($GLOBALS['HTTP_RAW_POST_DATA'])){
$GLOBALS['HTTP_RAW_POST_DATA'] = file_get_contents('php://input');
}
$data = $GLOBALS['HTTP_RAW_POST_DATA'];
$error = NULL;
$ch = curl_init($gatewayUrl);
// Turns verbose output on
curl_setopt($ch, CURLOPT_VERBOSE, 1);
// Sets CURLS post method
curl_setopt($ch, CURLOPT_POST, 1);
// Dumps the return to curl into a variable
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// Time out after 5 seconds
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
// Sets the header as amf - Does this have to change for amf0 and amf3?
curl_setopt($ch, CURLOPT_HTTPHEADER, array(AMFPHP_CONTENT_TYPE));
// Adds post fields to our request
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
// Follow any "Location: " header the server sends as part of the http header. This is recursive so we will follow as many as we get
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
// Run the query
$result = curl_exec($ch);
if (curl_errno($ch)) {
// Return the last curl error number
$error = 'CURL error: ' . curl_error($ch);
} else {
// Close the curl session
curl_close($ch);
}
//Is the result valid so far?
if($result[0] != chr(0))
{
//If chr(0) is not the first char, then this result is not good
//Strip html
$error = strip_tags($result);
}
if($data == NULL || $data == "")
{
echo "cURL and the debug gateway are installed correctly. You may now use the debug gateway from Flash.
" . "Gateway is set to: " . $gatewayUrl;
die();
}
if($error != NULL)
{
//Get the last response index, otherwise the error will not register
//In the NetConnection debugger
// $amf = new AMFObject(); // create the amf object
$amf = new AMFObject($GLOBALS["HTTP_RAW_POST_DATA"]); // create the amf object
foreach($filters as $key => $filter)
{
$filter($amf); // invoke the first filter in the chain
}
$output = $amf->outputStream;
$OutputFileHandle = fopen('amfPHPOutput.txt', 'w') or die("cant open file");
fwrite($OutputFileHandle, $output . " " . $error);
fclose($OutputFileHandle);
}
header(AMFPHP_CONTENT_TYPE);
header("Content-length: " . strlen($output));
print($output);
/**
* Create the chain of filters
* Subclass gateway and overwrite to create a custom gateway
*/
function registerFilterChain()
{
//filters
$filters['deserial'] = 'deserializationFilter';
$filters['auth'] = 'authenticationFilter';
$filters['batch'] = 'batchProcessFilter';
$filters['debug'] = 'debugFilter';
$filters['serialize'] = 'serializationFilter';
}
/**
* Create the chain of actions
* Subclass gateway and overwrite to create a custom gateway
*/
function registerActionChain()
{
$actions['adapter'] = 'adapterAction';
$actions['class'] = 'classLoaderAction';
$actions['security'] = 'securityAction';
$actions['exec'] = 'executionAction';
}
DMCA and What else to Consider When Implementing User-Contributed Social Media in Museum Exhibits and Displays
by Charles on Oct.29, 2010, under Social Media, Software, Web
The majority of the projects I have worked on this year at BPI involve visitor-generated content that appears on institutions’ Web sites or inside public exhibits. For each of these exhibits, there has almost always been some sort of content-review policy in effect. Even in the planning and bidding process of the majority of our new projects, it is always assumed that visitor-generated content must be reviewed before becomes public.
On the surface, this seems like common sense. Of course an institution should approve of all content that is publicly posted on their digital properties, because visitors of all ages and types are expected to be exposed to this content — right? What if someone were to write profanities or post something inappropriate? Doesn’t it make sense that this content should be weeded out before it is public?
According to the Digital Millennium Copyright Act (DMCA), implemented in 1998, an institution is at greater risk for liability under copyright infringement if they actively review submitted content and accidentally allow infringing content to be publicly posted. The DMCA plays a big role in the attempt to strengthen copyright-holders’ protections in a digital era. User-generated content — on social-media sites like Facebook and sites displaying user-provided content, such as YouTube — that potentially contain copyrighted material are strongly influenced by the DMCA.
The provision of the act that we are specifically concerned with is the notion of a “Safe Harbor.” The “Safe Harbor” section of the DMCA provides guidelines that an institution dealing with user-generated content should follow in order to reduce their risk to liability under the act. Safe Harbor was tested earlier this year in copyright-infringement litigation brought against YouTube by Viacom. An article on KeytLaw outlines Safe Harbor protections institutions and organizations that host user-generated content possess. According to this article, the “service provider,” or institution that hosts the user-generated content, is covered under the Safe Harbor provision if it has no way of knowing that the material is infringing and/or takes action to remove the material once it learns that it is infringing.
The Keytlaw article mentioned earlier provides great information on how to comply with these requirements. The Electronic Frontier Foundation (EFF) also provides helpful tips in their “Bloggers Legal Guide” under the question “When can I claim the safe harbor for comments others post on my blog?”. It seems like the easiest thing would be to designate an agent for notification with the Copyright Office.
So, what should a museum or visitor center do with an exhibit that posts user-generated content to a public venue?
After seeing the kind of content visitors are posting to the exhibits I have worked on; I would recommend not to let the idea of inappropriate material get in the way of implementing exhibits that incorporate user generated content. It has been my experience that if visitors are aware that the content they submit goes directly onto public Web sites and into exhibits, they have a greater tendency not to post inappropriate material. Reviewing and vetting content on the part of the institution not only uses staff members’ valuable time, but by doing so it also makes the institution liable as the “host” of the material and waives the institution’s protections under the Safe Harbor provision. On DMCA-protected sites, such as YouTube, content is not actively monitored but is removed upon the request of copyright-holders or the users themselves.
Museums, visitor centers and other institutions may also choose a similar tact with their own user-generated exhibit content, relying on the visitorship itself to point out and “vet” offensive or copyrighted material. This protects the institution, while still ensuring content is safe and appropriate for all visitors. Even so, the decision is ultimately in the hands of the institution to decide the route to take when navigating the exhibits of the Digital Age.
C-States Control and Power Management Can Cause Flash Performance Problems
by Jake on Oct.25, 2010, under Hardware, Software
During the testing phase of a recent project I came across a curious problem: a Flash application that was running on a Dell OptiPlex 780 seemed to be arbitrarily slowing down and speeding up; a phenomenon which had not occurred during testing on my development machine. Eventually I determined that the SWF’s framerate would be cut in half whenever I plugged an external drive into the kiosk. Further investigation led to me disabling C-States control in the machine’s BIOS. Apparently C-States are idle states that put the processor into a sort of light sleep mode depending on the current level of user activity. It seems that the processor was entering one of these modes, despite the running Flash application, and plugging the drive in caused it to wake up. Disabling C-States control fixed the problem.
Interestingly, when I tested a pre-10.1 version of the Flash player on the same hardware I did not have the problem. This leads me to believe that something in the new power management features of Flash player 10.1 was not sitting well with the C-States management. This problem has been reported with other software such as Windows Media Player as well (http://bugs.adobe.com/jira/browse/FP-1506).
To summarize: if your Flash app is experiencing a mysterious performance hit, check to make sure that your machine does not have some form of power management enabled.
Separating a Display Object’s 3D Rotation from the Stage’s Vanishing Point with AS3 in Flash.
by dnelson on Oct.12, 2010, under Software
If you were to create a simple square on the stage in Flash and used ActionScript to rotate it 90 degrees on its X-axis in 3D space, you may expect to not see anything. In theory, the square has no depth, so you should see nothing when viewing it at 90 degrees; however, if you try to create this, you will see the square rotated at an angle that does not appear to be 90 degrees. This is because the 90-degree rotation is in relation to the vanishing point of the stage, (which can be set using the 3D transform tool in the IDE). The vanishing point will affect all of your display objects by default, causing the 3D rotation to be a product of the vanishing point. But what if you don’t want your display object to rotate in 3D space in accordance with the vanishing point? What if you want to rotate your square 90 degrees and see a square rotated 90 degrees, regardless of its location on the stage?
You can deal with this using ActionScript 3 and PerspectiveProjection. By transforming the PerspectiveProjection of your square and setting the projection center to the X and Y position of your square, you can now rotate it independent of the stage’s vanishing point. By clicking the “toggle” button in the example, you can see the difference between a 90-degree rotationX in accordance with the vanishing point of the stage, versus setting the PerspectiveProjection center of the square, to the square’s X and Y position.
In the example below, the square is shown rotated at 90 degrees in 3D space. By clicking the “toggle” button, you can see how changing the PerspectiveProjection can separate the square’s 3D rotation from the constraints of the stage and its vanishing point.
Here is the code:
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.PerspectiveProjection;
public class Rotation3DPerspective extends Sprite
{
private var toggleOff:Boolean;
public function Rotation3DPerspective():void
{
toggleBtn.addEventListener(MouseEvent.CLICK, togglePerspectiveProjection);
// Rotate square 90 degrees (this will be 90 degrees in accordance to the vanishing point of the stage);
sq.rotationX = 90;
}
private function togglePerspectiveProjection(e:MouseEvent):void
{
if(! toggleOff)
{
/* By setting the PerspectiveProjection of the square to the square’s registration point, we can rotate the square 90 degrees without it being affected by the
vanishing point of the stage. */
sq.transform.perspectiveProjection = new PerspectiveProjection();
sq.transform.perspectiveProjection.projectionCenter = new Point(sq.x, sq.y);
toggleOff = true;
}else{
/* Remove the PerspectiveProjection that was set to the square’s X and Y, which will redisplay the square rotated 90 degrees in
accordance to the vanishing point of the stage. */
sq.transform.perspectiveProjection = new PerspectiveProjection();
toggleOff = false;
}
sq.rotationX = 90
}
}





