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.
Để 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:
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:
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:
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
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:
Bên cạnh đó, để chú chim bay lên và bay xuống ICANTECH sẽ thực hiệ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
Tiếp theo, đối với nhân vật ống nước chúng ta sẽ cầ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)
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
Người chơi sẽ thua cuộc trong các trường hợp sau:
# 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
Để 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:
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)
Â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')
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.