Unity Physics: Creating a Bowling Game Part 1
There is nothing I enjoy more in game development than starting a new project. The next two articles will serve as an overview for a small physics based bowling simulator. Let’s get into it!
Level Design
Organization is crucial to a good workflow, so I sort all of my environmental game objects into empty parent objects according to their contents. Here are my static objects.
This game has a lot of dynamic environmental objects that can be moved via Unity’s physics engine when impacted by regular and explosive bowling balls.
Here is a look from the scene view.
This is how the player views the room from the game view.
Because this is a small scene, and I want to have dynamic cast shadows on the bowling balls, I am using a few real-time lights and a single reflection probe. A little vignette and bloom, and I’m ready to go!
Game assets are from Filebase library by GameDevHQ.
Player Controls
The easiest way to sum up the player controller is to share an image of my controls panel.
Pressing the left-mouse button will start the trajectory line via the physics scene, and releasing the left button will throw the ball. If you don’t want to make your throw for any reason, a right-click will cancel the throw.
In this free play scene, you can freely throw as many balls as you wish, and reset the pins with a press of the space key. This will not be the case in the game scene, which I will cover in my next article.
The player can adjust the power and spin direction on the ball (left vs right) as well as the option to add back-spin.
While I have not yet implemented gamepad controls, I am using Unity’s input system, which will make that step very easy when the time comes.
Forces and Torque
The bowling balls use an interface with method parameters for velocity and torque velocity.
public interface IThrowable
{
//use for applying force and torque to rigidbody
public void Throw(Vector3 velocity, Vector3 torqueVelocity);
}
These values are used to apply force and relative torque to the Rigidbody on the bowling ball script.
public void Throw(Vector3 velocity, Vector3 torqueVelocity)
{
_rb.AddForce(velocity, ForceMode.Impulse); ;
_rb.AddRelativeTorque(torqueVelocity, ForceMode.Impulse);
}
The player script calculates the velocities by multiplying the force and direction, as well and the torque and spin direction. Then it’s as easy as passing this data to the ball via the iThrowable interface after instantiating it.
private void Throw()
{
_ball = Instantiate(_balls[_ballIndex], _firePoint.position, Quaternion.identity);
//check for IThrowable interface
IThrowable throwable = _ball.GetComponent<IThrowable>();
//calculate velocity and torque velocity
_velocity = _firePoint.forward * _force;
_torqueVelocity = _rotationDirection * _torque;
if (throwable != null)
throwable.Throw(_velocity, _torqueVelocity);
}
Physics Simulation
All of the room colliders are a child of one parent, which gets instantiated and moved to the physics scene for simulation. The jukebox has a physics version (no mesh renderer), that goes as well to show the ball bouncing off the jukebox. The physics ball is a duplicate of the bowling ball, also sans mesh renderer, so I don’t have to disable it in fixed update as I send it to the physics scene.
For a more detailed walkthrough of the physics scene, please read my article below on simulating trajectories.
Physic Materials
Physic materials play a very important role in this bowling simulation. The ball needs to be polished, and move move over another polished surface. The surface is not quite as slick as ice, but it lets me add torque to the ball to create a natural spin effect.
Here are the values I plugged into the bowling ball.
Here is the polished wood on the bowling lane.
When it comes to the mass of the ball and pins, I used google to find accurate values for 10 pin bowling to work with.
UI
Aside from the controls panel shown earlier in this article, which has an always visible UI text, I have a few visual cues for the player controls.
The radial fill shows the player power as it changes. The backspin arrow fills in when backspin is enabled, and both opaque and semi-transparent balls change visuals when the player switches between throwing options. The line renderer updates the trajectory line as the player changes these values.
Dynamic Environment
Most objects in the scene other than the walls and floor, can be moved or pushed with physics. The exploding ball of course causes the most disruption.
There is also a coke bottle in the scene which gets shaken up when hit.
The pins just fall as expected, and reset to their original position with an event call on the space key.
Exploding Ball
The exploding ball will be used for a bonus round in the game scene, but in the free play scene, the player can freely use it as much as they please.
Aside from the visuals, the exploding ball looks for a tag before gathering all Rigidbodies within a radius, and applying explosion force to them.
Audio
So far the audio in this game is really simple. A background soundtrack plays, and changes tracks when you hit the jukebox with a ball.
Main Menu
This simple main menu fades in a background soundtrack and has two buttons, one for each game scene. The image is a capture in real-time using Unity’s recorder package, as well as a little post-editing.
Optimization
There are a lot of things at play when it comes to optimizing framerate for this small game. The Max Physics Iterations, has a massive impact on performance the larger that value gets. The higher the value, the longer the line renderer is and lower the FPS goes. When sending the ball to the physics scene it gets run at deltaTime. This can be multiplied by a value to increase the length of the line renderer without increasing the max iterations. That being said, the more you push this value, the more inaccurate the simulation will become. Because I am using torque on the ball, I need a much more accurate simulation. If you are just throwing a ball, you could probably get away with a value between 3 or 5 here (deltaTime stretch).
Here it is in the code base, getting called in fixedUpdate.
The thing that got me the largest framerate increase, was caching local variables, especially those running in update or fixed update loops.
I was running the physics simulation between 2–10 FPS, which was horrible. Simply caching all of the local variables in by update functions pushed me immediately up to an average of 35–45 FPS!
Other things I can do to push my frame rate would be baking lighting and reducing the post-processing effects, but I feel ok for now with my real-time lights and occlusion culling working.
That’s it for this initial article on my bowling simulator. I hope you join me for part 2, where I dive into the game scene with score keeping and various throw patterns for the player to achieve. Thanks for reading and happy game development!