Bomb là đối tượng mà Bomber sẽ đặt và kích hoạt tại các ô Grass.Bomber có một lần được đi từ vị trí đặt Bomb ra vị trí bên cạnh.. Grass là đối tượng mà Bomber và Enemy có thể di chuyển x
Giới thiệu bài tập lớn “Lập trình ứng dụng game Bomberman”
Chúng em xin chân thành cảm ơn thầy đã hướng dẫn môn Lập trình Java trong kỳ học này Môn học này rất quan trọng, giúp chúng em tích lũy kinh nghiệm quý báu cho việc thực tập sau này.
Chúng em chọn đề tài Game đặt Bomb vì đây là một thể loại mà ai cũng đã từng chơi khi còn nhỏ Khi được tự do lựa chọn, cả 3 bọn em đều quyết định phát triển một Game đặt Bomb do chính tay mình làm, nhằm hiểu rõ hơn về Java và quy trình phát triển game Trong quá trình tạo dựng, chúng em đã xây dựng đầy đủ các yếu tố chính của game, chia thành hai nhóm: đối tượng động (Bomber, Enemy, Bomb) và đối tượng tĩnh (Grass, Wall, Brick, Portal, Item).
[09/05/2023 18:34:16] Đỗ Đăng Quyền: Các đối tượng
Nếu bạn là fan của trò chơi Bomberman, bạn sẽ nhận ra rằng các đối tượng trong game được phân chia thành hai loại chính Loại đầu tiên là nhóm đối tượng động, bao gồm Bomber, Enemy và Bomb Loại thứ hai là nhóm đối tượng tĩnh, bao gồm Grass, Wall, Brick, Portal và Item.
Bomber là nhân vật chính của trò chơi Bomber có thể di chuyển theo 4 hướng trái/phải/lên/xuống theo sự điều khiển của người chơi.
Bomber có khả năng đặt và kích hoạt Bomb tại các ô Grass Sau khi đặt Bomb, Bomber có một lần di chuyển từ vị trí đặt Bomb đến ô bên cạnh Sau 2 giây kích hoạt, Bomb sẽ tự nổ và tạo ra các đối tượng Flame.
Grass là đối tượng mà Bomber và Enemy có thể di chuyển xuyên qua, và cho phép đặt Bomb lên vị trí của nó
Wall là một đối tượng cố định trong trò chơi, không thể bị phá hủy bằng Bom và cũng không thể đặt Bom lên đó Cả Bomber và Enemy đều không thể di chuyển vào khu vực của Wall.
Brick là một vật thể được đặt trên các ô Grass, không thể đặt Bomb lên nó, nhưng có thể bị phá hủy bởi Bomb gần đó Bomber và Enemy thường không thể di chuyển vào ô Brick cho đến khi nó bị phá hủy.
Portal xuất hiện sau khi đối tượng Brick bị phá hủy Khi tất cả kẻ thù đã bị tiêu diệt, người chơi có thể di chuyển vào vị trí của Portal để chuyển sang Level tiếp theo.
Các Item được ẩn sau Brick và chỉ xuất hiện khi Brick bị phá hủy Bomber có thể thu thập Item bằng cách di chuyển vào vị trí của chúng.
SpeedItem tăng vận tốc di chuyển của bomber.
FlameItem tăng độ dài các Flame khi bomb nổ.
BombItem giúp tăng số lượng Bomb có thể đặt thêm một.
LifeItem tăng số mạng của bomber lên một.
TimeItem tăng thời gian chơi.
StrengthItem làm cho bomb có thể nổ xuyên tường (và item).
DetonatorItem giúp cho bomber có khả năng kích hoạt bomb nổ sớm bằng cách bấm phím D.
Enemy là các đối tượng mà Bomber phải tiêu diệt hết để có thể qua Level.
Balloom là Enemy đơn giản nhất, di chuyển ngẫu nhiên với vận tốc cố định.
Oneal di chuyển "thông minh" hơn, biết tìm đường để đuổi bomber.
Broom có khả năng đi xuyên qua gạch.
Bear có tốc độ di chuyển nhanh, có khả năng đuổi theo bomber ở một mức độ nhất định.
Frog khi chết sẽ tạo ra 2 Balloom tại vị trí của nó.
Fire di chuyển nhanh, có thể phá hủy item khi chạm vào.
Mô tả game play, xử lý va chạm và xử lý bom nổ
Danh sách thành viên thực hiện và đóng góp của các thành viên
TT Họ tên Mã số SV Nội dung thực hiện Ghi chú
Phân tích chức năng yêu cầu ứng dụng, giải pháp
Viết mô tả tài liệu thực thi
Mô tả các tính năng của ứng dụng
Tổng quát về chương trình
- Thư mục res: là thư mục chứa các dữ liệu cần xây dựng trong game(âm thanh,hình ảnh, …)
- Thư mục src Là thư mục chứa code để hình thành nên một game
2 File res Đây là nơi chứa các dữ liệu cần xây dựng trong trò chơi hoạt động Sau đây là các lớp có trong res a audio Đây là nơi chứa những đoạn âm thanh của game
- bom.wav là phần chứa video âm thanh khi đặt bom ,và đây là âm thanh của nó
- clear.wav là âm thanh khi chạy lại từ đầu
- dead1.wav là âm thanh khi chết lần 1
- dead2.wav là âm thanh khi chết lần 2 trở đi
- gameaudio.wav là âm thanh trò chơi
- getitem.wav là âm thanh khi nhận các item trong game
- homestay.mp3 là âm thanh khi ở màn hình chính
-intro.wav là âm thanh giới thiệu
-putbomb.wav là âm thanh khi đặt bom
-phần này nói về các phông chữ trong game :
Tệp UPHEAVTT.TTF c.fxml là một tệp FXML được sử dụng để định dạng giao diện người dùng cho ứng dụng JavaFX Tệp này được viết bằng ngôn ngữ XML và bao gồm các thành phần giao diện như VBox, Label và Button.
Trong tệp này, VBox được sử dụng để định dạng giao diện người dùng với thuộc tính alignment được thiết lập là CENTER, giúp căn giữa các thành phần con Đồng thời, thuộc tính spacing được đặt là 20.0, tạo khoảng cách 20 đơn vị giữa các thành phần, mang lại giao diện gọn gàng và dễ nhìn.
Trong VBox, có hai thành phần chính: một Label hiển thị văn bản "Bomberman" và một Button có fx:id là "playButton" với nội dung "Play" Button này được gán một xử lý sự kiện onAction là "#switchToGame", cho phép ứng dụng chuyển đổi sang giao diện trò chơi khi người dùng nhấp vào nó.
VBox có thuộc tính padding với giá trị Insets, cho phép điều chỉnh khoảng cách giữa các cạnh của VBox và các thành phần con bên trong.
+Đây là một bản đồ cho trò chơi, được biểu diễn bằng các ký tự Mỗi ký tự tương ứng với một vật thể trên bản đồ:
" " đại diện cho một ô trống.
"p" đại diện cho nhân vật chính.
"f" đại diện cho một quái vật.
"*" đại diện cho một vật phẩm.
"1", "2", "5", "6" đại diện cho các cửa chìa khóa, và chúng cần một chìa khóa tương ứng để mở ra.
"t" đại diện cho một chìa khóa.
"s" đại diện cho một cửa ra.
"b" đại diện cho một quả bom.
Trong trò chơi, các ký hiệu "d", "w", "x" đại diện cho các cửa đi qua, có khả năng mở hoặc đóng Bản đồ có kích thước 13x19, bao gồm các khu vực bên trong khoảng trống cùng với các vật thể, tạo nên hình ảnh một màn chơi độc đáo.
+Đây là một bản đồ cho trò chơi, được biểu diễn bằng các ký tự Mỗi ký tự tương ứng với một vật thể trên bản đồ:
" " đại diện cho một ô trống.
"p" đại diện cho nhân vật chính.
"f" đại diễn cho một quái vật.
"*" đại diễn cho một vật phẩm.
"1", "2", "3", "4" đại diễn cho các cửa chìa khóa, và chúng cần một chìa khóa tương ứng để mở ra.
"t" đại diễn cho một chìa khóa.
"s", "d", "w", "x" đại diễn cho các cửa đi qua, và chúng có thể mở hoặc đóng lại.
Bản đồ này có kích thước 13x19 và bao gồm các phần bên trong khoảng trống và các vật thể, hình ảnh một màn chơi của trò chơi.
+Đây là một bản đồ cho trò chơi, được biểu diễn bằng các ký tự Mỗi ký tự tương ứng với một vật thể trên bản đồ:
" " đại diễn cho một ô trống.
"p" đại diễn cho nhân vật chính.
"f" đại diễn cho một quái vật.
"*" đại diễn cho một vật phẩm.
"1", "2", "3", "4" đại diễn cho các cửa chìa khóa, và chúng cần một chìa khóa tương ứng để mở ra.
"t" đại diễn cho một chìa khóa.
"s", "d", "w", "x" đại diễn cho các cửa đi qua, và chúng có thể mở hoặc đóng lại.
Bản đồ này có kích thước 12x31 và bao gồm các phần bên trong khoảng trống và các vật thể, hình ảnh một màn chơi của trò chơi.
+Đây là một bản đồ cho trò chơi, được biểu diễn bằng các ký tự Mỗi ký tự tương ứng với một vật thể trên bản đồ:
" " đại diễn cho một ô trống.
"p" đại diễn cho nhân vật chính.
"f" đại diễn cho một quái vật.
"*" đại diễn cho một vật phẩm.
"1", "2", "3", "4", "5", "6" đại diễn cho các cửa chìa khóa, và chúng cần một chìa khóa tương ứng để mở ra.
"t" đại diễn cho một chìa khóa.
"s", "d", "w", "x" đại diễn cho các cửa đi qua, và chúng có thể mở hoặc đóng lại.
Bản đồ này có kích thước 12x31 và bao gồm các phần bên trong khoảng trống và các vật thể, hình ảnh một màn chơi của trò chơi. e.Sprites
Sau đây là các hình ảnh theo thứ tự từ trên xuống như hình trên :
+ Sau đây là các hình minh họa của enemy theo thứ tự từ trên xuống như hình trên :
+ Sau đây là các hình ảnh trong mục illustrations theo thứ tự như hình trên
+ Sau đây là hình ảnh của các phần tử trong map theo thứ tự như hình trên
+Sau đây là các hình ảnh của các phần tử trong phần player :
Sau đây là các hình ảnh có trong phần powerup theo thứ tự như hình trên:
+ các hình ảnh dưới đây sẽ phù hợp với thứ tự của hình trên :
The Java code snippet showcases the AIIntelligent class, which serves as a controller for the Enemy entity in a game This class implements the EntityController interface and includes a control method specifically designed to manage Enemy behavior The AIIntelligent class is instantiated as a singleton with a public static INSTANCE variable, and it utilizes the Random class for generating random values, enhancing the dynamic interactions within the game environment.
@Override public void control(Enemy enemy) {
In this code snippet, the player's position is obtained from the enemy's world, and the enemy's direction is set based on the calculated direction towards the player The method `getDirectionHigh` translates directional integers into corresponding movement directions, returning `Direction.NONE` for -1, `Direction.UP` for 0, `Direction.DOWN` for 1, `Direction.LEFT` for 2, and `Direction.RIGHT` for 3.
} throw new RuntimeException("Random.nextInt(4) return value out of range");
} public int getDirection (Player player , Enemy enemy) { if (player == null ) { return rand.nextInt( ) 4 ;
List path = findSortPath ( new EnemyMatrix(enemy), new Point(player.getTileX(), player.getTileY()), new Point(enemy.getTileX() , enemy.getTileY())) ; if (path == null) { return rand.nextInt( ) 4 ;
} else if (path.size() == ) { 1 return -1;
} else { return calculateDirection(path.get( ) 0 , path.get( )) 1 ;
Phương thức control sử dụng getDirection để xác định hướng di chuyển cho đối tượng Enemy Nếu không có đối tượng Player, phương thức sẽ trả về một hướng di chuyển ngẫu nhiên Khi có Player, nó áp dụng findSortPath để tìm đường đi ngắn nhất từ Enemy đến Player Nếu không tìm thấy đường đi, nó cũng trả về hướng di chuyển ngẫu nhiên Trong trường hợp chỉ cần một bước để đến đích, phương thức sẽ trả về hướng di chuyển NONE; nếu không, nó sẽ tính toán hướng di chuyển thông qua calculateDirection.
The method `calculateDirection` takes two `Point` objects, `start` and `end`, as parameters to determine the directional relationship between them It returns an integer based on the relative positions of the two points: it returns 0 if the end point is to the left of the start point, 1 if it is to the right, 2 if it is above, and 3 if it is below If the points are in the same position, it returns -1.
Phương thức calculateDirection xác định hướng di chuyển giữa hai điểm trên bản đồ bằng cách so sánh vị trí cột và hàng của chúng Nếu cột của điểm đích nhỏ hơn cột của điểm bắt đầu, hướng di chuyển sẽ là UP (0); nếu lớn hơn, sẽ là DOWN (1) Tương tự, nếu hàng của điểm đích nhỏ hơn hàng của điểm bắt đầu, hướng di chuyển trả về là LEFT (2); ngược lại, nếu hàng lớn hơn, sẽ là RIGHT (3).
2,BFS public class BFS { private static class Cell { int row ; int col ; int dist ;
Cell( int row , int col , int dist , Cell prev) { this.row = row ; this col = col ; this dist = dist ; this prev = prev ;
The function `findSortPath` utilizes Breadth-First Search (BFS) to identify a path in a matrix from a starting point to an endpoint, with a time complexity of O(n^2) and a space complexity of O(n^2) It first checks if the starting point is blocked; if so, it returns null The algorithm then retrieves the dimensions of the matrix, ensuring an efficient search for a valid path.
Cell[][] cells = new Cell[m][n] ; for int ( i = 0 ; i < m ; i++) { for (int j = 0; j < n ; j++) { if (!matrix.isBlocked(i, j)) { cells[i][j] = new Cell(i, j, Integer.MAX_VALUE, null); }
LinkedList queue = new LinkedList();
Cell src = cells[sx][sy] ; src.dist = 0 ; queue.add(src) ;
Cell p ; while ((p = queue.poll()) != null) { if (p.row == dx && p col == dy) { dest = p; break;
// moving up visit(cells, queue , p.row - 1 , p.col , p) ;
// moving down visit(cells, queue , p.row + 1 , p.col , p) ;
// moving left visit(cells, queue , p.row , p.col - 1 , p) ;
//moving right visit(cells, queue , p.row , p.col + 1 , p) ;
} if (dest == null ) { return null;
//LinkedList path = new LinkedList();
List path = new ArrayList(); do {
//System.out.println(p.x + " " + p.y); path.add(new Point(p.row , p col )) ;
} while ((p = p prev ) != null ; ) return path ;
} static void visit (Cell[][] cells , LinkedList queue , int x, int y, Cell parent) { if (x < 0 || x >= cells length || y < 0
|| y >= cells[0].length || cells[x][y] == null ) { return;
Cell p = cells[x][y] ; if (dist < p dist ) { p dist = dist ; p.prev = parent ; queue.add(p) ;
- Đây là một đoạn mã Java triển khai thuật toán BFS (Breadth-First Search) để tìm đường đi ngắn nhất giữa hai điểm trên một bản đồ
Phương thức findSortPath tìm đường đi ngắn nhất từ điểm bắt đầu đến điểm kết thúc bằng cách sử dụng ma trận matrix cùng với hai điểm start và end Thuật toán này lưu trữ thông tin của các ô trên bản đồ trong một mảng 2 chiều thuộc lớp Cell và sử dụng một hàng đợi LinkedList để quản lý các ô trong quá trình tìm kiếm.
Đầu tiên, chúng ta sẽ tạo một mảng 2 chiều gọi là cells, trong đó mỗi ô được khởi tạo là một đối tượng Cell với giá trị dist được gán là Integer.MAX_VALUE (vô cùng) và prev là null, ngoại trừ các ô bị chặn.
Để khởi tạo hàng đợi, ta thêm điểm bắt đầu với khoảng cách dist = 0 Trong quá trình hàng đợi không rỗng, thuật toán sẽ lấy phần tử đầu tiên và kiểm tra xem nó có phải là điểm đến hay không Nếu đúng, thuật toán đã tìm thấy đường đi và lưu trữ điểm đến vào biến dest.
Mô tả API(thư viện)chính được sử dụng trong code
JavaFX là một thư viện mạnh mẽ cho việc phát triển ứng dụng đồ họa trên nền tảng Java, cung cấp các thành phần giao diện người dùng (GUI) cần thiết để xây dựng các ứng dụng hấp dẫn và tương tác.
JavaFX bao gồm nhiều thành phần quan trọng như nút, trường văn bản, đối tượng hình học, hình ảnh, thanh trượt, bảng và các đối tượng media, giúp tạo ra giao diện người dùng phong phú và tương tác.
JavaFX mang đến nhiều tính năng nổi bật như hiệu ứng chuyển động, ánh sáng và chuyển đổi trang, cùng với khả năng quản lý màn hình hiệu quả Nó hỗ trợ đa nền tảng, tích hợp CSS và cung cấp các thành phần tương tác dễ dàng, giúp nâng cao trải nghiệm người dùng.
Các lớp được sử dụng javafx trong chương trình :
- javafx.application.Application thì cung cấp cấu trúc cơ bản cho ứng dụng
- EventHandler là một giao diện được cung cấp trong package javafx.event của JavaFX Nó được sử dụng để xử lý các sự kiện trong ứng dụng JavaFX.
Giao diện EventHandler có một phương thức handle() không có tham số, được thiết kế để xử lý sự kiện khi chúng xảy ra Phương thức này được kích hoạt khi có sự kiện xảy ra và nhận đối tượng sự kiện tương ứng.
Để sử dụng EventHandler, bạn cần tạo một đối tượng mới từ lớp triển khai giao diện này và thực hiện phương thức handle() để xử lý các sự kiện.
Sau đó, bạn có thể đăng ký đối tượng EventHandler với các đối tượng JavaFX như Node hoặc Scene để bắt đầu xử lý sự kiện.
+ Lớp Graphics2D đã thực hiện chức năng vẽ hình ảnh con ma lên màn hình trò chơi
Lớp java.awt.Image được sử dụng để biểu diễn hình ảnh trong các ứng dụng đồ họa, cho phép tạo ra các đối tượng Image từ tệp hình ảnh, URL hoặc dữ liệu đầu vào Lớp này cung cấp các phương thức hữu ích để vẽ hình ảnh lên các đối tượng đồ họa.
This code snippet demonstrates how to handle keyboard events when a key is pressed in a scene It checks if the pressed key is not already in the `pressedKeys` list; if not, it adds the key to the list and triggers the input handlers to process the key event.
}) scene addEventHandler(KeyEvent KEY_RELEASED , (keyEvent) -> { pressedKeys.remove(keyEvent.getCode()); for var ( handler : inputHandlers ) { handler.handle(keyEvent);
}) đoạn code này thì xử lí sự kiện khi một phím được thả
FXML là định dạng tệp XML dùng để mô tả giao diện người dùng trong ứng dụng JavaFX, giúp tách biệt giao diện và mã xử lý sự kiện Điều này làm cho việc phát triển và bảo trì ứng dụng trở nên đơn giản hơn Hàm private static Parent loadFXML(String fxml) throws IOException được sử dụng để tải tệp FXML.
FXMLLoader(Bomberman class getResource( "/fxml/" + fxml + ".fxml" )) ; return fxmlLoader.load() ;
} Đoạn mã trên là một phương thức tĩnh loadFXML() được sử dụng để tải một tệp FXML được định nghĩa trong ứng dụng Bomberman.
Phương thức loadFXML() có khả năng ném ra ngoại lệ IOException trong trường hợp tệp FXML không thể tải hoặc phân tích Do đó, việc khai báo ngoại lệ throws IOException là cần thiết để thông báo cho người dùng rằng phương thức này có thể gặp phải lỗi ngoại lệ.
ImageCursor là một lớp trong package javafx.scene của JavaFX, cho phép người dùng tạo con trỏ tùy chỉnh cho ứng dụng Lớp này cung cấp các phương thức để tạo con trỏ từ hình ảnh hoặc đường dẫn đến hình ảnh, ví dụ như scene.setCursor(new ImageCursor(ResourceManager.cursor)).
Parent là lớp cơ sở trong package javafx.scene của JavaFX, đóng vai trò quan trọng trong việc tạo ra các nút và bố cục Lớp này cho phép chứa các nút con khác, giúp xây dựng các bố cục phức tạp cho ứng dụng JavaFX.
Scene là một lớp trong package javafx.scene của JavaFX, có chức năng tạo khu vực hiển thị cho các thành phần giao diện người dùng trong ứng dụng Đây là một thành phần cơ bản, được khởi tạo từ một đối tượng Parent làm nút gốc.
Một đối tượng Scene có thể bao gồm nhiều đối tượng Parent và cần chỉ định kích thước thông qua chiều rộng và chiều cao khi tạo Scene cung cấp các phương thức để thiết lập con trỏ chuột và nền, giúp tối ưu hóa hiệu suất cho ứng dụng.
Image là một lớp trong package javafx.scene.image của JavaFX, cho phép tải hình ảnh vào ứng dụng JavaFX Lớp này được sử dụng để hiển thị hình ảnh như nút hoặc hình nền trong các phần tử giao diện người dùng.
ImageView là một lớp trong package javafx.scene.image của JavaFX, dùng để hiển thị đối tượng Image trong ứng dụng Nó là một thành phần giao diện người dùng, cho phép hiển thị hình ảnh trong các cửa sổ, bảng điều khiển, nút và nhiều thành phần khác.