Case Study — Grappling Hook Mechanic
Tensio includes a fully playable Grappling Hook demo in the Tensio/Demos/GrapplingHook folder, demonstrating how to dynamically instantiate, anchor, winch, and swing from ropes during gameplay.
Key Gameplay Concepts
- Object Pooling: Rather than calling
Instantiateper hook projectile, the demo pre-allocates a pooledRopeControllerGameObject and re-initializes it on demand. - Dynamic Pinning: Pins index
0to the player’s weapon tip and indexNto the raycast hit point on the wall or ceiling. - Tensile Retraction: Continuously decrements
rope.SetCurrentLength()while applying directional propulsion forces to the player’sRigidbody. - Natural Pendulum Motion: Setting
Compliance = 0.0fcreates a rigid tether, enabling physics-driven swinging without artificial spring bounce.
Core C# Implementation Breakdown
1. Firing & Anchor Attachment
public void FireHook(RaycastHit hit){ rope.gameObject.SetActive(true);
// Position rope root at launcher muzzle rope.transform.position = muzzleTransform.position;
float hitDistance = Vector3.Distance(muzzleTransform.position, hit.point); rope.InitSettings.Length = hitDistance; rope.InitializeRope();
// Anchor Start to Player & End to Contact Point rope.PinParticle(0, playerTransform, muzzleTransform.position); rope.PinParticle(rope.ParticleCount - 1, hit.transform, hit.point);}2. Motorized Winch Pulling
While the player holds the grapple reel button, cable length is retracted and tensile impulse is imparted to the player body:
void UpdateGrapplePull(){ // Retract resting cable length float newLength = rope.CurrentLength - pullSpeed * Time.deltaTime; rope.SetCurrentLength(Mathf.Max(minGrappleLength, newLength));
// Calculate pull vector towards anchor Vector3 pullDirection = (hitPoint - playerRb.position).normalized; float currentDistance = Vector3.Distance(playerRb.position, hitPoint);
if (currentDistance > 1.5f) { playerRb.AddForce(pullDirection * pullForce, ForceMode.Acceleration); }}3. Detachment & Release
Releasing the grapple instantly unpins both anchors and deactivates the rope game object back into the pool:
public void ReleaseHook(){ rope.gameObject.SetActive(false);}The player preserves their exit momentum, smoothly transitioning into airborne trajectories!