Actionscript 3 - How to include current movieclip/root location to this.currentFrame? - actionscript-3

I am trying to make save progress thingie with sharedobjects, I´ve figured out how those work, but now I should just try to figure out how to make my "save progress" button to not just remember "this.currentFrame", but also if this is on main timeline, or if it is not, which movieclip this is in so that when I upload the sharedObject, it goes to right location, in main timeline or movieclip.
thanks!

I have a feeling SharedObjects may not be able to hold actual movie clip references and be able to restore them reliably (correct me if I am wrong on this), but you could just store objects with key-data pairs in the SharedObject instead of just the frame number alone. Or if you have an unknown number of frame numbers (and movie clips) to remember, store an array of key-data pair objects and loop through them when it comes time to load.
Example of a way to store the data for each clip:
var someClip:Object = new Object();
// some id that refers to the clip (maybe an array/dictionary index)
// (or try replacing with the actual reference to the movie clip to see if it works)
someClip.id ="clipName";
someClip.frameNumber = 1; // the frame number of the clip to remember
Then just store the 'someClip' object into an array in the SharedObject data.
Maybe a more 'compact way' is to do away with having a temporary object and store the key-data pair as just a string with a delimiter. For example, you could just store the string "clipName,1", then when it comes time to load, split along the comma to get the clip id and parse the frame number back to an int.
Or I guess you could also store the frame numbers in a clip id index'ed dictionary and store that in the SharedObject data (as it may save the int parsing step on loading).

Related

Type coercion in AS3 Flash

I am making a simple jumper game in AS3 in Flash, and at this moment everything works but I get this note:
Error #1034: Type Coercion failed: cannot convert 2 to flash.display.Scene.
at scratch_theGame_kat_fla::MainTimeline/startkeyPressed()
I understand there must be a type of an instance that is incorrect when this note appears, but as I search around in my code to find the perpetrator, I realized the "2" that it must be referring to is this:
function startkeyPressed(event:KeyboardEvent):void
{
if (event.keyCode,Keyboard.ENTER)
{
trace("new player");
startGame = true;
gotoAndPlay(( 1, Scene (2)));
}
};
This part of the code is what makes it go (when ENTER is pressed) from scene 1 to scene 2, where the actual game begins. Does anyone have any idea what I should change?
That line makes absolutely no sense in terms of AS3 logic:
gotoAndPlay(( 1, Scene (2)));
If you look into "Example" section of the official gotoAndPlay(...) help, there are two possible uses of this method:
You pass a single "frame" argument: it is either a 1-based int frame index, or it is a String label of the desired frame.
Two arguments where the second one is the String name of a Scene that is a portion of the main timeline, and the first is, again, the frame index or frame label inside the said Scene.
Now let's decipher what you have there. You are passing as gotoAndPlay(...) arguments. Feel the difference:
// Your version: one argument grouped with additional brackets.
gotoAndPlay(( 1, Scene (2)));
// Alternate version: no additional brackets, two arguments.
gotoAndPlay(1, Scene (2));
Then, what is Scene (2) expression, you might probably ask? It is called typecasting, an operation where you:
Explicitly state the exact class of something you are working with, because there are moments where compiler does not know exactly, like what is the exact class of Event.target object. There's a nice example, well explained: AS3: cast or "as"?
You want to explicitly convert data from one type to another (the said type coercion), mostly used between int or Number and String types.
Lets see:
function onEvent(e:Event):void
{
// Explicit typecasting.
MovieClip(e.target).nextFrame();
// Explicit typecasting through "as" operator.
var aFrame:int = (e.target as MovieClip).currentFrame;
// Explicit type conversion.
trace("The current frame is", String(aFrame));
So, you are trying to convince Flash Player that integer value 2 is somehow a Scene object, but there's no way it is, hence the exception thrown by the Flash Player because it does not understand what do you want it to do.
The correct notation of what you are trying to achieve (moving the playhead to the second Scene) would be probably:
gotoAndPlay(1, "Scene2");
The "Scene2" argument is a string literal that should represent the exact name of that second scene of yours, I couldn't know what it is but it should probably be named "Scene2" or "Scene 2" by default.

How do I keep a variable consistant even after seperate play sessions?

I have a variable area which stores a number.
When the app is restarted, it is reset back to it's original value. How can I keep area persistent after being closed?
I'm using Flash CS6 for Android
You'll have to save the variable. There's multiple ways to do this but using a SharedObject is the easiest IMO.
First thing is you don't actually create a new instance of the SharedObject class, you instead call the static function getLocal and this sets your variable. So somewhere near the start of your program you'll want something like this:
var gameSave:SharedObject = SharedObject.getLocal("gameSave");
This either creates a new locally persistent shared object if one does not exist or it grabs the one with the same initialized name ("gameSave") on your computer. This way you can access the saved variables across multiple playthroughs.
Now to save a variable you simply use the dataObject on the shared object and write values to it, then you call the function flush when you're done writing values to immediately save the shared object to your computer.
So saving your area value would look something like this:
gameSave.data.area = Main.area;
gameSave.flush();
After that you'll want to set the area value to whatever the saved value is when your game launches:
if (gameSave.data.area !== undefined) Main.area = gameSave.data.area;
We check if the value is undefined because it might not exist yet if you're playing the game for the first time and the area hasn't been saved yet.
Last thing in case you want to expand the scope of this and save more values: you can only write specific values to the shared object. The way I understand it is you can only write certain class types and primitives. If you try to write anything that's not a primitive or the exception classes, it'll automatically convert that item to an Object and it more or less becomes useless. The classes that it can accept that you'll probably use the most are: int, uint, Number, String, Boolean, Object, and Array. It has a few others like ByteArray and XML, but you'll either not use those at all or not use them very frequently. If you want to save any other class type you'll have to add that functionality yourself.

method .attachMovie() is no longer supported .Flash to AS3 conversion

I am completing an online tutorial and manipulating it suit my website. I've come across this code...
`// Create a menu item movie clip in the menu_mc instance on the main timeline
// for each item element offsetting each additional further down the screen
var item_mc = menu_mc.attachMovie("movieitem","item"+item_count, item_count);
item_mc._x = item_count * item_spacing;
item_count++;`
The following line gives me a problem (the method is no longer supported)
var item_mc = menu_mc.attachMovie("movieitem","item"+item_count, item_count);
How can i achieve this?
I've tried the following with no joy. message too many arguments?
var mItem:movieitem = new movieitem;
var item_mc = menu_mc.addChild(mItem,mItem+item_count, item_count);
addChild() only accepts 1 argument, which is the display object itself. Also, it looks like you're missing brackets when you create your object and by convention, class names are capitalised.
var mItem:movieitem = new movieitem();
Edit based on my comment
Looking at the documentation for attachMovie() for AS2 (wow, been awhile since I've looked at this), it takes in 3 arguments:
id:String, name:String, depth:Number
Now the id is used to grab a movieclip from the library. This is no longer needed as you've already created a movieclip object from your library in the line before:
var mItem:Movieitem = new Movieitem();
The second argument name is used to create a unique instance name for the created moviclip from the library. You don't really need this. In the line where you create the movieclip (see above), you already have a unique reference you can use to access the movieclip. Interestingly, attachMovie() also returns a reference -I've never ever found a use for the instance names given with the 'name' argument. I just use the reference returned to access it, which you are already doing.
The third argument depth determines which depth the movieclip is placed at. In your case, I am guessing that ' item_count' is just a number that increases, which effectively puts that movie clip at the highest depth when that line is executed. By default, addChild() will automatically do this for you and put the display object (your movieclip) at the highest depth within the parent at the time it is added. So, unless you wanted it at a specific depth/overlapping order, you don't really need to pass this in either. If you did want to add something at a specific depth, look at addChildAt()
Hence as mentioned before, you can just pass in the reference to your movieclip/display object in to addChild().

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(...).

Swapping specific movieclips after event?

I've created a drag and drop "puzzle" that has 16 unique pieces, each with their own instance name.
The problem I have is that there are 4 target zones made up of arrays (4 pieces per zone, but the order of the pieces in the zone does not matter). When a piece gets dropped into its correct zone, I would like to "switch" it with another movieclip and have that new movieclip be in the drop target area.
So, for each of the 16 puzzle pieces, I also have 16 unique companion pieces that need to somehow be paired up so that when the visible puzzle piece gets dropped, it is both removed from view, but also replaced with its companion piece.
Any ideas on how to do this?
MovieClip is a dynamic class, meaning that you can add properties to it at runtime. Leveraging this, you can assign a property to your original pieces and call it something like pairedPiece. In this property, you'll store the appropriate value (the name of its pair in the library).
var firstMovieClip:MovieClip;
// do whatever you need to set up your firstMovieClip, attach listeners, etc
firstMovieClip.pairedPiece = "SecondMovieClip";
// the following will occur when the piece is dropped and you need to swap it
var secondMovieClip:MovieClip = new (getDefinitionByName(firstMovieClip.pairedPiece) as Class)() as MovieClip;
secondMovieClip.x = firstMovieClip.x;
secondMovieClip.y = firstMovieClip.y;
firtMovieClip.parent.addChildAt(secondMovieClip, firstMovieClip.parent.getChildIndex(firstMovieClip));
firstMovieClip.parent.removeChild(firstMovieClip);