Arrays and multi dimensional arrays
by Tim Doty · in Torque Game Builder · 03/31/2005 (5:58 pm) · 10 replies
I'm having trouble with arrays and the extra frustrating part is that it behaves differently when executing from file versus typing in the console. An excerpt of code from the file is:
This code is part of a .cs file. For testing I duplicated it with a different name so that it gets loaded twice. This did not alter, only extended, the behavior. $numDecks gets incremented at the bottom of each file. So after starting (and duplicating this .cs file) $numDecks is 2. However, the following produces errors of object not found.
However, the following work to address deck 0 and deck 1, respectively:
The thing is, using the variable $t instead of $cardDeck, I can execute the commands in the console and in that case:
so what gives? Any ideas?
$cardDeck[$numDecks] = new ScriptObject() {
Name = "TimDoty-Standard";
Face = true; // boolean for presence of a Face set
Back = true; // boolean for presence of a Back set
Width = 500; // cell width in pixels for a card
Height = 690; // cell height in pixels for a card
Scale = 0.005; // scaling factor for game dimensions
Size = 60; // number of cards in the set
FirstCard = 4; // index of first playing card
NumCards = 52; // number of regular playing cards
NumBacks = 60; // number of cards in the back set
};
if ($cardDeck[$numDecks].Face) {
// load images
for (%i=0;%i<$cardDeck[$numDecks].Size;%i++) {
if (%i / 4 < 10) %number = "_0" @ mFloor(%i / 4) @ "_0" @ %i % 4;
else %number = "_" @ mFloor(%i / 4) @ "_0" @ %i % 4;
%texturename = %path @ $cardDeck[$numDecks].Name @ "-Face" @ %number;
echo(%texturename);
$cardDeck[$numDecks].faceImageMap[%i] = new fxImageMapDatablock2D($cardDeck[$numDecks].Name @ %i @ "-FaceImageMap") {
mode = full;
textureName = %texturename;
};
// setup deck
$cardDeck[$numDecks,%i] = new fxStaticSprite2D() {
scenegraph = cardsSceneGraph2D;
};
$cardDeck[$numDecks,%i].setSize(%x SPC %y);
//$cardDeck[$numDecks,%i].setImageMap($cardDeck[$numDecks].faceImageMap[%i]);
$cardDeck[$numDecks,%i].suit = %i % 4; // 0 = spades, 1 = hearts, 2 = clubs, 3 = diamonds
$cardDeck[$numDecks,%i].rank = mFloor(%i / 4); // 1 = ace, 11 = jack, 12 = queen, 13 = king
// rank 0 are the "suit cards"
// rank 14, suit 0 is the high joker
// rank 14, suit 1 is the low joker
// rank 14, suit 2 is a blank card
// rank 14, suit 3 is the logo card
switch (%i) {
case 56:
$cardDeck[$numDecks,%i].suit = -1;
$cardDeck[$numDecks,%i].rank = 101;
case 57:
$cardDeck[$numDecks,%i].suit = -1;
$cardDeck[$numDecks,%i].rank = 100;
case 58:
$cardDeck[$numDecks,%i].suit = -1;
$cardDeck[$numDecks,%i].rank = -1;
case 59:
$cardDeck[$numDecks,%i].suit = -1;
$cardDeck[$numDecks,%i].rank = -2;
}
$cardDeck[$numDecks,%i].dump();
}
}This code is part of a .cs file. For testing I duplicated it with a different name so that it gets loaded twice. This did not alter, only extended, the behavior. $numDecks gets incremented at the bottom of each file. So after starting (and duplicating this .cs file) $numDecks is 2. However, the following produces errors of object not found.
$cardDeck[0,0].dump(); $cardDeck[0,1].dump(); $cardDeck[0].dump();
However, the following work to address deck 0 and deck 1, respectively:
$cardDeck.dump(); $cardDeck1.dump();
The thing is, using the variable $t instead of $cardDeck, I can execute the commands in the console and in that case:
$t[0,0].dump();
so what gives? Any ideas?
About the author
#2
In my code there is an array of card decks, $cardDeck[]. Each of those has an array of cards, $cardDeck[,]. I'm still getting a feeling for TorqueScript and have actually done it both as $cardDeck[,] and $cardDeck[].card[] -- the latter being more what you are doing.
What I really don't understand is why exec'ing the file produces a different result from doing it manually in the console. If I do the same commands manually then $t[0].dump() or $t[0,0].dump() provides the expected output, but if I exec the file and do $cardDeck[0].dump or $cardDeck[0,0].dump() then I get an object not found error. But $cardDeck[1].dump() does work. Just not $cardDeck[0].dump().
I can probably get it to work using your style of doing things... it just occurred to me why $cardDeck[0,0] wouldn't work, but I still don't understand why it works typing it in manually.
In a typed language I wouldn't have slipped like this (there I go with my crutches):
but
In other words the types mismatch. The only way I can think of to get that in C would be with cast pointers -- and even then you'd have to be careful if you tried to use pointer arithmetic. I don't know TorqueScript well enough to know if this would make [i]it fail or not, but it isn't a sound construct regardless.
03/31/2005 (8:12 pm)
Thanks for the response. I may have an incorrect understanding of multidimensional arrays in TorqueScript. I thought that the equivalent of C a[j][k] would be $a[%i,%j,%k].In my code there is an array of card decks, $cardDeck[]. Each of those has an array of cards, $cardDeck[,]. I'm still getting a feeling for TorqueScript and have actually done it both as $cardDeck[,] and $cardDeck[].card[] -- the latter being more what you are doing.
What I really don't understand is why exec'ing the file produces a different result from doing it manually in the console. If I do the same commands manually then $t[0].dump() or $t[0,0].dump() provides the expected output, but if I exec the file and do $cardDeck[0].dump or $cardDeck[0,0].dump() then I get an object not found error. But $cardDeck[1].dump() does work. Just not $cardDeck[0].dump().
I can probably get it to work using your style of doing things... it just occurred to me why $cardDeck[0,0] wouldn't work, but I still don't understand why it works typing it in manually.
In a typed language I wouldn't have slipped like this (there I go with my crutches):
$cardDeck[$numDecks] = new ScriptObject() {};but
$cardDeck[$numDecks,%i] = new fxStaticSprite2D() {};In other words the types mismatch. The only way I can think of to get that in C would be with cast pointers -- and even then you'd have to be careful if you tried to use pointer arithmetic. I don't know TorqueScript well enough to know if this would make [i]it fail or not, but it isn't a sound construct regardless.
#3
I began a post earlier trying to describe this, but couldn't prove to myself why it would affect your code the way it did, and couldn't validate the execution based on deskchecking, so wound up deleting it. Pretty sure however that the problem lies in what you said in your last post--the string expansion isn't working properly because of the added layer of the ScriptObject in there.
BTW, the reason your code doesn't work when typed in manually is because (unlike other script languages), each line of code typed in gets it's own scope, so any locally scoped variables go immediately out of scope as soon as that particular line is executed. I'm actually surprised that manually typing in the for loop didn't cause a "syntax error on input" error, since you couldn't close the scope block of the for loop in a single line...
03/31/2005 (8:57 pm)
Keep in mind that TorqueScript doesn't actually implement arrays at all. Instead, when your code goes through byte code compilation, it does string expansion to turn something like $playerDeck[0,0] into $playerDeck0_0, and $playerDeck[1,2,3] into $playerDeck1_2_3. I began a post earlier trying to describe this, but couldn't prove to myself why it would affect your code the way it did, and couldn't validate the execution based on deskchecking, so wound up deleting it. Pretty sure however that the problem lies in what you said in your last post--the string expansion isn't working properly because of the added layer of the ScriptObject in there.
BTW, the reason your code doesn't work when typed in manually is because (unlike other script languages), each line of code typed in gets it's own scope, so any locally scoped variables go immediately out of scope as soon as that particular line is executed. I'm actually surprised that manually typing in the for loop didn't cause a "syntax error on input" error, since you couldn't close the scope block of the for loop in a single line...
#4
I didn't see in your code where you initialized or incremented the $numDecks variable, so I added those, I also broke this beast down into functions so it is re-usable blocks instead of having to exec several files.
continued....
04/01/2005 (2:05 am)
Something like the following should work.I didn't see in your code where you initialized or incremented the $numDecks variable, so I added those, I also broke this beast down into functions so it is re-usable blocks instead of having to exec several files.
$numDecks = 0; // Make sure $numDecks is pre-initialised to a 0 value.
function createDeck()
{
// You could add arguements to the function and build your deck that way
$numDecks = $numDecks + 1; // We're adding a deck, so increase the counter
$cardDeck[$numDecks] = new ScriptObject()
{
Name = "TimDoty-Standard";
Face = true; // boolean for presence of a Face set
Back = true; // boolean for presence of a Back set
Width = 500; // cell width in pixels for a card
Height = 690; // cell height in pixels for a card
Scale = 0.005; // scaling factor for game dimensions
Size = 60; // number of cards in the set
FirstCard = 4; // index of first playing card
NumCards = 52; // number of regular playing cards
NumBacks = 60; // number of cards in the back set
};
return $numDecks; // Pass back the integer deck number
}
function createDeck2(%name,%face,%back,%width,%height,%scale,%size,%firstCard,%numCards,%numBacks)
{
// Build Deck from Arguements to the function
$numDecks = $numDecks + 1; // We're adding a deck, so increase the counter
$cardDeck[$numDecks] = new ScriptObject();
$cardDeck[$numDecks].Name = %name;
$cardDeck[$numDecks].Face = %face; // boolean for presence of a Face set
$cardDeck[$numDecks].Back = %back; // boolean for presence of a Back set
$cardDeck[$numDecks].Width = %width; // cell width in pixels for a card
$cardDeck[$numDecks].Height = %height; // cell height in pixels for a card
$cardDeck[$numDecks].Scale = %scale; // scaling factor for game dimensions
$cardDeck[$numDecks].Size = %size; // number of cards in the set
$cardDeck[$numDecks].FirstCard = %firstCard; // index of first playing card
$cardDeck[$numDecks].NumCards = %numCards; // number of regular playing cards
$cardDeck[$numDecks].NumBacks = %numBacks; // number of cards in the back set
}continued....
#5
04/01/2005 (2:05 am)
....continuedfunction buildFaceDeck(%deck)
{
// This seems to be something you'll call for multiple decks, just pass the deck number you want to work with
if ($cardDeck[%deck].Face)
{
// load images
for (%i=0;%i<$cardDeck[%deck].Size;%i++)
{
if (%i / 4 < 10)
{
%number = "_0" @ mFloor(%i / 4) @ "_0" @ %i % 4;
}
else
{
%number = "_" @ mFloor(%i / 4) @ "_0" @ %i % 4;
}
%texturename = %path @ $cardDeck[%deck].Name @ "-Face" @ %number;
echo(%texturename);
$cardDeck[%deck].faceImageMap[%i] = new fxImageMapDatablock2D($cardDeck[%deck].Name @ %i @ "-FaceImageMap")
{
mode = full;
textureName = %texturename;
};
// setup deck
$cardDeck[%deck,%i] = new fxStaticSprite2D()
{
scenegraph = cardsSceneGraph2D;
};
$cardDeck[%deck,%i].setSize(%x SPC %y);
//$cardDeck[%deck,%i].setImageMap($cardDeck[%deck].faceImageMap[%i]);
$cardDeck[%deck,%i].suit = %i % 4; // 0 = spades, 1 = hearts, 2 = clubs, 3 = diamonds
$cardDeck[%deck,%i].rank = mFloor(%i / 4); // 1 = ace, 11 = jack, 12 = queen, 13 = king
// rank 0 are the "suit cards"
// rank 14, suit 0 is the high joker
// rank 14, suit 1 is the low joker
// rank 14, suit 2 is a blank card
// rank 14, suit 3 is the logo card
switch (%i)
{
case 56:
$cardDeck[%deck,%i].suit = -1;
$cardDeck[%deck,%i].rank = 101;
case 57:
$cardDeck[%deck,%i].suit = -1;
$cardDeck[%deck,%i].rank = 100;
case 58:
$cardDeck[%deck,%i].suit = -1;
$cardDeck[%deck,%i].rank = -1;
case 59:
$cardDeck[%deck,%i].suit = -1;
$cardDeck[%deck,%i].rank = -2;
}
$cardDeck[%deck,%i].dump();
}
}
}
%deck = createDeck();
buildFaceDeck(%deck);
%deck = createDeck2("TimDoty-Standard","True","True",500,690,0.005,60,4,52,60);
buildFaceDeck(%deck);
#6
@Stephen: I wasn't clear enough about typing in manually: I didn't do the loop manually but I executed the commands inside the loop (not even all iterations). And, entered manually, it does work. That is (from memory),
@Harold: The code hasn't been cleaned up because I'm still planning it out. My goal here is to actually have as clean as possible an implementation done with T2D classes, reimplemented with C++ classes and reimplemented with the OO resource classes. Kind of a reference by example. I notice you increment $numDecks before using it rather than after. Incrementing after was deliberate to keep normal array indexing. Incidentally, have you tested your cleanup to work? (I can't check right now and will likely not have a chance to work on anything T2D for a few days.)
The reason I didn't break the code into functions is because it isn't sorted out yet how I'm going to handle different decks. There are at least four different types of decks so (some) of the loading code will have to be different. I'd already have the d*rn thing done in C++ or using the OO resource, but I'm trying to figure out how to do things with TorqueScript while not using the OO resource. Once I get a workable structure done in TorqueScript I can learn how to interface C++ and do a quick port (the OO resource version should be quite easy based on work I've done with it in another project).
Also, I didn't post all of the code, just the parts relevant to the multi-dimension array. In the current structure $numDecks gets initialized in client.cs before exec'ing the file. The reason for the structure (remember, I'm new to TorqueScript so I may be backwards here) is that I thought there was a function to exec all .cs in a directory. This way to add a deck you simply add the graphics and an appropriately named and adjusted .cs file. I was also planning on having all graphics for a deck (face side) in a single file, but with the limitations on imagemap size I've abandoned that part.
---
Was I right that using a ScriptObject then adding a dimension for the fxStaticSprite2D is causing the problem? Or is that an unknown?
04/01/2005 (8:54 am)
Thanks for taking the time to look through my code. I really appreciate it.@Stephen: I wasn't clear enough about typing in manually: I didn't do the loop manually but I executed the commands inside the loop (not even all iterations). And, entered manually, it does work. That is (from memory),
$i = 0;
$t[$i] = new ScriptObject() { .. };
$t[$i,$i] = new fxStaticSprite2D() { .. };
$t[0,0].dump();produces the expected dump output. But calling $cardDeck[0,0].dump(); gets an undefined object reference.@Harold: The code hasn't been cleaned up because I'm still planning it out. My goal here is to actually have as clean as possible an implementation done with T2D classes, reimplemented with C++ classes and reimplemented with the OO resource classes. Kind of a reference by example. I notice you increment $numDecks before using it rather than after. Incrementing after was deliberate to keep normal array indexing. Incidentally, have you tested your cleanup to work? (I can't check right now and will likely not have a chance to work on anything T2D for a few days.)
The reason I didn't break the code into functions is because it isn't sorted out yet how I'm going to handle different decks. There are at least four different types of decks so (some) of the loading code will have to be different. I'd already have the d*rn thing done in C++ or using the OO resource, but I'm trying to figure out how to do things with TorqueScript while not using the OO resource. Once I get a workable structure done in TorqueScript I can learn how to interface C++ and do a quick port (the OO resource version should be quite easy based on work I've done with it in another project).
Also, I didn't post all of the code, just the parts relevant to the multi-dimension array. In the current structure $numDecks gets initialized in client.cs before exec'ing the file. The reason for the structure (remember, I'm new to TorqueScript so I may be backwards here) is that I thought there was a function to exec all .cs in a directory. This way to add a deck you simply add the graphics and an appropriately named and adjusted .cs file. I was also planning on having all graphics for a deck (face side) in a single file, but with the limitations on imagemap size I've abandoned that part.
---
Was I right that using a ScriptObject then adding a dimension for the fxStaticSprite2D is causing the problem? Or is that an unknown?
#7
But on to my explanation.
In your problem you said:
worked to call deck 0 and 1 respectively, If you used $cardDeck.dump() vs. $cardDeck0.dump() and it worked, your $numDecks variable was not being defined prior to the script being executed.
$deck[0] = new ScriptObject();
$deck[0,1] = "Deck 1, Card 1";
should work as either.
or
TorqueScript arrays aren't true arrays so much as they are Variable Name shortcuts.
------
So what I still think is happening is that $numDecks is not initialised when the first file runs, add at the begining of the file:
Another way to check would be to do:
04/01/2005 (12:08 pm)
No I hadn't tested it... :)But on to my explanation.
In your problem you said:
$cardDeck.dump(); $cardDeck1.dump();
worked to call deck 0 and 1 respectively, If you used $cardDeck.dump() vs. $cardDeck0.dump() and it worked, your $numDecks variable was not being defined prior to the script being executed.
$deck[0] = new ScriptObject();
$deck[0,1] = "Deck 1, Card 1";
should work as either.
echo($deck[0]); echo($deck[0,1]);
or
echo($deck0); echo($deck0_1);
TorqueScript arrays aren't true arrays so much as they are Variable Name shortcuts.
------
So what I still think is happening is that $numDecks is not initialised when the first file runs, add at the begining of the file:
echo("-----------------------------------------------------------");
echo("$numDecks value is:" SPC $numDecks);
echo("-----------------------------------------------------------");Another way to check would be to do:
$cardDeck_0.dump(); or $cardDeck[,0].dump();
#8
so I know it is supposed to be initialized before getting used. I'm positive that's it. Thanks!!
04/01/2005 (12:33 pm)
Ahhhh... that makes sense, I think I know what happened, too (I can't check until I get home & have time): normally I'm very consistent in variable naming conventions and in C use something similar to Hungarian notation. The first thing I did was rough out the code in psuedo-C++ and the variable was probably declared as int iNumDecks. Then when I was writing the TorqueScript some of it was copied in from the psuedo-code and it became $iNumDecks, but I didn't want the initial i, removed it. And in the TorqueScript I don't uppercase the first letter so it became $numDecks. I bet where I initialize it it never got changed. In client.cs the code looks something like:$numDecks = 0;
$numGames = 0;
exec("./cards.cs");
exec("./cards/TimDoty-Standard.cs");so I know it is supposed to be initialized before getting used. I'm positive that's it. Thanks!!
#9
04/01/2005 (3:56 pm)
My memory isn't perfect (and I made time where I didn't have any) and it wasn't exactly that, but it was initialization. Out of curiousity, I thought that TorqueScript initialized variables to 0 on first use? (I'm more comfortable with initializing them as I prefer declared variables anyway so its not an issue of how I plan to do things, just curious about the language).
#10
04/01/2005 (4:26 pm)
There is a global preference that you can turn on to warn you if you're using a variable without it being declared... and for the life of me I can't remember it right now. I'll post it when I find it.
Torque 3D Owner Matthew Langley
Torque
$array = new ScriptObject();
$array.contents[0] = new ScriptObjects();
$array.content[0].content[0] = new ScriptObject();
seems to run very stable as well... the total code is massive but have entered 100,000 entries simultaneously before... the data back end has never failed me...
didn't get a chance to test this now, but might a little later... but off the top of my head it seems like your assigning data a bit weird
$cardDeck[$numDecks] = new ScriptObject()
then
$cardDeck[$numDecks,%i].setSize(%x SPC %y);
as if your referencing it as a single array, then a multi dimensional array...
this may be correct, just what I'd compare to start out with
another useful thing is "eval()"
it takes a string and executes it, very useful if used like this
eval($cardDeck[0, 0] @ ".dump();");
it takes what is stored in that array slot and puts it in the string... so say its an object ID.. like 1275, itd run the function
1275.dump();
... but I think the array is just being assigned as multiple things, so I would check on that first... sorry I couldn't be more helpful :) Later I'll give it another look if you still need help