Hi Daniel,
I don't understand how you imagine this inventory system: how does it look ? how does it work ?
From a simplified perspective I understand you have a list of items that will be loaded from an external source(csv file parsed using LoadVars, xml file, etc.) and you want to display them.
I would split it into this:
- a data source(txt,xml,etc.)
- a data provider - in the end you will have items for the invetory,each
item will have properties(label,image, price, etc.)
- a draw/render method (items in a horizontal/vertical list, tile list, data grid, etc.)
For displaying the item dinamically,
I recommend having a look at the MovieClipLoader class. You could use MovieClip's loadMovie() method, but MovieClipLoader is more flexible(you can find out if the item is loading(%), get it's dimensions, etc.) as opposed to the loadMovie() method.
Regardless of your data source, you will end up with an array of inventory objects that will have properties I presume.
Here is a basic approach to displaying inventory items:
//using dummy data, you would populate the array by parsing loaded vars or xml, whatever works best for you
var dataProvider:Array = [];
var dummyItems:Number = 20;
for(var i:Number = 0 ; i < dummyItems ; i++) dataProvider[i] = {label:'item '+i,source:'http://stackexchange.com/images/icon/stackoverflow.com'};
//make a container
var inventory:MovieClip = this.createEmptyMovieClip('inventory',1);
var inventoryMask:MovieClip = this.createEmptyMovieClip('inventoryMask',2);
inventoryMask.beginFill(0);inventoryMask.lineTo(Stage.width,0);inventoryMask.lineTo(Stage.width,50);inventoryMask.lineTo(0,50);inventoryMask.lineTo(0,0);inventoryMask.endFill();
inventory.setMask(inventoryMask);
//add items to it
for(i = 0 ; i < dummyItems ; i++) makeInventoryRenderItem(dataProvider[i],inventory,i);
//scroll on mouse over
inventory.onRollOver = function():Void{
inventory.onEnterFrame = function(){
inventory._x = -_xmouse;//this is just a stub, replace with any navigation method you wish
}
}
inventory.onRollOut = function():Void{
delete inventory.onEnterFrame;
}
//make a movie clip with a loader and a label
function makeInventoryRenderItem(data:Object,container:MovieClip,index:Number):Void {
var renderItem:MovieClip = container.createEmptyMovieClip(data.label,index);
var loader:MovieClipLoader = new MovieClipLoader();
loader.loadClip(data.source,renderItem);
var handler:Object = new Object();
handler.onLoadInit = function(target:MovieClip):Void{
target._x = (target._width + 2) * index;
var label:TextField = renderItem.createTextField(data.label+'Label',renderItem.getNextHighestDepth(),0,0,40,22);
label.text = data.label;
}
loader.addListener(handler);
}
and here's a preview:
Note that this is not a fast/efficient way of writing it, but is a simple one, to illustrate the idea easier.
A different approach:
As another option, if filesize isn't a problem, you could use components(you can get about 70KB of bload just from them). An advantage is, there already are ways to handle data without touching too much code and you can either use hacky way to display your items, or create custom cell renderers.
Here's a basic approach using a List and a XMLConnector:
Add a List component to the stage,
name it ls
Add a XMLConnector (from the Data components) and name it xml
- Create an xml file with the structure you choose.
I used a structure like this:
<data>
<item label="item 1" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 2" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 3" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 4" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 5" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 6" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 7" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 8" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 9" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 10" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 11" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 12" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 13" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 14" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 15" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 16" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 17" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 18" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 19" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
<item label="item 20" source="http://stackexchange.com/images/icon/stackoverflow.com"/>
</data>
In the Parameters tab of the Component inspector you need to set the URL to your xml,
and the direction to receive.
The next thing is to import the xml schema into the XML connector, so it can 'understand' the structure of your xml file. You do so by pressing the import schema button in the Schema Tab of the Component Inspector.It's the tiny button on the top right of the tab with the tiny blue arrow pointing downards. Also, make sure your results are selected.
You will see the results update and an array will be created from your xml, you can also see each object's property.
Now that the xml schema/structure is imported, we can create a binding. We do that by pressing the + icon the Bindings tab of the Component Inspector:
The Add Binding dialog will appear, this is where you select the Array element and press OK.
In my case it's called item, it could be called something else, depending on the xml, but the idea is you choose the element containing the repeating([n]) items.
The next step is to bind the incoming data to something, in this case, to our list component. Set the direction to out, then double click the bound to value:
The Bound To dialog will pop up. This is where we'll select the list and it's data Provider as the receivers.
That is all the component Inspector you need to do. Now you have something that loads and handles your xml and sends the data to the list when it's ready.
Now we just create an empty MovieClip, named Icon, we draw a 50x50 border, because it will hold the stackoverflow icon(48x48) inside, and we Export for Actionscript (Linkage)
These last steps involve 7 lines of actionscript.
In the main timeline we trigger the xml connector, we set the defaultIcon style property, set the row height, so the inventory image/logo will fit, and disable roll over, just to avoid redrawing on that event:
xml.trigger();//trigger the xml loading
ls.setStyle('defaultIcon','Icon');//use your library clip as an icon
ls.setStyle('useRollOver',false);//stop redrawing list item on rollOver
ls.rowHeight = 48;//you should know the size of the inventory item
Now the last 3 lines of code are quite hacky because what we're doing is using the Icon of the list(which usually is the same library item repeated) to find the index of the item from the icon clip itself, and so accessing the list, the data provider and therefore the data for each icon clip.
We place this code in the Icon movieClip:
var index:Number = parseInt(_parent._name.substr(7))-10;//hack #1 use the rendered icon clip's name property to get it's index
var image:MovieClip = createEmptyMovieClip('image',1);
image.loadMovie(_parent._parent._parent.dataProvider.getItemAt(index).source);//hack #2 'clip' up from the icon clip to the list to find the list and source property for current item
And that's it, you get a list that displays labes and images from an xml file:
This is an option if you are willing to use components, and just want a hacky way with less code. If you still want to use the components, but do it the right way, You need create a custom Cell Renderer, which will display data for each inventory item. There's a very good tutorial on the flash-db site for this.
HTH
UPDATE:
I've just read the rest of the comments.
@gmale is right, attachMovie is what you need if you plan to use items from the library.
you use it like this:
theContainerForYourItem.attachMovie('itemLinkageName','someOptionalName',depth);//note depth is a number
here's a simple test, you must change the itemSize and either linkage strings(either you have clips in the library with the same names the ones used in code, or you update the names in the code):
var selectedItem:MovieClip;//this will keep track of the selected item
var itemSize:Number = 67;//set this to the size of a inventory item
var inventoryIds:Array = ["New","Folder","Disk","Mail","Graph"];//item linkage ids, make sure you've got some movie clips in library with these ids, or update the array
var inventory:MovieClip = this.createEmptyMovieClip("inventory",0);//container
var level:MovieClip = this.createEmptyMovieClip("level",1);
//create items
for(var i:Number = 0 ; i < inventoryIds.length ; i++){
//create container for item
var itemContainer:MovieClip = inventory.createEmptyMovieClip('item'+i,i);
//draw border, invisible bg
itemContainer.lineStyle(1);itemContainer.beginFill(0,0),itemContainer.lineTo(itemSize,0);itemContainer.lineTo(itemSize,itemSize);itemContainer.lineTo(0,itemSize);itemContainer.lineTo(0,0);itemContainer.endFill();
//position, add library item
itemContainer._x = (itemSize+2) * i;//2 is just spacing
itemContainer.attachMovie(inventoryIds[i],'icon',0);
itemContainer.onPress = itemSelected;//selec item
}
function itemSelected():Void{
//if there was previously an item removed, restore it...depends on your game's logic, u need clicks though
if(lastItem != undefined) restoreItemToInventory();
trace('selected item is: ' + inventoryIds[this.getDepth()]);//trace ths selected item
this.getInstanceAtDepth(0).removeMovieClip();//and remove the icon from the invotory
delete this.onPress;//disable clicks
lastItem = this;//update the last Item for restoring
//draw an item inside the level
var levelItem:MovieClip = level.attachMovie(inventoryIds[this.getDepth()],'icon',0);
levelItem._x = Stage.width * .5;level._y = Stage.height * .5;//position item;
levelItem.onPress = itemUsed;
}
function restoreItemToInventory():Void{
lastItem.attachMovie(inventoryIds[lastItem.getDepth()],'icon',0);//attach the icon again
lastItem.onPress = itemSelected;//make restore click
}
function itemUsed():Void{
this.removeMovieClip();//remove from stage
trace('item is: ' + inventoryIds[lastItem.getDepth()] + ' was used');//do whatever to hero/enemies
restoreItemToInventory();//restore to inventory or not
}
Note that for each library item I use a container. The reason for this is, when I remove an item, in fact I just the remove the library item the container holds, and the container is still there, and mentains it's depths, which is the same as the index of the item in the array. This is used later to remove/attach inventory items. In general it's a bad practice, since there are tightly coupled elements, but for the sake of a simple demo, will do.
If in your game, new items will be added(player won't have all possible items at once) and removed, used...it might also be worth learning how to use the Array class, especially the splice() method which will allow you to add, remove items from an array at a given index. based on your updated inventory array you will display the items and setup interactivity.