Physics and Scripting 101
We’ve now got most of the groundwork out of the way and can start to dabble in physics and scripting, which will quickly start turning this abstract project into a game.
I will assume you have some amount of programming knowledge or experience, but if you don’t you can still follow along. I will explain what the code is doing.
I’ll use MonoDevelop for my instructions because that is available freely to all Unity users.
Ball Physics
Let’s start by giving the ball some physics behaviour. Physics is handled automatically by Unity, so we can get a lot of functionality for ‘free’ by using the physics engine.
The Play Button
Click the Play button in the main Unity window (near the top of the screen in the centre). This runs the current scene, though at the moment nothing happens. That’s to be expected since we haven’t implemented anything yet. Press Play again to return to editing mode.
Add a Rigidbody
What is a rigidbody 2d?
When a GameObject has a rigidbody, the built-in physics engine in Unity acts upon it automatically, giving it mass (e.g. for gravity to work on it).
Add the component
Add a RigidBody2D to the Ball GameObject:
- Select Ball in Hierarchy
- In Inspector click Add Component, select Physics 2D, then Rigidbody 2D.
Enter play mode and see what happens. The ball falls straight down! That is because the physics engine now acts upon the ball.
Making the Ball Bounce
The ball falls with a thud (forget for now that we don’t actually want the ball to fall ‘down’ the screen at all). Let’s make our ball bouncy, and while we’re at it we’ll make the paddles and walls bouncy too. For that we’ll need a physics material.
Materials
A physics material gives physical properties to colliders. These properties affect interactions between different objects.
Create a Material
- In the Assets folder, create a new folder called Materials.
- In the Materials folder right-click and choose Create | Physics2D Material.
- Rename this new material to ‘BouncyMaterial’.
- Select BouncyMaterial in the Materials folder so it opens in Inspector.
- Change the Bounciness property to 1, and the Friction property to 0.
Apply the Material
Select Ball in Hierarchy, then drag the new material into the Material field in the Circle Collider 2D in Inspector.
Now we want to make the walls bouncy too. Instead of doing it for all four walls we will simply make the prefab bouncy, which will then apply to each wall automatically.
- Select WallPrefab in the Prefabs folder (to open it in Inspector).
- Select the Materials folder and drag-and-drop the material from there to the prefab’s collider.
Do the same for PaddlePrefab.
Now hit the play button again and see what happens. If everything has gone according to plan the ball will now bounce! Great, we finally have some movement.
Defying Gravity
Because Pong is top-down we don’t want gravity. Gravity is a constant downward force applied to anything with a rigidbody, and we can change it via the physics settings.
From the menu choose Edit | Project Settings | Physics2D.
A Physics2DSettings pane appears in the Inspector. At the top of this pane are the gravity settings, which are X:0 and Y: -9.81 by default, Change that Y value to 0 to remove the influence of gravity:
![](https://www.grogansoft.com/wp-content/uploads/blog/011215_0004_BeginnersGu5.png)
Hit Play to test the ‘game’. The ball should no longer fall.
Exit Play mode.
Scripting
A script is a component like any other, so you create it like any other component.
- Create a new folder within the Assets folder called Scripts.
- Select the new folder, then right-click in the empty space and select Create | C# Script.
- A script appears in the folder. Rename this script to BallScript (don’t put an extension, just call it BallScript).
Before we go on, attach this script to Ball:
- Select Ball in Hierarchy
- Drag-and-drop the script file onto the blank area at the bottom of the Inspector window.
Double-click BallScript to open it in the code editor.
By default Unity scripts inherit MonoBehaviour, a special Unity class that contains a lot of automated functionality.
The two default methods are Start() and Update(). Start() executes automatically when the scene begins, and Update() runs automatically once per frame.
Modifying the Script
I’ll go through the script piece-by-piece, and then give the whole script in one big lump at the end. If you have any issues, just copy the whole script and replace the entire contents with it.
Add this code between the public class BallScript line and the void Start():
[SerializeField]
float forceValue = 4.5f;
This creates a field (a variable) called forceValue of type float.
We will use forceValue to add a force to make the ball move. [SerializeField] tells Unity that this variable should be changeable via the Inspector window, so we can modify the force from Unity. Save that script (Ctrl-S in MonoDevelop).
Then go back to Unity and select Ball to see it in the Inspector:
![](https://www.grogansoft.com/wp-content/uploads/blog/011215_0004_BeginnersGu7.png)
You can change that 4.5 value in the Inspector, and it will apply to this instance of the script (you could attach this script to multiple balls, and give each one a unique force value). You can use this to tweak the game later.
Instead of [SerializeField] you can make variables public, which has the same effect of making them accessible in Inspector, but you should avoid using public variables unless they need to be public.
Next, add the following to the scripts below the forceValue variable:
Rigidbody2D myBody;
Then, in the Start() method, between the curly braces, add:
myBody = GetComponent<Rigidbody2D>();
These lines create a new variable called myBody, and then assigns a reference to the ball’s GameObject’s rigidbody to that variable. After the Start() method has run we can then refer to rigidbody2D as ‘myBody’ for reasons we’ll investigate in future parts of this tutorial.
Still in the Start() method, add the following line after the previous line (but still before the closing curly bracket):
myBody.AddForce (new Vector2 (forceValue * 50, 50));
This line applies a force (a push) to the ball to get the game started. The Unity physics engine automatically calculates the ball’s movement.
Save the script and go back to Unity and hit the Play button. The ball should start moving towards one of the player paddles, and bounce around a little. Now we’re getting somewhere!
Final BallScript Script
Here’s the full script as it currently stands. You can paste this into BallScript.cs, but if you’ve been following along with no issues there is no need:
using UnityEngine;
using System.Collections;
public class BallScript : MonoBehaviour {
[SerializeField]
float forceValue = 4.5f;
Rigidbody2D myBody;
// Use this for initialization
void Start () {
myBody = GetComponent<Rigidbody2D>();
myBody.AddForce (new Vector2 (forceValue * 50, 50));
}
// Update is called once per frame
void Update () {
}
}
Recap
We learned a little about physics – that a rigidbody gives objects physical properties that Unity acts on via its physics engine. We also learned that gravity is just a constant downward force, which we turned off to make our game top-down. We also added a force to push our ball.
In our first scripting exercise we used [SerializeField] to make variables editable from the Inspector, and we got started learning about MonoBehaviour.
Make sure to save your project and scene. Things will really start to come together when we get some player input to move those paddles up and down and start hitting that ball around in the next part.
Hello, I’m having an issue where my ball is bouncing off the left and right walls (and paddles) perfectly but isn’t changing direction when it hits the top wall.
I’ve copied your script perfectly, even tried copy/pasting. but I can’t figure it out. My walls all have the same properties, colliders etc. Do you know why this would be?
Any help is appreciated, Dave
Sorry for the late reply (your message got picked up by the spam filter!). What exactly happens when the ball hits the top ball? Does it behave the same on the bottom wall? Do you have the bouncy material set up on the walls? Try downloading the complete project and see if that works as you expect.
Same issue happens to me – ball hits the ceiling and sticks, but in my case it only occurs if ‘Force Value’ is set to a smaller number, apparently below 4.2.
I think this is just a side effect of the physics simulation. I think the ball is moving correctly, but the vertical movement can become so slight that it’s effectively zero to the physics engine, so the ball just moves horizontally. There is not enough bounce/force to push the ball away from the top wall.
So How can this be fixed?
I’m having the same problem with the ball getting stuck at the top, and it looks like no-one’s solved it yet. Any solutions since the last comment in May 2016?
Well, toying with “edit collider button” (as Ian suggested) didn’t help. It basicly allows to change colliders “boundary” and position.
At the end I just slightly tweaked parameters in myBody.AddForce (new Vector2 (forceValue * 50, 50));
I increased coordinate y – (forceValue * 50, 60) . The ball impacted upper wall at less steep angle and rebounded happily…
Wow; I think I just pushed the “edit collider button” on the ball and it all now works!!!!
for some reason my ball disappears when I start the script :X
Check ball’s speed. Balls position is recalculated every frame, and it dependent on initial impulse, which is calculated as speed * 50. I assume if your speed is to high, x coordinate of the bal lduring one of iterations can be out of bounds (and well, it seems impact detection is not working in that case, since it is not a physical object after all. it just “teleports” out of the screen 🙂 )