Skip to main content

Overview

The player controls in Space Pong allow the paddle to move horizontally in response to keyboard input. The control system is tightly integrated with the ball’s game state, preventing movement until the game officially starts.

Player Script Architecture

The player paddle is implemented in scripts/player.gd as a CharacterBody2D with simple left-right movement:
extends CharacterBody2D

@export var speed = 100
var ball

func _ready(): 
	ball = get_parent().get_node("Ball")

func _physics_process(delta): 
	velocity = Vector2.ZERO  # Resetar a velocidade a cada frame
	
	if Input.is_action_pressed("ui_left") and ball.started == true:
		velocity.x -= speed
	if Input.is_action_pressed("ui_right") and ball.started == true:
		velocity.x += speed
	
	move_and_collide(velocity * delta)

Movement Speed

The player paddle has a configurable movement speed:
@export var speed = 100
The @export decorator makes the speed variable editable in the Godot editor, allowing designers to tweak the movement speed without modifying code.
In the player scene (player.tscn), the speed is set to 730 pixels per second, which provides:
  • Highly responsive controls for fast-paced gameplay
  • Ability to react quickly to ball direction changes
  • Smooth movement that feels natural on mobile and desktop

Node Initialization

During the _ready() callback, the player script obtains a reference to the ball:
func _ready(): 
	ball = get_parent().get_node("Ball")
1

Get Parent Node

get_parent() retrieves the parent node in the scene tree (typically the main game scene)
2

Find Ball Node

get_node("Ball") searches for a child node named “Ball” in the parent’s children
3

Store Reference

The ball reference is stored in the ball variable for later access
This implementation assumes the Ball node is a sibling to the Player node (both share the same parent). If the scene hierarchy changes, this reference will fail and movement will not work.

Input System

The player paddle responds to two input actions:

ui_left

Moves the paddle left (decreases X velocity)

ui_right

Moves the paddle right (increases X velocity)

Input Action Configuration

These are Godot’s default UI actions, typically mapped to:
  • ui_left: Left arrow key, A key
  • ui_right: Right arrow key, D key
You can customize these mappings in Project Settings → Input Map.

Movement Processing

The movement logic runs every physics frame in _physics_process():
func _physics_process(delta): 
	velocity = Vector2.ZERO  # Resetar a velocidade a cada frame
	
	if Input.is_action_pressed("ui_left") and ball.started == true:
		velocity.x -= speed
	if Input.is_action_pressed("ui_right") and ball.started == true:
		velocity.x += speed
	
	move_and_collide(velocity * delta)

Frame-by-Frame Breakdown

1

Reset Velocity

velocity = Vector2.ZERO sets velocity to (0, 0) at the start of each frame, ensuring the paddle only moves when input is actively pressed
2

Check Left Input

If “ui_left” is pressed AND the game has started, decrease X velocity by the speed value (-100)
3

Check Right Input

If “ui_right” is pressed AND the game has started, increase X velocity by the speed value (+100)
4

Apply Movement

move_and_collide(velocity * delta) moves the paddle by the velocity scaled to the frame time

Game State Integration

A critical feature of the control system is its dependency on the ball’s game state:
if Input.is_action_pressed("ui_left") and ball.started == true:
	velocity.x -= speed
if Input.is_action_pressed("ui_right") and ball.started == true:
	velocity.x += speed
Both movement checks include the condition ball.started == true, which means:

Before Game Start

The paddle is locked in place and will not respond to input until the player presses the Start button

After Game Start

Once ball.started becomes true, the paddle becomes fully responsive to player input
This design gives the player time to prepare before the ball launches. The paddle remains visible but immobile, clearly communicating that the game hasn’t started yet.

Movement Characteristics

Velocity Reset Pattern

velocity = Vector2.ZERO  # Resetar a velocidade a cada frame
Resetting velocity to zero every frame creates immediate stop behavior:
  • When the player releases a key, the paddle stops instantly
  • No momentum or sliding effects
  • Precise, arcade-style control
This differs from physics-based movement where objects would continue moving after input stops.

Delta Time Scaling

move_and_collide(velocity * delta)
The velocity is multiplied by delta (time since last frame) to ensure:
  • Frame-rate independence: The paddle moves the same distance per second regardless of FPS
  • Consistent speed: On a 60 FPS system, delta ≈ 0.0167, so the paddle moves about 1.67 pixels per frame at speed 100
  • Smooth motion: Even if frame rate fluctuates, movement appears smooth

Control Flow Diagram

Input Scenarios

// Ball has started, but no keys pressed
velocity = Vector2.ZERO
// No input conditions met
move_and_collide(Vector2.ZERO * delta)
// Result: Paddle doesn't move

Collision Detection

The player paddle uses move_and_collide() for movement:
move_and_collide(velocity * delta)
Unlike the ball script, the player script doesn’t handle the return value of move_and_collide(). This means:
  • The paddle will naturally stop when colliding with walls or other objects
  • No special collision response code is needed
  • The paddle acts as a solid object that can’t pass through other collision shapes
The paddle’s collision shape (configured in the Godot editor) determines what it collides with. Typically this includes screen boundaries to prevent the paddle from moving off-screen.

Design Patterns

State Coupling

Player controls are coupled to ball state through the ball.started flag, creating coordinated game flow

Direct Input

Uses is_action_pressed() for immediate response, making controls feel snappy and responsive

Zero Momentum

Velocity reset creates instant stop behavior preferred in arcade-style games

Exportable Parameters

The @export decorator allows non-programmers to tune movement speed in the editor

Customization Options

To modify the control system:

Change Movement Speed

@export var speed = 150  // Faster movement
@export var speed = 75   // Slower movement

Allow Pre-Game Movement

// Remove ball.started checks
if Input.is_action_pressed("ui_left"):
	velocity.x -= speed
if Input.is_action_pressed("ui_right"):
	velocity.x += speed

Add Momentum

// Don't reset velocity, add acceleration instead
if Input.is_action_pressed("ui_left"):
	velocity.x -= acceleration * delta
if Input.is_action_pressed("ui_right"):
	velocity.x += acceleration * delta
velocity.x = clamp(velocity.x, -max_speed, max_speed)

Build docs developers (and LLMs) love