icantech
Code mẫu Python
3974
15/11/2023

Hướng dẫn cách lập trình game Flappy Bird bằng Python

Flappy Bird là tựa game vô cùng nổi tiếng của tác giả Nguyễn Hà Đông từng gây sốt trên cộng đồng mạng vào năm 2013. Tại đây, người chơi sẽ điều khiển nhân vật chú chim Flappy của mình lần lượt vượt qua thử thách là ống nước để tích lũy nhiều điểm số nhất có thể. Trong bài viết này, ICANTECH sẽ hướng dẫn bạn cách lập trình game Flappy Bird bằng Python cực đơn giản.

1. Phân tích trò chơi Flappy Bird

Để lập trình Flappy Bird bằng Python, hãy cùng ICANTECH phân tích trò chơi này như sau:

  • Game có các nhân vật là chú chim, ống nước, hình nền và sàn 
  • Game có rất nhiều cặp ống nước. Mỗi 1 cặp ống nước được xếp thẳng hàng nhau và hở ra khoảng trống ở giữa 2 ống nước đó
  • Con chim sẽ bay vượt qua khoảng trống của cặp ống nước. Mỗi lần vượt qua được một cặp ống nước sẽ được cộng điểm
  • Con chim bay va chạm vào ống nước, sàn hoặc vượt ra màn hình đồng nghĩa với người chơi thua cuộc
flappy-bird

Như vậy, với cách phân tích trò chơi như trên để code Flappy Bird bằng Python chúng ta cần thực hiện các bước sau:

  • Khởi tạo & tạo hình nền trò chơi
  • Lập trình mặt đất cố định
  • Lập trình nhân vật chim di chuyển
  • Lập trình nhân vật ống nước
  • Xử lý các sự kiện va chạm
  • Thông báo thua cuộc và chơi lại
  • Lập trình tính điểm và level
  • Thêm âm thanh trong game

2. Hướng dẫn cách lập trình game Flappy Bird bằng Python dành cho người mới bắt đầu

2.1. Khởi tạo & tạo hình nền trò chơi 

Trước tiên, ICANTECH sẽ tạo màn hình trò chơi Flappy Bird với kích thước ngang 400 và dọc 768. Sau đó, lần lượt khai báo thời gian và tải hình nền game cùng thay đổi kích thước hình nền bằng cách sử dụng câu lệnh sau:

import pygame, sys, random

pygame.init()

WHITE = (255, 255, 255)

screenWidth = 400

screenHeight = 768

screen = pygame.display.set_mode([screenWidth, screenHeight])

pygame.display.set_caption('Flappy Bird')

clock = pygame.time.Clock()

gameFont = pygame.font.SysFont('Arial', 20)

# chèn background

bg = pygame.image.load('assets/flappy-bird/bg.jpg').convert()

bg = pygame.transform.scale(bg, (screenWidth, screenHeight))

bg_rect = bg.get_rect()

bg_rect.center = (screenWidth/2, screenHeight/2)

print('bg_rect', bg_rect)

Sau khi hoàn thành xong bước khởi tạo màn hình, ICANTECH sẽ có được màn hình trò chơi như sau:

flappy-bird

2.2. Lập trình mặt đất cố định 

Tại trò chơi này, mặt đất luôn di chuyển bởi vậy chúng ta sẽ cần vẽ hai hình ảnh mặt đất lên màn hình trò chơi với lần lượt hai sàn là sàn bên phải và sàn bên trái. 

Như vậy, sau mỗi lần lặp của trò chơi hai hình ảnh này sẽ di chuyển sang trái một lượng nhất định. 

# chèn sàn

floor = pygame.image.load('assets/flappy-bird/floor_2.png')

floor_x = 0  

Trong trường hợp mặt đất di chuyển, tức là mỗi lần lặp “while True” của game. Biến floor_x sẽ giảm đi 1 đơn vị tức là mặt đất sẽ di chuyển sang trái và tạo ra một khoảng trống dưới đáy của màn hình game. 

# sàn di chuyển về bên trái

    floor_x -= 1

    if (floor_x <= -screenWidth):

        floor_x = 0

# Vẽ sàn

    screen.blit(floor,(floor_x,screenHeight-130))    # Vẽ sàn bên trái

    screen.blit(floor,(floor_x+screenWidth,screenHeight-130))  # Vẽ sàn bên phải nối theo 

2.3. Lập trình nhân vật chim di chuyển

Sau khi đã hoàn tất lập trình bối cảnh, chúng ta sẽ tiến hành lập trình nhân vật chính của trò chơi - chú chim Flappy. Để lập trình điều khiển chú chim ICANTECH sẽ lần lượt: 

  • Tải 3 hình ảnh tương ứng với 3 trạng thái của bird khi vỗ cánh
  • Khai báo biến bird_x để lưu tọa độ x
  • Khai báo danh sách bird_list lưu các trạng thái khi bird vỗ cánh
  • Khai báo biến bird, bird_rect lưu hình ảnh bird với một trạng thái cụ thể
  • Sau mỗi lần lặp bird sẽ thay đổi trạng thái một lần

Bên cạnh đó, để chú chim bay lên và bay xuống ICANTECH sẽ thực hiện: 

  • Khai báo biến gravity (trọng lực) để lưu giá trị con chim di chuyển bay xuống dưới 
  • Khai báo biến bird_move để lưu giá trị con chim di chuyển bay lên trên
  • Sự kiện bấm phím space(cách) con chim di chuyển bay lên trên

Với cách phân tích như vậy, ICANTECH sẽ sử dụng các câu lệnh sau:

# Vẽ con chim

    bird_move += gravity

    bird_rect.centery += bird_move

    screen.blit(bird, bird_rect)

# tạo chim vỗ cánh

bird_down = pygame.image.load('assets/flappy-bird/bird-down.png').convert_alpha()

bird_mid = pygame.image.load('assets/flappy-bird/bird-mid.png').convert_alpha()

bird_up = pygame.image.load('assets/flappy-bird/bird-up.png').convert_alpha()

bird_down = pygame.transform.scale(bird_down,(50,38))

bird_mid = pygame.transform.scale(bird_mid,(50,38))

bird_up = pygame.transform.scale(bird_up,(50,38))

bird_x = 100

bird_index = 0

bird_list = [bird_down, bird_mid, bird_up]

bird = bird_list[bird_index]

bird_rect = bird.get_rect()

bird_rect.center = (bird_x, screenHeight/2)

# tạo timmer - sự kiện chim vỗ cánh(đổi trạng thái)

birdflap = pygame.USEREVENT + 1

print('birdflap', birdflap)

pygame.time.set_timer(birdflap, 200)  # 0.2 second sinh 1

# Bird di chuyển

gravity = 0.15

bird_move = 0 

2.5. Lập trình nhân vật ống nước

Tiếp theo, đối với nhân vật ống nước chúng ta sẽ cần:

  • Hai ống nước bên dưới và bên trên vào game
  • Vẽ ống nước bên dưới bên phải màn hình
  • Vẽ ống nước bên trên có cùng tọa độ x (đối diện) với ống nước bên dưới cách ống nước bên dưới một khoảng là 300
  • Vẽ hai các ống nước với tọa độ y ngẫu nhiên

# Vẽ ống nước

    score = 0

    for item in pipe_list:

        item[0] -= 5

        pipe_below_rect.midtop = (item[0], item[1])

        screen.blit(pipe_below, pipe_below_rect)

        pipe_above_rect.midbottom = (item[0], item[2])

        screen.blit(pipe_above, pipe_above_rect)

Bên cạnh đó, để hai cặp ống nước cùng di chuyển chúng ta sẽ cần sử dụng ý tưởng để ống nước di chuyển từ phải sang trái chúng ta sẽ thay đổi tọa độ x của ống nước. Thực tế ống nước được vẽ trên tọa độ của đối tượng hình chữ nhật Rect nên việc thay đổi tạo độ x của ống nước chính là thay đổi tọa độ x của đối tượng Rect.

Tọa độ x của đối tượng Rect chính là giá trị phần tử đầu tiên của danh sách pipe_one_list . Vì vậy chỉ cần thay đổi giá trị này là ống nước sẽ di chuyển.

Trong trường hợp muốn tạo ra nhiều ống nước di chuyển chúng ta sẽ tạo ra một sự kiện mới có tên là spawn_pipe. Sự kiện này sẽ lặp lại sau 0.8 giây. Tiếp theo, chúng ta sẽ lần lượt khai báo một danh sách pipe_list lưu giá trị của các cặp ống nước (biến pipe_one_list). 

Sau mỗi lần sự kiện spawn_pipe lặp lại, một đối tượng Rect (pipe_one_list) được sinh ra và được thêm vào cuối danh sách pipe_list. Duyệt danh sách pipe_list và vẽ hinh ống nước lên các tọa độ của đối tượng Rect trong danh sách. Mỗi lần lặp sẽ thay đổi tọa độ x đối tượng Rect một khoảng bằng -5.

# Tạo ống nước

pipe_above = pygame.image.load('assets/flappy-bird/pipe_above.png')

pipe_below = pygame.image.load('assets/flappy-bird/pipe_below.png')

pipe_above_rect = pipe_above.get_rect()

pipe_below_rect = pipe_below.get_rect()

pipe_distance = 300

pipe_below_height = [450, 500, 550, 600]

pipe_below_midtop_pos = random.choice(pipe_below_height)

pipe_one_list = [screenWidth,

                 pipe_below_midtop_pos,

                 pipe_below_midtop_pos - pipe_distance

                 ]

pipe_list = []

pipe_list.append(pipe_one_list)

# Tạo timmer - sự kiện nhân bản ống nước

spawn_pipe = pygame.USEREVENT + 2

pygame.time.set_timer(spawn_pipe, 800)  # 800 second sinh 1    pygame.display.update()

    clock.tick(120)

2.6. Xử lý các sự kiện va chạm

Trong trò chơi Flappy Bird chúng ta sẽ thấy có rất nhiều sự tương tác giữa các nhân vật với nhau. Ví dụ: nhân vật bird va chạm với ống nước,nhân vật bird va chạm với mặt đất; nhân vật bird va chạm với cạnh trên cửa sổ.

Bên cạnh đó, chúng ta cũng cần kiểm tra va chạm mặt đất bằng cách kiểm tra nếu bird bay thấp hơn tọa độ cạnh trên của mặt đất là va chạm. Kiểm tra chạm cạnh trên của màn hình game bằng cách kiểm tra bird bay cao hơn cạnh biên bên trên của màn hình game là va chạm.

Với cách phân tích như vậy, chúng ta sẽ sử dụng câu lệnh sau:

  #xử lý va chạm

        if bird_rect.colliderect(pipe_below_rect):

            game_running = False

            print('bird va cham pipe_below_rect')

        if bird_rect.colliderect(pipe_above_rect):

            game_running = False

            print('bird va cham pipe_above_rect')

        if bird_rect.centery > screenHeight-130 or bird_rect.centery < 0:

            game_running = False

            print('bird va cham sàn hoặc bay cao vượt cận trên')

        # Thông báo game_close

        if game_running == False:

            screen.blit(game_over, game_over_rect)

            hit_sound.play()

        if item[0] < bird_x:

            score += 1

2.7. Thông báo thua cuộc và lập trình chơi lại

Người chơi sẽ thua cuộc trong các trường hợp sau:

  • Nhân vật bird va chạm ống nước
  • Nhân vật bird va chạm vào sàn 
  • Nhân vật bird chạm vào biên trên 

# Trạng thái trò chơi

game_running = True

# Vẽ hình ảnh kết thua cuộc

game_over = pygame.image.load('assets/flappy-bird/game_over2.png')

game_over_rect = game_over.get_rect()

game_over_rect.center = (screenWidth/2, screenHeight/2)

# print('pipe_list', pipe_list)

    pygame.display.update()

    clock.tick(120)

Tiếp theo, ICANTECH sẽ lần lượt khai báo biến game_running xác định người chơi thua cuộc hay chưa. Tiếp theo, màn hình sẽ hiển thị thông báo người chơi thua cuộc. Trong trường hợp thua cuộc, người chơi bấm phím cách để chơi lại và lúc này danh sách ống nước pipe_list sẽ được làm mới.

while True:

    for event in pygame.event.get():

        if event.type == pygame.QUIT:

            pygame.quit()

            sys.exit()

        if event.type == pygame.KEYDOWN:

            if event.key == pygame.K_SPACE:

                if game_running == True:

                    bird_move = level_bird_move_list[level]  # di chuyển lên trên

                    flap_sound.play()

                else:

                    game_running = True

                    pipe_list.clear()

                    bird_move = 0

                    bird_rect.center = (bird_x, screenHeight/2)

        if event.type == birdflap:

            bird_index += 1

            if bird_index >= 2:

                bird_index = 0

2.8. Lập trình tính điểm và level

Để lập trình tính điểm và level trong trò chơi Flappy Bird, chúng ta cần lần lượt:

  • Khai báo biến score lưu số điểm trong lượt chơi hiện tại
  • Khai báo biến high_score lưu số điểm cao nhất trong tất cả các lượt chơi
  • Cách tính điểm mỗi lượt chơi như sau. Mỗi lần con chim vượt qua được ống nước sẽ được cộng một điểm hay là ống nước di chuyển qua vị trí x của con chim
  • Cách tính điểm cao nhất. Trong các lượt chơi nếu số điểm hiện tại cao hơn số điểm cao nhất thì sẽ gán số điểm cao nhất bằng số điểm hiện tại

Tiếp theo, để tăng độ khó cho game chúng ta sẽ thêm level cho trò chơi này bằng cách đổi tốc độ bay lên của con chim.

# Level

level = 0

level_bird_move_list = [-4, -5, -6, -7, -8, -9]

# Vẽ số điểm đang chơi

    score_surface = gameFont.render('Score: {}'.format(score), True, WHITE)

    score_rect = score_surface.get_rect()

    score_rect.center = (200, 50)

    screen.blit(score_surface, score_rect)

    # Vẽ điểm cao

    if game_running == False:

        if score > hight_score:

            hight_score = score

        hight_score_surface = gameFont.render('High Score: {}'.format(hight_score), True, WHITE)

        hight_score_rect = hight_score_surface.get_rect()

        hight_score_rect.center = (200, 100)

        screen.blit(hight_score_surface, hight_score_rect)

    # Vẽ level

    level = score // 5    score_surface = gameFont.render('Level: {}'.format(level), True, WHITE)

    score_rect = score_surface.get_rect()

    score_rect.center = (50, 50)

    screen.blit(score_surface, score_rect)

2.9. Thêm âm thanh trong game

Âm thanh hay âm nhạc là một thứ không thể thiếu trong cuộc sống của con người. Tiêu chuẩn của một tựa game chất lượng phải là sự kết hợp tinh tế giữa cả lối chơi, cốt truyện và âm nhạc. Vì âm nhạc đóng vai trò rất lớn trong việc “tạo cảm hứng” cho người chơi.

Tại trò chơi này, ICANTECH sẽ tiến hành tải âm thanh vào chương trình game với cú pháp pygame.mixer.Sound(path). Tiếp theo, để phát âm thanh này trong game chúng ta sẽ sử dụng cú pháp var.play().

# Chèn âm thanh

Flap_sound = pygame.mixer.Sound('assets/flappy-bird/sound/sfx_wing.wav')

hit_sound = pygame.mixer.Sound('assets/flappy-bird/sound/sfx_hit.wav')

Score_sound = pygame.mixer.Sound('assets/flappy-bird/sound/sfx_point.wav') 

3. Lời Kết

Như vậy, ICANTECH đã hướng dẫn bạn cách lập trình game Flappy Bird bằng Python cực đơn giản chỉ với 9 bước. Hi vọng bạn áp dụng những kiến thức ở trên để sáng tạo trò chơi Flappy Bird của riêng mình. Chúc các bạn thành công!

Nếu bạn đang quan tâm đến lập trình game trên python thì hãy đăng ký ngay khóa học lập trình Python Code Combat tại ICANTECH nhé!

Nguồn ảnh: ICANTECH. 

Share
Tags
Code mẫu Python

Bài tương tự