Object carrying is one aspect of the game that has had some problems for a while. I decided it was finally time to sit down and sort it out.
The object carrying script I’ve been using up until now was written about two years ago when I first started working on the project. I’m calling it the spring method because it uses a spring.
The gist of it is that when you find a box to pick up, i create a spring between the player and the box.
The values I use for the different spring properties are:
I also set these properties on the rigidbody of the box:
angular drag: 15
(These values aren’t actually that important. Putting it here more for myself to remember, should it be necessary in the future).
There are several things that I really like about the spring method.
1) It feels great
The feel when carrying the box is really nice. There’s a slight delay between the movement of the box and when you move the camera or the player. While carrying a box, if you move backwards, its distance to you gets stretched a little longer, and when you move forward, the distance gets smaller. There’s also a slight bounce at the end of a movement before it settles in its position. It’s very tactile and really nice.
To be honest, I haven’t seen object carrying done quite like this in other games before.
2) “Natural Physics” effects
You also get really nice “natural physics” effects, like when a box catches on a wall, it’ll get hold up a bit and the distance will stretch, before it bounces back to the player. When you push a box against wall, it’ll have a slight bounce back as well.
3) You can place the box on a ledge very easily
Placing objects on ledges above you is a really important game mechanic. With the spring method, it feels like a very natural, and is easy to do.
1) You can’t fall while carrying an object
Part of the problem here is that the acceleration of the box is different than that of the player, but the spring is still a significant problem. At the values I’ve set it at to make it feel good, the box gets too far away from the player to feel right.
Even if I get the terminal velocity correct, there still is this weird freakish effect that happens when falling:
2) Unpredictable Freakout
Sometimes this happens. This is what happens when drag is 0. The drag on the box is not 0, but I’ve seen it happen every now and then when you’re walking around with the box. It’s a really hard bug to replicate so I haven’t been able to debug it.
SINGLE RAYCAST METHOD
After playing around with different values of spring strength and drag, I decided to get rid of spring and physics altogether.
Instead, I just have the renderer of the box (let’s call it the Phantom Box), with no collider or rigidbody on it, and have it parented to the player.
The position of the Phantom Box is set using raycast.
I had a single raycast coming from the center of the camera straight out a certain distance (what the length of the spring would have been). If the raycast hit a wall, it would get the point it hit the wall at, as well as the surface normal of that wall, and then position the Phantom Box 0.5 units away from the wall, so that it was aligned right up against it.
If felt pretty good, except sometimes the box would go into an adjacent wall:
You can get a better view in this image below:
The issue is that the raycast is only looking at the wall in front, but we have no idea that the wall on side exists, so the box is being drawn into that side wall.
This is no good.
CENTER RAYCAST METHOD
I’m calling this method center raycast method because it uses 6 raycasts, one coming out of each face of the cube, from the center:
Basically, what I do is I send a single raycast forward. I use the end of that raycast (whether it hits a wall or not), as a point from which to draw 6 raycasts (I call these secondary center raycasts).
I use the secondary center raycasts to detect walls and figure out location of cube.
At first it seems movement is good:
I can place the box on a ledge:
BUT, if it’s in the corner, the box can go into the wall:
Since the rays are coming from the center of each face, none of the rays are detecting that adjacent wall, hence the box is drawn over the wall.
I tried using a SphereCast next. According to the Unity docs, it’s sort of like a “thick raycast”
I was putting the sphereCast sphere inside the box, like this:
At first, it seemed to work quite well. The box was no longer going into the wall:
However, I then found a major problem: it’s almost impossible to get the box on top of a ledge:
I believe this is because of the size of the sphere, it isn’t able to spherecast over the lip of the ledge. Well, this isn’t going to work then.
Also, while we’re being nitpicky, it does dig into the wall a little bit (because of the curvature of the sphere at the edges of the box):
CORNER RAYCAST METHOD
This should probably be called Center + Corner RayCast method. It’s like the center raycast method, but I also raycast from each corner.
So each face actually does 5 raycasts.
So along with the single raycast shot at the beginning to determine where to place the secondary raycasts, I have 31 raycasts:
Here’s a sketch showing the different raycasts from the different faces a little better:
It works really well!
The box doesn’t go into the wall at any point, and it’s also easy to place the box above a ledge!
Oh, and check out what it looks like when you fall while carrying a box this way:
Now that I’ve laid out my problem with carrying objects, what do you guys think of this the corner raycast solution? Is there a more efficient or better way I could have done it?
If it isn’t too expensive performance-wise, I’ll probably just leave it for now. It doesn’t feel *as good* as the spring method, but it doesn’t have any of the game-breakig bugs that the spring method had. It’s also way more reliable.