Source file unity-csharp/arcade-classics/pong/Paddle2D.cs from the GDnD code examples. Download raw file
// GDnD wiki example
// Demonstrates: keyboard input, clamped movement, and a one-line "track the ball" AI for the second paddle
// Related pages: [[overview-arcade-classics-as-learning-projects]], [[unity-input]], [[unity-transform]]
using UnityEngine;
// One script for both paddles. Set controlMode in the Inspector: Player reads an
// input axis; Ai chases the ball's height. The Ai branch is the seed of every
// later "enemy follows target" behaviour in the coding progression.
public class Paddle2D : MonoBehaviour
{
public enum ControlMode { Player, Ai }
[SerializeField] private ControlMode controlMode = ControlMode.Player;
[SerializeField] private float speed = 12f;
[Header("Player")]
[Tooltip("Vertical input axis name (e.g. \"Vertical\" or a custom second-player axis).")]
[SerializeField] private string verticalAxis = "Vertical";
[Header("AI")]
[SerializeField] private Transform ball;
[Tooltip("Caps AI reaction so it is beatable. Lower = lazier paddle.")]
[SerializeField, Range(0f, 1f)] private float aiResponsiveness = 0.65f;
private float halfHeight;
private float halfSize;
private Camera cachedCamera;
private void Awake()
{
cachedCamera = Camera.main;
halfSize = GetComponent<SpriteRenderer>().bounds.extents.y;
}
private void Update()
{
float move = controlMode == ControlMode.Player ? ReadPlayerInput() : ReadAiInput();
Vector3 position = transform.position;
position.y += move * speed * Time.deltaTime;
halfHeight = cachedCamera.orthographicSize - halfSize;
position.y = Mathf.Clamp(position.y, -halfHeight, halfHeight);
transform.position = position;
}
private float ReadPlayerInput()
{
return Input.GetAxisRaw(verticalAxis);
}
private float ReadAiInput()
{
if (ball == null)
{
return 0f;
}
// Move toward the ball, but scale by responsiveness so the AI lags and
// the player can win. A deadzone stops jitter when roughly aligned.
float difference = ball.position.y - transform.position.y;
if (Mathf.Abs(difference) < 0.1f)
{
return 0f;
}
return Mathf.Sign(difference) * aiResponsiveness;
}
}