Accessing AGS objects by array index / Hardcoding editor values in code

Started by Billbis, Wed 26/06/2013 09:57:09

Previous topic - Next topic

Monsieur OUXX

#20
integer IDs have a reason to exist only if they are unique (that is: even if you delete an object in the array, and create a new one somewhere else, then the new one cannot receive an ID that was given before).

And if they're used that way, they would only exist as "convenient" way for the end-scripter to compare two objects. For example, in a loop. By convenient, I mean "for someone who isn't comfortable with comparing references".

But, as it has been said before, if kept, the IDs couldn't be used any more as a way to iterate on arrays and stuff. They would become totally independent from indices.

==============

Ryan, I understand your point, but you're saying nothing new : using "character[1]" instead of "cSally" is bad coding practice. The scripter should use indices ( [1] ) only if he needs some abstract arithmetics on objects : iteration, addition, shifting, whatnot. And if he wants to do that, we assume he's scripted long enough to understand what he's doing. (e.g. "not deleting an object in an array while iterating on the array, using the last index as an exit condition" -- classic mistake with beginners, in any language)

 

Ryan Timothy B

#21
That right there is an example of borderline magic numbers - which lead to error prone code.

There are numerous ways to deal with something like that, one being this:

Code: ags

#define CHARACTER_COUNT 44
struct CharacterHat {
  Character* Hat;
};
CharacterHat characterHat[CHARACTER_COUNT];

void AssignHat(this Character*, Character* hatCharacter) {
  characterHat[hatCharacter.ID].Hat = hatCharacter;
}

function game_start() 
{
  if (CHARACTER_COUNT < Game.CharacterCount) AbortGame("Due to AGS limitations: CHARACTER_COUNT is less than Game.CharacterCount");
  
  cGeorge.AssignHat(cGeorgeHat);
}

function repeatedly_execute() 
{
  int i;
  while (i < Game.CharacterCount) {
    if (characterHat[i].Hat != null) {
      if (character[i].Room != characterHat[i].Hat.Room) {
        characterHat[i].Hat.ChangeRoom(character[i].Room);
      }
      characterHat[i].Hat.x = character[i].x;
      characterHat[i].Hat.y = character[i].y;
    }
    i++;
  }
}


And yes, before you mention it, I did use character.ID. Only reason is that I can't extend the Character struct (which to me is the main reason why anyone should ever need the ID). Edit: I've deleted the struct extend example because I'm quite sure I screwed it up.

Edit: With your example, if you suddenly realized you forget to add a character to the tree and its hat character, good luck getting his hat to match without deleting all characters to make the IDs match again.

Ryan Timothy B

#22
Quote from: Monsieur OUXX on Fri 28/06/2013 18:16:09
Ryan, I understand your point, but you're saying nothing new : using "character[1]" instead of "cSally" is bad coding practice.
No, quite frankly you don't see my point. You should NEVER have a reason to use character[1] instead of cSally. NEVER! Not even if you're a level 100 master programmer.  :-D

When you add a button in Visual Studio, does it tell you that the ID is 0. No. Why? Because why would you reference the button via button[0] when you have a completely error prone method via bButton1.

Quit trying to argue that it makes sense to use character[1] to point to cSally. It doesn't and never will. No. (face palm coming very soon)

Edit: Actually the funniest thing you've said is this:
QuoteAnd if he wants to do that, we assume he's scripted long enough to understand what he's doing.
This is AGS. Nearly every programmer making AGS games are completely new to the experience. If ANYONE, advanced programmer or complete noob use the array pointer instead of the syntax name (whatever the correct terminology is for that), they obviously don't know what they're doing. Unless you access it via array looping statement, but that's not what we're arguing here.

monkey0506

#23
Quote from: Ryan Timothy on Fri 28/06/2013 18:21:55
Code: ags
struct CharacterHat extends Character { ... };

// ...

cGeorge.Hat = cGeorgeHat;

Firstly, I wanted to say that the way you've defined it here isn't accepted in any real programming language. "cGeorge" is an instance of the base class Character, and will never be an instance of CharacterHat. Now, it would be feasible to allow extender attributes (in addition to extender methods), which would ultimately amount to the same thing. But your definition breaks good coding convention.

The following uses extender methods. If extender attributes were implemented, they would be syntactic sugar for the following.

Code: ags
Character *characterHats[];
import Character* GetHat(this Character*);
import void SetHat(this Character*, Character *hat);

function game_start()
{
  characterHats = new Character[Game.CharacterCount];
  cGeorge.SetHat(cGeorgeHat);
}

function repeatedly_execute()
{
  int i = 0;
  while (i < Game.CharacterCount)
  {
    Character *c = character[i];
    Character *hat = c.GetHat();
    if (hat != null)
    {
      if (c.Room != hat.Room) hat.ChangeRoom(c.Room);
      hat.x = c.x;
      hat.y = c.y;
    }
    i++;
  }
}


This example avoids the problem of linking the hat by ID, but iterating the characters and their hats (in the absence of a foreach loop (for wouldn't be sufficient, obviously)) still requires using the ID. For simplicity and readability sake, I've stored references in the pointers.

(Edit: I've also gone back and realized what you meant by "Due to AGS limitations" in your code snippet that did have an extender method. You were wrongly and falsely indicating that AGS provides no means of creating an array based on the size of Game.CharacterCount. Granted, your example is a primitive one, and in the real world the structure would likely be much more complex, and it is true that AGScript won't allow dynamic arrays of custom struct types (due to the no pointer issue). However, any keen module developer wouldn't stop writing just because they had to avoid using structures in favor of several file-scope arrays.)

I agree that in the majority of code, referencing something by it's ID should be avoided. Again though, without a foreach loop there's no way of iterating certain things without it.

Oh, and as for the "Game.Characters.IndexOf(Character*)" method:

Code: ags
int IndexOfCharacter(Character *c)
{
  if (c == null) return -1;
  int i = 0;
  while (i < Game.CharacterCount)
  {
    if (c == character[i]) return i;
    i++;
  }
  return -1;
}


Of course, this is exactly equivalent to just accessing Character.ID.

Ryan Timothy B

Lol about my extending example. I actually edited my post to remove it before I saw yours. I was sitting here working on my 3D modeling when it suddenly hit me how wrong that code was. I've only extended a Class a few times and that was over a year ago.  (laugh)

As for my example using a struct, I only did that for organization. Since you'd likely have X and Y offsets and such. I kept it simple as an example with only the character pointer, but you're right, my example should've been a dynamic array (or a bunch of dynamic arrays - if you were to add more elements). There's nothing wrong with characterHats_Hat[] versus characterHats[].Hat. I just have slight OCD tendancy when it comes to keeping things grouped together. lol

The main question is, do you agree about AGS not showing the developer what the index of the "Object" is in the tree?

Snarky

#25
Ryan, in your code you're almost literally recreating the wheel by creating an unnecessary duplicate of an already-existing data structure. Yes, it gives you some increased flexibility, but it has definite drawbacks as well (for example, the way you've implemented it you have to iterate through every character each cycle, even though you already know that half of them are hat-dummies). I really don't see it as any better than my example.

Quote from: Ryan Timothy on Fri 28/06/2013 18:21:55
That right there is an example of borderline magic numbers - which lead to error prone code.

Direct access to object array indices is a convenience/optimization that is useful for games programming. Like, say, pointer arithmetic (which is effectively what it is), it breaks out of the abstractions of the Object-Oriented layer, which means you should take care when using it. But as long as you're disciplined and know what you're doing, it works and makes for elegant code.

Quote from: Ryan Timothy on Fri 28/06/2013 18:21:55
Edit: With your example, if you suddenly realized you forget to add a character to the tree and its hat character, good luck getting his hat to match without deleting all characters to make the IDs match again.

That's a good argument for giving users a way to reorder sprites/characters/etc., or for inserting a new one in the middle of the sequence.

Quote from: Ryan Timothy on Fri 28/06/2013 18:41:46
When you add a button in Visual Studio, does it tell you that the ID is 0. No. Why? Because why would you reference the button via button[0] when you have a completely error prone method via bButton1.

UI programming isn't like games programming. But for analogy: once you add a button to a Window in e.g. C#, you can access it by indexing into that Window's Controls[]. You could abuse that by hardcoding references to certain indexes (which would break if you changed the Window controls), but that's no reason not to offer the functionality. (The main difference is that the index is assigned dynamically at runtime, rather than in the editor - although usually you can easily calculate what it's going to be ahead of time - but that just makes using the index more risky in C# than in AGS.)

Quote from: Ryan Timothy on Fri 28/06/2013 18:41:46Quit trying to argue that it makes sense to use character[1] to point to cSally. It doesn't and never will. No. (face palm coming very soon)

Mr. Ouxx explicitly said it doesn't make sense, that you should only use it for abstract arithmetics on characters (or other game objects).

Quote from: Ryan Timothy on Fri 28/06/2013 18:41:46This is AGS. Nearly every programmer making AGS games are completely new to the experience. If ANYONE, advanced programmer or complete noob use the array pointer instead of the syntax name (whatever the correct terminology is for that), they obviously don't know what they're doing. Unless you access it via array looping statement, but that's not what we're arguing here.

I think that's exactly what we're discussing here. Looping as well as pointer arithmetic-style calculations.

Ryan Timothy B

Quote from: Snarky on Fri 28/06/2013 19:58:21
I really don't see it as any better than my example.
I do. Flexibility and yours is chalked full of potential issues.

If you were creating a module, would you have:
  hatModule_SetStartCharacterIndex(50);
  hatModule_SetHatStartCharacterIndex(60);
  hatModule_SetHatCharacterAmount(10);

Nope. Or at least I would hope not.

If AGS had ArrayLists, I wouldn't need to iterate through every character, I could simply just iterate through the ArrayList which contains all the Characters with Hats.

QuoteDirect access to object array indices is a convenience/optimization that is useful for games programming.
Direct access yes, but not having AGS tell you beforehand so you can code everything with the indices - aka magic numbers.

Snarky

Quote from: Ryan Timothy on Fri 28/06/2013 20:28:13
If you were creating a module, would you have:
  hatModule_SetStartCharacterIndex(50);
  hatModule_SetHatStartCharacterIndex(60);
  hatModule_SetHatCharacterAmount(10);

Nope. Or at least I would hope not.

No, I would put in the readme file to edit the #define statements at the top of the module to match whatever had been set up in the editor.

Crimson Wizard

#28
I don't want to blame anyone, but frankly I don't like how this discussions goes: a bit of mess IMHO.
I think you are starting to mix numbers being Keys and numbers being Order, which is different things.
Like in above example:

hatModule_SetStartCharacterIndex(50);

What is 50? Is it an order of item in internal array, or a key? If it is a key, it is as valid as a string, or a pointer. The only serious difference is that remembering the string or object name may be easier for us, people (at least for normal ones ;)).
E: err, I should have said - "holds more obvious meaning", of course.

Ryan Timothy B

#29
It was just a code example based off the code Snarky posted about how he finds the index being shown to you editor side as useful.

Quote from: Snarky on Fri 28/06/2013 17:36:26
Code: AGS

#define HATTABLE_START 15
#define HATTABLE_COUNT 8
#define HAT_START      328

I didn't want to scroll up so I just tossed in arbitrary numbers as he had.

Edit: I was just proving my point at how unorganized it was.

Edit again: Snarky, how does someone take a hat off? ;)  (I meant with the module of yours - you don't have to post code, I was only being an arse)

Snarky

Quote from: Ryan Timothy on Fri 28/06/2013 21:34:50
Edit: I was just proving my point at how unorganized it was.

Configuring key values at the top of the script is disorganized now?

Quote from: Ryan Timothy on Fri 28/06/2013 21:34:50
Edit again: Snarky, how does someone take a hat off? ;)  (I meant with the module of yours - you don't have to post code, I was only being an arse)

Obviously neither your version nor mine is a complete solution, and the example is a bit contrived anyway because as I said up top, you could simply use FollowCharacter(). My point was to demonstrate using the array indices to iterate over a subset of characters and do logic based on the index. Which I maintain are useful coding techniques (not just for characters, but for views, sprites, hotspots, room objects, music tracks, etc.). If the only argument against it is "if you delete a character, you'll have to change the numbers you use for the indices," I don't find that a major problem, since with good coding practice it's a simple change in a single place in the script.

To talk about how to improve object referencing in general, I say get rid of the ridiculous hardcoded behavior for Hungarian notation, where you use different versions of the name in the AGS script and the dialog script IF the name is prefixed with certain magic characters. (The whole thing is confusing enough that I'm actually not 100% sure exactly how it works.)

Monsieur OUXX

#31
Quote from: Ryan Timothy on Fri 28/06/2013 18:41:46
Quit trying to argue that it makes sense to use character[ 1 ] to point to cSally. It doesn't and never will. No. (face palm coming very soon)

As I wrote: using that to access only cSally is bad practice. But otherwise, I believe what you wrote is not correct (and also very condescending). How do I iterate on a collection of objects if I have neither "objects[ i ]" nor an iterator (foreach or something else) ?

I understand how you misunderstood what I wrote.
But Crimson wizard is right : in this discussion, there are people talking about the Keys, and some talking about the Orders. That was the point of my very first post. Nobody can agree on anything until everybody has decided what they want to talk about.
 

tzachs

Quote from: Calin Leafshade on Thu 27/06/2013 13:45:34
foreach loops create extra work for the garbage collector because they create extra references. This can be especially problematic in game programming because it can potentially create several thousand new references every second (a particle system perhaps). Also the .NET GC is non-deterministic so you can never be sure exactly when the GC will do its work which can create random usage spikes which can severely fuck with your frame rate, especially in embedded systems like the Xbox360 or a phone.
Ok, so I did a search to try and find the source. I found this: http://blogs.msdn.com/b/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx

He didn't explain the weirdness of what he experienced, here's what's going on behind the scenes: the compiler, when facing a foreach wants to do the best it can. So when it sees a foreach on a list, array or pretty much stuff with indexers, it will translate it to a standard for..
In the examples in the link it didn't do it for Collection and IEnumerable because they don't have an indexer, so you couldn't write a standard for loop for those if you wanted to.
In the second example the author 'tricked' the compiler by passing a list to a method accepting IEnumerable, so the compiler couldn't make that optimization, and used the enumerator which is the extra reference..
Granted, that is something we should be aware of, but it's not such a common scenario that deserves the 'beware foreach' comment..

On the other hand, foreach gives us benefits, not counting the better readability.
First, it saves from a common sceanrio where the developer accesses the indexed object more than once inside the loop.
Second, since c# is a managed language, it is also safe, so you wouldn't accidentally access somebody else's memory. So when you access an index, it actually adds boundary checks, which hurts performance. When doing foreach it knows it can skip the boundary checks. In truth, it also make this optimization in the standard for loop, but you can easily trick it, for example in another common scenario where you take the length to a local member outside the for declaration. In c++ it's good for performance since it avoids extra access to the length property, but in c# it's the other way around, and by using foreach you won't be able to make that mistake..

Ryan Timothy B

Quote from: Monsieur OUXX on Fri 28/06/2013 22:24:30
How do I iterate on a collection of objects if I have neither "objects[ i ]" nor an iterator (foreach or something else) ?
I know you've crossed this text out, but it leaves me wondering if you or anyone actually believe I want to abolish accessing AGS "Object" members via array using indices. I realize after I had read them again that my posts above have come across this way, but this is not the case at all (I think it was this post. I had quickly quoted Crimson and Mite, wrote some code examples and then forgot to break up the quotes later to further explain that I hadn't been talking about the "Object" array - oh well).

I suppose whoever moved this thread over and named the thread "Accessing AGS objects by array index" didn't help matters.

Also I'm sorry if I've come across as condescending. We're like a group of friends gathering together on the net. I get heated up in a debate that, to me, is completely logical to rid AGS of the editor-side hardcoded indices. Having them assigned at compile time, where you wouldn't know what they are before compile which can only lead to fallible code.

Now with me having discussed ridding the Object.ID was mostly if AGS were to advance in the scripting department. So that was me talking about a semi-future AGS, not this one. Overall there isn't a huge issue having access to it in this manner, but I personally can't see you needing it. If you did though, you would have access to the index with the Object's ArrayList. On an unrelated personal opinion, I am slightly bothered by how it's called ID instead of Index - perhaps it's a personal vendetta. :-D

Quote from: Snarky on Fri 28/06/2013 22:05:45
Configuring key values at the top of the script is disorganized now?
In my opinion, from that example, yes. it's not exactly a coding practice I would teach anyone (on a side-note: there's actually a fog module that Dualnames mostly wrote off some code I supplied him. I did that very same thing with index start and amount. It was only as a quick example to show how the fog should be designed - graphically, not scripting. I never meant for it to turn into a module or ever be used in someone's game. I feel guilty about that module even existing. Ha).

Snarky

So if I understand you correctly this time around, Ryan, you are objecting to the idea that the object indexes (of characters, but the same system is used for views, sprites, fonts, rooms, GUIs, etc.) are shown in the editor and are known before compile time, so that people can use those values in their code as "magic numbers" and exploit the index-ordering in their game logic?

First, I think without this, the IDs are nearly useless, because unless you are simply looping through every character, you're going to want to restrict it to some index range, and that relies on knowing something about how they are ordered.

Second, not all the AGS object types have scripting names (sprites, views and speech clips being the most obvious), and it's not obvious that forcing a user to name every sprite (for example) is a good idea. I don't see us eliminating the notion of indices entirely from AGS, so there's a lot to be said for consistency in how they're presented and used.

Third, there's really no engine reason not to assign character IDs before compile-time. Even if we remove the character limit and make the number of characters dynamic (ArrayList instead of Array), they're still defined in the editor, no? Only if you actually wanted to generate new character dynamically at run-time would it be impossible to know the IDs ahead of time.

Fourth, I don't really see what your problem is with the existing feature. Some sort of visceral revulsion? That it "feels" too low-level and not properly object-oriented? Not compelling arguments to me.

Anyway, since different participants seem to have had different understandings of what we were discussing, I've renamed the thread again.

Ryan Timothy B

Quote from: Snarky on Sat 29/06/2013 09:58:53First, I think without this, the IDs are nearly useless, because unless you are simply looping through every character
Yep. The only reason they should have any use would be because we currently still require the ID for making matching arrays. Like the hats example (preferably the one Monkey posted). Unless in the future there was a way to add your own properties to any Object. Or a ListArray of any AGS variable type - including structs.

Quoteyou're going to want to restrict it to some index range, and that relies on knowing something about how they are ordered.
Which, as I've said, is error-prone and a very bad coding practice. ;)

QuoteNot all the AGS object types have scripting names (sprites, views and speech clips being the most obvious)
Views have their own variable name. Albeit the View is actually just an integer variable, and I'm pretty sure very few people actually use it.

My main argument was about Characters, Objects, GUIs and the Controls. Everything else can slowly follow along.

QuoteIt's not obvious that forcing a user to name every sprite (for example) is a good idea.
But the sprite is already named before you import the file. ;)   [/joke]
I haven't had a full desire of sprites dropping the ID number. But I certainly wouldn't argue as it's much nicer reading code that has readable sprite name like this   Sprites.George.Stand.Left001   vs    5.  What sprite is 5? I don't remember, let me keep browsing through all my sprite folders until I find it. (laugh)

QuoteOnly if you actually wanted to generate new character dynamically at run-time would it be impossible to know the IDs ahead of time.
Or as I've discussed about deleting a character via the editor before compiling. Calling it by the Index instead of the variable name is almost as bad as randomly doing  character[10]  and hoping it points to the right one. Without extensive searching through code to find the problem, no one would be able to work on your project, and you couldn't walk away from it for a year and come back. Once you delete that one character everything goes to hell.

QuoteFourth, I don't really see what your problem is with the existing feature. Some sort of visceral revulsion? That it "feels" too low-level and not properly object-oriented? Not compelling arguments to me.
To be honest, yes. Except for the visceral revulsion part, because that would be better described as your feelings. All my points why we shouldn't know the indices before compile are logical and would help make everyone a better coder. You want the exact opposite.

As for the low-level and not properly OO, that's the main reason. I haven't come across a single UI compiler that assigns the Index for you to see before compile; for the very reason that it allows the  possibility for poor coding.

QuoteAnyway, since different participants seem to have had different understandings of what we were discussing, I've renamed the thread again.
I still don't agree with the name because I never tried to change how we access objects by index. Which is why I suggested you to name it: 
AGS Indexing Objects  [shouldn't be assigned before compile]
That's all I wanted this thread to be talking about and I don't want others coming along thinking someone wants to eliminate accessing objects by array index.

As for why I ever mentioned removing the property Object.ID and replacing it for the Game.Characters.IndexOf(Character*) was for the very same reason. Having the ID as a property to the Object will give any inexperienced coder a sense of security that the index integer they receive will always point to their Character. But if it's something they can only get via the Character array, it may help them realize that it's not the Character "ID", it's actually the index of the Character in the array. Right now there's no issue having Object.ID as we don't have the ability for dynamic objects yet.

So could you please, just rename it to what I suggested and allow this thread be a tiny little bit less confusing.

MiteWiseacreLives!

I don't know if this topic is dead, but I just got the chance to read it. I just finished(well sorta finished) a game where I had to several times iterate through characters and objects, Crankosaur, to sometimes apply stuff that was not in the editor plane or just redundant and time consuming for 25 characters.
@Ryan, I know you don't want to abolish the ID #'s (character[ID] etc ), but not having them visible in the editor would be a nightmare! For example if you use folders, like I did, and go back up into the middle of the tree and add 13 characters to a folder these get assigned a sequential ID. Now how do I figure out if its Character[17] to Character[29] I want to suddenly move baselines on or Character[7] to Character[19], as it would seem if expand all the trees and start counting, without the ID's being visible. And as a newb protection, does not AGS adjust the visible numbering of all the Characters when you delete Character[2] or whatever, you could discover how you broke your game pretty quickly IMO by looking.
Just my thoughts.

Ryan Timothy B

The reason anyone would argue that it's useful to see the Index before compile is, simply and only, that they aren't an adept programmer; which, granted, is the majority of AGS users. Or they're being lazy. Since scripters have visible access to this index before compile, it allows them to possibly make faulty code (unless they were amazing and never deleted a single Object - which is likely super rare; or were clever enough to backtrack to all their code pointing to that specific index and renumber them).

There are numerous ways to store special Objects instead of relying on the visible Index - without having the Index A to B scripting method. With the index being visible to all, it only teaches people to rely on it and therefor become be a problematic scripter.

Properties is one method (although currently it's still read-only, but Crimson is doing a fantastic job at tweaking the engine). With that you could assign a boolean to every Object that is given this special treatment. But of course with this method you need to iterate through each and every character to find the ones with that property. Snarky's comment on that matter was quite moot as a deterrent, as iterating through 30-40 characters (likely to be the max in the majority of games) wouldn't show you any signs of slowdown.

Other methods being a dynamic array which holds each special Object. One basic solution being this (warning: typed in browser):
Code: ags
Character* specialCharacter[];
int specialCharacterCount;

void SpecialCharacter_Add(Character* specialCharacter) {
  z_specialCharacter[];
  if (specialCharacterCount > 0) z_specialCharacter = new Character[specialCharacterCount];
  specialCharacter = new Character[specialCharacterCount + 1];
  if (specialCharacterCount > 0) {
    int i;
    while (i < specialCharacterCount) {
      specialCharacter[i] = z_specialCharacter[i];
      i++;
    }
  }
  specialCharacter[specialCharacterCount] = specialCharacter;
  specialCharacterCount++;
}

void SpecialCharacters_ChangeRoom(int room) {
  int i;
  while (i < specialCharacterCount) {
    specialCharacter[i].ChangeRoom(room);
    i++;
  }
}

void SpecialCharacter_Remove(Character* removeCharacter) {
  int i;
  while (i < specialCharacterCount) {
    if (specialCharacter[i] == removeCharacter) {
      specialCharacterCount--;
      specialCharacter[i] = specialCharacter[specialCharacterCount];
      return;
    }
    i++;
  }
}

// called when the game starts, before the first room is loaded
function game_start() 
{
  SpecialCharacter_Add(player);    // Add a character to the special character custom List
  SpecialCharacters_ChangeRoom(player.Room);    // Change the room of ALL the special characters
  SpecialCharacter_Remove(player);    // Remove character from the special character List
}


Of course with the ability to have custom struct pointers and ArrayLists, or other fun stuff, something like this would be less than a dozen lines of code.

Crimson Wizard

Quote from: Ryan Timothy on Thu 04/07/2013 00:07:09
Properties is one method (although currently it's still read-only, but Crimson is doing a fantastic job at tweaking the engine).
Yeah...(heh) to the point when it stops working. (wtf)

Anyway, the thing is that it might be much faster both for user and for program to iterate between two indexes, rather then fill the custom array every time.
And what if the range is varied?
With indexes you can do
Code: ags

function DoActionWithObjects(int first, int last)
{
}

While without them you'll have to manually fill the custom array, checking some property maybe, and don't forget to change that property if you need to save the object from being included to that list.
Code: ags

         ---(pseudo-code)---
int obj;
while (obj < Room.ObjectCount)
{
   if (object[obj].GetProperty("blah") == 1)
      AddObjectToArray(obj);
   obj++;
}

DoActionWithObjectArray();


Yes, that's safer, and more formal, but that would be real pain to program to suit your particular needs. Besides it is slower than it could be. The latter may or may not be an issue, though I think I am getting paranoid over execution speed lately (seeing as a piece of code may slow down game execution by several percents if moved to separate function).


The real solution here, IMHO, would require to change the scripting paradigm. Scripter would need to seek the root of why he needs a range of indices in this particular case, and radically change the implementation. If the range of objects is constant, the special list could be precreated beforehand at the game start, or even at design time by creating a "filter" folder and filling it with visual "references". If the list is changing over time, it could be implemented as a linked list for faster insertion/removal.

Snarky

I left the topic alone because I felt it was going around in circles, but since it's come back to life...

Quote from: Ryan Timothy on Thu 04/07/2013 00:07:09
The reason anyone would argue that it's useful to see the Index before compile is, simply and only, that they aren't an adept programmer; which, granted, is the majority of AGS users. Or they're being lazy. Since scripters have visible access to this index before compile, it allows them to possibly make faulty code (unless they were amazing and never deleted a single Object - which is likely super rare; or were clever enough to backtrack to all their code pointing to that specific index and renumber them).

Being lazy is a positive trait! It's a matter of pragmatism: preferring a simple, straightforward solution that works to an overly complicated/slow workaround, even if it breaks some abstract notion of what "good code" looks like. (Similarly, the dialog system uses GOTO, even though it's often "considered harmful," because that's a simple and straightforward way to implement dialog trees.)

"Allows them to possibly make faulty code"? Any programming construct has the possibility of errors! Yes, if someone writes code that references specific items in the object arrays, they have to watch out for those references changing. Is that really so hard? I think with a few simple programming practices (e.g. defining index references at the top of the script, perhaps making references relative to the index of the bottom item), errors are not difficult to avoid or fix.

QuoteOf course with the ability to have custom struct pointers and ArrayLists, or other fun stuff, something like this would be less than a dozen lines of code.

If we could extend the built-in objects (properly, not the monkey-hack way), if we could have pointers to custom structs, and if we had ArrayLists, then many of the cases where array referencing is useful today could be solved equally well/easily with making your own object collections. Maybe then the argument would have some merit.

Quote from: Ryan Timothy on Sat 29/06/2013 11:24:14
Views have their own variable name. Albeit the View is actually just an integer variable, and I'm pretty sure very few people actually use it.

As I recall, you have to use the View index any time you want to assign an animation to an object, for example. OK, so Views aren't fully-fledged AGS data objects, but the logic is the same.

Quote from: Ryan Timothy on Sat 29/06/2013 11:24:14
My main argument was about Characters, Objects, GUIs and the Controls. Everything else can slowly follow along.

I haven't had a full desire of sprites dropping the ID number. But I certainly wouldn't argue as it's much nicer reading code that has readable sprite name like this   Sprites.George.Stand.Left001   vs    5.  What sprite is 5? I don't remember, let me keep browsing through all my sprite folders until I find it. (laugh)

Sure, but having the index is also very useful.

Quote from: Ryan Timothy on Sat 29/06/2013 11:24:14
QuoteAnyway, since different participants seem to have had different understandings of what we were discussing, I've renamed the thread again.
I still don't agree with the name because I never tried to change how we access objects by index. Which is why I suggested you to name it: 
AGS Indexing Objects  [shouldn't be assigned before compile]
That's all I wanted this thread to be talking about and I don't want others coming along thinking someone wants to eliminate accessing objects by array index.

The title of the thread shouldn't represent just your understanding of what it was about, when all (apparently) of the other participants understood it differently.

SMF spam blocked by CleanTalk