as3 Making a scrolling Movieclip - actionscript-3

I was wondering if its possible to create a scrolling MC after children have been added inside of it thats extends the parents boundaries. For instance I have a grade book UI mc, and inside of that I have a movie clip called student names. Inside student names I have code to add another movie clip that will dynamically show a students name from a db. The for loop repeats and another mc will be added below it. However, after they are all added, the children still show outside of the parent mc (student names). is it possible to make sure all the children inside student names stay inside the parent, and I can scroll down to see the rest of the children. (pretty much like a data grid) The children being added are light and dark shaded boxes containing the student names to be easily read.
function addStudentList():void
{
for (var i:int = 0; i < currentArr.length; i++)
{
if (i % 2 != 0)
{
var darkShade:mc_darkShade = new mc_darkShade;
darkShade.name = "darkShade";
darkShade.x = xCoordinate;
darkShade.y = yCoordinate;
darkShade.studentName.text = currentArr[i].lastname + ", " + currentArr[i].firstname;
studentArr.push(darkShade);
addChild(darkShade);
yCoordinate += 33.10;
}else
{
var lightShade:mc_lightShade = new mc_lightShade;
lightShade.name = "lightShade";
lightShade.x = xCoordinate;
lightShade.y = yCoordinate;
lightShade.studentName.text = currentArr[i].lastname + ", " + currentArr[i].firstname;
studentArr.push(lightShade);
addChild(lightShade);
yCoordinate += 33.10;
}
}
}
Thank you!
Josh

I found a reusable, touch scrollable list of items suitable for AIR apps targeted at iOS devices. You can download the source code and also one example here, if you want to see one example, before you download, check it here
The files use Greensocks ThrowProps so you will need to download as well.

Related

ActionScript 3 Adding images; different positions

In short, I have clickable objects with varying colours. I want these colours upon being clicked to appear in my placeholders (there will be 6). I currently have managed to code so that upon clicking any colour it is placed in the first placeholder.
In what way am I able to code to recognise that the first placeholder has been filled and that once filled, the second placeholder should become the target?
Preferably until the 6th has been filled and then stopped, so that the user can see all 6.
I am thinking something like a for loop would be fitting, but I am not sure how to go about it.
So far it's looking something like this:
//Placeholder
var placeHolder1:MovieClip = new MovieClip();
placeHolder1.x = 20;
placeHolder1.y = 245;
stage.addChild(placeHolder1);
//Placeholder2 (UNUSED CURRENTLY)
var placeHolder2:MovieClip = new MovieClip();
placeHolder2.x = 60;
placeHolder2.y = 245;
stage.addChild(placeHolder2);
//Click and select colours
var newBlue:cBlue = new cBlue();
numBlue.addEventListener(MouseEvent.CLICK, fBlue)
function fBlue(e:MouseEvent){
placeHolder1.addChild(newBlue);
}
var newRed:cRed = new cRed();
numRed.addEventListener(MouseEvent.CLICK, fRed)
function fRed(e:MouseEvent){
placeHolder1.addChild(newRed);
}
First, you probably want to learn about Arrays (or Vectors). Arrays/Vectors are lists, so you would put all your placeholders into an array:
var placeHolders:Array = [placeHolder1, placeHolder2];
Though, since there is a formula to your place holder creation, you probably would want to do this in a loop to make it DRYer (Don't Repeat Yourself)
This loop would create 10 place holders and add them to the array:
var placeholders:Array = new Array();
for(var i:int=0; i < 10; i++){
var placeHolder = new Sprite(); //if your not using timelines, just use Sprite instead of MovieClip as it's less overhead
placeHolder.x = 20 * (i + 1); //i starts at 0, and goes to 9
placeHolder1.y = 245;
stage.addChild(placeHolder); //add it to the display list
placeholders.push(placeHolder); //add it to the array
}
Now (continuing to be DRY), attached the same event listener to all your color buttons:
numBlue.addEventListener(MouseEvent.CLICK, selectColor);
numRed.addEventListener(MouseEvent.CLICK, selectColor);
In that event handler I've called 'selectColor' (see code comments)
function selectColor(e:Event):void {
//get the first element in the array
var placeHolder:Sprite = placeholders.shift(); //shift removes the first item from the array, and returns it
placeHolder.addChild(e.currentTarget); //e.currentTarget refers to item that you attached the event listener to, in this case either numBlue or numRed
}
So to summarize, this gets the first placeholder in the array, remove that item from the array, then adds color button that was clicked as a child of that placeholder.

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.

How do I select a part of an array? Or match parts of one array with parts of another?

I have some drag and drop function where there are 8 items (dragArray) that can be dropped onto 2 big 'landing zones' (matchArray). But since I don't want them lie on top of each other, I've made an array where they are given positions (posArray).
var dragArray:Array = [drag_1, drag_2, drag_3, drag_4, drag_5, drag_6, drag_7, drag_8];
var matchArray:Array = [drop_1, drop_1, drop_1, drop_1, drop_2, drop_2, drop_2, drop_2];
var posArray:Array = [{x:412,y:246},{x:530,y:218},{x:431,y:186},{x:470,y:152},{x:140,y:111},{x:108,y:162},{x:179,y:210},{x:113,y:254}];
When all 8 items are dropped, a check button appears and I want to check if they are dropped onto the correct big landing zone. I tried using the following:
if (posArray[i].x != dragArray[i].x || dragArray[i].y != posArray[i].y )
But then, not only the landing zone must match, but the positions must also match.
When I use
if (matchArray[i].x != dragArray[i].x || dragArray[i].y != matchArray[i].y )
it doesn't work, because the positions of the (dragArray) items don't match with the registration points of the (matchArray) landing zones.
Is there any way of checking if the first 4 (drag_1, drag_2, drag_3, drag_4) items match with ANY of the first 4 posArray positions and the last 4 (drag_5, drag_6, drag_7, drag_8) match with ANY of the last 4 posArray positions?
If the goal is to check each element of one set against all elements of another set then you'll need to have two loops, one "nested" within the other. The general form of this algorithm in AS3 looks like
var allMatched:Boolean = true;
for(var i:Number=0; i<array1.length; i++)
{
var matchFound:Boolean = false;
for(var j:Number=0; j<array2.length; j++)
{
if(array1[i]==array2[j])
{
matchFound=true;
break; //exit the inner loop we found a match
}
}
if(!matchFound)
{
allMatched=false;
break; //we found an element in one set not present in the other, we can stop searching
}
}
if(allMatched)
trace("Everything from array1 was found somewhere in array2"); //For an element a in the set A there exists an element b in set B such that a = b
Let me know if this helps

How to translate multiple labeled movieclip of Actionscript to Starling?

I'm new to starling and this may sound like a noob question but here goes nothing.
Imagine the following scenario (in Flash):
A movieclip named test
Test has 80 frames
Test has 4 labels at 20 frames each
When I script test in my project. I make it loop from label 0-1 (frames 1-19). Then I tell it to loop on label 2 on a certain event.
This way, I do not add or remove a movieclip or instantiate things just one.
Now, if I think about implementing it in starling. I'm thinking make 4 movieclips in flash. Export them as sprite sheets and then make four movieclips in the script. Add whichever moviclip needs to play in the juggler and similarly removechild it at that time.
This way, I'm adding the overhead cost of 'addchild' and 'removechild' everytime I want to switch between those animations. Is that a more cost effective way?
I presume you want to export a single clip, but control multipe(4 animations) rather than a single one. If this is the case, I wrote a few JSFL scripts a couple of years ago (when CS6 wasn't around to export spritesheets) which exported the main timeline of an .fla document as an image sequence, but used the frame labels in the filenames. This made it easy to integrate with TexturePacker. You can see video of it here.
Here's a JSFL snippet which will export a frame sequence with names generated based frame labels which should make it easy to manage in TexturePacker:
var d = (FLfile.getPlatform() == 'macos') ? '/' : '\\'; //delimiter
var doc = fl.getDocumentDOM(); //document
var tl = doc.getTimeline();tl.setSelectedLayers(0,true); //timeline
var cl = tl.layers[0]; //current layer
var numFrames = cl.frameCount;
var className = prompt("Name for your sequence", toClassName(doc.name.substr(0,doc.name.length-4)));
className = className.split('.')[0];//just in case the user adds .as
className = toClassName(className);//remove non alphabet chars
var docPath = doc.pathURI.substr(0,doc.pathURI.length - doc.name.length);
var exportPath = docPath+className+'_export'+d;
if(!FLfile.exists(exportPath)) FLfile.createFolder(exportPath);
fl.outputPanel.clear();
for(i = 0 ; i < numFrames; i++) {
if(cl.frames[i].name != ''){//if frame is labelled
tl.setSelectedFrames(i,i,true);
doc.exportPNG(exportPath+cl.frames[i].name+lpad(''+i,4)+'.png',true,true);
}
}
fl.trace("export complete!");
function lpad(number, length){
var result = '' + number;
while (result.length < length) result = '0' + result;
return result;
}
function toClassName(input){
return input.replace(/[^a-zA-Z]/g, "");
}
Also, I suggest having a look at generator tools like Dynamic-Texture-Atlas-Generator, Fruitfly, etc.

Re-stacking MovieClips in an Array

I was trying to make a similar thing with the game SameGame (ie. the block above the removed blocks fall downward). Before trying this with an Array that contains MovieClips, this code worked (tried it with int values). With MovieClips on the array, it seems not working the same way.
With int values, example:
popUp(0, 4): Before: 1,2,3,4,5,6,7,8,9,10; After: 1,2,3,4,6,7,8,9,10
But with MovieClips:
popUp(0, 4): Before: 1,2,3,4,5,6,7,8,9,10; After; 1,2,3,4
// Assume the numbers are movieclips XD
Basically, it strips everything else, rather than just the said block >_<
Here's the whole method. Basically, two extra arrays juggle the values above the soon-to-be removed value, remove the value, then re-stack it to the original array.
What could be wrong with this? And am I doing the right thing for what I really wanted to emulate?
function popUp(col:uint, row:uint)
{
var tempStack:Array = new Array();
var extraStack:Array = new Array();
tempStack = IndexArray[col];
removeChild(tempStack[0]);
for(var ctr:uint = tempStack.length-(row+1); ctr > 0; ctr--)
{
removeChild(tempStack[ctr]);
extraStack.push(tempStack.pop());
trace(extraStack);
}
tempStack.pop();
for(ctr = extraStack.length; ctr > 0; ctr--)
{
tempStack.push(extraStack.pop());
//addChild(tempStack[ctr]);
}
IndexArray[col] = tempStack;
}
PS: If it's not too much to ask, are there free step-by-step guides on making a SameGame in AS3 (I fear I might not be doing things right)? Thanks in advance =)
I think you just want to remove an element and have everything after that index shift down a place to fill what you removed. There's an inbuilt function for this called splice(start:uint, length:uint);
Parameters:
start - the index to start removing elements from
length - the amount of elements to remove
var ar:Array = ["hello","there","sir"];
ar.splice(1, 1);
ar is now -> ["hello", "sir"];
As per question:
Here's an example with different types of elements:
var ar:Array = [new MovieClip(), "some string", new Sprite(), 8];
ar.splice(2, 1);
trace(ar); // [object MovieClip], some string, 8
And further example to display the indexes being changed:
trace(ar[2]); // was [object Sprite], is now 8