After two previous attempts, I've finally got image_single working. These three commits (
#1,
#2,
#3), in order, comprise the basic solution.
Before explaining what my solution does, I need to explain why the previous two approaches fell short.
- Approach 1: #define image_single as image_index. The problem here is that, when image_single is set back to -1, image_index must be set back to its old value, including the fractional component (if, e.g., speed is <1). But the fractional component must be dropped if image_index was manually reset any time during that period.
- Approach 2: Use events.res to overwrite image_index in some event (say, End Step). The problem here is that image_single can be set by another event using "with(object)". This leads to flickering, as the image_index has likely advanced a frame, but image_single won't be applied until the next frame.
My approach is basically to create two classes that wrap gs_scalars/integers and overload operator= to track every access. Then, the following logic occurs:
- ImageIndex::operator=() -- Sets a "manual" flag to let the program know that image_index was set by the user (not by image_single). (Protects against image_index updated while image_single is still in control.)
- ImageSingle::operator=() -- If the new value is -1, restore the old value. Else, save the old value of image_index, but only if the manual flag is set. (Protects against multiple calls to image_single in a row.)
- The step event -- don't update if image_single is >=0.
This approach works very well (tested in Iji, a very image_single-heavy game). There's a potential issue with image_index getting a few frames ahead if image_single is called from another object's with() block, but it doesn't come up in practice, because everyone just resets image_index manually most of the time anyway when setting image_single to -1. This is, I think, part of the reason why image_single was dropped originally.
Caveat emptor: I'm not planning on merging this anytime soon. It adds a penalty to every image_index access even if image_single is not used, which I don't think is fair (since no-one uses it for new games). Also, it's only been tested on GM5 (yes, technically GM:S also supports image_single, and I've heard it behaves slightly differently). So I'm only presenting this as an overview to answer the question "What would be necessary to properly support image_single?". The nice thing is that these changes, although messy, are all relatively localized, so we could, in theory, enable them selectively at compile time.