[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

The origin of "flickering ghost marbles" in smooth scrolling mode

From: Andreas Lochmann
Subject: The origin of "flickering ghost marbles" in smooth scrolling mode
Date: Thu, 15 Apr 2021 15:41:54 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1

Hi everyone,

this is just information for you, in case you ever wondered why smooth scrolling mode is looking so bad, and what it has to do with programming paradigms.

I still try to increase the performance of Enigma. For the past two days I followed a particular trace, a very old bug: When a level is played in smooth scrolling mode, sometimes, for a split second, the marble is shown at the wrong position, slightly ahead of where it should be. This problem worsens if you move the marble fast or the system is slow. In "Hot Hurdle Race" for example it even looks like the marble is "flickering". You can easily observe it in "Tarzan" when you use "god" and "collision" and move along the bottom line of the level.

I figured that the second, "ghostly" marble is actually a superfluous blit, done just before the offset is corrected to place the marble back in the center. I searched this bug in the display source code for hours and hours.

I was wrong.

If you watch very carefully while performing the "Tarzan" experiment, you will see that *both* images are wrong. The marble always run slightly ahead of the center. The ghost marble is just even further away from where it should be.

I finally found the problem in a function called "gametick" in server.cc, which first calls player::Tick, then WorldTick. The function player::Tick fulfills several tasks, one of them is to provide the position of the marble to follow in smooth scrolling mode, the so-called "reference point". Only after this reference point is saved, WorldTick is called which recalculates the position of the marble. It should have been the other way around: First calculate the new position, then use the new position as reference point. To make things worse, WorldTick sometimes is called twice in a row (namely when the system is slow): This then leads to a double increase of the marble's position and hence to our flickering ghost marbles.

Now you might ask: Why not just call WorldTick first, and then player::Tick?

Because player::Tick has more than one duty. It also deals with respawning dead actors, and you would want this to happen before WorldTick is called.

I think this is one of the few examples where abstraction in programming is actually not helpful. We have a whole tree of tick-functions, and it is very difficult to determine which tick is called prior to which other tick. Then, as in the situation at hand, each tick may deal with several different tasks related to its object, even though some tasks are intertwined with tasks of other objects. A single, long, sequential list of instructions might have been better in this particular case, instead of the deep hierarchy of tick functions we are using right now.

Feel free to draw a different conclusion: That in object oriented programming, each function should have only one task and should be named by what it does, rather than by when it is called.

Still, maybe I'll flatten the hierarchy at some point in time. After all, those are lots of detours, jumping from one tick function to the next. Probably not that much of a performance killer, but still ...

If you found this little excursion interesting, feel free to answer with your own conclusions and suggestions :-)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]