Throwable blade sticking in objects: Looking for the right approach

Hi everyone,

I have a game where the player can throw non-kinematic Rigidbodies around, e.g. blades. To make it more fun, I would like to achieve that a blade sticks in another object, e.g. a wall under realistic circumstances. I could imagine that would be:

  1. Only stick if blade hits the wall with its tip 2) Only stick if blade has a certain velocity normal to the collider mesh of the wall

For both points I’m not sure what would be the best way to implement them

Has anyone ever done this? I imagine that it is quite hard to implement this reliably… What would be your approaches for this?

Thank you so much

Seemed like a fun little idea, so I took a stab (hehe) at a little prototype: Imgur: The magic of the Internet

It’s far from perfect but a decent starting point.

Here’s the code for the blade controller:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BladeController : MonoBehaviour
{
   public Collider sharpEnd;

   private Rigidbody rigidbody;

   private void Start()
   {
     rigidbody = GetComponent<Rigidbody>();
   }

   private void OnCollisionEnter(Collision collision)
   {
     foreach (ContactPoint contactPoint in collision.contacts)
     {
       // are we hitting with the pointy bit?
       if(contactPoint.thisCollider == sharpEnd)
       {
         // is it going fast enough?
         if (rigidbody.velocity.magnitude >= 20)
         {
           // embed it
           transform.SetParent(contactPoint.otherCollider.transform.root, true);

           // destroy this rigidbody so it stops performing physics on the embedded knife
           Destroy(rigidbody);

           return;
         }
       }
     }
   }
}

And what the prefab looks like in the hierarchy:

A couple of tips:

  • If you want just the tip, not the entire blade to stick into something, make sure you set the child collider object to something really small otherwise the whole blade has the potential to stick.
  • You should probably add a check to make sure the blade is facing the right way, assuming only one side is sharp.
  • You’ll definitely want to move the blade into the contact point a little bit, before destroying the rigidbody, otherwise you’ll see blades kinda floating in mid air since the physics system is pretty good at detecting collisions early so the blade ends up being like… 0.01 units inside, not very convincing visually.

Put a collider on the handle only.

When the handle collider hits something you work out if it’s something it can stick in or bounce out from the OnCollisionEnter() data e.g. normal of surface vs angle of the blade.

Hehe, awesome guys. Thanks alot. Your Demo rocks :slight_smile: And is a great test!

@GroZZleR : I believe one thing is missing - it should not only be decided based on the collider which is hit, but also the impact normal.

See the following examples, 1 should not stick, 2 does. This is how a blade would stick in reality. The arrow is the blade with its tip, the circle is the object to stick to.

Do you have any idea how this can be achieved?

@Arowx : Wouldn’t you miss a lot of cases where a collision occurs? E.g. in example 1) the blade would just fly past thhe object?

You would have to get the normal of the surface hit and another direction vector pointing down the length of the blade to the point. Then you could work out the difference in angle between the blade and surface and decide whether it sticks or glances off.

It’s just an adaptation of an arrow trick, because the collider is smaller than the object it ends up looking like it is embedded in it when it stops on impact.

Would your players notice the difference between the two, that depends on the spin speed of the blades and the speed they are thrown?

Also you could use throwing stars and get around the whole blade handle problem.

Dot-product of 2 direction vectors will tell how much they are aligned to eachother. 2 directions being collision point normal and knifes rotation.forward. Dot-product should always be a number within range 1 to -1 i think, where if it’s nearing 0 the angle difference is roughly 90. So i guess you would be asking if it’s > 0.7 or something. The smaller value the less demanding it is. Debug.Log the values when collision occurs.

1 Like

If you don’t mind me hijacking this thread slightly, I find this quite interesting, how would you do this with particle effects? I’ve seen demo reels where they have the classic ice spike magic in several bits sticking to the walls the developer has created and then you have slightly more complicated stuff with ice shards falling to the ground and staying there and so on.

Unity particles support collisions, which can be handled via scripts: Unity - Manual: Collision module

1 Like

That’s exactly what I needed, thank you so much for this.

Will try it out!

Added Zaflis’ math to the little prototype: Imgur: The magic of the Internet

Seems to help a lot.

  private void OnCollisionEnter(Collision collision)
   {
     foreach (ContactPoint contactPoint in collision.contacts)
     {
       // are we hitting with the pointy bit?
       if(contactPoint.thisCollider == sharpEnd)
       {
         // decent angle?
         if (Vector3.Dot(contactPoint.normal, transform.forward) <= -0.700f)
         {
           // is it going fast enough?
           if (rigidbody.velocity.magnitude >= 5)
           {
             // embed it
             transform.SetParent(contactPoint.otherCollider.transform.root, true);

             // destroy this rigidbody so it stops performing physics on the embedded knife
             Destroy(rigidbody);

             return;
           }
         }
       }
     }
   }
1 Like

Haha, so awesome! Will steal that for my Project :wink:

Thank you so much for this!