Let me set the stage because it's too much code to post everything:
I have a Main.as that is setting up my SoundController.as so I can trigger sounds from any other class (SoundController.as has all the functions needed to call all my sounds as needed)
I have a ControlPanel.as that can access these sounds by using docRef.soundControl.laserFire or whatever other function name I want, and in this case the laserFire sound would trigger once.
So here is my question. I want to let this laser sound effect finish playing before you can fire another laser. So in SoundController.as I've set up the following pieces of code:
private var _laserPlaying:Boolean = false;
internal function laserFire():void {
_sfxChannel = _laser.play(25);
_laserPlaying=true;
_sfxChannel.addEventListener(Event.SOUND_COMPLETE, laserFinished);
}
internal function laserFinished(event:Event):void {
_sfxChannel.removeEventListener(Event.SOUND_COMPLETE, laserFinished);
_laserPlaying=false;
}
public function get laserPlaying():Boolean {
return _laserPlaying;
}
public function set laserPlaying(value:Boolean):void {
_laserPlaying = value;
}
Now in my ControlPanel class in the enterFrameHandler function I want to do an
if (docRef.soundControl.laserPlaying()==false)
or something to that effect so I can check when the sound is done and allow the player to once again press the trigger to fire the laser. So far any variant I've tried on this either gives me an error (in this case 1195; Attempted access of inaccessible method laserPlaying through a reference with static type SoundController) or it actually compiles but after firing the first laser shot it never allows the trigger to be pressed again. So I'm obviously doing something wrong and am hoping someone can help.
Let me just state that the laser sound is playing just fine that first time, so don't worry about all the code I'm not bothering to show to make that portion of the code work. However, if more info is needed to understand how I'm making anything work just let me know. And Thanks in advance!
If your soundController AND ControlPanel are instantiated in Main:
handle the firing event, in ControlPanel, like this:
if(MovieClip(parent).soundController.soundChannel.position==0)
{
MovieClip(parent).soundController.laserfire();
}else{do nothing;}
Of course use proper instance names.
If this doesn't work you'll have to make your code a little easier to understand.
Sorry for wasting everyone's time. I ended up figuring out what I needed to do to make this work. This probably won't be of much use to anyone else since my setup was probably unique to my layout and not something that anyone else will try, but here is what I did anyway.
In my ControlPanel.as I added the following code:
private var _soundController:SoundController;
And then I have a function that waits for the ControlPanel to be added to the stage and once that occurs I fired:
_soundController = new SoundController(docRef);
Now by adding those I was able to simply call:
if(!_soundController.laserPlaying) { do stuff; }
It now seems to wait for laserPlaying to be false and then moves on as intended.
Related
I'm surprised I don't know how to do this, but as it turns out I really don't; simply put, I'm trying to make a side-scrolling shooter game, a basic one and in it, I have 50 stars spawned on-screen through a "for" loop upon the game starting. There is a function which does this and a listener is at the beginning. Problem is, when you lose the game and go back to main menu, 50 more stars would be spawned, which isn't what I want. So, I'm trying to make an "if" statement check at the beginning, so that the game checks whether there is an instance/movie clip of the star object/symbol before determining whether the function that spawns stars should be called out with a listener. So, how do I do this? I looked through some other checks and they didn't help as the codes presented were vastly different there and so I'm just getting errors.
Let me know if a better explanation is needed or if you would like to see some of the code. Note that the game overall already has a lot of code, so just giving all of it would probably not be helpful.
I suggest you rethink your approach. You're focusing on whether stars have been instantiated. That's ok but not the most basic way to think about it.
I would do this instead
private function setup():void{
loadLevel(1);
addListeners();
loadMusic();
// etc...
// call all functions that are needed to just get the app up and running
}
private function loadLevel(lev:int):void{
addStars();
// call all functions that are needed each time a new level is loaded
}
private function restartLevel():void{
// logic for restarting level,
// but this *won't* include adding star
// because they are already added
}
There are other ways to do this but this makes more sense to me than your approach. I always break my game functions into smaller bits of logic so they can be reused more easily. Your main workhorse functions should (IMHO) primarily (if not exclusively) just call other functions. Then those functions do the work. By doing it this way, you can make a function like resetLevel by assembling all the smaller functions that apply, while excluding the part about adding stars.
Here's what I did to solve my problem... Here's what I had before:
function startGame():void
{
starsSpawn();
//other code here
}
This is what I changed it to:
starsSpawn();
function startGame():void
{
//other code here
}
when you said existance, so there is a container, i named this container, (which contain stars , and stars was added to it) as starsRoot, which absolutely is a DisplayObject (right?)
now, to checking whole childrens of a DisplayObject, we have to do this :
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
}
then, how to check if that child is really star!?
as you said
whether there is an instance/movie clip of the star
so your stars's type is MovieClip, and they don't have any identifier (name), so how to find them and make them clear from other existing movieclips. my suggestion :
define a Linkage name for stars from library, thats a Class name and should be started with a capital letter, for example Stars
now, back to the code, this time we can check if child is an instance of Stars
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
if (child is Stars) {
// test passed, star exist
break;
}
}
I'm creating a game that uses the starling-layer (the game itself) and the classic display list which contains several Popups and Stuff like that.
I have one thing that troubles me:
If MouseEvents are generated on displayList-elements they always go through to the starling layer and produce TouchEvents etc. which is quite annoying.
I was wondering there is some general (and easy to use) approach to handle that.
One possibility was to listen on all displayList-Elements for the following Events:
interfaceElement.addEventListener(MouseEvent.MOUSE_MOVE, stopPropagationHandler);
interfaceElement.addEventListener(MouseEvent.MOUSE_DOWN, stopPropagationHandler);
interfaceElement.addEventListener(MouseEvent.MOUSE_UP, stopPropagationHandler);
private function stopPropagationHandler(e:MouseEvent):void {
e.stopPropagation();
}
But this looks quite nasty to me.
And even if I did it like that, I have one more issue:
If a starling-element is below that display-list-element and if it has a TouchEvent.TOUCH for rollover-behavior >> the rollover-appearance will not be removed from the starling if you hover over the display-list-element.
I also thought about putting a dummy-starling element behind every display-list-element,... to stop the events.. but that all sounds a bit "over-complicated" for such a "simple" task.
Or am I missing something?
A hint would be much appreciated.
Thanks.
You could create 1 main container in the displaylist (not the stage) and listen for ROLL_OVER and ROLL_OUT, and set somekind of global flag there, that your mouse is over the display-list container. Then in your starling events, check for this flag. This isn't the nicest solution out there i guess, but it should work
var isOverDisplayList:Boolean = false;
container.addEventListener(MouseEvent.ROLL_OVER, onRollOver);
container.addEventListener(MouseEvent.ROLL_OUT, onRollOut);
function onRollOver(e:MouseEvent) {
isOverDisplayList = true;
}
function onRollOut(e:MouseEvent) {
isOverDisplayList = false;
}
you have always been of great help for me throughout the last few years.
I could always find a solution to my programming problem.
This time however I couldn't find a solution to this one.
Although there are a few topics which discuss Loaders. Mine is a lot different.
The problem:
In the first game screen I load a movie (a movie converted to .swf).
And after I switch to the next state, it unloads and doesn't display any more.
At the end of the game I execute my own made reset function (which has not much to do
with the loader whatsoever, it just resets some static variables) and the game switches
to the first state.
The Loader once again shows up. But now when I switch states, the Loader is still displaying.
Note: I am using the flixel library. Although I don't think it makes a big difference in this case (though I figure it problably does since I still have the problem :P).
I have only placed the important code. I have three buttons. Let's say I push. the third button. In the switch case I enter case 2.
The reset function is a flixel function: FlxG.resetGame() but I figure it doesn't really
matter.
I hope this is enough information for someone to see the problem/solution.
Thanks in advance.
Here's the code:
AMCInlog.as
private var my_loader:Loader;
private var my_player:Object;
public function AMCInlog()
{
imgBackground = new FlxSprite(0, 0, Resources.imgStartMenuBackground);
add(imgBackground);
my_loader = new Loader();
my_loader.x = 40;
my_loader.y = 156;
my_loader.scaleX = 1.2;
my_loader.scaleY = 1.2;
//loadUserData();
moviePlayerSequence();
//userData.clear();
//createButtons();
}
private function moviePlayerSequence():void {
var request:URLRequest = new URLRequest("DGAME Movie.swf");
my_loader.load(request);
FlxG.stage.addChild(my_loader);
}
private function currentButtonFunction():void {
switch(currentButton) {
case 0:
my_loader.unloadAndStop();
FlxG.stage.removeChild(my_loader);
FlxG.switchState(new AMCRegister());
break;
case 1:
my_loader.unloadAndStop();
FlxG.stage.removeChild(my_loader);
FlxG.switchState(new AMCExistingAccountLogin());
break;
case 2:
my_loader.unloadAndStop();
FlxG.stage.removeChild(my_loader);
FlxG.switchState(new AMCPreferences());
break;
default:
break;
}
}
You never reset your loader, hence it just holds onto what it loaded last time, either simply try and reset (or re-initiate actually) your loader like so (not the best method (will go into flash garbage-collection which has never been that awesome) but hey, it works)
my_loader = new Loader();
Or (since i dont see it) try using simply unload(); instead of unloadAndStop(); (since well, you dont need to stop it, if you unload it properly, its gone anyway)
Good luck!
i am trying to create a puzzle game and so far had no problems with moving the pieces and all but when i tried to check piece position after stopDrag i got an error message:Error #1010: A term is undefined and has no properties.
this is the relevant code:
full1 is a movieclip that contains a picture of the puzzle with a low alpha and the puzzle pieces,each with it's own instance name.
in this example tr is an instance name of one of the pieces.
public function Move(even:MouseEvent)
{
even.target.startDrag();
}
public function stopMove(even:MouseEvent)
{
this.stopDrag();
checkPos(even.target.name);
}
public function checkPos(nameStr:String)
{
if(nameStr=="tr1")
{
if(this.full1.tr1.x>=460&&this.full1.tr1.x<=465.5&&this.full1.tr.y>=99&&this.full1.tr.y<=103)
{
this.full1.tr.x=460.2;
this.full1.tr.y=101.95;
}
}
}
if anyone sees any problem with what i wrote or has a better idea of how to approach this i would appreciate your help.
thanks.
Looks like it should be even.target.stopDrag() instead of this.stopDrag() (since you started the drag on even.target). Unless the error is occurring after stopDrag(), in which case it doesn't look like enough info to answer.
Side note, it would be better to do the name checking outside of the checkPos() function. e.g.:
this.stopDrag();
if(even.target.name == "tr1")
{
checkPos();
}
And remove the name checking from checkPos().
On one occasion, you use "even.target.startDrag();" to start dragging.
But in the other function, you use "this.stopDrag();" to stop dragging.
You should either always use "this" or always use "even.target". This could be the cause of your error.
It would also be good to know in which line exactly the crash happens.
Can someone help me to find out why I'm getting the error message "Access to undefined property: removeChild(goBack)" on the following snipped?
BTW, this is for flash CS4
function nameOfFunction() {
var goBack:backButton_mc = new backButton_mc();
goBack.x = 10;
goBack.y = 700;
goBack.back_text.text = myXML.*[buildingName].NAME;
goBack.name = "backBtn";
goBack.buttonMode = true;
addChild(goBack);
goBack.addEventListener(MouseEvent.CLICK, anotherFunction);
}
function anotherFunction(e:MouseEvent):void {
removeChild(goBack);
}
You are wrong with the scope. (surprise :-D)
The variable goBack is just defined inside of "nameOfFunction", when you try to access this from a another function like "anotherFunction" it will not exists anymore (even if it is on the display list)
There are different possibilities to solve this problem:
function anotherFunction(e:MouseEvent):void {
removeChild(e.currentTarget);
}
Or the best way would be: promote goBack as a class member of the class holding both functions. (Or if you don't use classes make goBack "global".)
Hippo is correct, but I feel it is important to explain a little more.
You created a local variable, i.e. var someVariable:DataType; within a function. This means that that variable will only be available to objects in the scope (inside) of the function (local to), and it will only last for the lifetime of the function. Soon as that function has ran the code is gone until ran again. It looks like you are probable programming directly inside the flash IDE on the time-line, which is fine, but, if you were using a document class, you could merely declare you variable in the Class scope just above the constructor function, and then set the value in the same function that your using now. This way, the reference to the variable doesn't exist within the function, it is merely set from within. This will allow that variable to be accessed from anywhere in the same class even if set to private.
This may help:
//Frame 1, Actions layer
//Slap goBack right onto the root / stage
var goBack:MovieClip;
/*
I noticed you had this data-typed differently,
i prefer to type to an interface, not an implementation.
Since your class is a movieclip in the library it extends
MovieClip and therefor IS A MovieClip, but ok either way.
*/
function nameOfFunction():void
{
goBack = new backButton_mc();
goBack.x = 10;
goBack.y = 700;
goBack.back_text.text = myXML.*[buildingName].NAME;
goBack.name = "backBtn";
goBack.buttonMode = true;
addChild(goBack);
goBack.addEventListener(MouseEvent.CLICK, anotherFunction);
}
function anotherFunction(e:MouseEvent):void
{
removeChild(goBack);
}
Scope is very important and after a while very easy to tackle. Stick with it, experiment, read up on conventions and standards that can help your development and get to loving the DocumentClass becuase even though it may be daunting to some at first, once you learn it and get used to it, it so hard to go back to programming in the flash IDE on the timeline, where I believe only display objects and audio have any place being.