Part 1 - Force is Faulty, and Torque is Tricky
Since January of 2018 I’ve been the lead programmer at a small studio named Almost Infinity LLC, which is a company that was formed as part of the Game Design program at Indiana University. Part of the program is to concept, prototype, build, and launch a game in roughly three semesters.
Our game is called Rollossus, a rolling-based action game built in Unreal where the player controls a ball that must dodge and outsmart enemies to survive seemingly impossible odds. Two major components that I’ve worked on are player movement and enemy implementation. You’re probably here because you want to get satisfying ball rolling in your game, or because you find this extremely specific topic interesting. Throughout this blog series I’ll cover the high-level overhead and some ways to implement the concepts. This will be the first post in a 3-part series on how I designed and implemented satisfying and expandable ball-rolling code in Rollossus. This first part is focused on where the movement code was at when I came onto the project, and what we learned from it as our team pivoted to a new implementation.
Force Is Faulty
When you’re riding a bike you don’t push linearly on the wheel and let the friction turn the wheel as a side-effect, and you shouldn’t do the same with your ball either. The effects of using force in-game isn’t obvious at first, but the effects were noticeable when the player began interacting with loops, inclines, really any irregular surface, and especially in the air. The player didn’t feel like they were rolling a ball, they just felt like they were pushing something along. If the ball you’re rolling has a clear pattern then it’s especially apparent (especially when you have a low friction value). The reason for this is that the player will notice the ball moving forward at a faster speed than they see the ball rotating, and they’ll know something is up. In short, using force to roll your ball creates this odd uncanny valley of rolling, where the player knows something is up, but can’t quite say what.
Stop using force, torque is the way forward. In Rollossus, one of the goals of movement was to make the player really feel like they were rolling a ball. The best way we found to do this was to actually have the player roll a ball using torque, because then the exact physics and interactions sort themselves out.
Torque can be Tricky (but it’s also very good):
We turn a wheel with torque, and that ends up pushing an object forward. A ball is pretty much just a spherical wheel, so it follows that we should not use force to create authentic rolling, we should use torque. As soon as we made the switch from force-based movement to torque-based movement, the results were very clear. Immediately people felt as if they were controlling a rolling ball, as opposed to just pushing an object along.
In Unreal you can very easily add torque to an object (in degrees or radians). Documentation can be found here: https://api.unrealengine.com/INT/BlueprintAPI/Physics/AddTorqueinRadians/index.html
Here is the plot twist: Did you know that a ball could get knocked on its side? Because I did not when I first started working on ball movement. You must keep in mind that your ball in Unreal is a static mesh, and a static mesh has a set forward and right vector. When that sphere starts getting rotated, the forward and right vectors start rotating with it. This doesn’t really present itself as a problem when you’re on flat ground, but when you start adding bounce pads, ramps, drops, traps, walls, etc. you’ll find that the ball can quickly get knocked on its side. The result of this is the ball can start to spin like a top instead of moving the intended direction, which halts pretty much all productive movement. In the gif to the right, you can see an early version of the player ball trying to move to the right after getting knocked on it’s side (blue arrow is right vector, red arrow is forward vector).
This is where the second ball comes in: the secret ingredient. In the diagram to the right (representing a 2D top-down look at our ball), you can see two spheres. We have a Visible Sphere, which is the thing that will roll, hit things and look pretty. We also have the Invisible Sphere, which has no weight or collision and is essentially just a transform inside of the Visible Sphere (so this could also be a cube or a point or whatever you want if it has a position and rotation). The arrow represents the forward vector of the Invisible Sphere, the importance of this will be explained later.
In Rollossus we programmed the Invisible Sphere to face wherever the Input Axes (Pitch and Yaw Specifically) faced, without any other influence. The math for this utilizes our spring arm. This spring arm is important because the rotation of this will adjust what 'forward' is relative to our player's view. We get the vertical axis of our movement stick and plug that into the pitch, and the horizontal axis and plug that into our yaw. We then rotate that around the yaw of our spring arm (to keep it relative to where the camera is facing). The Z value of 1 on the axis is due to a slight offset we have on our spring arm, but you may not have this.
Once that is achieved, the rest is easy. Since we have this Invisible Sphere which always points directly where we want to go, we can take the forward vector of the Invisible Sphere and then use that vector (multiplied by torque value) and apply it to the Visible Sphere. This solves the issue of the ball getting knocked on its side because the Invisible Sphere will always face where the player desires no matter what happens to the Visible Sphere.
That’s the torque, and our magic second ball, and our spring arm. The forward vector of our Invisible Sphere also creates a very handy vector value which we can use in the next part of this blog series, which will get posted next week (spoiler alert: force is good, sometimes…).