Actionscript 3 - How to access integer variable in main timeline from inside MovieClip - actionscript-3

First, sorry if my english is bad and I'm new to Actionscript 3.
I have a movieclip, I give it an instance name "symbol1" which include a code inside it, like this :
var a: int = 2;
var b: int = 3;
var total: int = a + b;
How can I access the "total" integer variable inside that movieclip in the main timeline? I try to trace it but the result is 0. In the main timeline I wrote this code :
trace(symbol1.total);
I appreciate the help, thanks

The "problem" is the order of execution of frames. The parent is executed first.
The value is 0 and not undefined because the property does indeed exist since the creation of the object which happens in a previous separate step.
You should be able to verify that by stepping through your code with the debugger.
I've made 6 games. each game is in the MovieClip including the game functions, times, scores, variables, etc. I want the total score of each game summed outside each MoviClips, which is in the main timeline. is there a solution to that problem?
This makes your timing problem even more apparent.
You arrive at a frame, which contains a game and you immediately want to access the total score of it. It should be obvious that the game first has to be played in order to obtain a score from it.
Asking a newborn baby what his favourite moment in the first 60 years of his live was doesn't make much sense.
You have to notify the main timeline that the game was finished. The best way to do this is to dispatch an Event from the game. Frames are totally unnecessary.
Your code could look something like this:
var game:Game = new Tetris();
addChild(game);
game.addEventListener(GameEvent.FINISH, onFinish);
function onFinish(e:GameEvent):void
{
trace("finished game with score " + game.score);
}
If you want to update the exterior score sum while the game is running (to immediately reflect any change in the score, not just when the game is finished), your best bet is to create a ScoreModel for the score which you pass to the game, the Game. The Game modifies the ScoreModel, which in turn causes it to dispatch Events:
var score:ScoreModel = new ScoreModel();
var game:Game = new Tetris(score);
addChild(game);
score.addEventListener(Event.CHANGE, onScoreChange);
function onScoreChange(e:Event):void
{
trace("score changed to " + score);
}
Both examples are "what your code could look like"-type of examples. There are many questions about how to dispatch events that explain how to do this in more detail.
Something that came up in the comments from #Jezzamon:
I'm pretty sure you're accessing the variable total correctly, otherwise I would expect it to cause an error (you can test this by trying to run trace(symbol1.variableNameThatDoesntExist)).
No, there cannot be an error for accessing a variable as seen in the question. The reason for that is that the property is accessed on a MovieClip object, which is a dynamic class. As such, the compiler doesn't know if accessing a particular property is valid, because that can change at runtime. And because nothing else relies on the value to be valid, there isn't a runtime error either.
Here's some example code to illustrate this:
trace("toString: " + {}.toString); //toString: function Function() {}
trace("bananas: " + {}.bananas); //bananas: undefined
This is one of the reasons why using MovieClip can be a bad idea. In addition to that, the Flash IDE modifies the code behind the scenes. That can lead to unexpected execution of code. A purely code based workflow sure is advantageous in this regard and recommended.

Related

Flash AS3 game loop : functions on separate frames

I want to use this to keep my functions on the current frame
function gameloop(e:Event) {
if(currentFrame > 1){
return;
}
}
But I also need to have functions in the game loop separate from frame 1, I just can't do that or else I get the error
duplicate function definition
I need help, and any is appreciated
It sounds like you aren't using OOP, and that is alright. Your problem is that you're remaking functions in subsequent keyframes. If you want to avoid using classes in AS3, the best way is to have a central layer with a single keyframe that spans the entirety of your movie. You put all your global variables and function on there. Then you can access them throughout the entire movie. You are getting a 'duplicate function definition' error because you are rewriting a function rather than extending its scope within the timeline.

Array and EnterFrame eventlistener

I have a problem that I hope you can help me resolve. I made that code:
var dates_array:Array =[y1,y2,y3];
var i= 1;
for each(var dates_sym:MovieClip in dates_array){
dates_sym.visible=false;
};
france_map.addEventListener(Event.ENTER_FRAME, fnCheckDate);
function fnCheckDate (evt:Event):void{
var i = france_map.currentFrame;
}
function fnDateSym (evt:Event):void{
dates_array[i].visible=true;
}
It is supposed to make a symbol (y1, y2 or y3 (there are more symbols, but didn't put them in the code for clarity) appear depending on what frame the main symbol is. When I compil, it shows no errors, but when I try it in my app, nothing happens.
I'm still a beginner, and I really don't see what's wrong.
If you need more context I can give it. Thanks in advance.
Jeryl
Your fnCheckDate function is called on enter frame, but that function never does anything except setting i. The other function - fnDateSym - sets the visible property based on the value of i. Which is what you want - but fnDateSym is never called anywhere in your posted code.
That may just be because you've left out some code. I'm guessing you might be calling fnDateSym from elsewhere and expect it to use the global i, as set by fnCheckDate. And yes, it will use the global i. But fnCheckDate doesn't set the global i:
var i = france_map.currentFrame;
The var keyword declares a variable within the current scope. A function creates a new scope. In other words, you're declaring a variable i local to your function and assigning the currentFrame value to that - rather than to the already existing variable i in the global scope (var i = 1). When your function exits, the local i is "lost" - and the global i hasn't changed - it will still be 1.
So the quick fix is to simply change it to:
i = france_map.currentFrame;
Now you're not declaring a new variable, but rather setting the value of your global i variable.
ETA: A bit of "teaching you how to fish rather than giving you a fish"... An easy way to debug these kinds of issues is to check the value of your variables using the trace function. For example:
function fnDateSym (evt:Event):void
{
trace("i is:", i);
dates_array[i].visible=true;
}
Now, if you don't see any traces in the output window that means your function isn't called at all. If you constantly see "i is: 1" then you know that i doesn't change and that this is the root of the problem. You could just use trace(i) - I just tend to add some kind of text to the trace - makes it easier to tell what each line in the output is, when you have more traces.
Unrelated, just a bit of code review...
Note that ENTER_FRAME is triggered on every frame refresh. I.e., it doesn't mean "when I enter a new frame on the timeline". It simply means, "when a frame is drawn in the player". In other words, it's called 24 times per second - or whatever frame rate you've chosen in Flash - no matter if currentFrame doesn't change (e.g. because you've called france_map.stop()).
This may be fine in your case - after all, setting visible to true 24 times per second doesn't actually cause any side effects. If you're doing more than that, however, it may be wasteful - or it may cause unexpected issues, since it's called more often than you really want.
One way to make something similar to a "enter timeline frame" event would be:
var previousFrame:int; // used for storing the last currentFrame we encountered
mc.addEventListener(Event.ENTER_FRAME, enterFrameListener);
function enterFrameListener(event:Event):void
{
// Are we on a different frame than last time?
if (previousFrame != mc.currentFrame)
{
currentFrameChanged();
previousFrame = mc.currentFrame;
}
}
function currentFrameChanged()
{
// Do stuff that should be done when the current frame changes
// - rather than on every frame refresh.
}
It's hard to tell exactly how you're doing things (again, because it seems a call to fnDateSym is left out) - but depending on how fnDateSym is called, mostly you wouldn't need fnCheckDate at all. Just do:
dates_array[france_map.currentFrame] = true;
Other than that, just for "niceness", you may want to declare the type for i:
var i:int = 0;

Loading a movie clip using SharedObject/AS3

Ok, so I'm working on a quiz game for work. I have each question on its own movie clip (I know that's not the preferred method, but it's what I'm most familiar with and a compressed project timeline kinda forced my hand).
Because players will only be able to play the game once (there's a prize involved), I'm attempting to implement a "save/load" system which will allow players to pickup where they left off, in case their browser crashes, they accidentally close the game window, etc. I already have a SO setup to accept save data. So for example, I have the following code on frame 1 of the Q1 scene:
var currentLevel = "Q1"; //first time the var is defined. "Q1" is the name of the scene
answersSO.data.currentLevel = currentLevel;
answersSO.flush();
And I have the following code on frame 1 of the very first scene of the movie:
function checkProgress() {
if(answersSO.data.currentLevel != undefined) {
currentLevel = answersSO.data.currentLevel;
MovieClip(this.root).gotoAndPlay(1, currentLevel);
} else {
gotoAndPlay(2);
}
}
checkProgress();
First, I gotta say that I'm a real nub at AS. I test play the game up to the Q1 scene, then close the window. I restart the game and it instantly skips all of scene 1 and proceeds to scene 2 (which is an intro to the game, not Q1). No error is thrown.
What I'm looking to do is save some data to the currentLevel variable, and save that variable to the SO. At the start of the game, the script should check if the SO has any data in it. If not, then there is no save data—proceed as normal. If there is data, load it and play the last recorded scene the player was at.
I can't figure out (1) how to get this working and (2), of somewhat less importance, why no error is being thrown.
EDIT!
This is my updated code:
stop();
import flash.net.SharedObject;
var answersSO:SharedObject = SharedObject.getLocal("PWFGame"); //DECLARE SO VARIABLE
var currentProgress = "";
//CHECK SO FOR PROGRESS
checkProgress();
function checkProgress() {
if(answersSO.data.currentLevel == null) {
nameField.text = "Enter Name Here";
gotoAndPlay(2);
} else {
currentProgress = answersSO.data.currentLevel;
MovieClip(this.root).gotoAndPlay(1, currentProgress);
}
}
It does work, but the last line in the else statement is acting strangely. It skips over the first scene completely and plays the next scene from frame 1 (which is called "Intro"). Even if I change currentProgress to "Q1" it does the same thing. Why would this line of code work elsewhere and not here?
SharedObjects can be deleted by the user. A player could delete that file and start again.
If there is a login name, you should store that data on the server using a server side script (php, asp, etc.)
So add a check at the beginning and let the user play just if his name has not been stored on the server. Than call this list form flash at the beginning of the game.
For the browser crash, you can store the data only when the game is ended. So when you refresh the page you can start it again.
If there is no username, you should get other data, but it isn't so simple as an IP could change and more important data can't be retrieved by the flash player (you can do it with a desktop application made with AIR).
At the and...
.gotoAndPlay(1, currentLevel);
Remeber that the first value is the scene and the second is the frame.
Nadia
Ok, after much digging, I've discovered that gotoAndPlay() on frame 1 can cause issues. I moved the updated code block (seen above) to frame 2, and everything works.

Having problems with hitTestObject-ing a child

I've just started to learn actionscript for a month or so, and I've been stuck on this part of the code for about 2 days now ><
So basically, I wanted to write a hitTestObject in a movieclip ("fire_mc") to detect if it overlaps the the child I added on stage (enemy)
So here's what I wrote in the main stage...
var newtarget:enemy=new enemy();
stage.addChild(newtarget);
newtarget.x=40;
newtarget.y=30;
and every time I traced the newtarget in the fire_mc, it turns out to be NULL...
So should I be tracing enemy or newtarget? (Cuz I tried both and nothing works).
And how can I hitTestObject in the fire_mc movieclip?
Is it possible for me to hitTestObject newtarget if I were to create multiple newtarget-s?
If not, what should I do?
And can someone tell me the difference between root, and MovieClip(root) (Because sometimes in a movieclip I have to use the former one to work, and sometimes the latter, and I have no idea why cuz I'm all referencing to the same place)
Sorry for these simple and lengthy questions, I'm really just a noob and I tried looking up for answers in the web for hours, but nothing helpful turned up><
Thanks in advance :)
In this statement
var newtarget:enemy=new enemy();
var - keyword used to define varibles, newtarget - variable name in which pointer to new class instance stored, :enemy - data type (the class name), new - keyword used to create new class instances, and finally enemy is class constructor (by the way there is a rule of good manners by which class names are capitalized)
So answer for you question which should you use when you want check is some is overlapping is 'newtarget'.
Now about hit test - all you need do to check if two objects hit each other is correctly use their references from the part of project where your code is writen.
For example if you have your fire_mc on MainTimeline created by IDE, and code of creation of you enemy instance stored in newtarget sameplace, then if you check will be placed in frame of MainTimeline where both object present it will be like this
fire_mc.hitTestObject(newtarget);
or this
newtarget.hitTestObject(fire_mc);
All these statements give you same result - if objects intersect each other you have true returned.
If you created 'newtarget' on MainTimeline and checks will be from fire_mc (which is on MainTimeline to) frame, then code will something like that
this.hitTestObject(MovieClip(root).newtarget);
Now about root. Primarily it is a property of DisplayObject in which reference to the top-most display object in swf-file structure is stored. So as such it is inherited by all child classes. So here's the trick. When you try get your objects in swf structure using root here the differences are based on the fact that root always return object as DisplayObject and that means what if you object contains something that DisplayObject shouldn't you can't get it. So you must convert returned reference to need data-type usign MovieClip(...).

Database for a multi-user RPG

I'm making a Flash turn-based RPG to practice OOP (who doesn't :P) I have a pretty good setup with the Weapons, Items, and all that Jazz. Though I'm currently considering how I will make my characters.
Currently I have an player and enemy class that extends the battler class.
Battler
/ \
/ \
Player Enemy
My player class has some functions that initialize the player itself, adding the graphics and all that. My party class calls on player, passing a paramater like so: player.setup(1) with 1 being the playerID.
To Clarify this is my player pseudocode:
{ setup(player_id)
player = **??????player_id??????????**
name = player.name
character_name = player.character_name
character_index = player.character_index
weapon_id = player.returnWeapon
/*---------
armor1_id = player.returnArmor //increase for other body parts
----------*/
level = player.level
}
My question, or more of a problem is how I will store the player data. I need to have many players as this is a game with many players in a party.
How will I actually use something like player.returnArmor ? Because when I do that it just calls a function, and it will not know who that player is (I guess I could use parameters, like player.returnArmor(player) but I think there is a better way to do this.
Any language is welcome, but just so you don't use assembly language as an example ;), C++, Actionscript 3, Ruby, and/or Java is fine. Please Help Me! Thank you in advance.
In AS3 you can have static and instance functions. If you call player.returnarmor(), you're calling a static function. You want to have an instance function, and call it for the instance of the player whose armor value you want.
If you have a few (<4) characters, you can just have named variables for each, but more than 3 or 4 and you should just have an array or other container for them.
var mainProtagonist:player;
var spunkySidekick:player;
var whiteMage:player;
var players:Array = new Array();
players.push(mainProtagonist);
players.push(spunkySidekick);
players.push(whiteMage);
Then to get a player's armor...we'll say you want the spunky sidekick's armor:
players[1].returnarmor();
// or
spunkySidekick.returnarmor();
You might have an array of all the players in existence, as well as another array, when used in battle, with just the players in the current party/battle. That way your enemies can target players at random, and only from those currently in the battle.
It might be worth considering using an entity system, where each item in the game is treated as a collection of unrelated properties (location, velocity, bitmap/mesh) which can be managed separately. This tends to make the hard problems easier (scalability, synchronisation, storage).
http://www.tomseysdavies.com/2011/01/23/entity-systems/
http://www.richardlord.net/blog/what-is-an-entity-framework
http://www.richardlord.net/blog/why-use-an-entity-framework