HƯỚNG DẪN LÀM GAME TOWER DEFENSE

Hi all! Trong nội dung bài viết này mình xin reviews với tất cả phần đa người một thư viện thích thú của bản thân nhằm viết game bằng Pyhẹp, đó là Pyglet. Pyglet khôn xiết dễ dàng và đơn giản cùng tiện lợi với đầy đủ đoạn code ngắn thêm nhằm thiết kế game, hỗ trợ cho bài toán earlsdaughter.comelopment nhanh hao rộng tương đối nhiều so với phần lớn ngữ điệu khác. Tlỗi viện này vô cùng tương xứng mang lại đa số các bạn new bước đầu vào tuyến đường xây dựng game, hoặc chỉ dễ dàng và đơn giản nhằm viết bài bác tập mập cho hầu hết môn học bên trên ngôi trường :)

Sau đây họ vẫn demo viết 1 project bởi Pyglet, rõ ràng là một trong những game Tower Defense cực kỳ hấp dân.

Bạn đang xem: Hướng dẫn làm game tower defense

1. Cài đặt Python3 bên trên thiết bị tính

Đối cùng với lắp thêm Windows, các bạn vào liên kết sau nhằm sở hữu Python3:https://www.pyhẹp.org/downloads/release/python-382/Sau đó các bạn chạy tệp tin cài đặt về để thiết đặt, chú ý trong những khi mua lưu giữ lựa chọn option "Add Pyeo hẹp khổng lồ PATH" nhằm về sau ta rất có thể chạy Python3 thuận tiện trên cmd.Với nhiều phần các phiên phiên bản của Linux, những bạn đã có python3 tức thì vào đồ vật của mình

2. Cài đặt Pyglet bên trên sản phẩm công nghệ tínhViệc thiết lập thỏng viện này cực kì đơn giản dễ dàng, ta chỉ cần chạy 1 lệnh (bên trên cmd với Windows/ bên trên Terminal cùng với Linux) như sau:pip install pygletĐợi lệnh chạy xong xuôi là họ đã cài thành công xuất sắc thỏng viện của mình.Việc hotline thỏng viện trong mã mối cung cấp cũng tương đối dễ dàng và đơn giản nlỗi sau:
3. Thiết lập những thư mục mang đến projectTrước Lúc bắt tay vào bài toán viết mã nguồn, bản thân tạo ra những thư mục cùng file nlỗi sau:


.├── res│ └── res│ ├── GFX│ │ ├── Game│ │ │ ├── Enemy│ │ │ │ ├── quái nhân Enemy│ │ │ │ ├── HealthBar│ │ │ │ ├── Normal Enemy│ │ │ │ ├── Smaller Enemy│ │ │ │ └── Tanker Enemy│ │ │ ├── Tilemap│ │ │ │ ├── Ground│ │ │ │ ├── Road│ │ │ │ ├── Spawner│ │ │ │ └── Target│ │ │ └── Tower│ │ │ ├── BuyNUpgrade.png│ │ │ ├── Machine Gun Tower│ │ │ ├── Normal Tower│ │ │ └── Sniper Tower│ │ └── GUI│ │ └── Button│ └── SFX└── src ├── Entity ├── __init__.py ├── main.py ├── mapInfo.txt ├── Screen └── Utils
Trong lập trình sẵn game, OOPhường. là khôn cùng quan trọng, vày vậy Việc phân chia các folder đến hầu như đối tượng người dùng làm việc vào game góp chúng ta dễ ợt cai quản dự án với viết code nkhô cứng hơn.Tlỗi mục res đang chứa toàn thể những file giao diện (GFX), âm thanh hao (SFX), mọi tài nguyên ổn này sẽ sở hữu trong repo Github của dự án công trình bản thân đính kèm cuối bài viết.Thỏng mục src tất yếu là vẫn cất mã nguồn, trong số đó :

main.py là công tác chính, để khởi hễ game ta vẫn chạy tệp tin này.mapInfo.txt cất tài liệu maps, lối đi trong gameScreen là folder cất interface mang lại screen hiển thị game, cùng rất mã mối cung cấp của màn hình hiển thị thực đơn bắt đầu game cùng màn hình hiển thị chơiUtils cất interface và mã nguồn của một vài dụng cụ hỗ trợ render giao diện, tính toán thù trong gameEntity cất interface cùng mã mối cung cấp của những đối tượng người sử dụng game nhỏng tháp, đối thủ, đạn với lối đi, shop giao thương mua bán vật phẩm,...Các các bạn cũng hãy nhờ rằng sản xuất những tệp tin __init__.py trống nghỉ ngơi từng tlỗi mục để hầu hết tệp tin mã nguồn rất có thể import các mã mối cung cấp khác, làm việc link cùng nhau. Và giờ đồng hồ chúng ta hãy bắt tay vào viết code thôi !

1. Viết class Texture nhằm render những đối tượng người sử dụng giao diện :

Đây là class đặc trưng nhất của game, thực hiện quá trình hiển thị, dịch rời các object của game, ta đã viết mã nguồn cho class này ngơi nghỉ tệp tin texture.py vào tlỗi mục Utils:


import pygletfrom Utils.drawing_util import Utilsclass Texture(Utils): def __init__(self, *args): if len(args) == 1: path = args<0> self.image = pyglet.image.load(path) self.sprite = pyglet.sprite.Sprite(self.image) elif len(args) == 3: path, x, y = args<0>, args<1>, args<2> self.image = pyglet.image.load(path) self.sprite = pyglet.sprite.Sprite(self.image) self.sprite.x, self.sprite.y = x, y def change_image(self, path): backup_data = (self.sprite.scale, self.sprite.x, self.sprite.y) self.image = pyglet.image.load(path) self.sprite = pyglet.sprite.Sprite(self.image) self.sprite.scale = backup_data<0> self.sprite.x, self.sprite.y = backup_data<1>, backup_data<2>
Từ kia bạn có thể thực hiện class này nghỉ ngơi những tệp tin mã mối cung cấp khác, tạo nên đầy đủ đối tượng người dùng bối cảnh cùng thao tác với chúng.Giải mê thích các thuộc tính của class Texture:

image: cất ảnh hiển thị của đối tượngsprite: hoàn toàn có thể coi đó là bản thân đối tượng người dùng được tạo thành từ hình họa, thỏng viện Pyglet đã draw từ ở trong tínhThuộc tính sprite cũng chính là class bao gồm sẵn trong Pyglet, bao gồm các ở trong tính x, y là vị trí hiển thị trên màn hình hiển thị. scale là form size hiển thị, nếu như scale == 1.0 thì đối tượng người sử dụng sẽ có được kích cỡ y y hệt như hình họa.

Class Texture được quá kế tự interface Utils, được thiết đặt vào file Utils/drawing_utils.py - cất các hàm để cách xử lý đối tượng người tiêu dùng sprite nhỏng chỉnh sửa form size, đổi địa điểm,... File này được viết nhỏng sau:


class Utils(object): def __init__(self): pass def get_x(self): return self.sprite.x def get_y(self): return self.sprite.y def set_x(self, value): self.sprite.x = value def set_y(self, value): self.sprite.y = value def set_coordinate(self, x, y): self.sprite.x, self.sprite.y = x, y def scale(self, ratio): self.sprite.scale = ratio def get_width(self): return self.sprite.width def get_height(self): return self.sprite.height def set_width(self, value): self.sprite.width = value def set_height(self, value): self.sprite.height = value def draw(self): self.sprite.draw()
import pygletfrom pyglet.gl import glfrom pkg_resources import parse_versionwindow = pyglet.window.Window(fullscreen=False)win_max_x = window.widthwin_max_y = window.height
Mã nguồn bên trên sẽ khởi tạo ra 1 hành lang cửa số new lúc bọn họ chạy công tác. Cửa sổ này vẫn Đen xì vị bọn họ chưa render gì lên cả (hàm on_draw() chưa làm gì). Nếu muốn game chạy toàn màn hình hiển thị các chúng ta có thể biến hóa tsay đắm số fullscreen=True vào constructor pyglet.window.Window(). win_max_x, win_max_y đựng thông báo form size màn hình hiển thị. Tiếp đó họ vẫn viết code cho những màn hình hiển thị game .

2. Viết mã nguồn cho screen

Vì game vẫn có không ít màn hình nghịch (thực đơn start game, màn hình hiển thị chơi trò chơi chính,..) mỗi màn bao gồm những công dụng không giống nhau cần mình vẫn viết ra 1 interface thông thường cho các screen trong file screen.py:


class Screen(object): def __init__(self): self.on_display = False def draw(self): pass def mouse_clicked(self, x, y): pass def on_mouse_motion(self, x, y): pass def on_hover(self, x, y, sprite): if sprite.get_x() x sprite.get_x() + sprite.get_width(): if sprite.get_y() y sprite.get_y() + sprite.get_height(): return True return False
Với code nlỗi trên, bọn họ khoác định khi 1 màn new được tạo nên thì sẽ không hiển thị, các thao tác làm việc thao tác với chuột, phím chưa được có mang nhưng mà đã diễn đạt rõ ràng nghỉ ngơi các class nhỏ ( các màn hình rõ ràng ). Hàm on_hover() dùng để xác minh coi bọn họ có di chuột lên một đối tượng người tiêu dùng (spirte) ví dụ như thế nào trên screen ko - một hàm nhưng ta sẽ áp dụng không hề ít trong tương lai, thậm chí còn là tức thì tới đây Lúc ta viết code mang đến màn hình hiển thị bước đầu game trên tệp tin start_screen.py vào thư mục Screen.


from Utils.texture import Texturefrom Screen.screen import Screenimport pygletclass StartScreen(Screen): def __init__(self, x, y): self.on_display = True self.width, self.height = x, y self.start_button_on_hover, self.load_button_on_hover = False, False self.switched, self.load = False, False path = <"./../res/res/GFX/GUI/Background/Background_main_screen.jpg", "./../res/res/GFX/GUI/Button/button.png", "./../res/res/GFX/GUI/Button/button-selected.png", "./../res/res/GFX/GUI/Button/LoadButton.png", "./../res/res/GFX/GUI/Button/LoadButton_selected.png",> background_image_path = path<0> self.start_button_image_path = , path<2>> self.load_button_image_path = , path<4>> self.background = Texture(path<0>) self.background.scale(self.width / self.background.get_width()) self.start_button = Texture(self.start_button_image_path<0>) x = self.width // 2 - (self.start_button.get_width() // 2) y = self.height // 2 - 150 self.start_button.set_coordinate(x, y) self.load_button = Texture(self.load_button_image_path<0>) x = self.width // 2 - (self.start_button.get_width() // 2) y = self.height // 2 - self.start_button.get_height() - 150 scale_ratio = self.start_button.get_width() / self.load_button.get_width() self.load_button.set_coordinate(x, y) self.load_button.scale(scale_ratio) def draw(self): self.background.draw() self.start_button.draw() self.load_button.draw() def mouse_clicked(self, x, y): if self.start_button_on_hover: self.on_display, self.switched = False, True elif self.load_button_on_hover: try: with open("save_data.txt", "r") as f: self.on_display, self.switched = False, True self.load = True except FileNotFoundError: pass def on_mouse_motion(self, x, y): if self.on_hover(x, y, self.start_button): if not self.start_button_on_hover: self.start_button.change_image(self.start_button_image_path<1>) self.start_button_on_hover = True elif self.start_button_on_hover: self.start_button.change_image(self.start_button_image_path<0>) self.start_button_on_hover = False if self.on_hover(x, y, self.load_button): if not self.load_button_on_hover: self.load_button.change_image(self.load_button_image_path<1>) self.load_button_on_hover = True elif self.load_button_on_hover: self.load_button.change_image(self.load_button_image_path<0>) self.load_button_on_hover = False
Trong class này, ta knhì báo một số đường truyền cất các file hình họa cho những nút ít (Button) sinh sống mảng path. Từ kia tạo những texture với file hình ảnh nhằm hiển thị lên màn hình tại đoạn code kế tiếp. Công đoạn render/display được chạy sinh sống hàm on_draw().Tiếp đó ta sẽ khởi tạo cảm giác cho những nút lúc con chuột được di đè lên những nút ít này. Cách tiến hành siêu dễ dàng bên trên hàm on_mouse_motion(), ta đã call mang lại hàm on_hover() đã được có mang trước nghỉ ngơi lớp Screen phụ vương, từ kia thay đổi hình họa hiển thị của nút bấm tùy vào Việc có con chuột di lên nút hay không.Cuối thuộc là bài toán chuyển sang screen chơi game Khi những nút Start, hoặc Load game được nhấn vào, ta vẫn gán phát triển thành self.on_display = False để dừng hiển thị màn hình ban đầu, biến hóa self.switched = False để thông báo screen chơi game bắt đầu hiển thị.

Xem thêm: Xem Việt Nam Thái Lan Ở Đâu, Bóng Đá Việt Nam Và Sức Hút Với Người Thái

Sau đó, ta viết 1 tệp tin game_screen.py dễ dàng không chạy các bước gì nhỏng sau:


from Utils.texture import Texturefrom Screen.screen import Screenclass GameScreen(Screen): def __init__(self, x, y): self.on_display = False self.width, self.height = x, y def draw(self): pass def on_mouse_motion(self, x, y): pass
lúc tự màn hình hiển thị bắt đầu chuyển sang màn hình hiển thị chơi trò chơi, ta đang thấy screen Black xì như Lúc new chạy chương trình thiết yếu, vì chưng game_screen chưa render gì cả.

Cuối cùng, ta sửa đổi tệp tin main.py nhằm chạy chức năng chuyển màn hình hiển thị nhỏng sau:


import pygletfrom pyglet.gl import glfrom pkg_resources import parse_versionfrom Screen.start_screen import StartScreenfrom Screen.game_screen import GameScreenwindow = pyglet.window.Window(fullscreen=True)win_max_x = window.widthwin_max_y = window.heightstart_screen = StartScreen(win_max_x, win_max_y)game_screen = None
window.eventdef on_draw(): global game_screen window.clear() if start_screen.on_display: start_screen.draw() else: if start_screen.switched: start_screen.switched = False game_screen = GameScreen(win_max_x, win_max_y) game_screen.draw()
window.eventdef on_mouse_motion(x, y, dx, dy): if start_screen.on_display: start_screen.on_mouse_motion(x, y) else: game_screen.on_mouse_motion(x, y)
window.event("on_mouse_press")def mouse_clicked(x, y, button, modifiers): if start_screen.on_display: start_screen.mouse_clicked(x, y) else: game_screen.mouse_clicked(x, y)if __name__ == "__main__": screen_index = 0 pyglet.ứng dụng.run()
Lần này ở lịch trình thiết yếu ta import 2 class Screen ta đang viết ngơi nghỉ trước, hàm on_draw() sẽ render 1 trong các 2 màn hình hiển thị, các thao tác làm việc clichồng, di con chuột cũng trở thành gọi hàm on_mouse_motion(), mouse_clicked() sống 1 trong những 2 screen tương ứng, tùy thuộc vào vấn đề màn hình hiển thị nào đang rất được hiển thị.

vì vậy là kết thúc rồi ! Chúng ta hãy chạy test game coi sao.Trên CMD (Windows) hoặc Terminal (Linux), ta cần sử dụng lệnh cd nhằm dịch rời cho tới thỏng mục project game, kế tiếp chạy lệnh sau:python3 main.pyTa đã thấy màn hình hiển thị bắt đầu game nlỗi sau:

*
Màn hình render khá đẹp đề nghị ko ? Các bạn có thể di chuột lên các nút để check hiệu ứng hover, kế tiếp cliông xã vào nút ít Start để gửi quý phái màn hình hiển thị chơi trò giải trí.Trong thời điểm này screen sẽ hiển thị chỉ 1 màu sắc black vì game_screen không làm gì. Các chúng ta nhận nút Esc để dừng lại công tác.

Ở những phần tiếp sau, bọn họ vẫn viết mã mối cung cấp đến game_screen nhằm game chạy tiếp một trong những tác dụng.