Pygame - Một số khái niệm cơ bản

04/01/2022   PyGame
Pygame - Một số khái niệm cơ bản
Pygame - Một số khái niệm cơ bản
1. Tọa độ pixel (Pixel Coordinates) |
1. Tọa độ pixel (Pixel Coordinates)
Cửa sổ mà chương trình Thế giới Hello Hello tạo ra chỉ bao gồm các chấm vuông nhỏ trên màn hình của bạn được gọi là pixel. Mỗi pixel bắt đầu là màu đen nhưng có thể được đặt thành một màu khác nhau. Hãy tưởng tượng rằng thay vì một đối tượng Surface rộng 400 pixel và cao 300 pixel, chúng ta chỉ có một đối tượng Surface là 8 pixel x 8 pixel. Nếu Bề mặt 8x8 nhỏ bé đó được phóng to để mỗi pixel trông giống như một hình vuông trong lưới và chúng tôi đã thêm số cho trục X và Y, thì một đại diện tốt của nó có thể trông giống như thế này:
Chúng ta có thể tham khảo một pixel cụ thể bằng cách sử dụng hệ thống tọa độ Descartes. Mỗi cột của trục X và mỗi hàng của trục Y sẽ có một địa chỉ tên miền là một số nguyên từ 0 đến 7 để chúng ta có thể định vị bất kỳ pixel nào bằng cách chỉ định các số nguyên trục X và Y.
Ví dụ, trong hình ảnh 8x8 ở trên, chúng ta có thể thấy các pixel ở tọa độ XY (4, 0), (2, 2), (0, 5) và (5, 6) đã được sơn màu đen, pixel tại (2, 4) đã được sơn màu xám, trong khi tất cả các pixel khác được sơn màu trắng. Tọa độ XY cũng được gọi là điểm. Nếu bạn đã học một lớp toán và học về tọa độ Descartes, bạn có thể nhận thấy rằng trục Y bắt đầu từ 0 ở trên cùng và sau đó tăng dần xuống, thay vì tăng khi nó tăng lên. Đây chỉ là cách tọa độ của Cartesian hoạt động trong Pygame (và hầu hết mọi ngôn ngữ lập trình).
Khung Pygame thường đại diện cho tọa độ Descartes là một bộ gồm hai số nguyên, chẳng hạn như (4, 0) hoặc (2, 2). Số nguyên đầu tiên là tọa độ X và thứ hai là tọa độ Y.
2. Nhắc nhở về Hàm (function), Phương thức (method), Hàm Khởi tạo (Constructor Functions) và Hàm trong Mô-đun (Functions in Modules ) và Sự khác biệt giữa Chúng
Chức năng và phương thức gần như giống nhau. Cả hai đều có thể được gọi để thực thi mã trong đó. Sự khác biệt giữa một hàm và một phương thức là một phương thức sẽ luôn được gắn vào một đối tượng. Thông thường các phương thức thay đổi một cái gì đó về đối tượng cụ thể đó (bạn có thể nghĩ về đối tượng đính kèm như một loại đối số vĩnh viễn được truyền cho phương thức).
Đây là một lời gọi hàm của một hàm có tên foo ():
foo() |
Đây là một lời gọi phương thức của một phương thức cũng có tên foo(), được gắn vào một đối tượng được lưu trữ trong một biến có tên duckie:
duckie.foo() |
Một lời gọi đến một hàm (function) bên trong một mô-đun có thể trông giống như một lời gọi phương thức (method). Để cho biết sự khác biệt, bạn cần nhìn vào tên đầu tiên và xem nếu đó là tên của một mô-đun hoặc tên của một biến có chứa một đối tượng. Bạn có thể nói rằng sys.exit() là một lệnh gọi hàm (function) bên trong mô-đun, bởi vì ở đầu chương trình sẽ là một câu lệnh nhập giống như nhập sys.
Hàm khởi tạo (Constructor Functions) là điều tương tự như một lệnh gọi hàm thông thường, ngoại trừ giá trị trả về của nó là một đối tượng mới. Chỉ cần nhìn vào mã nguồn, một hàm và hàm xây dựng trông giống nhau. Các hàm xây dựng (hay còn gọi đơn giản là một hàm tạo) chỉ là một tên được đặt cho các hàm trả về một đối tượng mới. Nhưng thông thường các bác sĩ bắt đầu với một chữ in hoa. Đây là lý do tại sao khi bạn viết chương trình của riêng bạn, tên hàm của bạn chỉ nên bắt đầu bằng một chữ cái viết thường.
Ví dụ, pygame.Rect() và pygame.Surface() đều là các hàm khởi tạo bên trong mô-đun pygame trả về các đối tượng Rect và Surface mới.
Ở đây, một ví dụ về một lời gọi hàm, một lời gọi phương thức và một cuộc gọi đến một hàm bên trong một mô-đun:
import whammy |
Mặc dù tất cả các tên này được tạo thành, bạn có thể biết đó là lời gọi hàm, lời gọi phương thức và lời gọi đến một chức năng bên trong một phương thức. Tên whammy dùng để chỉ một mô-đun, vì bạn có thể thấy nó đang được nhập trên dòng đầu tiên. Tên fizzy() không có gì trước nó và dấu ngoặc đơn sau nó, vì vậy bạn biết đó là một hàm gọi.
Wombat() cũng là một hàm gọi, trong trường hợp này, nó là hàm xây dựng trả về một đối tượng. (Chữ in hoa bắt đầu, đảm bảo rằng nó là hàm khởi tạo chứ không phải là hàm thông thường, nhưng đó là đặt cược an toàn.) Đối tượng được lưu trữ trong một biến có tên là trứng. lời gọi egg.bluhbluh() là một lời gọi phương thức (method), bạn có thể biết vì bluhbluh được gắn vào một biến có một đối tượng trong đó.
Trong khi đó, whammy.spam() là một lệnh gọi hàm, không phải là một lời gọi phương thức. Bạn có thể nói nó không phải là một phương thức vì tên whammy đã được nhập dưới dạng một mô-đun trước đó.
3. Surface Objects và The Window
- Các đối tượng bề mặt là các đối tượng đại diện cho một hình ảnh 2D hình chữ nhật. Các pixel của đối tượng Surface có thể được thay đổi bằng cách gọi các hàm vẽ Pygame (được mô tả sau trong chương này) và sau đó hiển thị trên màn hình. Đường viền cửa sổ, thanh tiêu đề và các nút không phải là một phần của đối tượng Surface hiển thị.
- Cụ thể, đối tượng Surface được trả về bởi pygame.display.set_mode() được gọi là Surface hiển thị. Bất cứ thứ gì được vẽ trên màn hình Đối tượng Surface sẽ được hiển thị trên cửa sổ khi hàm pygame.display.update() được gọi. Việc vẽ trên một đối tượng Surface sẽ nhanh hơn rất nhiều (chỉ tồn tại trong bộ nhớ máy tính) so với việc vẽ một đối tượng Surface lên màn hình máy tính. Bộ nhớ máy tính thay đổi nhanh hơn nhiều so với pixel trên màn hình.
- Thường thì chương trình của bạn sẽ vẽ một số thứ khác nhau cho một đối tượng Surface. Khi bạn đã hoàn tất việc vẽ mọi thứ trên màn hình đối tượng Surface cho lần lặp này của vòng lặp trò chơi (được gọi là khung, giống như hình ảnh tĩnh trên DVD bị tạm dừng được gọi) trên đối tượng Surface, nó có thể được vẽ lên màn hình. Máy tính có thể vẽ khung hình rất nhanh và các chương trình của chúng tôi thường sẽ chạy khoảng 30 khung hình mỗi giây (nghĩa là 30 FPS). Điều này được gọi là tốc độ khung hình trên mạng và được giải thích sau trong chương này.
4. Về Màu sắc (Colors)
- Có ba màu chính của ánh sáng: đỏ, lục và lam. (Đỏ, xanh lam và vàng là màu chính cho sơn và bột màu, nhưng màn hình máy tính sử dụng ánh sáng chứ không phải sơn.) Bằng cách kết hợp số lượng khác nhau của ba màu này, bạn có thể tạo thành bất kỳ màu nào khác. Trong Pygame, chúng tôi đại diện cho màu sắc với bộ ba số nguyên. Giá trị đầu tiên trong bộ dữ liệu là bao nhiêu màu đỏ trong màu. Giá trị nguyên là 0 có nghĩa là không có màu đỏ trong màu này và giá trị 255 có nghĩa là có lượng màu đỏ tối đa trong màu. Giá trị thứ hai là cho màu xanh lá cây và giá trị thứ ba là cho màu xanh. Các bộ ba số nguyên được sử dụng để thể hiện một màu thường được gọi là các giá trị RGB.
- Vì bạn có thể sử dụng bất kỳ kết hợp nào từ 0 đến 255 cho mỗi ba màu chính, điều này có nghĩa là Pygame có thể vẽ 16.777.216 màu khác nhau (nghĩa là 256 x 256 x 256 màu). Tuy nhiên, nếu cố gắng sử dụng một số lớn hơn 255 hoặc một số âm, bạn sẽ gặp một lỗi trông giống như Value ValueError: “ValueError: invalid color argument”.
Color |
RGB Values |
Aqua |
( 0, 255, 255) |
Black |
( 0, 0, 0) |
Blue |
( 0, 0, 255) |
Fuchsia |
(255, 0, 255) |
Gray |
(128, 128, 128) |
Green |
( 0, 128, 0) |
Lime |
( 0, 255, 0) |
Maroon |
(128, 0, 0) |
Navy Blue |
( 0, 0, 128) |
Olive |
(128, 128, 0) |
Purple |
(128, 0, 128) |
Red |
(255, 0, 0) |
Silver |
(192, 192, 192) |
Teal |
( 0, 128, 128) |
White |
(255, 255, 255) |
Yellow |
(255, 255, 0) |
5. Về màu trong suốt (Transparent Colors)
- Khi bạn nhìn qua một cửa sổ kính có tông màu đỏ đậm, tất cả các màu phía sau nó có một màu đỏ được thêm vào chúng. Bạn có thể bắt chước hiệu ứng này bằng cách thêm giá trị số nguyên từ 0 đến 255 vào giá trị màu của bạn.
- Giá trị này được gọi là giá trị alpha. Nó là thước đo mức độ mờ đục (nghĩa là không trong suốt) của một màu. Thông thường khi bạn vẽ một pixel lên một đối tượng bề mặt, màu mới sẽ thay thế hoàn toàn bất kỳ màu nào đã có ở đó. Nhưng với các màu có giá trị alpha, thay vào đó, bạn có thể chỉ cần thêm một tông màu cho màu đã có.
- Ví dụ, bộ ba số nguyên này dành cho màu xanh lục: (0, 255, 0). Nhưng nếu chúng ta thêm một số nguyên thứ tư cho giá trị alpha, chúng ta có thể biến màu này thành một nửa màu xanh lục trong suốt: (0, 255, 0, 128). Giá trị alpha là 255 hoàn toàn mờ đục (nghĩa là hoàn toàn không minh bạch). Các màu (0, 255, 0) và (0, 255, 0, 255) trông giống hệt nhau. Giá trị alpha bằng 0 có nghĩa là màu hoàn toàn trong suốt. Nếu bạn vẽ bất kỳ màu nào có giá trị alpha bằng 0 đến một đối tượng bề mặt, nó sẽ không có hiệu lực, vì màu này hoàn toàn trong suốt và vô hình.
- Để vẽ bằng các màu trong suốt, bạn phải tạo một đối tượng Surface bằng phương thức convert_alpha(). Ví dụ: đoạn mã sau tạo một đối tượng Surface có thể vẽ màu trong suốt:
anotherSurface = DISPLAYSURF.convert_alpha() |
- Khi mọi thứ đã được vẽ trên đối tượng Surface được lưu trữ trong một Mặt khác, thì một Mặt khác có thể được làm mờ (tức là được sao chép) sang DISPLAYSURF để nó sẽ xuất hiện trên màn hình. (Xem hình vẽ bản vẽ với phần pygame.image.load() và phần blit() sau trong chương này.)
- Điều quan trọng cần lưu ý là bạn không thể sử dụng màu trong suốt trên các đối tượng Surface không được trả về từ lệnh gọi convert_alpha(), bao gồm cả Surface hiển thị được trả về từ pygame.display.set_mode().
- Nếu chúng ta tạo ra một bộ màu để vẽ Kỳ lân hồng vô hình huyền thoại, chúng ta sẽ sử dụng (255, 192, 192, 0), cuối cùng trông hoàn toàn vô hình giống như bất kỳ màu nào khác có 0 cho giá trị alpha của nó. Rốt cuộc, nó là vô hình.
6. pygame.Color Objects
- Bạn cần biết cách thể hiện màu sắc bởi vì các chức năng vẽ của Pygame Sắp cần một cách để biết bạn muốn vẽ màu gì. Một bộ ba hoặc bốn số nguyên là một cách. Một cách khác là như một đối tượng pygame.Color. Bạn có thể tạo các đối tượng Color bằng cách gọi hàm khởi tạo pygame.Color() và truyền ba hoặc bốn số nguyên. Bạn có thể lưu trữ đối tượng Màu này trong các biến giống như bạn có thể lưu trữ các bộ dữ liệu trong các biến. Hãy thử nhập nội dung sau vào vỏ tương tác:
>>> import pygame >>> pygame.Color(255, 0, 0) (255, 0, 0, 255) >>> myColor = pygame.Color(255, 0, 0, 128) >>> myColor == (255, 0, 0, 128) True >>> |
- Bất kỳ chức năng vẽ nào trong Pygame (mà chúng ta sẽ tìm hiểu một chút) có tham số cho màu sắc có thể có dạng tuple hoặc dạng đối tượng Màu của một màu được truyền cho nó. Mặc dù chúng là các loại dữ liệu khác nhau, một đối tượng Màu bằng với một bộ bốn số nguyên nếu cả hai đều đại diện cho cùng một màu (giống như cách 42 == 42.0 sẽ đánh giá là True).
- Bây giờ bạn đã biết cách biểu diễn các màu (dưới dạng một đối tượng pygame.Color hoặc một bộ ba hoặc bốn số nguyên cho màu đỏ, xanh lá cây, xanh lam và alpha tùy chọn) và tọa độ (như một bộ hai số nguyên cho X và Y), hãy tìm hiểu về các đối tượng pygame.Rect để chúng ta có thể bắt đầu sử dụng các hàm vẽ của Pygame.
7. Rect Objects
- Pygame có hai cách để thể hiện các khu vực hình chữ nhật (giống như có hai cách để thể hiện màu sắc). Đầu tiên là một bộ gồm bốn số nguyên:
1. Tọa độ X của góc trên cùng bên trái. 2. Tọa độ Y của góc trên cùng bên trái. 3. Chiều rộng (tính bằng pixel) của hình chữ nhật. 4. Sau đó, chiều cao (tính bằng pixel) của hình chữ nhật. |
- Cách thứ hai là một đối tượng pygame.Rect, chúng ta sẽ gọi các đối tượng Rect là ngắn. Ví dụ: mã bên dưới tạo một đối tượng Rect với góc trên cùng bên trái tại (10, 20) rộng 200 pixel và cao 300 pixel:
>>> import pygame >>> spamRect = pygame.Rect(10, 20, 200, 300) >>> spamRect == (10, 20, 200, 300) True |
- Điều tiện lợi ở đây là đối tượng Rect sẽ tự động tính toán tọa độ cho các tính năng khác của hình chữ nhật. Ví dụ: nếu bạn cần biết tọa độ X của cạnh phải của đối tượng pygame.Rect mà chúng tôi đã lưu trữ trong biến spamRect, bạn chỉ có thể truy cập vào thuộc tính Rect object:
>>> spamRect.right 210 |
- Mã Pygame cho đối tượng Rect tự động tính toán rằng nếu cạnh trái ở tọa độ X 10 và hình chữ nhật rộng 200 pixel, thì cạnh phải phải ở tọa độ X 210. Nếu bạn gán lại thuộc tính bên phải, tất cả các thuộc tính khác các thuộc tính được tự động tính toán lại:
>>> spamRect.right = 350 >>> spamRect.left 150 |
- Ở đây, một danh sách tất cả các thuộc tính mà các đối tượng pygame.Rect cung cấp (biến mà đối tượng Rect được lưu trữ trong một biến có tên là spamRect):
Attribute Name |
Description |
myRect.left |
The int value of the X-coordinate of the left side of the rectangle. |
myRect.right |
The int value of the X-coordinate of the right side of the rectangle. |
myRect.top |
The int value of the Y-coordinate of the top side of the rectangle. |
myRect.bottom |
The int value of the Y-coordinate of the bottom side. |
myRect.centerx |
The int value of the X-coordinate of the center of the rectangle. |
myRect.centery |
The int value of the Y-coordinate of the center of the rectangle. |
myRect.width |
The int value of the width of the rectangle. |
myRect.height |
The int value of the height of the rectangle. |
myRect.size |
A tuple of two ints: (width, height) |
myRect.topleft |
A tuple of two ints: (left, top) |
myRect.topright |
A tuple of two ints: (right, top) |
myRect.bottomleft |
A tuple of two ints: (left, bottom) |
myRect.bottomright |
A tuple of two ints: (right, bottom) |
myRect.midleft |
A tuple of two ints: (left, centery) |
myRect.midright |
A tuple of two ints: (right, centery) |
myRect.midtop |
A tuple of two ints: (centerx, top) |
myRect.midbottom |
A tuple of two ints: (centerx, bottom) |
8. Primitive Drawing Functions
- Pygame cung cấp một số chức năng khác nhau để vẽ các hình dạng khác nhau lên một đối tượng bề mặt. Những hình dạng như hình chữ nhật, hình tròn, hình elip, đường hoặc pixel riêng lẻ thường được gọi là hình vẽ nguyên thủy. Mở trình soạn thảo tập tin IDLE và nhập vào chương trình sau đây và lưu nó dưới dạng draw.py (Tải source tại draw.py)
1. import pygame, sys |
Khi chương trình này chạy, cửa sổ sau được hiển thị cho đến khi người dùng đóng cửa sổ:
- Lưu ý cách chúng ta tạo các biến không đổi cho mỗi màu. Làm điều này làm cho mã của chúng tôi dễ đọc hơn, bởi vì nhìn thấy XANH trong mã nguồn dễ hiểu hơn nhiều vì đại diện cho màu xanh lá cây hơn (0, 255, 0).
- Các chức năng vẽ được đặt tên theo hình dạng mà chúng vẽ. Các tham số bạn truyền các hàm này cho chúng biết đối tượng Surface sẽ vẽ trên đó, vẽ hình dạng ở đâu (và kích thước nào), màu gì và độ rộng để tạo các đường. Bạn có thể thấy các hàm này được gọi như thế nào trong chương trình vẽ vẽ, nhưng đây là một mô tả ngắn về mỗi hàm:
· Fill(color) - Phương thức fill() không phải là một hàm mà là một phương thức của các đối tượng pygame.Surface. Nó sẽ hoàn toàn điền vào toàn bộ đối tượng Surface với bất kỳ giá trị màu nào bạn vượt qua như đối với tham số màu.
· Pygame.draw.polygon(surface, color, pointlist, width) - (bề mặt, màu sắc, danh sách điểm, chiều rộng) - Một đa giác có hình dạng chỉ được tạo bởi các cạnh phẳng. Các tham số bề mặt và màu sắc cho biết chức năng trên bề mặt nào để vẽ đa giác, và màu gì để tạo ra nó.
- Tham số danh sách điểm là một tuple hoặc danh sách các điểm (nghĩa là tuple hoặc danh sách các tuple hai số nguyên cho tọa độ XY). Đa giác được vẽ bằng cách vẽ các đường giữa mỗi điểm và điểm xuất hiện sau điểm đó trong bộ dữ liệu. Sau đó, một dòng được vẽ từ điểm cuối cùng đến điểm đầu tiên. Bạn cũng có thể vượt qua một danh sách các điểm thay vì một loạt các điểm.
- Tham số chiều rộng là tùy chọn. Nếu bạn để nó ra, đa giác được vẽ sẽ được điền vào, giống như đa giác màu xanh lá cây của chúng ta trên màn hình được tô màu. Nếu bạn vượt qua một giá trị số nguyên cho tham số chiều rộng, chỉ có đường viền của đa giác sẽ được vẽ. Số nguyên biểu thị chiều rộng đa giác của đường viền đa giác. Vượt qua 1 cho tham số chiều rộng sẽ tạo ra một đa giác mỏng, trong khi vượt qua 4 hoặc 10 hoặc 20 sẽ tạo ra các đa giác dày hơn. Nếu bạn truyền số nguyên 0 cho tham số chiều rộng, đa giác sẽ được điền vào (giống như nếu bạn để hoàn toàn tham số chiều rộng).
Tất cả các hàm vẽ pygame.draw đều có các tham số chiều rộng tùy chọn ở cuối và chúng hoạt động giống như tham số chiều rộng của pygame.draw.polygon (). Có lẽ một tên tốt hơn cho tham số chiều rộng sẽ là độ dày, vì tham số đó kiểm soát độ dày của các đường bạn vẽ.
· Pygame.draw.line(surface, color, start_point, end_point, width) – (bề mặt, màu sắc, start_point, end_point, width) - Hàm này vẽ một đường giữa các tham số start_point và end_point.
· Pygame.draw.lines (surface, color, closed, pointlist, width) – (bề mặt, màu sắc, đóng, danh sách điểm, chiều rộng) - Hàm này vẽ một loạt các dòng từ điểm này sang điểm tiếp theo, giống như pygame.draw.polygon (). Sự khác biệt duy nhất là nếu bạn truyền sai cho tham số đã đóng, sẽ không có một dòng từ điểm cuối cùng trong tham số danh sách điểm đến điểm đầu tiên. Nếu bạn vượt qua True, thì nó sẽ vẽ một đường thẳng từ điểm cuối cùng đến điểm đầu tiên.
· Pygame.draw.circle(surface, color, center_point, radius, width) - (bề mặt, màu sắc, centre_point, bán kính, chiều rộng) - Hàm này vẽ một vòng tròn. Tâm của vòng tròn nằm ở tham số centre_point. Số nguyên được truyền cho tham số bán kính đặt kích thước của vòng tròn.
- Bán kính của một vòng tròn là khoảng cách từ tâm đến cạnh. (Bán kính hình tròn luôn bằng một nửa đường kính.) Vượt qua 20 cho tham số bán kính sẽ vẽ một hình tròn có bán kính 20 pixel.
· Pygame.draw.ellipse(surface, color, bounding_rectangle, width) (bề mặt, màu sắc, ràng buộc_r hình chữ nhật, chiều rộng) - Hàm này vẽ một hình elip (giống như một vòng tròn bị ép hoặc kéo dài). Hàm này có tất cả các tham số thông thường, nhưng để cho hàm biết độ lớn và vị trí vẽ hình elip, bạn phải chỉ định hình chữ nhật giới hạn của hình elip. Một hình chữ nhật giới hạn là hình chữ nhật nhỏ nhất có thể được vẽ xung quanh một hình. Dưới đây, một ví dụ về hình elip và hình chữ nhật giới hạn của nó:
- Tham số ràng buộc có thể là một đối tượng pygame.Rect hoặc một bộ gồm bốn số nguyên. Lưu ý rằng bạn không chỉ định điểm trung tâm cho hình elip giống như bạn làm cho hàm pygame.draw.circle().
· Pygame.draw.rect(surface, color, rectangle_tuple, width) – (bề mặt, màu sắc, hình chữ nhật_tuple, chiều rộng) - Hàm này vẽ một hình chữ nhật. Hình chữ nhật_tuple là một tuple gồm bốn số nguyên (đối với tọa độ XY của góc trên cùng bên trái và chiều rộng và chiều cao) hoặc đối tượng pygame.Rect có thể được chuyển qua. Nếu hình chữ nhật có cùng kích thước cho chiều rộng và chiều cao, hình vuông sẽ được vẽ.
9. Đối tượng pygame.PixelArray
- Thật không may, có một hàm duy nhất mà bạn có thể gọi sẽ đặt một pixel thành một màu (trừ khi bạn gọi pygame.draw.line () có cùng điểm bắt đầu và điểm kết thúc). Khung Pygame cần chạy một số mã phía sau hậu trường trước và sau khi vẽ lên một đối tượng Surface. Nếu nó phải làm điều này cho mỗi pixel bạn muốn đặt, chương trình của bạn sẽ chạy chậm hơn nhiều. (Theo thử nghiệm nhanh của tôi, vẽ pixel theo cách này chậm hơn hai hoặc ba lần.)
- Thay vào đó, bạn nên tạo một đối tượng pygame.PixelArray (chúng tôi sẽ gọi chúng là các đối tượng PixelArray) của một đối tượng Surface và sau đó đặt các pixel riêng lẻ. Tạo một đối tượng PixelArray của một đối tượng Surface sẽ khóa lại đối tượng Surface. Trong khi một đối tượng Surface bị khóa, các chức năng vẽ vẫn có thể được gọi trên nó, nhưng nó không thể có các hình ảnh như hình ảnh PNG hoặc JPG được vẽ trên nó bằng phương thức blit (). (Phương thức blit () được giải thích sau trong chương này.)
- Nếu bạn muốn xem liệu một đối tượng Surface có bị khóa hay không, phương thức Surface get_locked () sẽ trả về True nếu nó bị khóa và Sai nếu không.
- Đối tượng PixelArray được trả về từ pygame.PixelArray () có thể có các pixel riêng lẻ được đặt bằng cách truy cập chúng bằng hai chỉ mục. Ví dụ: dòng 28 Ngược pixObj [480] [380] = BLACK sẽ đặt pixel ở tọa độ X 480 và tọa độ Y 380 thành màu đen (hãy nhớ rằng biến BLACK lưu trữ tuple màu (0, 0, 0)).
- Để nói với Pygame rằng bạn đã vẽ xong các pixel riêng lẻ, hãy xóa đối tượng PixelArray bằng một câu lệnh del. Đây là những gì dòng 33 làm. Xóa đối tượng PixelArray sẽ mở khóa đối tượng của đối tượng Surface để bạn có thể một lần nữa vẽ hình ảnh trên nó. Nếu bạn quên xóa đối tượng PixelArray, lần sau khi bạn cố gắng làm mờ (nghĩa là vẽ) một hình ảnh lên Surface, chương trình sẽ đưa ra một lỗi có nghĩa là, pygame.error: Các bề mặt không được khóa trong quá trình blit.
10. Hàm pygame.display.update ()
- Sau khi bạn gọi xong các chức năng vẽ để hiển thị đối tượng Surface trông giống như bạn muốn, bạn phải gọi pygame.display.update() để hiển thị Surface thực sự xuất hiện trên màn hình người dùng.
- Một điều mà bạn phải nhớ là pygame.display.update() sẽ chỉ hiển thị Surface (nghĩa là đối tượng Surface được trả về từ lệnh gọi tới pygame.display.set_mode()) xuất hiện trên màn hình. Nếu bạn muốn hình ảnh trên các đối tượng Surface khác xuất hiện trên màn hình, bạn phải làm mờ chúng (nghĩa là sao chép chúng) vào đối tượng Surface hiển thị bằng phương thức blit() (được giải thích tiếp theo trong hình vẽ của Vẽ phần).
11. Animation (Hoạt hình)
Bây giờ chúng ta đã biết làm thế nào để có được khung Pygame để vẽ lên màn hình, hãy cùng với học cách tạo ra những bức tranh hoạt hình. Một trò chơi chỉ có hình ảnh tĩnh, không di chuyển sẽ khá buồn tẻ. Hình ảnh hoạt hình là kết quả của việc vẽ một hình ảnh trên màn hình, sau đó một giây sau đó vẽ một hình ảnh hơi khác trên màn hình. Hãy tưởng tượng cửa sổ Chương trình có chiều rộng 6 pixel và cao 1 pixel, với tất cả các pixel màu trắng ngoại trừ pixel đen ở 4, 0. Nó sẽ trông như thế này:
Nếu bạn thay đổi cửa sổ sao cho 3, 0 là màu đen và 4.0 là màu trắng, nó sẽ trông như thế này:
Đối với người dùng, có vẻ như pixel đen đã di chuyển sang bên trái. Nếu bạn vẽ lại cửa sổ để có pixel đen ở 2, 0, nó sẽ tiếp tục trông giống như pixel đen đang di chuyển sang trái:
Nó có thể trông giống như pixel đen đang di chuyển, nhưng đây chỉ là ảo ảnh. Đối với máy tính, nó chỉ hiển thị ba hình ảnh khác nhau mà mỗi hình ảnh chỉ có một pixel đen. Xem xét nếu ba hình ảnh sau đây được hiển thị nhanh chóng trên màn hình:
- Đối với người dùng, nó sẽ trông giống như con mèo đang tiến về phía con sóc. Nhưng với máy tính, họ chỉ là một loạt các pixel. Mẹo để tạo hiệu ứng trông đáng tin cậy là để chương trình của bạn vẽ một bức tranh ra cửa sổ, đợi một phần của giây và sau đó vẽ một bức tranh hơi khác.
- Dưới đây là một chương trình ví dụ minh họa một hình ảnh động đơn giản. Nhập mã này vào trình chỉnh sửa tệp IDLE và lưu nó dưới dạng catanimation.py. Nó cũng sẽ yêu cầu tệp hình ảnh cat.png nằm trong cùng thư mục với tệp catanimation.py. Bạn có thể tải xuống hình ảnh này từ cat.png source code catanimation.py
1. import pygame, sys 2. from pygame.locals import * 3. 4. pygame.init() 5. 6. FPS = 30 # frames per second setting 7. fpsClock = pygame.time.Clock() 8. 9. # set up the window 10. DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32) 11. pygame.display.set_caption('Animation') 12. 13. WHITE = (255, 255, 255) 14. catImg = pygame.image.load('cat.png') 15. catx = 10 16. caty = 10 17. direction = 'right' 18. 19. while True: # the main game loop 20. DISPLAYSURF.fill(WHITE) 21. 22. if direction == 'right': 23. catx += 5 24. if catx == 280: 25. direction = 'down' 26. elif direction == 'down': 27. caty += 5 28. if caty == 220: 29. direction = 'left' 30. elif direction == 'left': 31. catx -= 5 32. if catx == 10: 33. direction = 'up' 34. elif direction == 'up': 35. caty -= 5 36. if caty == 10: 37. direction = 'right' 38. 39. DISPLAYSURF.blit(catImg, (catx, caty)) 40. 41. for event in pygame.event.get(): 42. if event.type == QUIT: 43. pygame.quit() 44. sys.exit() 45. 46. pygame.display.update() 47. fpsClock.tick(FPS) |
Nhìn con mèo hoạt hình đó đi!
12. Các khung hình mỗi giây và các đối tượng pygame.time.Clock
- Tốc độ khung hình hoặc tốc độ làm mới là số lượng hình ảnh mà chương trình vẽ mỗi giây và được đo bằng FPS hoặc khung hình mỗi giây. (Trên màn hình máy tính, tên chung cho FPS là hertz. Nhiều màn hình có tốc độ khung hình là 60 hertz hoặc 60 khung hình mỗi giây.) Tốc độ khung hình thấp trong các trò chơi video có thể khiến trò chơi trông rối mắt hoặc tăng vọt. Nếu chương trình có quá nhiều mã để chạy để vẽ lên màn hình đủ thường xuyên, thì FPS sẽ giảm. Nhưng các trò chơi trong cuốn sách này đủ đơn giản để chiến thắng này có thể phát hành ngay cả trên các máy tính cũ.
- Một đối tượng pygame.time.Clock có thể giúp đảm bảo chương trình của chạy ở một FPS tối đa nhất định. Đối tượng Đồng hồ này sẽ đảm bảo rằng các chương trình trò chơi của không chạy quá nhanh bằng cách đặt các khoảng dừng nhỏ trên mỗi lần lặp của vòng lặp trò chơi. Nếu không có những tạm dừng này, chương trình trò chơi của sẽ chạy nhanh như máy tính có thể chạy nó. Điều này thường quá nhanh đối với người chơi và khi máy tính nhanh hơn, họ cũng sẽ chạy trò chơi nhanh hơn. Một cuộc gọi đến phương thức tick () của một đối tượng Đồng hồ trong vòng lặp trò chơi có thể đảm bảo trò chơi chạy ở cùng tốc độ cho dù máy tính có chạy nhanh như thế nào. Đối tượng Đồng hồ được tạo trên dòng 7 của chương trình catanimation.py.
7. fpsClock = pygame.time.Clock() |
Phương thức Clock tick() được gọi ở cuối vòng lặp trò chơi, sau lệnh gọi pygame.display.update(). Độ dài của tạm dừng được tính dựa trên khoảng thời gian kể từ cuộc gọi trước đó để đánh dấu(), sẽ diễn ra vào cuối vòng lặp trước của vòng lặp trò chơi. (Lần đầu tiên phương thức tick() được gọi, nó hoàn toàn không tạm dừng.) Trong chương trình hoạt hình, nó có chạy trên dòng 47 như là hướng dẫn cuối cùng trong vòng lặp trò chơi.
Tất cả những gì bạn cần biết là bạn nên gọi phương thức tick() một lần mỗi lần lặp thông qua vòng lặp trò chơi ở cuối vòng lặp. Thông thường, điều này là ngay sau cuộc gọi đến pygame.display.update()
47. fpsClock.tick(FPS) |
Hãy thử sửa đổi biến hằng FPS để chạy cùng một chương trình ở các tốc độ khung hình khác nhau. Đặt nó thành một giá trị thấp hơn sẽ làm cho chương trình chạy chậm hơn. Đặt nó thành một giá trị cao hơn sẽ làm cho chương trình chạy nhanh hơn.
Vẽ hình ảnh với pygame.image.load() và blit()
Các chức năng vẽ sẽ ổn nếu bạn muốn vẽ các hình đơn giản trên màn hình, nhưng nhiều trò chơi có hình ảnh (còn được gọi là họa tiết). Pygame có thể tải hình ảnh lên các đối tượng Surface từ các tệp hình ảnh PNG, JPG, GIF và BMP.
Hình ảnh của con mèo được lưu trữ trong một tập tin có tên cat.png. Để tải tập tin này, hình ảnh, chuỗi 'cat.png' được truyền cho hàm pygame.image.load(). Lệnh gọi hàm pygame.image.load() sẽ trả về một đối tượng Surface có hình ảnh được vẽ trên đó. Đối tượng Surface này sẽ là một đối tượng Surface riêng biệt với đối tượng Surface hiển thị, vì vậy chúng ta phải làm mờ (nghĩa là sao chép) đối tượng Surface Surface hình ảnh vào đối tượng Surface hiển thị. Blits đang vẽ nội dung của một Surface lên một Surface khác. Nó được thực hiện với phương thức đối tượng Blit().
Nếu bạn nhận được thông báo lỗi như “pygame.error: Couldn't open cat.png”, khi gọi pygame.image.load(), thì hãy đảm bảo tệp cat.png nằm trong cùng thư mục với tệp catanimation.py trước đó bạn chạy chương trình
39. DISPLAYSURF.blit(catImg, (catx, caty)) |
- Dòng 39 của chương trình hoạt hình sử dụng phương thức blit() để sao chép catImg sang DISPLAYSURF. Có hai tham số cho blit(). Đầu tiên là đối tượng Surface nguồn, đây là những gì sẽ được sao chép vào đối tượng Surface HIỂN THỊ. Tham số thứ hai là một tuple hai số nguyên cho các giá trị X và Y của góc topleft nơi hình ảnh sẽ được làm mờ.
- Nếu catx và caty được đặt thành 100 và 200 và chiều rộng của catImg là 125 và chiều cao là 79, cuộc gọi blit() này sẽ sao chép hình ảnh này vào DISPLAYSURF để góc trên cùng bên trái của catImg nằm ở tọa độ XY (100 , 200) và tọa độ XY của góc dưới bên phải là (225, 279).
- Lưu ý rằng bạn không thể chuyển sang Surface mà hiện tại đã bị khóa khóa (chẳng hạn như khi một đối tượng PixelArray đã được tạo từ nó và chưa bị xóa.)
- Phần còn lại của vòng lặp trò chơi chỉ là thay đổi các biến catx, caty và direction để con mèo di chuyển xung quanh cửa sổ. Ngoài ra còn có một cuộc gọi đến pygame.event.get() để xử lý sự kiện QUIT.
13. Phông chữ (Font)
- Nếu bạn muốn vẽ văn bản lên màn hình, bạn có thể viết một số cuộc gọi đến pygame.draw.line () để vẽ ra các dòng của mỗi chữ cái. Đây sẽ là một vấn đề đau đầu để loại bỏ tất cả các cuộc gọi pygame.draw.line () và tìm ra tất cả các tọa độ XY, và có lẽ sẽ rất tốt.
- Thông báo trên sẽ mất bốn mươi mốt cuộc gọi đến hàm pygame.draw.line () để thực hiện. Thay vào đó, Pygame cung cấp một số chức năng đơn giản hơn nhiều cho phông chữ và tạo văn bản. – Đây là một chương trình Hello World nhỏ sử dụng các chức năng phông chữ Pygame. Nhập nó vào trình soạn thảo tập tin IDLE và lưu nó dưới dạng fonttext.py (tải source fonttext.py)
1. import pygame, sys 2. from pygame.locals import * 3. 4. pygame.init() 5. DISPLAYSURF = pygame.display.set_mode((400, 300)) 6. pygame.display.set_caption('Hello World!') 7. 8. WHITE = (255, 255, 255) 9. GREEN = (0, 255, 0) 10. BLUE = (0, 0, 128) 11. 12. fontObj = pygame.font.Font('freesansbold.ttf', 32) 13. textSurfaceObj = fontObj.render('Hello world!', True, GREEN, BLUE) 14. textRectObj = textSurfaceObj.get_rect() 15. textRectObj.center = (200, 150) 16. 17. while True: # main game loop 18. DISPLAYSURF.fill(WHITE) 19. DISPLAYSURF.blit(textSurfaceObj, textRectObj) 20. for event in pygame.event.get(): 21. if event.type == QUIT: 22. pygame.quit() 23. sys.exit() 24. pygame.display.update() |
Có sáu bước để làm cho văn bản xuất hiện trên màn hình:
1. Tạo một đối tượng pygame.font.Font. (Giống như trên dòng 12)
2. Tạo một đối tượng Surface với văn bản được vẽ trên đó bằng cách gọi phương thức Font render (). (Dòng 13)
3. Tạo một đối tượng Rect từ đối tượng Surface bằng cách gọi phương thức Surface get get_rect (). (Dòng 14) Đối tượng Rect này sẽ được đặt chính xác chiều rộng và chiều cao cho văn bản được hiển thị, nhưng các thuộc tính trên cùng và bên trái sẽ là 0.
4. Đặt vị trí của đối tượng Rect bằng cách thay đổi một trong các thuộc tính của nó. Trên dòng 15, chúng tôi đặt tâm của đối tượng Rect là 200, 150.
5. Làm mờ đối tượng Surface bằng văn bản lên đối tượng Surface được trả về bởi pygame.display.set_mode (). (Dòng 19)
6. Gọi pygame.display.update () để hiển thị Surface hiển thị trên màn hình. (Dòng 24)
- Các tham số cho hàm xây dựng pygame.font.Font () là một chuỗi của tệp phông chữ sẽ sử dụng và một số nguyên kích thước của phông chữ (tính theo điểm, như cách bộ xử lý văn bản đo kích thước phông chữ). Trên dòng 12, chúng tôi chuyển 'freesansbold.ttf' (đây là phông chữ đi kèm với Pygame) và số nguyên 32 (cho phông chữ có kích thước 32 điểm).
- Các tham số cho lệnh gọi phương thức render () là một chuỗi văn bản cần kết xuất, giá trị Boolean để chỉ định nếu chúng ta muốn khử răng cưa (giải thích sau trong chương này), màu của văn bản và màu của nền. Nếu bạn muốn có một nền trong suốt, thì chỉ cần bỏ tham số màu nền trong lệnh gọi phương thức.
14. Khử răng cưa (Anti-Aliasing)
Khử răng cưa là một kỹ thuật đồ họa để làm cho văn bản và hình dạng trông bớt khối hơn bằng cách thêm một chút mờ vào các cạnh của chúng. Phải mất thêm một chút thời gian tính toán để vẽ với khử răng cưa, vì vậy mặc dù đồ họa có thể trông đẹp hơn, chương trình của bạn có thể chạy chậm hơn (nhưng chỉ một chút thôi).
Nếu bạn phóng to một dòng bí danh và một dòng chống răng cưa, chúng sẽ trông như thế này:
Để làm cho văn bản Pygame sườn sử dụng tính năng khử răng cưa, chỉ cần truyền True cho tham số thứ hai của phương thức render(). Các hàm pygame.draw.aaline() và pygame.draw.aalines() có cùng tham số với pygame.draw.line() và pygame.draw.lines(), ngoại trừ chúng sẽ vẽ các đường chống răng cưa (trơn tru) của các dòng bí danh (khối).
15. Âm thanh (Sound)
- Phát âm thanh được lưu trữ trong các tệp âm thanh thậm chí còn đơn giản hơn hiển thị hình ảnh từ các tệp hình ảnh. Trước tiên, bạn phải tạo một đối tượng pygame.mixer.Sound (mà chúng ta sẽ gọi ngắn gọn là các đối tượng Âm thanh) bằng cách gọi hàm xây dựng pygame.mixer.Sound (). Nó nhận một tham số chuỗi, là tên tệp của tệp âm thanh. Pygame có thể tải các tệp WAV, MP3 hoặc OGG.
- Để phát âm thanh này, hãy gọi phương thức Âm thanh đối tượng play(). Nếu bạn muốn dừng ngay lập tức đối tượng Âm thanh phát, hãy gọi phương thức stop(). Phương thức stop() không có đối số. Đây là một số mã mẫu:
soundObj = pygame.mixer.Sound('beeps.wav') soundObj.play() import time time.sleep(1) # wait and let the sound play for 1 second soundObj.stop() |
Bạn có thể tải xuống tệp beeps.wav từ beep.wav.
- Việc thực hiện chương trình tiếp tục ngay sau khi play() được gọi; nó không đợi âm thanh phát xong trước khi chuyển sang dòng mã tiếp theo.
- Các đối tượng Âm thanh rất tốt cho các hiệu ứng âm thanh để chơi khi người chơi nhận sát thương, chém một thanh kiếm hoặc thu thập một đồng xu. Nhưng các trò chơi của bạn cũng có thể tốt hơn nếu chúng có nhạc nền chơi bất kể chuyện gì đang xảy ra trong trò chơi. Pygame chỉ có thể tải một tệp nhạc để phát ở chế độ nền tại một thời điểm. Để tải tệp nhạc nền, hãy gọi hàm pygame.mixer.music.load() và truyền cho nó một đối số chuỗi của tệp âm thanh để tải. Tập tin này có thể là định dạng WAV, MP3 hoặc MIDI.
- Để bắt đầu phát tệp âm thanh được tải dưới dạng nhạc nền, hãy gọi hàm pygame.mixer.music.play (-1, 0.0). Đối số -1 làm cho nhạc nền lặp vòng lặp mãi khi đến cuối tệp âm thanh. Nếu bạn đặt nó thành một số nguyên 0 hoặc lớn hơn, thì âm nhạc sẽ chỉ lặp số lần đó thay vì lặp mãi mãi. 0,0 có nghĩa là bắt đầu phát tệp âm thanh từ đầu. Nếu bạn vượt qua một số nguyên lớn hơn hoặc float, âm nhạc sẽ bắt đầu phát nhiều giây trong tệp âm thanh. Ví dụ: nếu bạn vượt qua 13,5 cho tham số thứ hai, tệp âm thanh bắt đầu phát tại điểm 13,5 giây ngay từ đầu.
- Để dừng phát nhạc nền ngay lập tức, hãy gọi hàm pygame.mixer.music.stop(). Hàm này không có đối số.
- Dưới đây là một số mã ví dụ về các phương thức và chức năng âm thanh:
# Loading and playing a sound effect: soundObj = pygame.mixer.Sound('beepingsound.wav') soundObj.play() # Loading and playing background music: pygame.mixer.music.load('backgroundmusic.mp3') pygame.mixer.music.play(-1, 0.0) # ...some more of your code goes here... pygame.mixer.music.stop() |
Bài này bao gồm những điều cơ bản để tạo ra các trò chơi đồ họa với khung Pygame.
Cám ơn bạn đã xem bài viết.

