Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make object sorting position on screen always defined #2311

Open
ivan-mogilko opened this issue Jan 23, 2024 · 4 comments · May be fixed by #2627
Open

Make object sorting position on screen always defined #2311

ivan-mogilko opened this issue Jan 23, 2024 · 4 comments · May be fixed by #2627
Assignees
Labels
context: graphics type: bug unexpected/erroneous behavior in the existing functionality

Comments

@ivan-mogilko
Copy link
Contributor

ivan-mogilko commented Jan 23, 2024

Problem

This is a very old problem in AGS, although not mentioned very often. It was brought up around a year ago, and I had thoughts of fixing this in 3.6.1, but forgot to write a ticket, and it fell out of my head.

When the engine sorts objects for drawing, it uses their Baseline/zorder property. The objects with equal baseline/zorder will get random sort order. Well, strictly speaking, not random, but point is that it is undefined. This may sometimes conflict with the scene setup: if there are numerous overlapping objects, any change of any object or character may cause completely unrelated objects visually "drop" below others.

The only exception from this are GUI, which use 2 factors when sorting: zorder and their numeric ID. Which means, if zorder is equal, a GUI with the less ID is drawn behind (or other way... I forgot).

Goal

Make the sorting order among the given set of game objects always defined, so that 2 objects do not change their relative drawing order on screen unless one of them changes its zorder.

Possible solution

The first obvious choice is to sort all objects in the game using a combination of zorder and ID. There are two problems though.

  1. Different types of game objects do not share same ID sequence. There may be Character with ID 10 and RoomObject with ID 10, and some walk-behind with ID 10. So either their IDs have to be converted to a merged ID sequence of a bigger scale somehow for this sorting, or third parameter used (an arbitrary object type index).
  2. Some types of objects do not have explicit IDs. Well, actually, Overlays are ones. They have either a fixed "internal index", which is assigned by looking for an empty slot in array, or, theoretically, an order of creation (it's not currently assigned, but could be). The latter may be implemented using a always incrementing counter, for example.

I will assign this to 3.6.2 update, although wanted to have this in 3.6.1, but 3.6.1 is currently feature-fixed, and in last testing stage...
But this may be done in AGS 4 right away, and backported later if wanted.

UPDATE 1:
Done for Overlays in 3.6.1 (for backwards compatibility, see comments below). Now they are using an always incrementing "creation index" as an "ID".

UPDATE 2:
Walkbehinds do not require different IDs, as they cannot overlap each other. And, according to already existing AGS logic, they always have lower priority when sorting. This makes it possible to just use INT32_MIN for them as a smallest possible "ID".

@ivan-mogilko ivan-mogilko added type: bug unexpected/erroneous behavior in the existing functionality context: graphics labels Jan 23, 2024
@ericoporto
Copy link
Member

I noticed in games where a "character" is made of more than one (ags) character, it needs some sort of "grouping". In Dave's (and I think Francisco's too) games, there's this issue a "character" may pass in front of another but the head of the "character" that is behind is instead in front, this usually happens by the chance when the 4 (head+body char1 and head+body char2) are all in the same baseline.

By being predictable at least if the scenes are tested and some way is found for this not happen when it does at least there's an expectation that using different compilers/ports won't change the tested behavior.

@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Jan 30, 2024

I found that 3.6.1 introduced a problem related to object sort, after optimizing Overlays storage, which I did not realize earlier.

Previously the overlays were constantly pushed into the vector, so newer overlays had always higher container indexes. After optimizing this storage for speed (#2048) the internal container index is no longer related to the order of creation.
This, simply put, breaks overlays sorting on screen in the old games, where they did not have ZOrder property.

EDIT: to think of this, maybe this was potentially broken earlier, when overlays got sorted among guis, because previously they were not z-sorted at all and just pushed to a render list according to their internal storage order.

In the past there were likely not many games with multiple overlapping overlays on screen, maybe that's why this has not been noticed. I noticed this by pure luck, because of my TypedText Demo game where I create 2 overlays on top of each other instead of merging them into 1 image:
https://github.com/ivan-mogilko/ags-script-modules/tree/master/demos/TypedTextDemo

It looks like I will have to add some solution for overlays at least, which would keep their sort in the order of creation.

UPDATE:
done as experimental commit 278dbc4

@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Jul 11, 2024

An update: today I got reminded of this problem, and after thinking over the code, realized that it's actually trivial to get rid of the special rules for sorting the room objects. These rules existed only for walk-behinds, where they always have less priority (in case of equal baseline). So it's possible to pass a minimal possible value as their "tag" instead of using this hack:
4b522b2
UPD: also pushed to release-3.6.1 branch, because

  • looks safe enough; affects only character-walkbehind interaction
  • fixes sorting of room overlays among themselves

What remains for this task is to figure out a good rule for defining this "id" tags for objects and characters, and this problem will get resolved.

@ivan-mogilko ivan-mogilko self-assigned this Dec 19, 2024
@ivan-mogilko
Copy link
Contributor Author

Different types of game objects do not share same ID sequence. There may be Character with ID 10 and RoomObject with ID 10, and some walk-behind with ID 10. So either their IDs have to be converted to a merged ID sequence of a bigger scale somehow for this sorting, or third parameter used (an arbitrary object type index).

Thinking about this made me realize I missed a good option here.
There's an idea that I had for a while, but could not find spare time to work on:
#969 (comment)
where there will be a "Drawables" interface, and each runtime object will receive its "drawable" id.

Even without a fully implemented system like that, we may have a global "drawable" id still. This id then may be used in this sorting algorithm, in order to achieve a persistent sorting.
There's a "creation id" assigned to overlays now, it may be replaced with this "drawable id", which will have similar result in effect.
Static objects may receive it at the game load / room load. Given there's a fixed "max amount" of room objects currenly, there may be a always fixed range of drawable ids in low numbers. Any dynamically created object will receive ids above that range.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
context: graphics type: bug unexpected/erroneous behavior in the existing functionality
Projects
None yet
2 participants