Grappling hook physics

Hello,

I’m trying to create a grappling hook type weapon, primarily for hooking into a wall and pulling the player towards it, rather than any kind of swinging. I’ve seen other questions regarding grappling hooks, but they all seem to either use LaunchCharacter, which I don’t think will work for my purposes, or be focused on swinging without any additional force.

I have an extremely crude diagram of what I’m trying to accomplish:

  1. Player launches the grapple, it connects to a wall 100 units away.

  2. After 1 second, the length of the grapple “chain” has shrunk by 20 units.

  3. As a result, the player is moved accordingly. They should also have a velocity of 20 u/s, meaning if they release the rope, they would continue to fly forward

  4. At the same time, the player is hit by some weapon. The impact adds velocity that pushes them off course. The cable either slightly elongates to account for the horizontal shift, or constrains their movement to that of an arc. The difference between the two is minimal, so I don’t think it really matters what happens here. The important bit is that the player can be thrown off track.

  5. The grapple has not been released, so the player is moved another 20 units closer to the wall. The speed from the grapple is the same, but the direction is different, and there is probably still residual movement from the earlier impact.

The impact is one of the reasons I don’t think LaunchCharacter will work. Setting the XY and Z override parameters make it simple to give the character velocity towards the grapple-point, but will eliminate any external velocity. If it’s possible to use LaunchCharacter and combine the velocities seamlessly with those two bools set to false, I honestly can’t see how.

From googling, I think that a PhysicsConstraint is the best option. It certainly seems the closest, but I can’t tell from the documentation if it’s actually capable of doing what I need. Most of the examples I found were of things like 2 cubes being connected by an invisible “rod” that held them in place. If shortening the rod caused the subobject to move towards the primary object with some velocity, then it would be perfect: I could connect the player to the hook with a constraint and shorten the connection length every second, causing the player to be launched towards the hook. Which is exactly what I want to happen.

I have some code for this, but it’s not working at all. I have no idea if the physics constraint is being set up correctly. The documentation is pretty lacking when it comes to the necessary steps for anything to actually occur.

Code below. The constraint is being set up between the character and a placeholder actor, representing the impact point for the hook. The placeholder has a sphere component set up as the root component. From what I’ve read, the constraint will only work if the Character is simulating physics. Setting that in the blueprint prevents wasd motion but doesn’t make the grapple suddenly work.

	hookplaceholder->SetActorLocation(traceloc);
		
	FConstraintInstance ConstraintInstance;
	ConstraintComp = NewObject<UPhysicsConstraintComponent>(hookplaceholder);
	if(!ConstraintComp)
	{
		//UE_LOG constraint UObject could not be created!
		return;
	}

	cabledist = (traceloc - start).Size();
	ConstraintInstance.SetLinearLimitSize(cabledist);
	ConstraintInstance.bLinearZPositionDrive = true;
	ConstraintInstance.bLinearVelocityDrive = true;
	ConstraintInstance.LinearXMotion = ELinearConstraintMotion::LCM_Locked;
	ConstraintInstance.LinearYMotion = ELinearConstraintMotion::LCM_Locked;
	ConstraintInstance.LinearZMotion = ELinearConstraintMotion::LCM_Limited;
	ConstraintInstance.LinearVelocityTarget = FVector(0, 0, 300);

	ConstraintComp->SetWorldLocation(traceloc);
	ConstraintComp->ConstraintInstance = ConstraintInstance;

	ConstraintComp->AttachTo(hookplaceholder->GetRootPrimitiveComponent(), NAME_None, EAttachLocation::KeepWorldPosition);
	ConstraintComp->SetConstrainedComponents(hookplaceholder->GetRootPrimitiveComponent(), NAME_None, PawnOwner->GetSkeletalComp(), NAME_None);

And then in Tick():

	cabledist -= 30;
	ConstraintComp->ConstraintInstance.SetLinearLimitSize(cabledist);
	ConstraintComp->ConstraintInstance.UpdateLinearLimit();

Absolutely nothing happens when I try this. The code is definitely being called, hookplaceholder->GetRootPrimitiveComponent() is returning the spherecomponent, etc. I don’t know if I’m just missing some kind of critical initialization, or if the physics constraint simply won’t work for players, simulating physics or not.

Alternatively, is there a better solution for this kind of thing? A physics constraint looks absolutely perfect on paper, but that requires me to get it to work first. And even then, it’s possible the actual implementation won’t be what I expect. Most of the setup was taken from this page:

Thank you.

Did you work this stuff out? I know it’s old but worth a shot.