BIG SUGGESTION: Engine Rewrite Ideas

Started by Alynn, Tue 30/01/2007 07:34:59

Previous topic - Next topic

Alynn

I'm sure some of this is in the tracker, but with CJ's graphical upgrade to the editor, and the migration to .NET I thought of a few things to completely objectize the rest of the engine. These aren't all my suggestions, there are some in here that have come from other sources, however as I don't remember who made the suggestion I will just repost them here with my own take on what they should be. This will probably get very long. So please bare with me. Also, I have tons of notes I wrote up for this, and my son convieniently decided to destroy many of them, so I will probably forget something, so feel free to add :).

These are the Objects (note, Objects with a capital O refers to the classes (Not sure if .NET uses the same terminology as Java, but since I know java better, so I'm using it's terms) while objects is the name for the items normally found in the editor. In other words capital O is Object in the programming sense, and lower o is an object in the AGS sense. So if you see a capital letter, I'm refering to an Object name, and lowercase I am not.

Vector Based instead of Array Based: For those of you that don't know, a Vector is a dynamic Array. It resizes itself to fit the current contents of the Objects stored in it. They are much more flexable than Arrays. The advantage to this is, those that use way less than the (current) maximum limits will get the benefit of having a smaller memory footprint and game size. On the other end, those that need way more than the engine's current limits will no longer be limited to a certain size Array, and can make their game as big as they want.

Seperate Data Structures (Classes): Currently, certain things like objects, are assigned to a certain room that they are created in in the engine. While I believe that objects should be their own Object and placed in a room by code. This provides objects having the same functionality as characters, so characters can pick up and drop objects in any room (if coded to do so). This brings me to the next suggestion.

Global Structures: Much of AGS is already OO, but not all of it, there are still some methods out there that belong to no parent object. Trying to keep with what AGS already has I'd like to add a few other Parent classes

Screen - Handles Screen rendering methods, such as getViewportX, and Rawdraw.
Room - Handles Room Calls
Character - placement and animation, of characters
Object - placement and animation of objects.
Media - Handles Sound, Music, and Video.
Inventory - Handles Inventory Item calls.
Mouse - Handles Mouse placement, mode, and so on
Game - Handles everything else, such as click and keypress handling.

Now Game holds a Vector of Room. Room holds a Vector of Object pointers and Character Objects pointers that currently exist in it (that is to say, it doesn't actually hold the Object, but a pointer to the Object). This would mean that like Characters, Objects would become global, and could therefore exist anywhere in the game. I'd also like to be able to assign rooms script names as you can with characters and objects, such as rNorthHallway. Also, assigning script names to Views, so I could have cEgo and vEgo one of course is the character script name, while the other is the view script name for that character. Walkable Areas, Regions, and Hotspots will still remain as Vectors in Room, as there is no reason to have those global. However making those vectors as well will make them virtually unlimited (save memory requirements), and make the memory size smaller if they aren't being used.

Now if both the Character and Object Vectors are made public within the rooms, this gives 2 ways to access the data within, by globally calling (such as cEgo.Say) or through room Calls (rHallway.GetCharacter(cEgo)). However, I think the best bet would to make the Vectors protected, so they can not be directly written from the rooms, perhaps only read from.

Consistency: Some of you may have noticed that some things like Character.x and Character.y while everything else is Thing.X and Thing.Y. The naming convention should be consistant across the board. This is personal preference on my part. Now you may have noticed the Media class above, I added this class to add some consistancy as well. For instance, PlaySound() PlayMusic() are script commands that are just straight typed in. Not consistant at all with the OO approach AGS is going for. The Media class will now be the parent class for these types of methods. So now we have Media.PlaySound() and Media.PlayMusic, Screen.GetViewportX, Screen.GetViewportY. Also, consistancy for sprites, right now characters are referenced by the bottom center pixel, but rooms are not. For all sprites on screen, including characters and objects, the same reference point (such as the bottom center pixel) should be used. GUI's are fine using the upper left corner as their reference point, as that is normal with most programming.

More OO Approach: Currently there is alot of directly accessing data inside of the Objects. Such as able to set Character.x. In most OO, it's bad practice to directly manipulate primitives. Instead, use Get and Set type methods. player.GetX(), player.SetX(int XValue).

Serialize For Saves: When saving, the current instance of the game can be serialized (Java term, don't know the .NET name for it, however it may very well be a universial term). And when loaded deserialized. This may make the save games smaller. I can't say for sure, since I currently don't know exactly what AGS saves currently.

I probably forgot a few things, but from the notes I had these are the ones I can remember, and the fact that I have to leave for work, so I was rushed in typing all this up, so I may have missed a detail or two. Now don't get me wrong. I'm not saying that these changes should be done by yesterday. But it's something I'd like CJ to consider for AGS 3.0.

scotch

I think CJ has already said he has no intention to rewrite the engine in to use .NET, but I wouldn't mind a few of your suggested script features, implemented in C++.

Dynamically sized containers for the script, certainly, the array stuff is harder to understand, makes code more complicated, and wastes space.  Along with that if objects, characters, etc could be constructed with the script, and methods overridden and added, that'd be great.

I don't see any reason to hide the useful properties of the AGS objects, it's shorter to write things without a load of getX() and setX() pattern functions. They're reasonable in Java or C++, to prevent reliance on a particular implementation, but not so much for a scripting language with property support like AGS (when you say cEgo.x you're calling a function internally already).

On the other hand, the inconsistancies in capitalisation style and so on can improve of course.

Basically for this theoretical AGS 3 I'd suggest dropping AGS script entirely. It feels oppressive coding in a statically typed C clone when it's going to be interpreted anyway, and it'd be fairly difficult to add some of these features to a statically typed language. Squirrel is pretty good low footprint script language, supporing classes, polymorphism, dynamic containers, tables etc, and is probably easier to learn than the current stuff. There are lots more pre made languages to consider though.

Serialising things for saves... well, I don't see a reason to use a full general purpose object serialization library, it'd probably make for much larger save games than just saving the necessary data. The reason they exist is for convencience and speed of development, rather than efficiency. As long as saves work I don't think it matters a lot.

Khris

While some (very few, actually) of those suggestions seem thought-through, most of them either a) are already implemented/in the tracker or b) just don't make sense.

E.g. Media.PlaySound() instead of PlaySound()?
Why?

scotch

The positive reason for that (asides from dots look like we're doing OO code, cool!), is that partitioning the related static functions and data makes them easier to find. It's a slight improvement, with the autocomplete and stuff, and CJ already did it with classes like Room, Game, and so on, so it's consistent.

Media.PlaySound(id) is a bit ugly to me, because while the benefit of knowing all the sound functions start with Media is there, it's negated by the function being more annoying to type. Something like Sound.Play(id) is fine, though.

SSH

12

Gilbert

Or sBell.Play() ...

* Gilbot V7000a is about to feel that excessive OO is really silly (alright, it may help produce more readible codes if done right, but not when you overdo it).

monkey0506

Regarding the "room script names" I could just be talking bullocks, but wouldn't that type of implementation require information to be loaded into the script for every available room (i.e., information would have to be accessible for any room, not just the current one)?

It would be nice if we could have more access over things in other rooms, but I can understand the reasoning behind the current implementation as well.

I think a vector system would be wonderful. Especially if we could have some type of vector template so we could even implement vectors of user-defined classes (similar to the C++ "template <class T> class MyClass"). Of course this is no light undertaking, it would be something I would find extremely beneficial to the entire AGS system.

Regarding the consistency of AGS's current OO implementation, it is vital that we recognize the reasoning behind some things (such as a Character's x and y co-ordinates) being lowercase while others (such as an Object's x and y co-ordinates) are uppercase.

In previous versions of AGS (AGS 2.62 and earlier) structures already existed which allowed the user access to certain variables such as a character's x and y co-ordinates. However no such structure existed to allow the user direct access to an object's x and y co-ordinates. In order to provide backwards compatibility as best as was possible, the existing structures maintained the case of these variables, while in accordance with better OO style the new structures used uppercase data members.

Updating these variables to uppercase versions to provide consistency is a reasonable request, but we must take care not to assume such things are acts of carelessness (this isn't directed at anyone in particular, just a general guideline ;)).

As has already been pointed out regarding the direct access to certain data members, these access points already call functions internally. Since this access is already managed, doesn't it then make more sense as-is? For example, would you really rather have to type "player.SetX(player.GetX() + 1);" instead of just typing "player.x++;"? AGS also has a "writeprotected" access modifier which would mean that users could then directly read the data member without having access to write it. As such wouldn't it make more sense to use writeprotected members instead of all this "GetXXXX" business?

I'm not sure what serialization does, although scotch seems to think it would drastically increase save file size instead of decreasing it. That wouldn't seem very good. But I agree with what scotch said:

Quote from: scotch on Tue 30/01/2007 08:12:02As long as saves work I don't think it matters a lot.

I'd just also like to say that I think Khris was a bit over-critical. I'd say that Alynn did take the time to think through these suggestions. Even just the amount of time it would take to type up that post shows a fair amount of consideration. Though I think some of his suggestions could stand some second opinions, saying that he thought "very few" of them through properly seems a bit harsh. Just my two cents. ;)

Good topic. It's always nice to add some more to Chris' To-Do List ;D :P ;D

Khris

I must admit my reply was pretty harsh but the whole idea behind the post struck me a bit as "make us type more letters while scripting and make AGS more complicated than necessary to satisfy my personal need of true OO".

AGS is an Adventure Game Engine, not a new commercial programming language we're beta-testing.

I'm sure that's not how Alynn sees his suggestions, but seriously: Media.PlaySound? The only, and I mean ONLY difference of this implentation: We have to type more letters. There's no benefit at all, at least none that I can see.

And what is this:
rHallway.GetCharacter(cEgo)?
Is this gonna return cEgo? Or what?

And referencing rooms by bottom center? But not GUIs?

Alynn

I only mentioned GUI's to differenciate them from sprites. I didn't mention rooms because since they are, for all intents and purposes, static. I just singled out those 3 items because they are drawn over top of the backgrounds. So what I meant to say was, neither Rooms nor GUI's need to change. Using the upper left corner is a programming standard, and I see no reason to change that.

As far as the get and set commands, yes, personal opinion, it just seems right to me, probably because I've been programming that way longer than I've used AGS. It's safer for the data, and keeps people from writing when they should have be reading. Makes them really think about what they are doing. You can't accidently type player.SetX().

It's mostly about being consistant, and organizing everything onto base Casses to making finding what you want a bit easier. If I type "player." a whole list of everything I can do with the player Class pops up. With this, if I type "Media." everythiing I can do with music and sound appears letting me know everything I can do with music and sound. "Screen." will show me everything I can do with the screen. Fading, rawdrawing, so on and so forth. To me, it becomes more intuitive, and all you really have to memorize is the main Parent Classes, you then don't have to memorize everything that falls underneath it. It's a starting point. A reference. The same is true for Set and Get commands. Typing in "player.Set" will give me everything I can set on the character, while "player.Get" will give me everything I can get from the character.

What serialization does, in essense, is take the Class state (the instanciated object, and all data marked for serialization in that object) and saves it, this can be compressed. Yes, it will perhaps make the saves bigger, but using this will also allow for saving room data for over 300 rooms, currently the only real work around for the 300 room state save limit, is to use a global variables, and to me it seems silly to use a global variable for something that should be kept local. As you should always keep variables at the lowest scope needed for that variable. But since I really don't know exactly what the current save algo does, it was more of "have you considered this?" type of suggestion.

Now that you mention the two paths to reference things (both global and using room variables) it may in fact, be better to make the internal vectors private. Honestly, accessing the pointers though the rooms was an after thought that I tacked on, when I realized that it would indeed allow two paths to access, and isn't really needed since characters and objects would be global anyway. So I pull back that statement. However, to answer your question Khris, it would either return cEgo, or Null if cEgo wasn't in the room.

Gilbot... I actually already use something like this. Currently I have 45 seperate sounds. In order to work around the whole not able to label sounds. When I put a new sound in my sound folder, I add the sound to an enum in my Util module so I don't have to figure out what sound is what, espeically the sounds that I use over and over, such as the doors opening, and the rimshot. Similar to this:
Code: ags

enum Sound {
  sAxeHit = 1, 
  sDoorOpen = 2, 
  sRimshot = 3, 
  sExplosion = 4, 
  sSplash = 5
};


Scotch: Regarding Sound.Play(id) this is also viable. I was just thinking of a way to keep the current commands as is, and just organizing them under a larger parent class.

And finally KhrisMUC, honestly though, any suggestion that is ever made is because someone has a personal need for it. Nobody would ever suggest anything unless they personally thought they needed it (or the engine needs it). Suggestions are all about personal opinions. So I honestly don't see what is very different from what I put up, than from what anyone else typed up.

After all, this is "Just things as I see it" and anybody and everybody is entitled to love it, hate it, or find a way to improve it. Howver, if I never mentioned it, then none of the above could even happen.

And finally (phew), Out of everything up there, the items I think are the most vital are the vector based storage. And I'll admit that most of the suggestions are based off of ignorance of how CJ actually implemented the engine, only he knows for sure exactly how things are done now, so I can only guess. So maybe I should change it from SUGGESTION to HAVE YOU CONSIDERED but that goes back to typing more than needed ;).

Khris

I've just browsed through the manual and I noticed that the amount of functions without a dot is even smaller than I thought.
There are the Game / Global functions, the Multimedia functions and the Room functions, pretty much everything else is already organized in a Parent.Function way.

Plus, in the Game / Global functions, there is a good amount with "Game." in front of them, the reason being that they are static:
QuoteNOTE: This is a static function, and thus need to be called with Game. in front of it. See the example for more.

You could always expand your util module with something like:

Code: ags
// header
struct Media {
  import static bool PlaySnd(int soundNumber);
  ...
}

// script
static bool Media::PlaySnd(int soundNumber) {
  PlaySound(soundNumber);
}

...


That way, typing "Med" will auto complete to "Media.", then display the member functions.

Using Get() and Set() seems annoying to me, too. I know that I won't accidentally modify player.x.
If anything, I'd want to have it the other way 'round, e.g. being able to do GI[2].Value++; instead of having to type SetGlobalInt(2, GetGlobalInt(2)+1);
I don't use GlobalInts anyway, but you get the point.

Pumaman

The only reason for using SetX() and GetX() is as a workaround in languages that don't support getters and setters for properties -- this applies to C++ for example, but since AGS Script has proper support for properties, it'd be silly to take a retrograde step and go back to using get and set methods.

As for Vector based arrays, I can see the benefits of adding some sort of typed Collection class to the script as opposed to using arrays. For AGS internally though, when the engine starts up it only allocates enough memory for the content of the game -- most of the limits are because the editor uses statically sized arrays. Incidentally the new 2.8 editor should allow many of these limits to be removed.

monkey0506

Khris, regarding your Media workaround, that seems reasonable to me as a workaround. I think Alynn was just asking about any future possibility for future implementation of such an idea.

As for the global ints, I think a Game.GlobalInt[X] would make more sense. And be more consistent. Then you could do Game.GlobalInt[X]++;, etc. Of course global ints are really rather silly once one learns how to script them oneself. ;)

Regarding the Room.GetCharacter() function Alynn...the implementation you've defined sounds to me like:

Code: ags
if (character[x].Room == player.Room) {

Khris

@monkey:
It was meant as a workaround, to solve this:
Quote from: Alynn on Wed 31/01/2007 07:15:40It's mostly about being consistant, and organizing everything onto base Casses to making finding what you want a bit easier.
[..]
With this, if I type "Media." everythiing I can do with music and sound appears letting me know everything I can do with music and sound.
[...]
To me, it becomes more intuitive, and all you really have to memorize is the main Parent Classes, you then don't have to memorize everything that falls underneath it.
The downside is that "moduling" Media.PlaySound isn't possible, one has to alter the name slighty.

Alynn

Pumaman: Yes I was actually refering to the editor itself, to remove those limits, with the editor moving to .NET I figured I'd mention that if you hadn't thought of it. Looking back I did say engine a few times, but as in that instance, I really meant the editor, in my mind I don't differenciate between the two, as you can't really access anything in the engine short of the editor (well I guess a plugin as well, but you probably get my point).

Java supports direct access to public properties in classes, perhaps it's changed, but last I checked it was bad practice to directly access properties, but that may have to do more with making portable code, or maybe it was just something I was taught and just kept doing...  Either way, not a huge deal really.

Snarky

You are thinking of member values. Several other OO languages (notably C#) have a notion of "properties" that appear like member values (i.e. variables) but are actually a pair of methods. I think they're adding it to Java in the next version, too.

Really all it means is that you type

Object.X = 5;

and the compiler translates it into

Object.SetX(5);

for you. It just makes the code more readable.

monkey0506

Quote from: monkey_05_06 on Wed 31/01/2007 20:40:20Khris, regarding your Media workaround, that seems reasonable to me as a workaround. I think Alynn was just asking about any future possibility for future implementation of such an idea.

Read both sentences Khris? :P

Anyway, I forgot to mention in my last post that I think it would be woooonnnnderful to get rid of these icky system limits. Great jorb CJ!

Regarding the "Media.PlaySound isn't possible" issue...seeing as it's been brought up...is this actually a bug? IMO it seems like one, but others might feel differently.

Khris

I did read both, but thinking that Alynn maybe didn't know that Media.Stuff() can be implemented by the User, I just wanted to point out it is possible.

About "Media.PlaySound":
Using
Code: ags
struct Media {
  import static bool PlaySound(int soundNumber);
}
will throw an "name already in use error", so it's not a real bug. But it could be considered one, that's true, since there's no actual "function PlaySound"-line in my code. It's probably impossible due to internal reasons.

Alynn

No I was aware Khris, but thanks anyway :). And yes, using Media.PlaySound won't work as the script can't extend engine member methods. I'm not exactly sure that you can even overload them, I've never tried.

Snarky: Ahhh gotcha, I knew I couldn't have been that far out of the loop (it's been awhile since I've actively done anything programming, been busy with other things) so mostly just a difference of what AGS was doing, and what I percieved it as doing, so anyway that's nifty.

monkey0506

Quote from: Alynn on Fri 02/02/2007 09:15:47No I was aware Khris, but thanks anyway :). And yes, using Media.PlaySound won't work as the script can't extend engine member methods. I'm not exactly sure that you can even overload them, I've never tried.

readonly int Character.Room
static readonly int Room.ObjectCount

FTW!

Character.Room is defined before the Room structure, so the compiler doesn't detect any collision. ;)

Anyway...it's possible with certain names, with others it's not.

Electroshokker

A suggestion: make GetLocationType also detect inventory items

currently there's:

eLocationNothing    nothing, GUI or inventory
eLocationHotspot    a hotspot
eLocationCharacter  a character
eLocationObject     an object

an "eLocationInventoryItem" would be a most welcome addition.

SMF spam blocked by CleanTalk