SLToo, Bomber countdown alignment

Started by WillLem, October 21, 2021, 04:22:46 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

WillLem

Edit Simon: Split off SuperLemminiToo Build Instructions: How to build from source




On further investigation of the Bomber number issue, it appears to be dependent on each lemming state. For example, the Faller actually has the number in the correct position:



Meanwhile, we already know that the Walker has the number 3px too far to the left:



Furthermore, the Builder has the number several pixels too high (presumably to keep clear of the brick as it comes over the lemming's head):



So, it appears that the reason for the bug is that the number is dependent on the actual lemming graphic, at least to some extent. It needs to be tied instead to the lemming's pixel position. This is, therefore, a deeper bug than simply moving the graphic 3px to the right (whether in the code or by modifying the graphic itself), so... if Charles or anyone with a bit more experience fancies jumping in at any point, please do!

Meanwhile, Pooty and I will continue to investigate this :lemcat:




OK... so, Pooty created a new variable which ties the number graphic to the lemming's foot position on the Y axis. This can be used to vertically position the number according to the lemming's feet (rather than the top of the graphic, as it is currently):



-18 pixels seems to be the sweet spot for this for all but Builders and Floaters, which need the extra space for bricks and umbrella respectively. The Amiga version has the number move up for these states, so it's almost certainly worth keeping this consistent (and therefore using Pooty's variable to create different ypos rules for just these states).

Meanwhile, the X axis is indeed 3px too far to the left; this can be confirmed by looking again at the Amiga version, which has the number 3px over to the right for fallers, but perfectly centrally aligned for all other states. This is easily fixed by adding + 3 to this line (note that one line of code has been added, so this was line 1818:



So, where we're up to is that it's likely that the horizontal position will simply be fixed by adding + 3 to the xpos, and then either removing excess height from the Builder & Floater graphics, or adding lines of code to deal with these states specifically.

For now though, sleep time! :sleep:




Massive thanks to Pooty - I would have still been floundering away on my Mac without your help, no doubt.

Charles

I think you were in the right section earlier... It's the same code that draws the timer in all 3 situations.

In GameController.java, line 1815/


            //draws any countdown graphics if necessary
            LemmImage cd = l.getCountdown();
            if (cd != null) {

                int x = mx - xPos - cd.getWidth() / 2;
                int y = ly - yPos - cd.getHeight();
                if (x + cd.getHeight() > 0 && x < Core.getDrawWidth()
                        && y + cd.getHeight() > 0 && y < LemminiFrame.LEVEL_HEIGHT) {
                    g.drawImage(cd, x, y);
                }
            }


I think the trick is looking at how it decides where to draw the image. 
g.drawImage draws the countdown graphic with x,y as the top-left corner of where to start drawing.

So, x is the left side of the countdown graphic, and y is the top of the countdown graphic. (The top left corner of the level is [0,0].)

For the horizontal centering bug we'll want to look at x. For the height bug on the builder, we'll want to look at y.

x = mx - xPos - cd.getWidth() / 2

  • mx is defined earlier as the midX() of the lemming
  • xPos is a static variable in GameController that keeps track of the horizontal scrolling offset for the level.
  • cd.getWidth() / 2 is getting the middle of the countdown graphic
So, at first glance, it looks like everything is set as it should be to center things.  We're getting the middle of the lemming, and the middle of the countdown graphic.

So, the next step is to look deeper into those variables. Let's start with mx. For a shortcut in Eclipse, you can select any reference to that variable, and press F3 to jump to it's declaration (or where it's defined).  If you do that on line 1818, you'll go to int mx = l.mid();. Next step is to look at what l.mid() is really doing, so click on midX() and press F3.

That will jump you to Lemming.java line 1925, where you can see:

    public int midX() {
        return x;
    }


But wait... a little further down there's this:

    public int footX() {
        return x;
    }

Which is it? they both return the exact same thing, but one's supposed to be the foot and the other is supposed to be the middle...
And further, the x variable itself has the comment x coordinate of foot in pixels.

It looks like the bug is not in the countdown graphics, but instead in the lemming.midX() function!

So, change that to:
    public int midX() {
        return x + width()/2;
    }

And your problem is solved!  Except, not quite... because there are other functions that depended on the incorrect behaviour of midX(), and by fixing the function, you've broken all those other things that relied on the bad code.

The only thing to do then is fix all those references one by one. Right-click on midX(), and choose references-->Project. That will show you everywhere that function is called. You can then go one by one and replace references to midX() with footX() instead.

Now, this is purely theoretical, mind you... I haven't tested any of that -- only walked through the code, but I think working at it from that angle will put you on the right track.

WillLem

@Charles

Just seen your reply after editing my previous message with an update. Pooty figured out what the mx function was, and we got as far as the work detailed above. Your suggestion definitely seems worth a try though, I'll look at that tomorrow :thumbsup:

WillLem

@Charles @Pooty @Anyone else interested

I've read through Charles' suggestion of how to tackle this issue, and I like it. However, one thing I'd like to try first is to add 3px to the xpos whilst employing Pooty's my variable for the ypos on 3 separate lines of code - one to deal with Builders, one to deal with Floaters, and one to deal with all other states (I'm guessing these will either need an if/then or an if/else function). If this solves the problem sufficiently, then it means not disturbing the midX function - however, there may be benefits to fixing this anyway, and dealing with the fallout as Charles suggested.

This is a flying forum visit; I don't have time to tinker with it this evening, but I will make some time to look at this properly during the day tomorrow. Suggestions welcome in the meantime!

WillLem

#4
Update! Thanks again to everyone so far who's encouraged and helped me to get stuck in to this :thumbsup:




OK, so I've scoured through the code and can't find a way to specify lemming states as a condition. I've tried
if (Lemming.Type.FLOATER = true || Lemming.Type.BUILDER = true)
to no avail.

So, I tried Charles' suggestion instead in the meantime. The midX function has 8 references throughout the project, so 7 other things (cursor position being one of them, obvs) are affected by tinkering with this:

LemminiPanel.java line 925
LemmCursor.java line 206
Lemming.java lines 1208 & 1112
Sprite.java line 249, 359 & 361

(I changed all of these to footX, as suggested).

The result was that the number appeared very far off to the right of the lemming:



Rather than change everything back to midX, however, I've kept the other 7 references as footX, and instead made the midX function return x + 3. This fixes the x-Position of the number for all states except the right-facing Faller (even the left-facing Faller has a perfectly central number):



(As you can see, though, the left-facing faller appears as if it's slightly inside the terrain block, whereas the right-facing faller is in a better position relative to it. This is clearly a different problem, then, which seems to be specific to the Faller graphic. The left-facing one needs to be moved 3px to the left, which would mean that the timer number would be 3px too far to the right for both Faller states.)

This at the very least makes the countdown number behave similarly to the Amiga version (i.e. xPos = 3px over to the right for right-facing Fallers, and perfectly central for everything else). So, I'm happy that this is fixed, although may want to add a line of code to shunt it 3px to the left (or, indeed, not move it at all) for Fallers when I can figure out how to specify lemming states as a condition.




This only leaves the yPos, which is currently dependent on the actual sprite graphics themselves, with the timer number appearing higher above the head for Floaters, Builders, Miners and even Diggers (due to the terrain spray). My feelings here are that only Floaters really need the extra headroom; the other states only feature momentary overlaps between the lemming sprite and the timer number. So, again, once I know how to specify lemming states as a condition I'll move the timer number 18px above the lemming's foot for all states except Floater.

I wonder if it's worth adding an extra function which returns y - 18 in order to achieve this, and use the original midY (which returns y - lemRes.size) for the case of Floaters. This would mean that all other code which depends on midY would stay as it is, whilst the timer number code can remain relatively tidy. Alternatively, using Pooty's int my = l.footY(); variable seems an elegant enough way to achieve the desired result using only the existing functions.




Incidentally, I had a look at how the timer number appears in WinLemm, and it's all over the place! It seems Lemmini actually reduced the bugginess of this particular feature.

Charles

Lemming.Type is an enum (short for enumeration).

Basically, those are fixed values... it'd be the equivalent to you checking "if (2 == true)".  Remember, the Lemming reference (in Lemming.Type) refers to the Lemming class (i.e *all* lemmings), not the one specific lemming object you want to know about.

The lemming object that's drawing the countdown graphic is l (lower-case L).  So your code should be

if (l.getSkill() == Lemming.Type.FLOATER || l.getSkill() == Lemming.Type.BUILDER) {
}

∫tan x dx

Another thing that might be something to consider is the use of Java's ability to expand upon enums.

Java basically implements enums as classes in their own right, which means that enums can define their own methods and constructors. In particular, one could have some field with the x/y offset values, and populate that field via a private enum constructor.

This way, you simply do not need to check for the state being a few oddball edge cases. Instead you would get the offset directly from the current state and simply apply that value.

Hope this helps! :thumbsup:

WillLem

#7
All done! I've fixed the Bomber number position using the following code (with help from Pooty, Charles and tan_x_dx):

   
            //draws any countdown graphics if necessary
            LemmImage cd = l.getCountdown();
            if (cd != null) {
                int x = mx - xPos - cd.getWidth() / 2;
               
                Lemming.Type currentSkill = l.getSkill();
                int deltaY = (currentSkill == Lemming.Type.FLOATER || currentSkill == Lemming.Type.FLOATER_START)
                    ? ly
                    : my;

                int y = deltaY - yPos - cd.getHeight();
               
                if (x + cd.getHeight() > 0 && x < Core.getDrawWidth()
                    && y + cd.getHeight() > 0 && y < LemminiFrame.LEVEL_HEIGHT){
                        g.drawImage(cd, x, y);
                    }
                }


Note that the code now moves the number upwards to lfp - 18 on the y Axis (where lfp is the lemming's foot position) for ALL states except the Floater*.

Meanwhile, the number has also been moved 3px to the right for all states, in order to align with the lemming centrally. The only state for which this now isn't the case is the right-facing Faller. I considered a number of solutions to this, including extra lines of code to deal with Fallers (overly messy and cluttered), and moving the sprite itself 3px to the right; both of these ideas created a domino effect of other problems, since a Faller can transition to a number of states, including Floaters, Exploders, Splatters, Burners, etc... so adapting the code for Fallers makes the number jump around, and adapting the Faller sprites makes the other sprites jump around.

So, after some reflection and experimentation, I'm settled on leaving the number as-is for right-facing Fallers and not making any changes in this regard. It's the same in the Amiga version anyway (i.e. too far to the right for right-facing fallers), so it's good enough for me! :lemcat:

I'm going to concentrate my coding efforts on other parts of SL for now, see what else I can have a tinker with. This has been a fun and productive learning process, so thanks again to everyone who has helped and encouraged me with it! :thumbsup:




*The Floater has 2 states, FLOATER and FLOATER_START (where it hasn't yet finished opening up its umbrella). At the moment, FLOATER_START is 16 frames, but for the purposes of the Bomber number position it only needs to be 6 frames. I wonder whether the code can be adapted further to have the Bomber number only change from frame 7 of FLOATER_START, but I don't wonder too hard about this ;P