using UnityEngine; using UnityEngine.InputSystem; [RequireComponent(typeof(Collider2D))] [RequireComponent(typeof(Rigidbody2D))] public class PaddleScript : MonoBehaviour { [Header("Movement")] [SerializeField] private float moveSpeed = 10f; [Header("Bounds")] [Tooltip("Extra gap between the paddle edge and the camera edge.")] [SerializeField] private float edgePadding = 0.1f; private float _minX; private float _maxX; private float _halfWidth; private bool _useMouse = true; void Awake() { // Paddle is player-driven via transform — kinematic prevents physics forces from interfering. GetComponent().bodyType = RigidbodyType2D.Kinematic; } void Start() { _halfWidth = GetComponent().bounds.extents.x; // Derive horizontal limits from the camera viewport so the paddle never leaves the screen. Camera cam = Camera.main; float distToCamera = Mathf.Abs(cam.transform.position.z); _minX = cam.ViewportToWorldPoint(new Vector3(0f, 0f, distToCamera)).x + _halfWidth + edgePadding; _maxX = cam.ViewportToWorldPoint(new Vector3(1f, 0f, distToCamera)).x - _halfWidth - edgePadding; } void Update() { var keyboard = Keyboard.current; var mouse = Mouse.current; float keyInput = 0f; if (keyboard != null) { if (keyboard.aKey.isPressed || keyboard.leftArrowKey.isPressed) keyInput -= 1f; if (keyboard.dKey.isPressed || keyboard.rightArrowKey.isPressed) keyInput += 1f; } // Any keyboard movement disables mouse; any mouse click re-enables mouse. if (Mathf.Abs(keyInput) > 0.01f) _useMouse = false; else if (mouse != null && mouse.leftButton.wasPressedThisFrame) _useMouse = true; Vector3 pos = transform.position; if (!_useMouse && Mathf.Abs(keyInput) > 0.01f) { // Keyboard: direct movement at moveSpeed. pos.x += keyInput * moveSpeed * Time.deltaTime; } else if (_useMouse && mouse != null) { // Mouse: smoothly move toward the cursor's world X at moveSpeed. Camera cam = Camera.main; Vector2 mouseScreen = mouse.position.ReadValue(); Vector3 mouseWorld = cam.ScreenToWorldPoint( new Vector3(mouseScreen.x, mouseScreen.y, Mathf.Abs(cam.transform.position.z))); pos.x = Mathf.MoveTowards(pos.x, mouseWorld.x, moveSpeed * Time.deltaTime); } pos.x = Mathf.Clamp(pos.x, _minX, _maxX); transform.position = pos; } private void OnCollisionEnter2D(Collision2D collision) { if (!collision.gameObject.CompareTag("Ball")) return; Rigidbody2D ballRb = collision.rigidbody; if (ballRb == null) return; // Map hit position to [-1, 1]: -1 = left edge, 0 = centre, +1 = right edge. float hitOffset = (collision.transform.position.x - transform.position.x) / _halfWidth; hitOffset = Mathf.Clamp(hitOffset, -1f, 1f); // Preserve the ball's current speed so movement effects still apply. BallScript ballScript = collision.gameObject.GetComponent(); float speed = ballScript != null ? ballScript.GetCurrentSpeed() : 10f; // A centre hit goes straight up; edge hits angle up to 75 degrees to either side. float angle = hitOffset * 75f * Mathf.Deg2Rad; ballRb.linearVelocity = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)) * speed; } }