How to push instantiated MC into Array dynamically? - actionscript-3

Im really stuck. I have 5 MC´s that are being spliced from one array at a certain time. In that same function I want to push another movieclips into another array. The two arrays holds mc's that represent right or wrong answers. So when one question is being given a correct answer that questions visualisation alters.
This function holds a incrementing variable as I do want the mc's to be pushed by the user and one at the time. The thing is I cant seem to refer them properly.
I´ve tried
pQuestSum = this[pQuest + pQuestNumber];
and
pQuestSum = this[pQuest] + pQuestNumber;
and pretty much everything I´ve imagined would work...but the problem is I havent tried
the right thing.
when I trace pQuestSum (which would be the reference) I get an error saying thats its not a number.
this is one of 5 mc's named from 1-5:
var passedquest1:PassedQuest = new PassedQuest();
this is the vars that i try to to build a reference of
var pQuest = "passedquest";
var pQuestNumber = 1;
var pQuestSum;
var questCorrArray:Array = [];
if(event.target.hitTestObject(questArray[ix])){
removeChild(questArray[ix]);
questArray.splice(ix,1);
pQuestNumber ++;
pQuestSum = this[pQuest] + pQuestNumber;
trace("pQuestSum"); // NaN
questCorrArray.push(pQuestSum);
//trace(questArray.length);
pointsIncreased = false;
questPoints = 0;
}
How do I refer an existing movieclip when the reference consists of both a string and a number? Hope I made myself somewhat clear:)

If you had an instance of an object on your timeline called "passedquest1" (as an example), then you could access it this way:
var myObj = this["passedquest" + 1];
Or,
var pQuest = "passedquest";
var pQuestNumber = 1;
var myObj = this[pQuest+ pQuestNumber.toString()];
When you do this: pQuestSum = this[pQuest] + pQuestNumber;, you are trying add the number to an object (this[pQuest]), unless you have number/int var called "passedquest", this will result in NaN.

Related

Array of stagewebviews

I am in the need of multiple staged WebViews for holding multiple loaded websites at the same time.
I was hoping to manage this by making an array of webviews object, so i could call them later as view[i].
var view:Array=[webview0, webview1, webview2];
for each (var v in view){
var v:StageWebView = new StageWebView();
This gives error: 1086: Syntax error: expecting semicolon before left bracket.
Does someone know how to make an array like that?
You're doing something really weird there in terms of syntax. If you just want an Array of freshly created instances, it goes like that:
// Initialize the array.
var Views:Array = new Array;
// This loop counts 0,1,2.
for (var i:int = 0; i < 3; i++)
{
// Create a new instance.
// Yes, you can omit () with new operator if there are no arguments.
var aView:StageWebView = new StageWebView;
// Assign the new element to your array.
Views[i] = aView;
}
Or, if you need only 3 then you don't need to go algorithmic.
var Views:Array = [new StageWebView, new StageWebView, new StageWebView];
Not on topic but related:
Here is an example of one HTML page hold multiple StageWebViews
https://www.w3schools.com/graphics/tryit.asp?filename=trymap_basic_many

Save items(MovieClips) and dynamically create them

I made an invetory in AS3 which allows me to put items on slots in a closet, or in slots in the inventory. It completely works, but there is one problem.
In the game you are supposed to be able to buy new items and add them to the closet. I want this to be saved so that it is available the next time you play.
To do this, I want to save an Array to a SharedObject, then create the items dynamically from the array.
Right now I'm using the old fashioned hard coding for each object;
Itemwrench = new WrenchItem();
Itemwrench.x = par.toolCloset.kast_1.slotTC1.x + 400;
Itemwrench.y = par.toolCloset.kast_1.slotTC1.y + 245;
Itemwrench.gotoAndStop(2);
Itemwrench.name = "slotTC1";
Itemwrench.TC = 1;
NotinventoryParentTC.addChild(Itemwrench);
However, to add them dynamically I'd have to use getChildByName before it is added to the stage, which is not possible.
If possible could you show me how to do this correctly?
The information you need:
-The items are all stored in a closet with slots(Instances in the closet movieclip).
-The items need to get the name slotTC + the integer in a for loop.
-The name of the items change according to the slot number they are assigned when you take them out of the closet or put them back into the closet.
for(var i:int = 0; i < itemsInTC.length - itemsInTC.indexOf(e.currentTarget.name) - 1; i++)
{
nextSlotTC = "slotTC" + (itemsInTC.indexOf(e.currentTarget.name) +2 +i);
trace("Next Slot: " + nextSlotTC);
TempStrTC = "slotTC" + (itemsInTC.indexOf(e.currentTarget.name) +1 +i).toString();
trace("temp string: " + TempStrTC);
NotinventoryParentTC.getChildByName(nextSlotTC).x =
par.toolCloset.kast_1.getChildByName(TempStrTC).x + 400;
NotinventoryParentTC.getChildByName(nextSlotTC).y =
par.toolCloset.kast_1.getChildByName(TempStrTC).y + 245;
if(Boolean(NotinventoryParentTC.getChildByName(nextSlotTC)))
{
NotinventoryParentTC.getChildByName(nextSlotTC).name = TempStrTC;
}
}
This way I assign a new name and place them in the slot with the new name they received.
So now my question:
How do make it so that you can save the items to a shared object so that they are in the closet the next time you play the game.
Sorry for the long question.
Thanks in advance,
Milan.
You cannot directly store a DisplayObject in a SharedObject, as it contains memory links which will not be valid if you load such an object. A comon way to work around this is to store a significant data portion of that object. For example, you devise a following structure:
class SlotStructure {
public var slotID:int;
public var itemID:int;
public var itemName:String;
public var itemParameters:Array; // stuff simple types here
}
Then, for each of your items in inventory, you generate a SlotStructure object describing a particular inventory object. For your wrench it could look like this:
var ss:SlotStructure=new SlotStructure();
ss.slotID=1;
ss.itemID=getID(item); // assuming a function that returns a type of an item
ss.itemName=item.name;
ss.itemParameters=new Array();
for (var param:String in item) ss.itemParameters.push({name:param,value:item[param]});
Then you store an array of these into your SharedObject. To retrieve an inventory from a SharedObject you do:
public static const
registerClassAlias("SlotStructure",SlotStructure); // to be able to typecast from SO
for (var i:int=0;i<slots.length;i++) {
var ss:SlotStructure=slots[i];
var item:Item=new getClassFromID(ss.itemID)(); // a function that returns class
// say 1 - wrench, 2 - short sword, 3 - long sword, etc, one type=one ID
for each (var o:Object in ss.itemParameters)
item[o.name]=o.value;
placeIntoSlot(item,ss.slotID); // this does manipulation with x&y and display
}
A function getClassByID() might look like this:
private static const CLASSES:Array=
[StoneItem,WrenchItem,ShortswordItem,LongswordItem,...];
// manually stuff all your items in this!
public function getClassByID(id:int):Class {
return CLASSES[id];
}
The entire solution can be tailored to particular task, for example, in my game I have gems, that differ by location, type, size and score, so I store just these values and then I create new gems, set location, type, size and score with one function that sets all the other relevant parameters of that gem to align with stored info, and call it after making a gem with new Gem(). Your items might too be only worthy of a class name and ID in the class table, so store these with slot numbers and create objects that will have all their properties already set.

as3 dynamic variable within a loop

I need to have the screenPage var accessible for later calls. I am dynamically creating several pages. The issue is when I call screenPage.startDrag(); then it only drags the last page. How can I add a var in the name or make all the screenPages accessible through code?
Here is code in short:
var screenPage:MovieClip;
for(var p = 1; daTotalPages >= p; p++)
{
screenPage = new theFlagScreen();
}
Can I make screenPage a dynamic var and add like a 1 at the end and then a 2 and so forth with the loop?
Why not use an array ?
var pages:Array = new Array;
for(var p = 1; daTotalPages >= p; p++)
{
var screenPage:MovieClip = new theFlagScreen();
pages.push(screenPage)
}
Now you have an array containing all of your instances.
var myPage:MovieClip = pages[5] as MovieClip;
myPage.startDrag();
Also, the code you have above is creating an instance each time through, but since you then go ahead and create a new one each iteration and assign it to the same variable without storing it or adding it to the display list.... once you create a new one, the last one is marked for garbage collection.
The result is only the LAST instance you created still exists as it's the only one that has a variable that references it.
screenPage is a reference to just ONE thing. In your loop you keep overwriting it as you go and so you end up with it pointing to the very last instance of theFlagScreen... all the others are now lost.
You should follow prototypical's advice and store these instances in an array, that way you don't lose them.

AS3 class instances names

I really wonder. I made a MovieClip class Apple, I wrote a function that creates a new instance with a name "apple". Each time a new instance is pushed into an Array "apples". I call the function 5 times and I get 5 apples. I can manipulate them by calling them i.e. apples[0]. And when I trace my array I see 5 [object Apple] things. So maybe I don't really understand the structure of AS3 objects but shouldn't each object have a name?
When I set apple.name and get an array with 5 different names, I can't manipulate objects by names like apple1.x = 10. How does computer know which apple is where if each has own coordinates? Is the only way to call them: apples[0]-apples[4]? And if I create a code that should be same for all apples, how should I address the function, to "this"? Cause when I write class code I don't have any names yet...
For example, if I want to make Apple class a picture(MovieClip) that can be dragged, create any number of apples, up to a million, I can't possibly add apples[0].addEventListener, apples[1].addEventListener ... apples[1000000].addEventListener to the code. How do I make it global?
I'm asking cause when I'm directly coding for a specific instance, it has a name and I know exactly what am I addressing. And working with a class and making many objects I kinda don't... Sorry, I'm green
You don't need names to be able to access and manipulate your instances.
You can do something like this:
var apples:Array = new Array();
for (var i:int = 0; i < 100; i++)
{
var apple:Apple = new Apple();
apples.push(apple);
apple.x = Math.random() * 500;
apple.y = Math.random() * 500;
addChild(apple);
apple.addEventListener(MouseEvent.CLICK, onAppleClick);
}
function onAppleClick(e:MouseEvent):void
{
var ind:int = apples.indexOf(e.currentTarget);
var apple:Apple = apples[ind];
trace(ind);
apples[ind].visible = false;
//or
//apple.visible = false;
}
The same problem, huh? :)
For example Apple extends Sprite and inherits property name.
It's public, this means that you can change its name.
var apple:Apple = new Apple() ;
apple.name = "MegaApple" ;
Also, if you add the apple to stage, you can get him via name.
stage.addChild(apple) ;
get apple back:
var oldApple:Apple = stage.getChildByName("MegaApple") ;
But that never means, that you can use apple like that:
MegaApple.move() - because name of apple is supposed to be a property of apple, not a name of a variable.
Of course, you can create a lot of apples manually:
var apple1 = new Apple() ;
var apple2 = new Apple() ;
var apple3 = new Apple() ;
But if they all behave the same way, there is no point in doing. That's why you store them into array.
Hope you understand what I mean.

AdvancedDataGrid total sum of branch nodes

Introduction:
I have an AdvancedDataGrid displaying hierarchical data illustrated by the image below:
The branch nodes "Prosjekt" and "Tiltak" display the sum of the leaf nodes below.
Problem: I want the root node "Tavle" to display the total sum of the branch nodes below. When i attempted to do this by adding the same SummaryRow the sum of the root node was not calculcated correctly(Every node's sum was calculated twice).
dg_Teknikktavles = new AutoSizingAdvancedDataGrid();
dg_Teknikktavles.sortExpertMode="true";
dg_Teknikktavles.headerHeight = 50;
dg_Teknikktavles.variableRowHeight = true;
dg_Teknikktavles.addEventListener(ListEvent.ITEM_CLICK,dg_TeknikktavlesItemClicked);
dg_Teknikktavles.editable="false";
dg_Teknikktavles.percentWidth=100;
dg_Teknikktavles.minColumnWidth =0.8;
dg_Teknikktavles.height = 1000;
var sumFieldArray:Array = new Array(context.brukerList.length);
for(var i:int = 0; i < context.brukerList.length; i++)
{
var sumField:SummaryField2 = new SummaryField2();
sumField.dataField = Ressurstavle.ressursKey + i;
sumField.summaryOperation = "SUM";
sumFieldArray[i] = sumField;
}
var summaryRow:SummaryRow = new SummaryRow();
summaryRow.summaryPlacement = "group";
summaryRow.fields = sumFieldArray;
var summaryRow2:SummaryRow = new SummaryRow();
summaryRow2.summaryPlacement = "group";
summaryRow2.fields = sumFieldArray;
var groupField1:GroupingField = new GroupingField();
groupField1.name = "tavle";
//groupField1.summaries = [summaryRow2];
var groupField2:GroupingField = new GroupingField();
groupField2.name = "kategori";
groupField2.summaries = [summaryRow];
var group:Grouping = new Grouping();
group.fields = [groupField1, groupField2];
var groupCol:GroupingCollection2 = new GroupingCollection2();
groupCol.source = ressursTavle;
groupCol.grouping = group;
groupCol.refresh();
Main Question: How do i get my AdvancedDataGrid's (dg_Teknikktavles) root node "Tavle" to correctly display the sum of the two branch nodes below?
Side Question: How do i add a red color to the numbers of the root node's summary row that exceed 5? E.g the column displaying 8 will exceed 5 in the root node's summary row, and should therefore be marked red
Thanks in advance!
This is a general answer, without code examples, but I had to do the same just couple of days ago, so my memory is still fresh :) Here's what I did:
Created a class A to represent an item renderer data, extended it from Proxy (I had field names defined at run time), and let it contain a collection of values as it's data member. Once accessed through flash_proxy::getPropery(fieldName) it would find a corresponding value in the data member containing the values and return it. Special note: implement IUID, just do it, it'll save you couple of days of frustration.
Extended A in B, added a children property containing ArrayCollection of A (don't try to experiment with other collection types, unless you want to find yourself examining tons of framework code, trust me, it's ugly and is impossible to identify as interesting). Let B override flash_proxy::getPropery - depending of your compiler this may, or may not be possible, if not possible - call some function from A.flash_proxy::getPropery() that you can override in B. Let this function query every instance of A, which is a child of B, asking the same thing, as DataGrid itself would, when building item renderers - this way you would get the total.
When creating a data provider. Create an ArrayCollection of B (again, don't try to experiment with other collections--unless you are ready for lots of frustration). Create Hierarchical data that uses this array collection as a source.
Colors - that's what you use item renderers for, just look up any tutorial on using item renderers, that must be pretty basic.
In case someone else has the same problem:
The initial problem that everything was summed twice, was the result of using the same Array of SummaryField2 (sumFieldArray in the code) for both grouping fields(GropingField2 tavle and kategori)
The Solution to the main question: was to create a new array of summaryfields for the root node(in my intial for loop):
//Summary fields for root node
var sumFieldRoot:SummaryField2 = new SummaryField2();
sumFieldRoot.dataField = Ressurstavle.ressursKey + i;
sumFieldRoot.summaryOperation = "SUM";
sumFieldArrayRoot[i] = sumFieldRoot;
Answer to the side question:
This was pretty much as easy as pointed out by wvxyw. Code for this solution below:
private function summary_styleFunction(data:Object, col:AdvancedDataGridColumn):Object
{
var output:Object;
var field:String = col.dataField;
if ( data.children != null )
{
if(data[field] >5){
output = {color:0xFF0000, fontWeight:"bold"}
}
else {
output = {color:0x006633, fontWeight:"bold"}
}
//output = {color:0x081EA6, fontWeight:"bold", fontSize:14}
}
return output;
}