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

Releasing a Holdable entity inside a wall makes it disappear #133

Open
coloursofnoise opened this issue Apr 6, 2020 · 1 comment
Open

Comments

@coloursofnoise
Copy link
Member

Upon release, if the entity's hitbox is within a solid, it disappears.
It doesn't seem to get removed, its position remains the same, and it doesn't appear in debug render.

@DashingCat
Copy link
Contributor

I took a look at the root cause for this issue, and here is the relevant code (the source file is Celeste/Holdable.cs, some variables were renamed for clarity)

public void Release(Vector2 force)
{
    if (base.Entity.CollideCheck<Solid>())
    {
        if (force.X != 0f)
        {
            bool collideFlag = false;
            int sign = Math.Sign(force.X);
            int increment = 0;
            
            // 1)
            while (!collideFlag && increment++ < 10)
            {
                if (!base.Entity.CollideCheck<Solid>(base.Entity.Position + sign * increment * Vector2.UnitX))
                {
                    collideFlag = true;
                }
            }
            if (collideFlag)
            {
                base.Entity.X += sign * increment;
            }
            // end 1)
        }

        while (base.Entity.CollideCheck<Solid>())
        {
            base.Entity.Position += Vector2.UnitY; // 2)
        }
    }


    // ... more code not relevant to the issue ...
}

This method Release is called whenever a Holdable is either thrown or released on the ground; its parameter force contains the direction of the throw in it's X property; and base.Entity refers to the Holdable.

All vanilla Holdables have a collider with a width of at most 8 units, which is the width of a tile too.
As they are aligned with Madeline's sprite, they will never collide with side walls on release in vanilla.
sidewall

So in vanilla, the condition actually only checks for ceilings, and the code:

  1. attempts to move the Holdable forward a bit to see if it can fit further after the ceiling;
  2. and if this fails, proceeds to move the Holdable down so it doesn't get stuck in the ceiling.

However, with modded, wider Holdables, it goes through the same processes with sidewalls as well, because the hitbox of the Holdable extends into the wall (here is a TheoCrystal with a modded width of 12 units):
widertheo

  1. doesn't do anything, because it keeps pushing the entity in the wall so it will keep on colliding;
  2. and proceeds to keep moving the entity down until it doesn't collide with solids (which does warp the Holdable either to a below floor or out of bounds below the level).

In our example, here is where the TheoCrystal ends up after a release (the bottom of the screenshot corresponds to the bottom of the room):
oobtheo

I'm not sure if there is a fix that would work for any given width, and until then I would recommend that modders re-implement this method to fit their needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants