[SUG] New skill - Downwards-Builder / "Ladderer" [POLL]

Started by WillLem, July 10, 2023, 10:18:39 AM

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

What shape should the Ladderer's "ladder" be?

45 degree staircase (as it is currently)
1 (25%)
45 degree slope (Shimmier-friendly)
2 (50%)
Some other shape (please specify in a comment)
0 (0%)
I don't mind
1 (25%)

Total Members Voted: 4

Voting closed: August 04, 2023, 12:09:48 AM

WillLem

#15
Quote from: Strato Incendus on July 29, 2023, 05:17:05 PM
So now I guess the frame where the brick swings into position from below refers to the vertical bricks of the ladder, whereas the bricks that swing into place from above are the horizontal bricks? ;)

Something like that is what I imagine. Whether or not it's actually possible to do it this way remains to be seen...!

jkapp76

The (Jacob's ladder) method seems to have the potential to be much faster than a downward builder would be.
I think a good old-fashioned downward builder would be good. But a faster ladderer seems much better to me.

This seems like something of a Lemmings 3 skill too. I think only L3 had downward building. It's nice to break loose
from the Lemmings 2 skills for a minute.

I'm beginning to think the ladderer will be more useful than the upward digger. I want to see how it works in conjunction
with builders and platformers too.

The runner seemed like a cool feature, but I can't see that being too useful often. I'm thinking the ladderer might be the one.

...Jeremy Kapp

WillLem

#17
Presenting the Ladderer!



Here's a demo video of the current action.

Planned changes:

Rucksack will need to be a different colour to the Builder rucksack, and have a better animation for those last few frames of slamming the origin brick down.

We need some terrain checks - the animation should stop if the "ladder" comes into contact with terrain at any point.

Questions:

Should the ladder start at the same spot as the first Builder brick (current behaviour - see video), or the same spot as the first Platformer brick (i.e. lem's foot position, no height gain)?

Is the sound a bit much? The plan was for it to add some "weight" to the cascading bricks - what do we think?

What should happen when a Ladderer is Cloned? At the moment, the following happens:

Cloned Ladderer

Note that this is not by design, it's purely a result of how the Cloner skill works:


Fig 1. Cloner is assigned to Laddering lem on this frame


Fig 2. The Cloned Ladderer begins from the same frame, and the entire ladder is drawn (this is because, at this point, it's the sprite that we're seeing, not the actual ladder)


Fig 3. Once the animation finishes, we see that only the last part of the actual ladder is built

My own feeling on this is that the entire ladder should be built, but it would be easy enough to mod the sprite so that only the currently-being-built bricks are drawn if we prefer the current behaviour.

Any other suggestions?

WillLem

#18
Bonus challenge!

Can any mathematicians / logicians or anyone who's good at recognising patterns suggest a way that I can simplify this procedure by using a formula or algorithm to calculate the X and Y values relative to each LemPhysicsFrame?

There's a Mars Bar in it for whoever can solve this. NOTE: You'd be getting one-up on OpenAI if you can figure this one out - ChatGPT's answer didn't work!

procedure TLemmingGame.LayLadder(L: TLemming);
var
  X, Y: Integer;
begin
    case L.LemPhysicsFrame of
      9: begin
           for X := 1 to 5 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY -1, BrickPixelColors[9]);
         end;
      11:begin
           X := 5;

           for Y := 0 to 1 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      12:begin
           for X := 5 to 8 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 2, BrickPixelColors[9]);
         end;
      13:begin
           X := 8;

           for Y := 3 to 4 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      14:begin
           for X := 8 to 11 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 5, BrickPixelColors[9]);
         end;
      15:begin
           X := 11;

           for Y := 6 to 7 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      16:begin
           for X := 11 to 14 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 8, BrickPixelColors[9]);
         end;
      17:begin
           X := 14;

           for Y := 9 to 10 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      18:begin
           for X := 14 to 17 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 11, BrickPixelColors[9]);
         end;
      19:begin
           X := 17;

           for Y := 12 to 13 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      20:begin
           for X := 17 to 20 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 14, BrickPixelColors[9]);
         end;
      21:begin
           X := 20;

           for Y := 15 to 16 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      22:begin
           for X := 20 to 23 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 17, BrickPixelColors[9]);
         end;
      23:begin
           X := 23;

           for Y := 18 to 19 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + Y, BrickPixelColors[9]);
         end;
      24:begin
           for X := 23 to 26 do
             AddConstructivePixel(L.LemX + X * L.LemDx, L.LemY + 20, BrickPixelColors[9]);
         end;
    end;
end;


The Frame number is the one on the left (9, 11, 12, 13 .. 24).

The idea is to get AddConstructivePixel down to a single call, which then uses a formula to calculate the values based on the frame number. It might be necessary to do 2 calls - one for the horizontally-drawn pixels, and one for the vertically-drawn pixels.

We can say "for odd frames, do this, and for even frames, do this" and we can also say "for {these} frames, do this, and for {those} frames, do this".

Strato Incendus

While the cloned behaviour does look odd, indeed, it's precisely how it affects the Stacker, too: If you clone a Stacker mid-performance, only the upper parts of the stack will be built, while at the bottom, a gap remains. I've actually created a level recently (for NeoLemmix) that relies on this.

I think this behaviour makes the most sense if we think of the Ladderer as an angular Glue Pourer. Because that's indeed what it currently looks like in action, at least to me. ;) The glue accumulates at the bottom, in this case.

I don't know what happens in between Fig. 2 and Fig. 3. I assume the upper part of the ladder just disappears from one frame to the next.
If the animation played backwards at the end of skill performance, with the bricks being deconstructed from above, until only the part of the ladder that actually became terrain remains, that would fit with the glue-pouring idea.

Perhaps this could be implemented in general, so that it's independent of the Cloner. A regular ladder would then simply not be deconstructed at all, because the entire terrain built by the skill remains. Meaning, the "deconstruct from above" backwards animation could still play — but the number of deconstructed bricks (=the variable you'd have to enter for this) would assume the value 0.
My packs so far:
Lemmings World Tour (New & Old Formats), my music-themed flagship pack, 320 levels - Let's Played by Colorful Arty
Lemmings Open Air, my newest release and follow-up to World Tour, 120 levels
Paralems (Old Formats), a more flavour-driven one, 150 levels
Pit Lems (Old Formats), a more puzzly one, 100 levels - Let's Played by nin10doadict
Lemmicks, a pack for (very old) NeoLemmix 1.43 full of gimmicks, 170 levels

Simon

Quote from: WillLem on July 30, 2023, 05:14:07 AM
simplify this procedure by using a formula or algorithm to calculate the X and Y values relative to each LemPhysicsFrame?
2 calls - one for the horizontally-drawn pixels, and one for the vertically-drawn pixels.
for odd frames, do this, and for even frames, do this

The basic structure can become:

    if L.LemPhysicsFrame < 9 and L.LemPhysicsFrame <> 10 then begin
        Exit;
    end;
    if L.LemPhysicsFrame mod 2 = 0 then begin
       
// even frame
    end; else
       
// odd frame
    end;


Sadly, frame 9 is special: Frame 9 produces a pixel more than the other horizontal-building frames (11, 13, 15, ...). Above basic structure doesn't account for that yet. Ignore frame 9, complete your desired refactrorings for frames >= 11, then see how to marry the old code for frame 9 into the refactored code. Maybe you can produce a pixel more in frames 11, 13, 15, ..., too, and then they'll match the idea behind frame 9.

For the horizontal starting coordinate in even frames, you want an expression f with
f(12) = 5,
f(14) = 8,
f(16) = 11,
f(18) = 14.
This f will be: 3 * ((L.LemPhysicsFrame - 10) div 2) + 2

(How does one see this? First, choose the division by 2 and multiplication by 3 to match the slope, i.e., the pattern of how 2 steps in the input take you 3 steps in the output. Afterwards, shoehorn it onto the correct offsets with the additions/subtractions; for these, it's easy to make mistakes. Test the expression mentally with 2 or 3 examples.)

Find three more such expressions for the vertical starting coordinate in even frames, and for both coordinates in odd frames.

There are many possibilities for the refactoring. One idea: Create two local procedures, one for a vertical brick and one for a horizontal brick. Both will take as input only a starting point. Both will contain the loop and compute the end point for the loop from the passed starting point.

-- Simon

jkapp76

#21
I think the ladder should start at the same height as the platformer brick. If you're trying to save a large
crowd from a splat height you don't want them stepping any higher. This would also let the ladder one
Pixel lower.

The current cloned behavior is probably good either way.

Could use the L2 orange sack color, like the stacker?

The sound is pretty good. Seems loud. (I would have probably tried a higher-pitched dominoes-like click)
...Jeremy Kapp

WillLem

#22
Quote from: Strato Incendus on July 30, 2023, 08:44:39 AM
While the cloned behaviour does look odd, indeed, it's precisely how it affects the Stacker, too: If you clone a Stacker mid-performance, only the upper parts of the stack will be built

Yes, that is indeed the case. I think it's probably best to maintain this as it's likely what players will expect. I've now adapted the sprite so that it only displays the currently-drawn brick for each frame. That way, the Cloned lem only shows the bricks which will actually exist.

The skill shadow also follows suit, as can be seen in the video at the end of this post.

Quote from: Simon on July 30, 2023, 11:20:35 AM
Ignore frame 9, complete your desired refactrorings for frames >= 11, then see how to marry the old code for frame 9 into the refactored code.
---
One idea: Create two local procedures, one for a vertical brick and one for a horizontal brick. Both will take as input only a starting point. Both will contain the loop and compute the end point for the loop from the passed starting point.

Thanks for this, Simon! I've managed to simplify it down to the following method. A similar version of this is also used for drawing the skill shadow:

EDIT: Posted this again after finding another way to simplify it further


procedure TLemmingGame.LayLadder(L: TLemming);
var
  i: Integer;
  PosX, PosY: Integer;
  FrameOffset: Integer;
const
  VerticalBrick: array[0..3, 0..1] of Integer = (
       (4, 0),
       (4, 1),
       (4, 2),
       (4, 3));

  HorizontalBrick: array[0..3, 0..1] of Integer = (
       (1, 0), (2, 0), (3, 0), (4, 0));
begin
  PosX := L.LemX + L.LemDX;
  PosY := L.LemY;

  /// Horizontal bricks
  for i := 0 to Length(HorizontalBrick) - 1 do
  begin
    // First ladder frame need an extra pixel at lem's foot position
    if L.LemPhysicsFrame = 10 then
      AddConstructivePixel(PosX, PosY, BrickPixelColors[9]);

    // Only draw horizontal bricks on the following frames
    if L.LemPhysicsFrame in [10, 12, 14, 16, 18, 20, 22, 24] then
    begin
        case L.LemPhysicsFrame of
          10: FrameOffset := 0;
          12: FrameOffset := 3;
          14: FrameOffset := 6;
          16: FrameOffset := 9;
          18: FrameOffset := 12;
          20: FrameOffset := 15;
          22: FrameOffset := 18;
          24: FrameOffset := 21;
        end;

      if L.LemDX > 0 then
        AddConstructivePixel((PosX + FrameOffset) + HorizontalBrick[i, 0],
                             (PosY + FrameOffset) + HorizontalBrick[i, 1], BrickPixelColors[9])
      else
        AddConstructivePixel((PosX - FrameOffset) - HorizontalBrick[i, 0],
                             (PosY + FrameOffset) + HorizontalBrick[i, 1], BrickPixelColors[9]);
    end;
  end;

  /// Vertical bricks
  for i := 0 to Length(VerticalBrick) - 1 do
  begin
    // Only draw vertical bricks on the following frames
    if L.LemPhysicsFrame in [11, 13, 15, 17, 19, 21, 23] then
    begin
        case L.LemPhysicsFrame of
          11: FrameOffset := 0;
          13: FrameOffset := 3;
          15: FrameOffset := 6;
          17: FrameOffset := 9;
          19: FrameOffset := 12;
          21: FrameOffset := 15;
          23: FrameOffset := 18;
        end;

      if L.LemDX > 0 then
        AddConstructivePixel((PosX + FrameOffset) + VerticalBrick[i, 0],
                             (PosY + FrameOffset) + VerticalBrick[i, 1], BrickPixelColors[9])
      else
        AddConstructivePixel((PosX - FrameOffset) - VerticalBrick[i, 0],
                             (PosY + FrameOffset) + VerticalBrick[i, 1], BrickPixelColors[9]);
    end;
  end;
end;


Quote from: Simon on July 30, 2023, 11:20:35 AM
Maybe you can produce a pixel more in frames 11, 13, 15, ..., too, and then they'll match the idea behind frame 9.
Quote from: jkapp76 on July 30, 2023, 02:17:46 PM
I think the ladder should start at the same height as the platformer brick.

Agreed - in fact, lowering the starting brick by 1 pixel allows it to be 1 pixel shorter, meaning that all horizontal bricks are 4px long. So, this solves the "extra pixel on first frame" conundrum - the extra pixel was required so that the Ladderer had a pixel at their foot position, preventing them from walkng through the "checkerboard" if that first pixel wasn't there. Lowering the first brick 1px removes the need for this.

Furthermore, it grants an extra pixel of "Ladderer can start here", meaning that there's an extra frame of assignability - ideal for real-time play.

I've also started the ladder cascade on frame 10 instead of 9 now, so there isn't a skipped frame. This makes the animation and sound pattern a lot smoother.

Quote from: jkapp76 on July 30, 2023, 02:17:46 PM
Could use the L2 orange sack color, like the stacker?

The Stacker in SLX already has orange. I was thinking maybe purple, teal or dark brown...?

Quote from: jkapp76 on July 30, 2023, 02:17:46 PM
The sound is pretty good. Seems loud. (I would have tried a higher-pitched dominoes-like click)

Great idea! I have a set of dominos which make nice sounds, I'll see about getting a recording :thumbsup:

Here's a new video demo, complete with skill shadow and corrected Cloner interaction:


jkapp76

I'm wondering if you stand at the end of the ladder and begin another ladder if it'll continue as one single long ladder? Or if it'd create a step where the new one begins. One single ladder would be cool
And be like the builder.

I attached the pull down ladder picture as it reminds me of the ladderer. I think a purple sack would get lost in the purple button color. Green and blue would get lost in the lemming colors. Teal sounds okay, or a light blue. IMO

...Jeremy Kapp

WillLem

#24
Quote from: jkapp76 on July 31, 2023, 04:37:04 AM
I'm wondering if you stand at the end of the ladder and begin another ladder if it'll continue as one single long ladder?

No, it doesn't unfortunately - it continues on directly from the last step, but is a little bit further forward. It also isn't Shimmyable on the underside, but we already have Builders and Platformers for that.

However, one thing I noticed when testing today is that the trajectory is identical to the Laserer - it's therefore possible to connect 2 laser tunnels (that were created by the same Laserer) using a Ladderer, like so:



I also think that the Ladderer's near-immediate action more than makes up for its shortcomings, and - like the other construction skills - I'm sure it will prove to be very versatile.

Quote from: jkapp76 on July 31, 2023, 04:37:04 AM
I think a purple sack would get lost in the purple button color. Green and blue would get lost in the lemming colors. Teal sounds okay, or a light blue.

Agreed :)

Strato Incendus

Yes, the interaction with the Laserer angle is certainly a great unique new feat! :thumbsup:

The only way to add an interaction with the Shimmier... would be to remove the steps all together and turn the ladder into a ramp, while keeping the angle the same (45 degrees) as for the Laserer. The slope would be walkable from above and shimmier-friendly from below.

This would be closer to the old idea of using the Roper as a downward Builder. Back then, "Ramper" was one of the names we were considering. I guess that would technically be closer to a diagonal-downward Platformer than a downward Builder.

So the question is: Are we attached to the name "Ladderer", and the shape of the Jacob's Ladder to go along with it?
Or do we want to maximise game-mechanical use? In that case, the 45-degree ramp would be more versatile. "Ramper", "Roper", or "Glue Pourer" would all make sense as names here.

Since the idea of the lemming letting down a ladder isn't too different from the lemming letting down a rope, "Roper" would be fitting.
Then again, usually, when people climb a rope in real life, it's a vertical rope. So if anything, a Roper would be a downward Stacker that creates walls for Climbers... :D
My packs so far:
Lemmings World Tour (New & Old Formats), my music-themed flagship pack, 320 levels - Let's Played by Colorful Arty
Lemmings Open Air, my newest release and follow-up to World Tour, 120 levels
Paralems (Old Formats), a more flavour-driven one, 150 levels
Pit Lems (Old Formats), a more puzzly one, 100 levels - Let's Played by nin10doadict
Lemmicks, a pack for (very old) NeoLemmix 1.43 full of gimmicks, 170 levels

jkapp76

#26
I think Will's ladderer animation looks great.

And I think Strato's idea to make the ladderer shimmier-interactive is great too.

I've been looking at Jacob's ladder toys and they seem to all be straight, not in the "stairs" shape. I think if he decides to make this ladder
straight it should still be called the ladderer. The proper extending animation makes it a ladderer more than the final shape.

I'm sure he's put alot of time and work into the current ladder animation and It'd almost be a shame to make it straight now, but I
see the advantages too. And the possibility of this interaction wasn't considered until late.
...Jeremy Kapp

WillLem

The current plan is to release the new skills (Ballooner and Ladderer) in 2.6 - a pre-release RC version will be distributed to anyone that would like to volunteer to give the new skills a test run.

I'd like us to try out the Ladderer as it is now, because it's quite unique and may offer enough interesting possibilities in its current form. If it becomes clear that people specifically want the 45-degree ramp, then we can look at changing it later. I'd probably keep the name "Ladderer", and the ramp would cascade out in the same way.




On second thoughts, that's three people now who've suggested it should be a smooth slope (nin10doadict commented this on the video). Maybe we should just go with that...

I've put up a poll.

Strato Incendus

#28
As reigning King of Shimmiers, my vote is clear. 8-)

I'm sorry for potentially having created additional workload for you, WillLem. ;) However, if there is popular demand for the Ladderer being a 45° slope, then it would be more efficient to change the behaviour now than at some undefined later point in time. The programming effort would be the same, but if a majority of players end up being in favour of this, and we change it later, chances are higher that it will additionally affect existing levels.

Of course, that depends on whether SuperLemmix will be considered "stable" at that point or not. Then again, Mike is already maintaining a SuperLemmix version of his pack, as it seems. So I guess the transition from SuperLemmix being "in development" to being treated as "stable" by at least some players / level designers is going to be gradual.

Also, thanks to jkapp76 for discovering that most Jacob's Ladders are indeed straight lines at the end of "unfolding"! :thumbsup: That way, we can indeed keep the name "Ladderer". Now the question is just about game-mechanical use.



Another argument in favour of the slope, which has nothing to do with Shimmiers, is the ease with which lemmings can walk through the staircase from the opposite side. With Builders, this is something we treat as a given — and we actively have to use three-Builder walls to stop it.

With the Ladderer, if the staircase is angular, it should basically never be possible for a lemming to pass through the staircase from the other side, because the lemming will always run against a vertical brick and turn around. If you then have to bash through the ladder to let the crowd on the other side, you need to reseal that gap again with a Builder. Which kind of defeats the purpose of the Ladderer. It should be possible to e.g. only provide Ladderers on a given level, without always having to provide additional Builders and Bashers, just in case some lemming gets stuck on the other side.

The Cloner example in the video doesn't test this, because for the one staircase where a lemming does pass through from underneath, there is actually another vertical step right before slipping through the terrain. Meaning, the vertical height he then has to overcome in order to slip through the staircase is just one pixel — not the standard brick height of a vertical Ladderer brick. Normally, the vertical height of the bricks seems to be at least two pixels? I don't know how lemmings behave, then, if there is also a "ceiling" (=a horizontal brick) above that vertical brick.

Perhaps it is indeed possible for lemmings to slip through the angular ladder — of course, I haven't been able to test this myself yet. ;) Even then, though, I'd argue this would be confusing for the player. Because there are lots of cases where horizontal terrain on top of vertical terrain means lemmings won't be able to pass through that (such terrain configurations normally also stop Climbers). And then, there's these weird fringe situations, in which the lemming only has to overcome one pixel or so, or in which Climbers can climb up a wall despite that wall having 1 pixel of protruding terrain. (For example, Climbers climbing through the wooden staircases in the Pillar tileset if you put a slight vertical dent into them from above.)

In short: The ladder at least looks like it should never be possible to pass through it from the other side (especially on flat ground, rather than from below, as in the Cloner example in the video). Even if it is possible to pass through the angular staircase from the other side, I'd argue it's not what the player would expect. Hence, such player confusion should be avoided, if possible.



In contrast, if the ladder is a slope / ramp, lemmings will clearly be able to pass through it from below, just like with a Builder staircase, and then continue to walk on top of it. This would eliminate the nuisance of lemmings constantly getting stuck on the other side of the ladder (which is something that can already happen easily with Stackers).

There are also plenty of levels where such slopes are part of the terrain, of course (think of the blue lines in the Crystal tileset). The ladder would then behave the same way. Hence, it would be consistent with player experience from regular terrain, and therefore also consistent with player expectations.
My packs so far:
Lemmings World Tour (New & Old Formats), my music-themed flagship pack, 320 levels - Let's Played by Colorful Arty
Lemmings Open Air, my newest release and follow-up to World Tour, 120 levels
Paralems (Old Formats), a more flavour-driven one, 150 levels
Pit Lems (Old Formats), a more puzzly one, 100 levels - Let's Played by nin10doadict
Lemmicks, a pack for (very old) NeoLemmix 1.43 full of gimmicks, 170 levels

WillLem

Quote from: Strato Incendus on August 01, 2023, 07:59:55 AM
I'm sorry for potentially having created additional workload for you, WillLem. ;) However, if there is popular demand for the Ladderer being a 45° slope, then it would be more efficient to change the behaviour now than at some undefined later point in time

No worries, tbh it was a satisfying challenge to get the angular ladder working, so that was its own reward.

The more I think about it, though, a slope would be better - it would continue on the same trajectory like Builders and Platformers, and could therefore be used to properly connect Laser tunnels, and it becomes Shimmyable, which is too much of a benefit to ignore, really.

Turns out, as well, that the slope would actually be a lot simpler to code, since it would be made up of bricks that are all the same size and shape rather than vertical and horizontal bricks, as it is currently; a slope, then, should be easier to bugfix and maintain, in theory.

Quote from: Strato Incendus on August 01, 2023, 07:59:55 AM
With the Ladderer, if the staircase is angular, it should basically never be possible for a lemming to pass through the staircase from the other side

It is possible, but I can see why a player might expect it not to be.

Quote from: Strato Incendus on August 01, 2023, 07:59:55 AM
There are also plenty of levels where such slopes are part of the terrain, of course (think of the blue lines in the Crystal tileset). The ladder would then behave the same way

Indeed! This is the exact piece that I'm using as a template for the slope ;P