flappy_bird_game

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 4

# Advanced Flappy Bird Replica

# Requires Godot 4.3

extends Node2D

# Game state management


enum GameState {
MENU,
PLAYING,
GAME_OVER
}

# Configurable game parameters


@export var scroll_speed : float = 200.0
@export var jump_force : float = -400.0
@export var gravity : float = 980.0
@export var pipe_spawn_interval : float = 2.0
@export var pipe_gap : float = 250.0

# References to game nodes


@onready var player : CharacterBody2D = $Player
@onready var pipe_container : Node2D = $PipeContainer
@onready var score_label : Label = $CanvasLayer/ScoreLabel
@onready var game_over_label : Label = $CanvasLayer/GameOverLabel
@onready var start_label : Label = $CanvasLayer/StartLabel

# Game variables
var current_game_state : GameState = GameState.MENU
var score : int = 0
var high_score : int = 0

# Pipe scene reference


var pipe_scene : PackedScene = preload("res://pipe.tscn")

# Spawn timer for pipes


var pipe_spawn_timer : float = 0.0

func _ready():
# Initialize game
reset_game()

# Hide game over and score labels initially


game_over_label.visible = false
score_label.visible = false
start_label.visible = true

# Load high score from persistent storage


load_high_score()

func _process(delta):
match current_game_state:
GameState.MENU:
handle_menu_input()
GameState.PLAYING:
handle_playing_state(delta)
GameState.GAME_OVER:
handle_game_over_input()

func handle_menu_input():
# Start the game on first jump
if Input.is_action_just_pressed("jump"):
start_game()

func start_game():
# Reset game state
reset_game()

# Change game state


current_game_state = GameState.PLAYING

# Hide start label, show score label


start_label.visible = false
score_label.visible = true
game_over_label.visible = false

func handle_playing_state(delta):
# Spawn pipes at regular intervals
pipe_spawn_timer += delta
if pipe_spawn_timer >= pipe_spawn_interval:
spawn_pipe()
pipe_spawn_timer = 0.0

# Update score label


score_label.text = "Score: %d" % score

func handle_game_over_input():
# Restart game on jump input
if Input.is_action_just_pressed("jump"):
start_game()

func spawn_pipe():
var pipe : Node2D = pipe_scene.instantiate()

# Randomize pipe height


var viewport_height = get_viewport_rect().size.y
var randomized_height = randf_range(100, viewport_height - pipe_gap - 100)

pipe.position = Vector2(
get_viewport_rect().size.x,
randomized_height
)

# Connect score signal


pipe.connect("score_point", Callable(self, "_on_pipe_score"))

pipe_container.add_child(pipe)

func _on_pipe_score():
score += 1

# Play score sound effect


$ScoreSound.play()

# Update high score if needed


if score > high_score:
high_score = score
save_high_score()
func reset_game():
# Clear existing pipes
for pipe in pipe_container.get_children():
pipe.queue_free()

# Reset player position


player.position = Vector2(
get_viewport_rect().size.x * 0.3,
get_viewport_rect().size.y * 0.5
)

# Reset game variables


score = 0
pipe_spawn_timer = 0.0

func save_high_score():
# Save high score to config file
var config = ConfigFile.new()
config.set_value("game", "high_score", high_score)
config.save("user://game_config.cfg")

func load_high_score():
# Load high score from config file
var config = ConfigFile.new()
var err = config.load("user://game_config.cfg")
if err == OK:
high_score = config.get_value("game", "high_score", 0)

# Player script (separate script for Player)


# Save this as player.gd
extends CharacterBody2D

@export var jump_force : float = -400.0


@export var gravity : float = 980.0

@onready var game : Node2D = get_parent()


@onready var animated_sprite : AnimatedSprite2D = $AnimatedSprite2D
@onready var collision_shape : CollisionShape2D = $CollisionShape2D

func _physics_process(delta):
# Only process physics if game is in playing state
if game.current_game_state != game.GameState.PLAYING:
return

# Apply gravity
velocity.y += gravity * delta

# Handle jump input


if Input.is_action_just_pressed("jump"):
velocity.y = jump_force
$JumpSound.play()
animated_sprite.play("jump")

# Move and slide


move_and_slide()

# Check for collision


for i in get_slide_collision_count():
var collision = get_slide_collision(i)
if collision.get_collider().is_in_group("pipes") or
collision.get_collider().is_in_group("ground"):
game_over()

func game_over():
# Trigger game over state
game.current_game_state = game.GameState.GAME_OVER
game.game_over_label.text = "Game Over\nScore: %d\nHigh Score: %d" %
[game.score, game.high_score]
game.game_over_label.visible = true
$CollisionSound.play()

# Pipe script (save this as pipe.tscn)


# Attach this script to the Pipe scene
extends Node2D

signal score_point

@export var scroll_speed : float = 200.0

func _process(delta):
# Move pipe to the left
position.x -= scroll_speed * delta

# Remove pipe when off-screen


if position.x < -100:
queue_free()

func _on_score_area_body_entered(body):
if body.is_in_group("player"):
emit_signal("score_point")

# Project Structure Recommendation:


# Main Scene (main.tscn)
# - Node2D (root)
# |- Player (player.tscn)
# |- PipeContainer (Node2D)
# |- CanvasLayer
# |- ScoreLabel (Label)
# |- GameOverLabel (Label)
# |- StartLabel (Label)
# |- ScoreSound (AudioStreamPlayer)
#
# Pipe Scene (pipe.tscn)
# - Node2D (root)
# |- UpperPipe (Sprite2D)
# |- LowerPipe (Sprite2D)
# |- ScoreArea (Area2D)
# |- CollisionShape2D

You might also like