-
-
Notifications
You must be signed in to change notification settings - Fork 29
Home
- Is the source project free to use?
- The ball keeps slowing down
- The AI keeps missing the ball
- How do I set a maximum speed for the ball?
- How can I change the bounce direction depending on where the ball hits the paddle?
- There are no functions available to select for the score trigger
- Script variables are not showing up in the editor
- Error: The namespace EventSystems does not exist
- Error: Can't add script component because the script class cannot be found
- How do I write the "≠" symbol in the code?
Yes, you are free to use the project for any purpose. However, keep in mind that copyright and/or trademark laws can still apply to the original material since many of the games in my tutorials were not originally authored by me. I open source my own code for the community to learn from, but the project is intended for educational purposes only.
This usually is an indication that the ball has drag which causes it to slow down over time. If you want your ball to maintain the same velocity and not slow down, set the Linear Drag
property on the Rigidbody
component to zero.
If the ball slows down when hitting a wall, it is because of the friction between the two objects colliding. To prevent this friction, add a Physics Material
to your ball's collider component with the Friction
value set to 0 and the Bounciness
set to 1. However, the physics interactions can be weird sometimes, so it doesn't always work.
If you still have problems with the ball slowing down, try adding the following function to your Ball.cs
script.
private void FixedUpdate()
{
rigidbody.velocity = rigidbody.velocity.normalized * speed;
}
This code will ensure the ball's velocity remains constant the entire time. You will probably need to decrease the value of the speed
property, though. In the video, we used a value of 200, but with this new code a value of around 5 works pretty well. Feel free to adjust it to your preference.
Try changing the Mass
and Linear Drag
on the Rigidbody
component of your AI paddle. Reducing these values allow the paddle to more easily switch directions, which will help it to be in the right place at the right time to hit the ball. Be careful though, because you can create the opposite problem where the paddle never misses. Adjust the numbers to your preference. You can also change the speed
property that we added to the paddle script to make it faster or slower overall.
To ensure the speed of the ball doesn't exceed some maximum value, we can clamp the magnitude (speed) and then re-apply it back. This would be done inside the FixedUpdate
function of the Ball
script.
private void FixedUpdate()
{
float speed = rigidbody.velocity.magnitude;
speed = Mathf.Min(speed, maxSpeed);
rigidbody.velocity = rigidbody.velocity.normalized * speed;
}
Many implementations of Pong make the gameplay more dynamic and interesting by changing the bounce direction depending on where the ball hits the paddle. It will bounce like normal if it hits the center, but it will bounce at an even steeper angle the further from the center it hits.
First, let's add the tag "Ball" to our ball game object in the Unity editor. This will make it easy to determine which object we are colliding with. In the Paddle.cs
script, let's add the OnCollisionEnter2D
function and only proceed if colliding with the ball.
private void OnCollisionEnter2D(Collision2D collision)
{
// Exit early if we collided with something other than the ball
if (!collision.gameObject.CompareTag("Ball")) {
return;
}
}
The physics engine will handle bouncing the ball off the paddle like normal; we just need to rotate the direction vector even more depending on where the ball hit the paddle. The full logic would look like this:
private void OnCollisionEnter2D(Collision2D collision)
{
// Exit early if we collided with something other than the ball
if (!collision.gameObject.CompareTag("Ball")) {
return;
}
Rigidbody2D ball = collision.rigidbody;
Collider2D paddle = collision.otherCollider;
// Gather information about the collision
Vector2 ballDirection = ball.velocity.normalized;
Vector2 contactDistance = ball.transform.position - paddle.bounds.center;
Vector2 surfaceNormal = collision.GetContact(0).normal;
Vector3 rotationAxis = Vector3.Cross(Vector3.up, surfaceNormal);
// Rotate the direction of the ball based on the contact distance
// to make the gameplay more dynamic and interesting
float maxBounceAngle = 75f;
float bounceAngle = (contactDistance.y / paddle.bounds.size.y) * maxBounceAngle;
ballDirection = Quaternion.AngleAxis(bounceAngle, rotationAxis) * ballDirection;
// Re-apply the new direction to the ball
ball.velocity = ballDirection * ball.velocity.magnitude;
}
A common mistake here is dragging the GameManager.cs
file into the field rather than the "Game Manager" object in your scene. After dragging in the scene object, you should see the functions available on each component attached to that object, including the functions made available in our script.
The other common mistake is not marking your functions as public
in your code. Only public functions are available in the menu. If you don't explicitly set them to be public, then they will default to private.
public void PlayerScores()
{
//...
}
There are two ways for a field to show up in the editor. It can be marked public
:
public float speed;
Or you can use a special attribute:
[SerializeField] private float speed;
If the variable still does not show up, this might be an indication that you have a compiler error. Your code must successfully compile before any new fields will display in the editor. Check your console for any potential errors.
The EventSystems
namespace is available in the Unity UI package, so if this error is occurring it implies that package is not installed in your project. Usually this package is installed by default, but you can manually install it from Unity's package manager, Window > Package Manager
.
Alternatively, there's an even easier solution to the ScoringZone.cs
script compared to the original video tutorial that does not rely on Unity's event systems. I would actually recommend using this code instead:
using UnityEngine;
using UnityEngine.Events;
public class ScoringZone : MonoBehaviour
{
public UnityEvent scoreTrigger;
private void OnCollisionEnter2D(Collision2D collision)
{
Ball ball = collision.gameObject.GetComponent<Ball>();
if (ball != null) {
scoreTrigger.Invoke();
}
}
}
This is a common error that occurs if the name of the script does not match exactly the name of the class in the script. If your script is called MyClass
, then the class name must be MyClass
. This is also case-sensitive. Double check to make sure that this is not the issue.
If you are still running into the problem, it might help to recreate the script file again. When you create the script in the Unity editor, Unity automatically generates a class with the exact same name.
Be careful when copying other people's code into your files because it's possible the name of the class in the code might not match the name of your script. You may need to change the class name in these cases.
In the video I had font ligatures turned on in my editor which displays certain character combinations differently. This is something I've turned off for future videos to prevent confusion for those who aren't familiar with it. The ≠
symbol is actually written as !=
, which means "not equal".