Godot Version
Godot Engine v4.3.stable.
Question
2D Pong game for everyone!!
I cannot add another thing to the showcase… but below a fully working pong game with increasing speed and dificulty and commentary.
- Create a new Node2D scene
- Attach a script.
- Copy code below
- And have Fun!.
Why am i doing this?.. just to share code and maybe you can learn from it
My 2 cents!
extends Node2D
# Game Variables
var screen_size
var score_player = 0
var score_computer = 0
var game_over = false
var game_started = false
var ball_speed = 400
var base_ball_speed = 400
var speed_increase = 20 # Speed increase per rebound
var computer_difficulty = 0.7 # Higher = more difficult (max 1.0)
var difficulty_increase = 0.02 # Difficulty increase per rebound
var consecutive_hits = 0
var commentary_label
# Nodes
var player_paddle
var computer_paddle
var ball
var player_score_label
var computer_score_label
var message_label
func _ready():
randomize()
screen_size = get_viewport_rect().size
reset_game_parameters()
# Create player paddle
player_paddle = ColorRect.new()
player_paddle.color = Color.GREEN
player_paddle.size = Vector2(15, 80)
player_paddle.position = Vector2(30, screen_size.y / 2 - player_paddle.size.y / 2)
add_child(player_paddle)
# Create computer paddle
computer_paddle = ColorRect.new()
computer_paddle.color = Color.RED
computer_paddle.size = Vector2(15, 80)
computer_paddle.position = Vector2(screen_size.x - 30 - computer_paddle.size.x, screen_size.y / 2 - computer_paddle.size.y / 2)
add_child(computer_paddle)
# Create ball
ball = ColorRect.new()
ball.color = Color.WHITE
ball.size = Vector2(15, 15)
ball.position = Vector2(screen_size.x / 2 - ball.size.x / 2, screen_size.y / 2 - ball.size.y / 2)
add_child(ball)
# Create score labels
player_score_label = Label.new()
player_score_label.position = Vector2(screen_size.x / 4, 20)
player_score_label.text = "Player: 0"
add_child(player_score_label)
computer_score_label = Label.new()
computer_score_label.position = Vector2(3 * screen_size.x / 4, 20)
computer_score_label.text = "Computer: 0"
add_child(computer_score_label)
# Create message label
message_label = Label.new()
message_label.position = Vector2(screen_size.x / 2 - 100, screen_size.y / 2 - 20)
message_label.text = "Press SPACE to start"
add_child(message_label)
# Create commentary label
commentary_label = Label.new()
commentary_label.position = Vector2(screen_size.x / 2 - 150, screen_size.y - 40)
commentary_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
commentary_label.size = Vector2(300, 30)
commentary_label.visible = false
add_child(commentary_label)
# Create a midline
var midline = Line2D.new()
midline.width = 2
midline.default_color = Color(1, 1, 1, 0.3)
midline.add_point(Vector2(screen_size.x / 2, 0))
midline.add_point(Vector2(screen_size.x / 2, screen_size.y))
add_child(midline)
# Setup ball velocity (will be assigned on game start)
ball.set_meta("velocity", Vector2.ZERO)
func _process(delta):
if game_over:
if Input.is_action_just_pressed("ui_select"): # Restart game
score_player = 0
score_computer = 0
reset_game_parameters()
update_score_labels()
game_over = false
message_label.text = "Press SPACE to start"
message_label.visible = true
return
if not game_started:
if Input.is_action_just_pressed("ui_select"):
game_started = true
message_label.visible = false
reset_ball()
show_commentary("Game on!")
return
# Player paddle movement
var player_movement = 0
if Input.is_action_pressed("ui_down"):
player_movement = 1
if Input.is_action_pressed("ui_up"):
player_movement = -1
player_paddle.position.y += player_movement * 500 * delta
player_paddle.position.y = clamp(player_paddle.position.y, 0, screen_size.y - player_paddle.size.y)
# Computer AI (follows the ball with slight delay)
var target_y = ball.position.y + ball.size.y / 2 - computer_paddle.size.y / 2
# Add some difficulty scaling - only move towards ball if it's coming to the computer's side
var ball_velocity = ball.get_meta("velocity")
if ball_velocity.x > 0:
# Add some intentional "error" based on difficulty
var error_margin = (1.0 - computer_difficulty) * 100
target_y += randf_range(-error_margin, error_margin)
var computer_speed = 400 * computer_difficulty
if computer_paddle.position.y < target_y:
computer_paddle.position.y += computer_speed * delta
elif computer_paddle.position.y > target_y:
computer_paddle.position.y -= computer_speed * delta
computer_paddle.position.y = clamp(computer_paddle.position.y, 0, screen_size.y - computer_paddle.size.y)
# Ball movement
var velocity = ball.get_meta("velocity")
ball.position += velocity * delta
# Ball collision with top and bottom walls
if ball.position.y <= 0 or ball.position.y + ball.size.y >= screen_size.y:
velocity.y = -velocity.y
ball.set_meta("velocity", velocity)
# Ball collision with paddles
if ball.position.x <= player_paddle.position.x + player_paddle.size.x and \
ball.position.y + ball.size.y >= player_paddle.position.y and \
ball.position.y <= player_paddle.position.y + player_paddle.size.y and \
velocity.x < 0:
# Adjust angle based on where ball hit the paddle
var hit_pos = (ball.position.y + ball.size.y/2) - player_paddle.position.y
var normalized_hit_pos = hit_pos / player_paddle.size.y - 0.5 # Range from -0.5 to 0.5
velocity.x = -velocity.x
velocity.y = normalized_hit_pos * 2 * ball_speed
# Increase consecutive hits
consecutive_hits += 1
# Increase consecutive hits
consecutive_hits += 1
# Increase ball speed and computer difficulty
ball_speed += speed_increase
computer_difficulty = min(computer_difficulty + difficulty_increase, 1.0)
# Update velocity with new speed
velocity = velocity.normalized() * ball_speed
ball.set_meta("velocity", velocity)
# Display current speed and difficulty (for debug)
update_debug_info()
# Show commentary
show_computer_hit_commentary()
# Show commentary
show_player_hit_commentary()
if ball.position.x + ball.size.x >= computer_paddle.position.x and \
ball.position.y + ball.size.y >= computer_paddle.position.y and \
ball.position.y <= computer_paddle.position.y + computer_paddle.size.y and \
velocity.x > 0:
# Adjust angle based on where ball hit the paddle
var hit_pos = (ball.position.y + ball.size.y/2) - computer_paddle.position.y
var normalized_hit_pos = hit_pos / computer_paddle.size.y - 0.5 # Range from -0.5 to 0.5
velocity.x = -velocity.x
velocity.y = normalized_hit_pos * 2 * ball_speed
# Increase ball speed and computer difficulty
ball_speed += speed_increase
computer_difficulty = min(computer_difficulty + difficulty_increase, 1.0)
# Update velocity with new speed
velocity = velocity.normalized() * ball_speed
ball.set_meta("velocity", velocity)
# Display current speed and difficulty (for debug)
update_debug_info()
# Ball out of bounds (scoring)
if ball.position.x < 0:
score_computer += 1
update_score_labels()
consecutive_hits = 0
show_commentary("Computer scores! That's rough!")
check_for_game_over()
reset_ball()
if ball.position.x > screen_size.x:
score_player += 1
update_score_labels()
consecutive_hits = 0
show_commentary("You scored! Nice one!")
check_for_game_over()
reset_ball()
func reset_game_parameters():
# Reset ball speed and computer difficulty to their initial values
ball_speed = base_ball_speed
computer_difficulty = 0.7
consecutive_hits = 0
update_debug_info()
func reset_ball():
ball.position = Vector2(screen_size.x / 2 - ball.size.x / 2, screen_size.y / 2 - ball.size.y / 2)
# Randomize direction but ensure it's not too vertical
var angle = randf_range(-PI/4, PI/4)
if randf() > 0.5:
angle += PI
var velocity = Vector2(cos(angle), sin(angle)).normalized() * ball_speed
ball.set_meta("velocity", velocity)
# Pause briefly
game_started = false
message_label.text = "Get ready..."
message_label.visible = true
await get_tree().create_timer(1.0).timeout
game_started = true
message_label.visible = false
func update_score_labels():
player_score_label.text = "Player: " + str(score_player)
computer_score_label.text = "Computer: " + str(score_computer)
func update_debug_info():
# Optional debug information - you can add a label to your game to display this
print("Ball Speed: ", ball_speed, " | Computer Difficulty: ", computer_difficulty)
func show_commentary(text):
commentary_label.text = text
commentary_label.visible = true
# Auto-hide commentary after a delay
var timer = get_tree().create_timer(2.0)
await timer.timeout
if is_instance_valid(commentary_label):
commentary_label.visible = false
func show_player_hit_commentary():
var comments = [
"Nice hit!",
"You're on fire!",
"Keep it going!",
"Speed increased! Getting spicy!",
"That was sick!",
"The AI is sweating now!",
"BOOM! Another hit!",
"Computer be like: 'Not fair!'",
"You're making this look easy!"
]
if consecutive_hits > 3:
comments.append("Combo x" + str(consecutive_hits) + "! Impressive!")
comments.append("This is getting ridiculous!")
comments.append("Are you a pro or what?!")
if ball_speed > base_ball_speed + 100:
comments.append("This ball is FLYING now!")
comments.append("Speed demon activated!")
show_commentary(comments[randi() % comments.size()])
func show_computer_hit_commentary():
var comments = [
"Computer returns!",
"AI's getting good!",
"The machine fights back!",
"Denied by the computer!",
"Computer's not giving up!",
"Computer: 'Is that all you got?'",
"Getting faster...",
"The robot's learning!",
"Computer's like 'Nope!'"
]
if consecutive_hits > 3:
comments.append("Rally streak: " + str(consecutive_hits) + "!")
comments.append("This rally is epic!")
if computer_difficulty > 0.9:
comments.append("Computer's almost at max difficulty!")
comments.append("AI's almost reached its final form!")
show_commentary(comments[randi() % comments.size()])
func check_for_game_over():
var win_score = 5
if score_player >= win_score:
game_over = true
message_label.text = "You win! Press SPACE to restart"
message_label.visible = true
show_commentary("VICTORY! You showed that AI who's boss!")
elif score_computer >= win_score:
game_over = true
message_label.text = "Computer wins! Press SPACE to restart"
message_label.visible = true
show_commentary("Game over! The machines win this time...")