adventuregamestudio / ags

AGS editor and engine source code
Other
699 stars 160 forks source link

AGS 4: Parent class for game objects #1228

Open ivan-mogilko opened 3 years ago

ivan-mogilko commented 3 years ago

As we expand script api and try to bring all game objects to consistent behavior it is clear that they share functionality but do not have any base class that would help apply it uniformly. For example, if one likes to add a new generic visual property, they would have to add it separately to each of the game object types. This includes both script declaration and api handlers in the engine code.

(The only example of a parent class in existing script API is GUIControl that shares functionality with rest of control classes)

The proposal is to add one or more base classes to the script api, move existing shared properties and functions there, and use these in future whenever we might need to add more api shared among all objects.

I think we may begin with most obvious:

In the past I wrote a wiki page with some thoughts on potential class hierarchy. That is not a real plan, just something I was thinking over.

My suggestion is to have at least two parent classes for now: I called them "Thing" ("Thing2D" is an alternate proposal) and "GraphicItem".


Thing or Thing2D defines an object in 2D space, which basically has a position (X, Y). I believed it should be a separate base class, because there might be subclasses that need only that. An example could be an "audio emitter" that plays sound simulating it coming from certain position in space. Later this class may be amended with settings, to give some example, which define which coordinate space (layer) the object is located in.


GraphicItem defines an object which has a graphic representation. Note that it does not have to have explicit Graphic (sprite) property, as it is not necessarily drawing one of the game sprites (see GUI). What it should have is a full collection of settings that adjust looks: visibility, transparency, tint, blend mode (one of the recent additions), and so forth. Scaling and rotation should go there too; as anything we add for visual effect (shader support?).

Following existing objects will become a child of GraphicItem: Character, GUI, GUIControl, Object, Overlay.


Viewport and Camera are a questionable at the moment. It's not clear to me at the moment whether Viewport should be a child of Thing or GraphicItem. It depends on how do we see the viewport as an object. Technically it's hardcoded as the rectangle where camera is rendered. It may be made visible, and I was thinking about adding transparency. Probably it could have blend mode too, as it renders, maybe be even e.g. rotated. However, it's scaling only makes sense in connection with camera (it scales whatever camera shows). If we suppose for the moment that camera's image for viewport is like sprite to an object, then yes, there's definitely same kind of scaling. Maybe it's functionality could be reviewed to be represented more consistently. Hypothetically in the future AGS may have camera applied to any object replacing its graphic, so this is also something to keep in mind. LATER EDIT: Or perhaps it would be more convenient to let Viewport be a part of the "room space", similar to the room overlay proposal (#1209).

OTOH, Camera may be rotated, and probably could be applied a tint or another shader, but transparency and blend mode would not make much sense there, as it provides certain image but does not apply that image over anything. Even Visible flag does not seem to make much sense... or does it? e.g. one could set camera visible = false, then all viewports that connect to it will display nothing.

Optionally it may be possible to have them originate from GraphicItem, but ignore certain properties as non-applicable. If that makes sense.

ericoporto commented 3 years ago

Tween and any other module that extends existing game objects I think could benefit greatly from this change, since there's a lot of script code duplication today to add things like TweenPosition to all the different game objects.

ericoporto commented 2 years ago

I have been thinking about this, and an alternative would be to have a Transform object, which could be modified with Scale, Translation and Rotation properties, and have the game objects have an attribute to their transform objects, some other object to map pixel transformations (tint, blend, ...) and then the game objects would own these. About transform, the origin is different (characters have at their feet, room objects at bottom left, GUIs at top left), so this should be taken account somehow.

The transform idea I took from neoSphere.

AlanDrake commented 2 years ago

Having a Transform property was actually in the plans. The doubts were if it should only be visual or more.

ivan-mogilko commented 2 years ago

@ericoporto

and an alternative would be to have a Transform object

Could you clarify, you suggest this as an alternative to what (there are many proposals mentioned above)?

ivan-mogilko commented 2 years ago

I realized that forgot to mention another important use for having a class hierarchy of the script objects: it's the ability to cast types. I.e. if you only need to work with basic object's properties or functions, you would do something like (pseudo-code):

BaseType* obj = BaseType.GetAtScreenXY(mouse.x, mouse.y);
obj.RunInteraction(eModeLookat);

Right now you have to check for location type, or call GetAtScreenXY repeatedly for each possible object type.

If someone (@fernewelten ?) will add a dynamic downcast capability to the compiler (engine will likely have to use RTTI for that #1259), then we also can learn the actual object type from the parent's pointer.

ericoporto commented 2 years ago

@ericoporto

and an alternative would be to have a Transform object

Could you clarify, you suggest this as an alternative to what (there are many proposals mentioned above)?

I meant similar to Unity Transform usage: https://docs.unity3d.com/ScriptReference/Transform.html

It would be an attribute of script objects and group the behavior of things that either Translate, Rotate or Resize the object - the matrix transformations. I would not use it to hold positional information since that is used for game logic too, but instead the Translation I was thinking was more in the sense of an offset, like the currently z property which I think is a bad name for YOffset. And perhaps Offset is a less confusing name (vs Translate as from languages). A Transform object and having base objects are not exclusive though. Both could be done.

ivan-mogilko commented 2 years ago

Yes, Unity3d is component-based, while AGS script is rather hierarchy based, so unless we change to component-based system, these attributes will have to be inherited from some top parent or mid-parent type, and not added to every type that has to have them (like you do in unity3d an similar engines).

ivan-mogilko commented 1 year ago

Something I did not mention in the ticket's description, so I will make a quick note now, but this is to be expanded later.

For the most trivial hierarchy, declaring API is the simple part of job. But this must be preceded with internal changes that would allow to implement inheritance of all the script objects from one parent.

The problem is following: the script API functions receive an address to an object, and if the functions are shared (declared in the parent script class), then the exported and passed object pointer should of course be the parent's pointer. Whether this parent contains the shared properties, or uses virtual methods to get/set them in its children, is a secondary question, but it must be possible to reach to the child's implementation. This means that either

First method seem preferable at the first glance, because it's simpler to understand, but the second is a fallback method in case the first will be inconvenient for technical reasons.

Another problem is the storage and the object's lifetime. At the moment the AGS features not less than 3 kinds of objects:

The room objects currently seem most problematic, and it's a good question whether these may be exported to script directly. Because if you do, in current circumstances, then their exported addresses will become an invalid memory as soon as room is left. By the way, this is a curious situation, if we imagine that all objects may be created and deleted dynamically at some point in the future: how should the room objects behave then? Anyway, that's a question for the unknown future.

Right now there seem to be two options:

Also, speaking of dynamically created objects, if we change any of the "static" objects to "dynamic" ones, allowing their creation and deletion at runtime, we must be sure to not store these in plain vectors, but in containers that store them as pointers, as any vector reallocation invalidates the addresses of its elements. But I guess that should be obvious...