I rarely use sounds in AS3/Flash. I am using Flash Pro CS6, but I can't seem to figure out how to access, control (play, stop, etc) sounds embedded in an external SWF loaded into the main SWF.
It's easy to control them when embedded on the main swf. However, on an externally loaded SWR, I get all kinds of errors. For this app, I really need to embed them in the external SWF.
I read several solutions, but none seem to work.
I embed the sound an mp3 file called soundSegment1.mp3 using Flash CS6 import tool and then open the actionscript properties panel on flash to select the class name: SoundSegment1. Then I edit the class code and create a file called SoundSegment1.as and it's saved right next to my document class main.as in the same directory. The code of the SoundSegment1 class looks like this:
package {
import flash.media.*;
public class SoundSegment1 extends Sound
{
public function SoundSegment1 ()
{
// no code in here
}
public function playSound()
{
var soundSegment1:Sound = new SoundSegment1();
var channel:SoundChannel = soundSegment1.play();
}
}
}
Then, in my main.as, I have done several attempts to play this sound such as:
var fileLocation:URLRequest = new URLRequest(SWFToLoad);
loader.load(fileLocation);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressListener);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeListener);
loader.contentLoaderInfo.addEventListener(Event.INIT, initListener);
function initListener(e:Event):void // I also placed this code on the completeListener and it didn't work
{
loader.content.soundSegment1.playSound(); // doesn't work.
}
I get:
Line XXX 1061: Call to a possibly undefined method playSound through a reference with static type flash.display:DisplayObject.
or, I also read that I should be able to do something like this anywhere in the Main.as file:
var theClass:Class = Class(loader.content.getDefinitionByName("SoundSegment1"));
var theSound:theClass = new theClass();
theSound.play() //doesn't work either.
I also tried on the completeListener:
var TheClass:Class = e.target.applicationDomain.getDefinition("SoundSegment1") as Class;
var theSound:TheClass = new TheClass();
theSound.play() //doesn't work either.
I get:
ReferenceError: Error #1065: Variable SoundSegment1 is not defined.
at flash.system::ApplicationDomain/getDefinition()
I am stuck and I really need to get this to work. I would be genuinely grateful for your help.
Thank you in advance for any help provided. I really need to get it to work, because I can't simply embed them in the main SWF or load them individually externally one by one.
Thanks again!
user SnickelFritz from Kirupa gave me a fabulous answer with much easier code, which can be very powerful when using multiple sounds. This is just great, because you can use only one preloader per SWF, instead of having multiple loader for each file:
code for the main.as file
http://www.kirupa.com/forum/showthread.php?305098-Playing-a-embedded-sound-in-an-external-swf
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
public class Main extends MovieClip
{
var swf:MovieClip;
public function Main()
{
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);
l.load( new URLRequest("child.swf") );
}
private function swfLoaded(e:Event):void
{
swf = e.target.content as MovieClip;
addChild(swf);
swf.playSound();
}
}
}
Code for the loaded swf "child.as"
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
public class Child extends MovieClip
{
private var s:Sound1;
private var sc:SoundChannel;
public function Child()
{
s = new Sound1();
sc = new SoundChannel();
// All of the following lines are actually optional, if all your graphic elements are already inside the swf prepared in flash pro
var g:Graphics = this.graphics;
g.beginFill(0x666666);
g.drawRect(0,0,550,400);
g.endFill();
}
public function playSound():void
{
sc = s.play();
}
}
}
User "kglad.com" on the Adobe Forums also gave me a good answer:
http://forums.adobe.com/message/5681137#5681137
Related
I am receiving an error to suggest that my URL is not found. I am running the below simple script from Flash Builder. As I understand the application launches from bin-debug directory within the main project folder.
I have a image folder also within the main project folder yet it will not find the image. It works when I type the full directory.
The code I have is:
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.net.URLRequest;
[SWF(width="550", height="400", backgroundColor="#FFFFFF", frameRate="60")]
public class Kitties extends Sprite
{
//Declare the variables for the background.
public var backgroundURL: URLRequest;
public var backgroundLoader: Loader;
public var background: Sprite;
public function Kitties()
{
backgroundURL = new URLRequest();
backgroundLoader = new Loader();
background = new Sprite();
backgroundURL.url = "..\\images\\background.png";
backgroundLoader.load(backgroundURL);
background.addChild(backgroundLoader);
stage.addChild(background);
}
}
}
I understand I need to add an event listener to capture this error but for now it's not necessary as i know the file exists. Has anyone experienced this before?
Thank you.
You shouldn't use backslashes in actionscript3. Normal slashes work on every OS, even on Windows.
Try this:
backgroundURL.url = "../images/background.png";
If the file exists, it should load correctly.
I am working on an Air 2.6 project with an embedded SWF.
I am using the following embed code:
[Embed(source = "../../assets/click_feedback.swf", symbol="sub_circle")]
[Bindable]
public static var click_feedback:Class;
And the following code to get an instance of the click_feedback class:
private var cfb:MovieClip = new Assets.click_feedback() as MovieClip
The problems are:
The asset sub_circle has a frame labeled 'respond'. However, it just plays non stop whether or not the label is called with gotoAndPlay.
And, at the end of the animation, there is an Event.COMPLETE called, which is not being picked-up by my code.
I have tested the sub_circle asset in CS5 where I built it, and, in that environment it does not animate until 'respond' is called, and the event it triggers can be heard by my script.
Is this the correct way to handle embedded assets from an SWF?
Embedding of separate symbols from swf in general isn't a good idea:
It slows the compilation of your project, because of compiler must transcode swf format.
Embedding delete ALL AS code from timeline (I didn't check, but may be it remove labels as well, and it can be the reason of your issue).
I recommend embed the hole swf file and loads its bytes in runtime, a little more code to handle the async loading, but much more freedom and flexibility in use:
you safe all as3 code
you can choose ApplicationDomain where to load classes
you can easily switching from Embedding to runtime swf loading by url at any time, if you want to separate the as code and art/sounds assets.
organize your assets to library with the AssetsManager (with api like load(ByteArray or URL), getSkin(name):DisplyObject)
Code example adapted for your assets:
package
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
[SWF(width="800", height="200", backgroundColor="0x8B8B8B")]
public class astest extends Sprite
{
[Embed(source="../../assets/click_feedback.swf", mimeType="application/octet-stream")]
private static const common_art:Class;
private var loader:Loader;
private var domain:ApplicationDomain = ApplicationDomain.currentDomain;
public function astest()
{
init();
}
public function init():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
var loaderContext:LoaderContext = new LoaderContext(false, domain);
loaderContext.allowCodeImport = true;
loader.loadBytes(new common_art() as ByteArray, loaderContext);
}
private function onLoaded(event:Event):void
{
var clip:MovieClip = getSkin("sub_circle") as MovieClip;
addChild(clip);
}
private function getSkin(name:String):DisplayObject
{
if(domain.hasDefinition(name))
{
var clazz:Class = domain.getDefinition(name) as Class;
return new clazz() as DisplayObject;
}
return null;
}
}
}
The bitmap resource, It's usually make the bitmap generate the SWF file ,and use Loader class to load into the application.
I search some answers from google, find two ways to generate SWF File, one. use mxmlc tool. and another, use jsfl.
I know we can embed the bitmap or swf file into As code. and use mxmlc command like this:
the as file is Vip.as , and the code :
package
{
public class Vip
{
[Embed(source="vip.gif"]
public static var vip:Class;
}
}
and now, I use mxmlc Vip.as
...
It's has Vip.swf file, upload the Vip.swf file to Server.
Then, In flashBuilder, create a new ActionScript project, the application code is :
public class LoadUI extends Sprite
{
public function LoadUI()
{
init();
}
private function init():void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
loader.load( new URLRequest('http://localhost/swfResouce/Vip.swf'));
}
private function completeHandler(e:Event):void {
var loaderInfo:LoaderInfo = e.currentTarget as LoaderInfo;
}
and debug the application, Error is:
VerifyError: Error #1014: Class Not Found mx.core::BitmapAsset.
I don't know how to use mxmlc generate swf file . And no error when debug the code.
Another way is that use JSFL to generate SWF in flash cs5, But I don't know how to use this. Ah, very pain.
I am guessing you want to display an embedded image (gif).
Here is how its done:
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
public class Main extends Sprite
{
[Embed(source="vip.gif")]
private var embeddedVip : Class;
public function Main()
{
var vip : Bitmap = new embeddedVip();
addChild(vip);
}
}
}
Why don't you just load the images directly (from Loader) and wrap them in a Sprite? A GIF doesn't exactly need a timeline. :)
To avoid
VerifyError: Error #1014
try to compile with static linking:
mxmlc -static-link-runtime-shared-libraries=true -debug=true Main.swf --Main.as
[EDIT]
mxmlc -static-link-runtime-shared-libraries=true -debug=true Main.as
I have a swf which load an external swf. The loader swf has a variable which i want to access from the loaded swf. I use MovieClip(parent.parent).myVar but it return this error
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at card01_fla::MainTimeline/frame1()
The loader swf has a custom Document Class which i think is the problem.
Thanks in advance.
EDIT
This is the as of the main swf
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
import flash.text.TextField;
/**
* ...
* #author chchrist
*/
public class CardSender extends Sprite
{
private var loader:Loader;
private var viewButtonArray:Array;
private var sendButtonArray:Array;
private var cardContainer:Sprite;
public var testVar:String
public function CardSender() {
testVar = "it worked!!!";
init();
}
private function init() {
viewButtonArray = [cardsenderMC.view01, cardsenderMC.view02, cardsenderMC.view03, cardsenderMC.view04];
for each( var viewButton in viewButtonArray) {
viewButton.buttonMode = true;
viewButton.addEventListener(MouseEvent.CLICK, onViewClick);
}
}
private function onViewClick(e:MouseEvent):void {
var cardName = "card"+e.target.name.substring(4)+".swf";
loader = new Loader();
loader.load( new URLRequest(cardName));
loader.contentLoaderInfo.addEventListener(Event.INIT, onCardInit);
}
private function onCardInit(e:Event):void {
addChild(loader);
var content:* = loader.content;
content.closeButton.addEventListener(MouseEvent.CLICK, onCloseClick);
}
private function onCloseClick(e:MouseEvent):void {
removeChild(loader);
}
}
}
and I am trying to access the test variable from the loaded swf with this code
trace(MovieClip(parent.parent).testVar);
EDIT#2
If I addChild(loader) not in the onCardInit but in the onViewClick and in the first frame of the loaded swf i have Object(parent.parent).testVar it works...but why it doesn't want to be inside the onCardInit function?
You have just one loader variable and you're creating four Loader instances and assigning them to it - so if you are clicking all four of them in quick succession, the loader variable will effectively contain the Loader object corresponding to the last click. All your addChild calls will act on that same Loader object - the others will not be added and their parents will continue to be null
Make the following changes to the code:
private function onCardInit(e:Event):void
{
addChild(LoaderInfo(e.currentTarget).loader);
var content:DisplayObject = loader.content;
trace(content);
trace(content.closeButton);
content.closeButton.addEventListener(MouseEvent.CLICK, onCloseClick);
}
private function onCloseClick(e:MouseEvent):void
{
trace(e.currentTarget);//should be the closeButton
trace(e.currentTarget.parent);//should be the loaded swf
trace(e.currentTarget.parent.parent);//should be the Loader object that loaded it
//The following will work only if last three traced correctly
removeChild(e.currentTarget.parent.parent);
}
Answer to the following update in the question:
If I addChild(loader) in the onViewClick instead of onCardInit, then Object(parent.parent).testVar in the first frame of the loaded swf works. Why doesn't it work if I addChild inside the onCardInit function?
Again, that might be because you are adding a different loader object - are you clicking on more than one viewbuttons? Click on a view-button and wait till it is loaded to see it working.
parent.parent is wrong.
try using:
MovieClip(MovieClip(e.currentTarget.parent).parent).myVar ;
You have to cast the first parent to some class like MovieClip and then get this new MovieClip's parent and then getting inside variable.
try tracing parent and parent.parent, I'm sure it's because of an aditional "parent"
loader.content is NOT a movieclip, so it doesn't have the same capabilities. try
myLoadedClip:MovieClip = MovieClip(loader.content);
then your myLoadedClip.parent.myVar should show up
you might want your handler to fire on a Event.COMPLETE instead of on an Event.INIT
This only line code in loaded swf resolves it! ;)
MovieClip(MovieClip(parent.parent).root).play();
I'm trying to load an external and local XML file to read its data, but I don't really know how to detect when the file has been loaded, I'm just able to open the broser window,
here is what I have done
package {
import flash.display.Sprite;
import flash.events.;
import flash.net.;
import flash.net.URLRequest;
public class cargadorXML extends Sprite {
public var cuadro:Sprite = new Sprite();
public function cargadorXML() {
cuadro.graphics.beginFill(0xFF0000);
cuadro.graphics.drawRoundRect(0,0,100,100,10);
cuadro.graphics.endFill();
cuadro.addEventListener(MouseEvent.CLICK,init);
addChild(cuadro);
}
public function init(e:Event) {
var file:FileReference;
file = new FileReference();
file.browse();
file.addEventListener(Event.COMPLETE,bien);
}
public function bien(e:Event) {
trace("cargado");
}
}
}
but no "cargado" message appears, also I don't really think the Event.COMPLETE is the correct event at all xD
could some one help me here??
thanks
done, it's Event.SELECT instead of Event.COMPLETE