Hang starts but no PullUp

pako

New member
I'm trying to make the Third Person Controller character hang from the top surface of a wall and then pull up on top of the wall. The hang should start after a standing or running jump.

When I test it using a running jump, Hang starts, and then the HangState changes to Shimmy, but after that, the character never pulls up. The character either dops a little and remains about 0.5m below the top of the wall (in mid-air but touching the wall), while it continues to play the Hang animation. Alternatively, sometimes the character drops to the ground and runs against the wall.

The Animator Monitor Debug Log is (AbilityIndexParameter for Hang = 104):

774 Changed AbilityIndex to 104 on GameObject
774 Changed AbilityIntData to 2 on GameObject
777 Execute OnAnimatorHangStartInPosition on GameObject
781 Execute OnAnimatorHangStartInPosition on GameObject
783 Execute OnAnimatorHangStartInPosition on GameObject

I stepped through code and, although I might be wrong about his, it seemed to me that the Vertical Velocity should be reset to zero for the PullUp to start. So, since OnAnimatorHangStartInPosition is triggered (3 times for some reason), I subscribed to this event in the Awake() inside my custom PlayerInput, and reset both horizontal and vertical axis values to zero:

private void OnHangStartInPosition()
{
verticalAxisValue = 0f;
horizontalAxisValue = 0f;
}

These values are then used and returned inside GetAxisRawInternal.

However, for some reason, OnHangStartInPosition() doesn't get called while the character is stuck hanging in the wall, even though the subscription inside Awake() runs properly.

EDIT: I solved the problem of the OnHangStartInPosition() handler not running. Initially, I thought that since the handler is independent of the Character, I could treat it as a global event, and not reference any GameObject. Apparently, whether an event can be handled globally or on a specific GameObject depends on whether it executes with a specific GameObjectReference or not (I think :unsure:). Anyway, I noticed the debug statements saying that the event executes on GameObject. So, I added the relative reference, and the character pulls up after I use the controls to move it forward ?. I'm very happy to have fixed this on my own!

However, the problem remains that since the character drops down about 0.5m from the top of the wall, and then it starts hanging. So, the pull-up occurs through the wall, and then the character falls, apparently since there's no collider to support it.

Even if add a higher jump force, the character always drops down about 0.5m from the top of the wall. Is there a way to fix this?



I've been trying to solve this on my own for a few days, but now I'm really stuck.

I'd really appreciate your help!
 
Last edited:
However, the problem remains that since the character drops down about 0.5m from the top of the wall, and then it starts hanging. So, the pull-up occurs through the wall, and then the character falls, apparently since there's no collider to support it.

Even if add a higher jump force, the character always drops down about 0.5m from the top of the wall. Is there a way to fix this?
Glad you are making progress. Can you post a gif of what is happening?
 
Glad you are making progress. Can you post a gif of what is happening?

I couldn't upload a gif, since even the compressed gif of 4.8MB size was too large.

So, here's a link to my OneDrive folder with both an uncompressed gif and video.

As you'll be able to see:
- the character doesn't hang and pull up properly and falls to the ground
- subsequently, he can't hang and pull up again, whether running (in place) next to the wall, or even if standing idle.

The debug log is as follows:

570 Changed AbilityIndex to 1 on GameObject
596 Changed AbilityIndex to 0 on GameObject
596 Changed AbilityIndex to 2 on GameObject
625 Changed AbilityIndex to 0 on GameObject
625 Changed AbilityIndex to 104 on GameObject
625 Changed AbilityIntData to 2 on GameObject
627 Execute OnAnimatorHangStartInPosition on GameObject
631 Execute OnAnimatorHangStartInPosition on GameObject
634 Execute OnAnimatorHangStartInPosition on GameObject
793 Changed AbilityIntData to 7 on GameObject
945 Execute OnAnimatorHangComplete on GameObject
945 Changed AbilityIndex to 0 on GameObject
945 Changed AbilityIntData to 0 on GameObject
946 Changed AbilityIndex to 2 on GameObject
993 Changed AbilityIntData to 1 on GameObject
1223 Changed AbilityIndex to 0 on GameObject
1223 Changed AbilityIntData to 0 on GameObject
1225 Changed AbilityIndex to 1 on GameObject
1229 Changed AbilityIndex to 104 on GameObject
1229 Changed AbilityIntData to 2 on GameObject
1229 Changed AbilityIndex to 0 on GameObject
1229 Changed AbilityIntData to 0 on GameObject
1230 Changed AbilityIndex to 2 on GameObject
1231 Execute OnAnimatorHangStartInPosition on GameObject
1236 Execute OnAnimatorHangStartInPosition on GameObject
1240 Execute OnAnimatorHangStartInPosition on GameObject
1255 Changed AbilityIntData to 1 on GameObject
1493 Changed AbilityIndex to 0 on GameObject
1493 Changed AbilityIntData to 0 on GameObject
1495 Changed AbilityIndex to 1 on GameObject
1498 Changed AbilityIndex to 104 on GameObject
1498 Changed AbilityIntData to 2 on GameObject
1498 Changed AbilityIndex to 0 on GameObject
1498 Changed AbilityIntData to 0 on GameObject
1499 Changed AbilityIndex to 2 on GameObject
1501 Execute OnAnimatorHangStartInPosition on GameObject
1505 Execute OnAnimatorHangStartInPosition on GameObject
1510 Execute OnAnimatorHangStartInPosition on GameObject
1525 Changed AbilityIntData to 1 on GameObject
 
Last edited:
I couldn't upload a gif, since even the compressed gif of 4.8MB size was too large.

So, here's a link to my OneDrive folder with both an uncompressed gif and video.

As you'll be able to see:
- the character doesn't hang and pull up properly and falls to the ground
- subsequently, he can't hang and pull up again, whether running (in place) next to the wall, or even if standing idle.

The debug log is as follows:
...

I fixed this by setting the y value of RelativeHangOffset to 0.5, from the default -0.17.

However, I cannot understand how Nolan in the demo scene works with a value of -0.17. The description for RelativeHangOffset is:

"The offset from the top of the character to the hang object."

When I compare Nolan to my character, I can see that they are both below the hang object. Consequently, the y value of RelativeHangOffset should be either + or - in both cases, but they are not! Additionally, both Nolan and my character are about the same distance below the hang object, so, their top is also the same distance below the hang object. Accordingly, one would expect that the y value should be approximately equal!

A more detailed description and an example for the use/value of RelativeHangOffset would have been very very helpful!

Additionally, I must say that one of the first things I had tried to fix this, many days ago, and before even posting in the forum, was to try some y values of RelativeHangOffset, because it was the obvious thing to do, and I'm pretty sure that I had tried 0.5 too. However, in that case, it didn't work, because the forward speed of the character was not 0. I had to spend countless hours stepping through code to actually discover that the hang won't work unless the forward speed is 0 (or below the ChangeStateSensitivity setting, if I remember well).

Please note that I had read all the documentation before attempting to customize anything, and there was no mention of the forward speed requirement for the hang ability anywhere in the documentation!

This is just friendly feedback! Please provide better documentation.
 
Thanks for digging into it. I am currently improving the hang ability to work with the climbing pack and will see if I can add any visuals to make debugging easier. I will also do a pass at the documentation.

The Relative Hang Offset is used on the raycast hit point:

Code:
                var targetPosition = MathUtility.TransformPoint(m_RaycastResult.point, raycastRotation, m_RelativeHangOffset);

This hit point depends on the settings that you used for the min and max start offset. I will change the docs to make that more clear.

You should be able to start hanging while running regardless of the m_ChangeStateSensitivity. This sensitivity is used for changing the hang state (such as transferring up or down) and not starting the ability. If you are unable to start when running you should adjust the cast offset/distance to be behind the character a bit more.
 
Thanks for digging into it. I am currently improving the hang ability to work with the climbing pack and will see if I can add any visuals to make debugging easier. I will also do a pass at the documentation.

The Relative Hang Offset is used on the raycast hit point:

Code:
                var targetPosition = MathUtility.TransformPoint(m_RaycastResult.point, raycastRotation, m_RelativeHangOffset);

This hit point depends on the settings that you used for the min and max start offset. I will change the docs to make that more clear.

You should be able to start hanging while running regardless of the m_ChangeStateSensitivity. This sensitivity is used for changing the hang state (such as transferring up or down) and not starting the ability. If you are unable to start when running you should adjust the cast offset/distance to be behind the character a bit more.

Thank you for your response,

Everything is working fine right now, but I'll try adjusting the cast offset/distance as you recommend, as it might work even better.
 
I revisited this and realized that there is a misunderstanding.

I am sorry if I did not communicate this correctly right from the beginning, but now I have isolated the REAL problem, and I am also more familiar with the product.

The REAL problem is that I need the Pull Up to start immediately after hanging Idle, without any more input.

It is my understanding that currently, Hang does not support this, as it requires a "forward move" input, in order to transition from the Hanging Idle animation to the PullUp animation, (or alternative inputs to shimmy or Transfer Up/Down).

In my previous posts, I mentioned "hang won't work unless the forward speed is 0", and I apologize for this! I meant to say that "Pull Up won't start if m_CanChangeVertically does not become true, which happens inside Hang.Update():

// The up button should be released before the character can move up vertically again.
if (!m_CanChangeVertically && !m_GroundedStart) {
m_CanChangeVertically = Mathf.Abs(m_CharacterLocomotion.RawInputVector.y) <= m_ChangeStateSensitivity;
}

i.e. if RawInputVector.y is approximately equal to 0, and then it subsequently becomes greater that 0:

else if ((m_CharacterLocomotion.RawInputVector.y > 0 || m_TryMoveUp) && (m_AllowedMovements & AllowedMovement.PullUp) != 0) {
// There is space for the character to pull up on.
... ...

m_HangState = HangState.PullUp;

In other words, the m_HangState CANNOT be set to HangState.PullUp unless the RawInputVector.y becomes almost 0 and subsequently greater than 0.

Since m_CanChangeVertically is private it's not possible to check its value in "HangExtended", a child class of Hang.cs, in order to achieve the "automated pullup" without modifying the base class.

However, even if m_CanChangeVertically were made protected, then there are problems further down the road. If HangExtended is used in the character, and all Inspector settings were coppied from Hang, the AdjustPullUpCastDistanceHangPreset would complain at runtime that it needs a "Hang" object.

So, at this point, I gave up on "not modifying Hang.cs", and managed to achieve the necessary functionality, which of course will break with any updates.

So, I explained the problem here in detail, since it's related to my original post, and I also started a new simpler post:

Automatic Pull Up after Hang Starts
 
Top