Inventory System, here we go again...
by Vlad I · in Torque Game Builder · 01/11/2012 (11:32 am) · 16 replies
I've searched the entire forums and was surprised to find so little about inventory system in TGB.
I'm trying to make an inventory for collectable objects, and use them in other levels.
Something like here:
What I found is that there are 2 ways of doing it one via GuiBuilder the other with TGB Builder using scene view and scripting it. I cant find much information about GuiBuilder and the reference doesn't explain much.
So I guess I'd stick to the old way. However do I need to create inventory window in every scene of my project?(30 scenes)
From what I get while using GuiBuilder it is sort of always dynamically in the background in every level and could be called by a hotkey or onMouseEnter. So is it possible to do it with out GuiBuilder?
thank you
I'm trying to make an inventory for collectable objects, and use them in other levels.
Something like here:
What I found is that there are 2 ways of doing it one via GuiBuilder the other with TGB Builder using scene view and scripting it. I cant find much information about GuiBuilder and the reference doesn't explain much.
So I guess I'd stick to the old way. However do I need to create inventory window in every scene of my project?(30 scenes)
From what I get while using GuiBuilder it is sort of always dynamically in the background in every level and could be called by a hotkey or onMouseEnter. So is it possible to do it with out GuiBuilder?
thank you
About the author
#2
01/11/2012 (4:39 pm)
Here you go man! This may be better used in Resources but I'll let others be the judge of that. Hope this helps!// This code only works for a single player game. It will not work with networking since it uses global variables. However, it could be tweaked in order to include multiplayer
// functionality if someone wanted to try.
// Any item you want in your inventory system will need to have the following variables in their datablock:
// name <-- gotta have it. It's the way the code distinguishes one item from another
// amount <--- if you don't add it, it will get added for you but this keeps up with how many the player has in their inventory
// maxAmount <--- if you don't want the player to have a cap on the amounts of items they carry, you'll need to take this out of the addToInventory code. The code will not
// work if you don't initialize this variable to something other than 0
// type <---- if you want to make specific lists from your inventory such as a list of all the player's weapons, you will need to specify the type of item it is
// salable <---- if you want the player to be able to sell items from their inventory but you don't want everything from the inventory to be salable, this is the way to do
// it. Set salable to true or false
// create an inventory list
if ( !isObject( $INVENTORY ) )
$INVENTORY = new SimSet();
// this list will be explained more later
if ( !isObject($LIST))
$LIST = new SimSet();
// add an object to the inventory
function addToInventory(%item){
// check to see if we already have at least one of the the same item we're trying to add in our inventory
if($INVENTORY.isMember(%item)){
for(%i = 0; %i < $INVENTORY.getCount(); %i++){
if(%item.name $= $INVENTORY.getObject(%i).name){
// found it. Since we already have at least one in the inventory, we will just add 1 to the amount we already have.
%item = $INVENTORY.getObject(%i);
%item.amount++;
// keep this part in if you want there to be a maximum amount of a particular item that the player can hold.
if(%item.amount > %item.maxAmount)
%item.amount = %item.maxAmount;
return;
}
}
}
// item doesn't exist in the list. Put it in there
else{
%item.amount++;
$INVENTORY.add(%item);
$INVENTORY.bringToFront(%item);
}
}
// remove an item from the inventory
function removeFromInventory(%item){
%item.amount--;
echo("Removing "@%item.name@" Amount left "@%item.amount);
if(%item.amount == 0)
$INVENTORY.remove(%item);
}
// checks to see if a specified item is in the inventory, SEND THIS FUNCTION THE ITEM NAME
function nameInInventory(%name){
for(%i = 0; %i < $INVENTORY.getCount(); %i++){
%object = $INVENTORY.getObject(%i);
if(%name $= %object.name)
return true;
}
return false;
}
// checks to see if a specified item is in the inventory, SEND THIS FUNCTION THE ITEM DATABLOCK
function inInventory(%item){
for(%i = 0; %i < $INVENTORY.getCount(); %i++){
%object = $INVENTORY.getObject(%i);
if(%object.name $= %item.name)
return true;
}
return false;
}
function getInventorySize(){
return $INVENTORY.getCount();
}
function inventoryToConsole(){
$INVENTORY.listObjects();
}
#3
01/11/2012 (4:41 pm)
// These are functions that utilize $LIST. $LIST is a way to make a secondary list of all the objects of a certain type in the player's inventory for you to use
// It's set up to use up to four different types of objects but you can easily add more if you need to
// For example, you could make a list of only the weapons in the player's inventory, or if you want a list of all equipment: weapon,armor,helm,accessory
function makeList(%type,%type2,%type3,%type4){
$LIST.clear();
for(%i = 0; %i < $INVENTORY.getCount(); %i++){
%item = $INVENTORY.getObject(%i);
echo(%item.type);
if(%item.type $= %type || %item.type $= %type2 || %item.type $= %type3 || %item.type $= %type4)
$LIST.add(%item);
}
}
function getListSize(){
return $LIST.getCount();
}
function listToConsole(){
$LIST.listObjects();
}
// Keep in mind, this also removes the item from the inventory list as well
function removeFromList(%item){
removeFromInventory(%item);
if(%item.amount < 1)
$LIST.remove(%item);
}
// This makes a list based on wether the item is salable. Very useful for selling back items to shops from the player's inventory
function makeSalableList(){
$LIST.clear();
for(%i = 0; %i < $INVENTORY.getCount(); %i++){
%item = $INVENTORY.getObject(%i);
if(%item.salable)
$LIST.add(%item);
}
}
#4
You mentioned you still have a Gui control with 4 item slots. So I still need to make a Gui control for it?
The more I look into this the more it becomes confusing, there is so little information about GuiBuilder it just amazes me.
Also where does this code go ? into .gui or .cs file?
01/12/2012 (2:57 am)
Thank you Andrew. Do you think my inventory window with items I collected will still be in other levels I load?You mentioned you still have a Gui control with 4 item slots. So I still need to make a Gui control for it?
The more I look into this the more it becomes confusing, there is so little information about GuiBuilder it just amazes me.
Also where does this code go ? into .gui or .cs file?
#5
Torque has great tools/editors for making your game look the way you want, but to make your game play the way you want, you're still going to need to write a lot of code.
01/12/2012 (1:52 pm)
Hey vlad. Technically you can put this code in any file as long as it gets executed when you run the game. It would make more sense to put it in a .cs file since it's obviously not a gui. It seems like you may need to read up on more tutorials/books about coding in Torque just in general. To implement an inventory system into your guis you will need to code it. You won't be able to do it using only the gui builder. The gui builder just saves time by allowing you to add, tweak and change the placement and look of your guis. Since everyone has a different concept of how they want their guis to work, you'll have to program their functionality yourself.Torque has great tools/editors for making your game look the way you want, but to make your game play the way you want, you're still going to need to write a lot of code.
#6
01/14/2012 (8:25 am)
Vlad definitely put the time in to learn Simsets it make your life easier making inventory systems or any type of databases you may need. You could also just make your own with arrays and variables but Simsets are more intuitive and there are many helpful methods already created to speed you along.
#7
The GUI Route
T2D's GUI Controls are what are used to make the actual Torque Game Builder! On one hand that proves you can build a full GUI. On the other hand, it isn't obvious you can make an "organic" layout like you seek with swirls and see-through parts, but I don't know for sure. In GUI parlance, it looks like you need a scroll list laid out horizontally and you need the list to hold icons which may overlap the edges a bit. You also need to drag-and-drop between the inventory and the scene, it seems. I'm not sure you can do that with the Torque GUI controls.
Try these tutorials for the best intro on the GUI. It's kind of hidden away unfortunately: http://tdn.garagegames.com/wiki/TGB/MiniTutorials
If you *can* use the GUI, then it will stay loaded while your scenes are loaded one by one.
The scene object route
Supposing your decide to use regular scene objects to make a GUI instead, which would probably be wise. You *may* get some help from the "persist" flag. (Look for it under the "scripting" tab of your scene objects). This will keep the scene objects saved outside of your scene and instead in a directory called "managed" where they will be loaded with each scene. But this means *every* scene, like your splash screen and stuff. (I can't use "persist" because they have trouble with behaviors scripts, surprise.)
Can I assume you consider each "room" of your hidden-object game to be a scene? You could probably save your "gui" in its own level file and then add it at the start of each scene via sceneWindow's addToLevel.
You will load new scenes so often that there may be some advantage to rewriting the loadScene function and its friends that are in the common directory of your project. Well, I'm assuming you could use more control of the process. The one that comes in the common dir is pretty, er, convoluted and simple.
Good luck!
01/14/2012 (9:18 pm)
I feel your pain and have little idea what you should do. Some quick thoughts:The GUI Route
T2D's GUI Controls are what are used to make the actual Torque Game Builder! On one hand that proves you can build a full GUI. On the other hand, it isn't obvious you can make an "organic" layout like you seek with swirls and see-through parts, but I don't know for sure. In GUI parlance, it looks like you need a scroll list laid out horizontally and you need the list to hold icons which may overlap the edges a bit. You also need to drag-and-drop between the inventory and the scene, it seems. I'm not sure you can do that with the Torque GUI controls.
Try these tutorials for the best intro on the GUI. It's kind of hidden away unfortunately: http://tdn.garagegames.com/wiki/TGB/MiniTutorials
If you *can* use the GUI, then it will stay loaded while your scenes are loaded one by one.
The scene object route
Supposing your decide to use regular scene objects to make a GUI instead, which would probably be wise. You *may* get some help from the "persist" flag. (Look for it under the "scripting" tab of your scene objects). This will keep the scene objects saved outside of your scene and instead in a directory called "managed" where they will be loaded with each scene. But this means *every* scene, like your splash screen and stuff. (I can't use "persist" because they have trouble with behaviors scripts, surprise.)
Can I assume you consider each "room" of your hidden-object game to be a scene? You could probably save your "gui" in its own level file and then add it at the start of each scene via sceneWindow's addToLevel.
You will load new scenes so often that there may be some advantage to rewriting the loadScene function and its friends that are in the common directory of your project. Well, I'm assuming you could use more control of the process. The one that comes in the common dir is pretty, er, convoluted and simple.
Good luck!
#8
Charlie you are awesome! I didnt know about "persist" :)
Yeah after 4 days of going through the boards and your help I decided to stick to The scene object route as Charlie described.
You are right each scene is a separate level.
I changed my inventory bar window just to 7 item slots ( no scrolling I dont want to spend my time on it, it's been 2 years since I started on my project). I mounted 7 item slots on the inventory bar and made it slide up and down onMouseEnter/Leave. I saved it as a separate level and named it 2tdSceneGrapgh-Inventory.
So, now I'm gonna search how to call it on different levels and how to keep objects in the item slots so I could use them in other levels.
Is this a sensible way?
01/15/2012 (2:25 am)
Thank you all guys.Charlie you are awesome! I didnt know about "persist" :)
Yeah after 4 days of going through the boards and your help I decided to stick to The scene object route as Charlie described.
You are right each scene is a separate level.
I changed my inventory bar window just to 7 item slots ( no scrolling I dont want to spend my time on it, it's been 2 years since I started on my project). I mounted 7 item slots on the inventory bar and made it slide up and down onMouseEnter/Leave. I saved it as a separate level and named it 2tdSceneGrapgh-Inventory.
So, now I'm gonna search how to call it on different levels and how to keep objects in the item slots so I could use them in other levels.
Is this a sensible way?
#9
I have made 2 levels and inventory level with the an inventory bar. 1st level as sceneGraph room1 , the 2nd level as sceneGraph room2, inventory level has sceneGraph name InventoryBar.
I added t2dSceneWindow(Inventory) in my mainScreen.gui :
And changed my game.cs:
Here is what I have in Inventory.cs :
And now when I run level01 (room01) I can see the level and my Inventory bar. The bar slides up and down onMouseEnter/Leave but the objects on the level can not be accessed. Looks like the HUD is on top of room01 blocks all mouse events for objects. The console doesnt show any errors.
What gives? I can give you my project to have a look if needed.
Thank you
01/15/2012 (11:28 am)
Ok, I got some progress, and got stuck on pickPoint to make my room1 (first scene) active.I have made 2 levels and inventory level with the an inventory bar. 1st level as sceneGraph room1 , the 2nd level as sceneGraph room2, inventory level has sceneGraph name InventoryBar.
I added t2dSceneWindow(Inventory) in my mainScreen.gui :
//--- OBJECT WRITE BEGIN ---
%guiContent = new GuiControl(mainScreenGui) {
canSaveDynamicFields = "0";
Profile = "GuiBlackContentProfile";
HorizSizing = "width";
VertSizing = "height";
Position = "0 0";
Extent = "1024 768";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
useVariable = "0";
new t2dSceneWindow(sceneWindow2D) {
canSaveDynamicFields = "0";
Profile = "GuiContentProfile";
HorizSizing = "width";
VertSizing = "height";
Position = "0 0";
Extent = "1024 768";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
lockMouse = "0";
useWindowMouseEvents = "1";
useObjectMouseEvents = "1";
};
new t2dSceneWindow(Inventory) {
canSaveDynamicFields = "0";
Profile = "GuiDefaultProfile";
HorizSizing = "width";
VertSizing = "height";
Position = "0 0";
Extent = "1024 768";
MinExtent = "8 8";
canSave = "1";
Visible = "1";
lockMouse = "0";
useWindowMouseEvents = "1";
useObjectMouseEvents = "1";
};
};
//--- OBJECT WRITE END ---And changed my game.cs:
// startGame
// All game logic should be set up here. This will be called by the level builder when you
// select "Run Game" or by the startup process of your game to load the first level.
//---------------------------------------------------------------------------------------------
function startGame(%level)
{
// exec("./ho.cs");
exec("./Inventory.cs");
Canvas.setContent(mainScreenGui);
Canvas.setCursor(DefaultCursor);
new ActionMap(moveMap);
moveMap.push();
$enableDirectInput = true;
activateDirectInput();
enableJoystick();
sceneWindow2D.loadLevel(%level);
// Inventory.setUseObjectMouseEvents( true );
Inventory.loadLevel("game/data/levels/Inventory01.t2d");
}
// MyObject is just an example name. This can be anything you name
function Inventorytrigger::onMouseEnter(%this, %modifier, %worldPosition, %clicks)
{
// Picks objects intersecting point with optional group/layer masks
// %worldPos is The coordinate of the point as
// either ("x y") or (x,y)
// Returns a space separated list of object IDs that intersect
%objects = room1.pickPoint(%worldPos);
// Find out how many objects were picked/intersected
%objectCount = getWordCount(%objects);
// Loop through all the objects to trigger their onTouchDown
for(%i = 0; %i < %objectCount; %i++)
{
// Get an object at the current index (%i)
// starts at 0, then increments by 1 each loop
%object = getWord(%objects, %i);
// Trigger the onMouseEnter for the current object
%object.onMouseEnter(%worldPos);
}
}
//---------------------------------------------------------------------------------------------
// endGame
// Game cleanup should be done here.
//---------------------------------------------------------------------------------------------
function endGame()
{
sceneWindow2D.endLevel();
moveMap.pop();
moveMap.delete();
}I also named the inventory bar as InventoryButton and gave it Inventorytrigger class in my Inventory01.t2d scene.Here is what I have in Inventory.cs :
function Inventorytrigger :: onMouseEnter (%this, %modifier, %worldPosition, %clicks)
{
%this.setLinearVelocityY(-60);
}
function Inventorytrigger :: onMouseLeave (%this, %modifier, %worldPosition, %clicks)
{
%this.setLinearVelocityY(60);
}And now when I run level01 (room01) I can see the level and my Inventory bar. The bar slides up and down onMouseEnter/Leave but the objects on the level can not be accessed. Looks like the HUD is on top of room01 blocks all mouse events for objects. The console doesnt show any errors.
What gives? I can give you my project to have a look if needed.
Thank you
#10
I'm no expert on this stuff, but I seem to remember that those mini-tutorials (I referenced above) had something about setting a gui control to a "modeless dialog" so that clicks pass through.
Good luck!
01/15/2012 (1:21 pm)
Wow that's pretty clever! I did not expect you making *another* scene window. I wasn't sure that would work. The good news is that your inventory should stay loaded between rooms, I think.I'm no expert on this stuff, but I seem to remember that those mini-tutorials (I referenced above) had something about setting a gui control to a "modeless dialog" so that clicks pass through.
Good luck!
#11
Really dont have a clue why I dont have mouse events in room1 with this :
01/16/2012 (3:35 am)
@Charlie GuiModlessDialogProfile doesnt change anythingReally dont have a clue why I dont have mouse events in room1 with this :
// MyObject is just an example name. This can be anything you name
function Inventorytrigger::onMouseEnter(%this, %modifier, %worldPosition, %clicks)
{
// Picks objects intersecting point with optional group/layer masks
// %worldPos is The coordinate of the point as
// either ("x y") or (x,y)
// Returns a space separated list of object IDs that intersect
%objects = room1.pickPoint(%worldPos);
// Find out how many objects were picked/intersected
%objectCount = getWordCount(%objects);
// Loop through all the objects to trigger their onTouchDown
for(%i = 0; %i < %objectCount; %i++)
{
// Get an object at the current index (%i)
// starts at 0, then increments by 1 each loop
%object = getWord(%objects, %i);
// Trigger the onMouseEnter for the current object
%object.onMouseEnter(%worldPos);
}
}
#12
Is there a way to make the inventory scene window tightly wrap your inventory objects? I see the position and size of it currently cover the entire window.
If this doesn't fix it, I think you'll have to combine your room and inventory graphs on each room load! This is just my best guess.
01/16/2012 (11:39 am)
Bummer. Well again, I'm outside of my zone of comfort here. I'm not testing this stuff as I make it up. :P However, I get the feeling that your "inventory" scene window is covering the room with a transparent sheet and eating the mouse before the room can get it.Is there a way to make the inventory scene window tightly wrap your inventory objects? I see the position and size of it currently cover the entire window.
If this doesn't fix it, I think you'll have to combine your room and inventory graphs on each room load! This is just my best guess.
#14
Yes I'm aware of that thread :) Prior to starting this thread I litterally went through all of them, which included words HUD, inventory, mouse events. Even TGE and iTGB forums.
William described a way he does it in the thread you refered to, but I didnt try it since it says dont try it if you are not skilled at C++, and obviously I'm not. Besides I dont understand where I have to go to change the code.
The other way is to manually reposition and resize the HUD to make the level scene recieve mouse events. I tried changing it and when I run the game the Inventory Bar was either too narrow or too small or over stretched. Is there a way to know exactly its position and extent so I could put into this? :
I really wish there was a tutorial for this. Really sad.
If I can't do it then I'd have to pay someone to do it for me. How much would it cost?
I just dont know why I bought TGB , when there was one kid 15 years old from Iran willing to do the entire game for 100$ in just C++ , he was mega fast and amazed me with his skills to fix anything with out even seeing the code. You'd just describe what the problem is and he'd tell you what to add or remove. Unfortunately I cant get a grip of him at the moment. Sorry for moaning like a bitch.
01/17/2012 (7:26 am)
Hey Patrick !!! Thank you man, glad too see you participating!Yes I'm aware of that thread :) Prior to starting this thread I litterally went through all of them, which included words HUD, inventory, mouse events. Even TGE and iTGB forums.
William described a way he does it in the thread you refered to, but I didnt try it since it says dont try it if you are not skilled at C++, and obviously I'm not. Besides I dont understand where I have to go to change the code.
The other way is to manually reposition and resize the HUD to make the level scene recieve mouse events. I tried changing it and when I run the game the Inventory Bar was either too narrow or too small or over stretched. Is there a way to know exactly its position and extent so I could put into this? :
new t2dSceneWindow(Inventory) {
canSaveDynamicFields = "0";
isContainer = "0";
Profile = "GuiContentProfile";
HorizSizing = "bottom";
VertSizing = "right";
Position = "0 0"; // <-- This is the position
Extent = "1024 768"; // <-- This is the size
MinExtent = "8 8";
canSave = "1";
Visible = "1";
hovertime = "1000";
lockMouse = "0";
useWindowMouseEvents = "0";
useObjectMouseEvents = "1";
};I really wish there was a tutorial for this. Really sad.
If I can't do it then I'd have to pay someone to do it for me. How much would it cost?
I just dont know why I bought TGB , when there was one kid 15 years old from Iran willing to do the entire game for 100$ in just C++ , he was mega fast and amazed me with his skills to fix anything with out even seeing the code. You'd just describe what the problem is and he'd tell you what to add or remove. Unfortunately I cant get a grip of him at the moment. Sorry for moaning like a bitch.
#15
05/29/2012 (8:39 am)
Who is this kid? Can I get his number? LOL
#16
So basically you are creating projections of your objects onto the GUI scenewindow.
Additionally since they aren't actually visible, you could also have them readjust their position intermittently without worrying about interpolation, allowing for moving objects. Though I would be careful with that -- find a way to limit it to when the object is moving, and even then only do it about 10 times a second at most.
Otherwise you don't need to worry about the efficiency of this either -- I routinely use several thousand visible objects on my screen and manage a good 50-60 fps on an old computer.
Edit: Let me know if I need to clarify, because I am absolutely certain that this would work, and would hate to see you give up on the dual scenewindow setup and the autonomy that entails.
05/30/2012 (11:12 am)
Okay, I believe I have a work around for you, since it looks like you are only using one scenewindow and your objects will not be moving. First, implement the callback passing from your GUISceneWindow to your gameSceneWindow, then give all the items you want to be clickable a field to distinguish them, for instance "Interactive", then:function t2dSceneObject::onAdd( %this ) {
if(%this.Interactive == 1){
%obj = new t2dSceneObject() {
Scenegraph = GUIWindow2d.getSceneGraph();
Position = %this.Position;
Size = %this.Size;
Rotation = %this.Rotation;
SuperClass = "clickPasser";
CollisionPolyList = %this.CollisionPolyList; // I think that affects clickable area
LinkedObject = %this;
};
%this.LinkedObject = %obj;
}
}
function clickPasser::onMouseDown( %this, %modifier, %worldPos, %clicks ) {
if(isObject(%this.LinkedObject))
%this.LinkedObject.onMouseDown( %modifier, %worldPos, %clicks );
else error("No objected linked to click passer " @ %this @ "!");
}
// Repeat for other mouse functions
function t2dSceneObject::onRemove( %this ) {
if(%this.LinkedObject !$= "" && isObject(%this.LinkedObject))
%this.LinkedObject.safeDelete();
}So basically you are creating projections of your objects onto the GUI scenewindow.
Additionally since they aren't actually visible, you could also have them readjust their position intermittently without worrying about interpolation, allowing for moving objects. Though I would be careful with that -- find a way to limit it to when the object is moving, and even then only do it about 10 times a second at most.
Otherwise you don't need to worry about the efficiency of this either -- I routinely use several thousand visible objects on my screen and manage a good 50-60 fps on an old computer.
Edit: Let me know if I need to clarify, because I am absolutely certain that this would work, and would hate to see you give up on the dual scenewindow setup and the autonomy that entails.
Torque Owner Andrew Son
inventory system and also utilizes a Gui that can contain up to 4 inventory items that pop up when a key is held down.
http://www.youtube.com/watch?v=5sHRABjAFdM&feature=youtu.be
If you're needing something like this you'll probably need to code it. It really isn't that bad though. Just create a new list of objects and add whatever you want to be in the inventory to it. You shouldn't need to create an inventory window in every scene unless you're wanting the inventory window to be a tangible object in your game. You can make an inventory gui in your PlayscreenGui and it will always stay there. To turn it on and off, simply use the gui's setVisible(false) method. I'll try to post some code I used for my inventory if I can later on.