NetBeans là một môi trường phát triển tích hợp (IDE) cho Java. NetBeans IDE là một công cụ hỗ trợ lập trình viết mã code miễn phí được cho là tốt nhất hiện nay, được sử dụng chủ yếu cho các lập trình viên phát triển Java tuy nhiên phần mềm có dung lượng khá là nặng dành cho các máy cấu hình có RAM, CPU tương đối cao để vận hành.
NetBeans IDE là môi trường phát triển tích hợp và cực kỳ cần thiết cho các lập trình viên, công cụ này có thể hoạt động tốt với rất nhiều nền tảng hệ điều hành khác nhau như Linux, Windows, MacOS,… là một mã nguồn mở cung cấp các tính năng cần thiết nhất nhằm tạo ra các ứng dụng web, thiết bị di động, desktop.
NetBeans IDE hỗ trợ rất nhiều những ngôn ngữ lập trình như Python, Ruby, JavaScript, Groovy, C / C + +, và PHP.
Lý do Netbeans được dùng rộng rãi là bởi vì cùng với Eclipse, đây là 2 IDE mạnh nhất dùng để lập trình Java cùng nhiều hỗ trợ, và mình tin rằng các bạn học Java đều đã làm quen với 2 phần mềm này. Đối với các bạn muốn học Java, thì Netbeans cũng là một phần mềm dễ làm quen, dễ sử dụng và có rất nhiều hướng dẫn trên Youtube, Google,.. Và tin mình đi, làm quen với nó rồi bạn sẽ bị “yêu” nó luôn và không muốn chuyển qua lập trình Java với phần mềm khác đâu 😀
2. Hướng dẫn tải và cài đặt Netbeans.
Trước tiên, chúng ta cần cài đặt Java SE Development Kit (JDK) trước mới cài đặt được Netbeans.
3. Tạo Project mới trong Netbean
Vậy là đã xong phần cài đặt môi trường và tạo được 1 Project mới rồi, sau đây, chúng ta sẽ cùng tìm hiểu về cách lập trình game Pikachu bằng Java cùng NetBean nha ^^
4. Xây dựng giao diện của game Pikachu
Đối với NetBeans, đây là một phần mềm hỗ trợ tạo giao diện của một ứng dụng Java rất dễ dàng với việc hỗ trợ thiết kế trực tiếp bằng việc kéo thả các Icon trong Java Swing với phần Design của JFrame, JPanel. Đối với các bạn quen dùng Visual Studio, thì phần thiết kế của NetBeans tương tự với phần Design trong Visual Studio. Tuy nhiên ở bài viết này, mình sẽ dùng cách Code thay vì Design bằng việc kéo thả, để các bạn có thể áp dụng trong phần mềm bất kỳ dùng để code Java . Bắt đầu thôi ^^
Tại đây, chúng ta có thể thấy màn hình chính chia làm 2 phần, 1 là màn hình chứa các ảnh(icon) của các nhân vật đáng yêu trong Pokemon, phần còn lại ở phía trên là thanh điểm cùng thanh thời gian. Hôm nay chúng ta sẽ tìm hiểu về cách tạo ra các Icon của trò chơi và hiển thị chúng lên một cách ngẫu nhiên.
4.1. Xử lý thuật toán đối với các Icon
Vấn đề cần xử lý với các Icon ở đây là: Làm sao để chúng hiển thị lên được đầy đủ, ngẫu nhiên và số các Icon giống nhau luôn là chẵn?
Từ bây giờ, chúng ta sẽ coi như các Icon xuất hiện trong game cũng giống như các con số xuất hiện trong ma trận. Để các phần tử trong matrix nhận giá trị ngẫu nhiên, mình dùng lớp Random để tạo ra các số ngẫu nhiên. Ở trong phần code của mình, mình có 21 icon , nên mình tạo ra một biến imgCount = 21 và 1 biến index được chọn ngẫu nhiên trong các số từ 1 đến 21 với câu lệnh int index = rand.nextInt(imgCount) + 1; Đây là giá trị của các ô trong ma trận mình tạo ra, và đồng thời tương ứng là giá trị của các Icon dùng để so sánh với nhau.
int index = rand.nextInt(imgCount) + 1;
Vậy còn vị trí của các Icon hiển thị lên thì sao?
Sau đó, chúng ta sẽ dùng 1 biến pointIndex được lấy giá trị random theo giá trị size() của listPoint. Với mỗi pointIndex được lấy ra, chúng ta gán giá trị của matrix[pointIndexx][pointIndex.y] = index; đồng thời remove giá trị pointIndex này ra khỏi listPoint .Việc remove này giúp chúng ta bỏ qua những ô đã được gán giá trị trong ma trận, tránh việc vị trí các ô được lấy qua hàm random trùng lặp nhau, qua đó tất cả các ô sẽ đều được nhận 1 giá trị ngẫu nhiên và không bỏ qua 1 ô nào cả.
int size = listPoint.size(); int pointIndex = rand.nextInt(size); matrix[listPoint.get(pointIndex).x][listPoint.get(pointIndex).y] = index; listPoint.remove(pointIndex);
Bằng cách này, chúng ta sẽ khởi tạo được vị trí ngẫu nhiên của các Icon game được hiển thị ra, và đồng thời đảm bảo tất cả các phần tử của matrix đều nhận những giá trị ngẫu nhiên.
Tuy nhiên, còn một vấn đề nữa với các Icon mà chúng ta phải giải quyết, đó là làm sao để số các Icon giống nhau luôn là chẵn? Tại sao chúng lại phải chẵn? Chúng ta đều từng chơi Pokemon rồi, 1 cặp Pokemon giống nhau nếu thỏa mãn về đường đi sẽ biến mất. Vậy nếu tất cả đều là ngẫu nhiên, các Icon hiển thị ra bị lẻ, thì chẳng phải game của chúng ta sẽ không thể thắng được sao?
Để giải quyết điều này, mình đặt tất cả quá trình gán giá trị ngẫu nhiên cho các phần tử trong matrix trong 1 vòng for chạy 2 lần. Các bạn hãy theo dõi đoạn code sau:
for (int j = 0; j < 2; j++) { int size = listPoint.size(); int pointIndex = rand.nextInt(size); matrix[listPoint.get(pointIndex).x][listPoint.get(pointIndex).y] = index; listPoint.remove(pointIndex); }
Khi đặt quá trình gán giá trị ngẫu nhiên cho các phần tử trong matrix trong vòng for ấy, mỗi khi 1 icon được tạo ra với giá trị tương ứng là index trong matrix, sẽ luôn có 1 Icon nữa có giá trị cũng bằng index ở 1 vị trí khác. Nói cách khác, khi đó, chúng ta sẽ không bao giờ tạo ra các Icon đơn lẻ, mà luôn tạo ra các cặp icon giống nhau. Vấn đề hoàn toàn được giải quyết.
Còn một vấn đề nữa đối với việc khởi tạo giá trị của các icon theo ma trận matrix, đó là vì tất cả đều ngẫu nhiên, cho nên sẽ có trường hợp các icon bị trùng lặp quá nhiều, có khi cả trò chơi có 100 ô thì đến 50 ô đều là 1 icon giống nhau thì… Bạn biết đấy, sẽ nhàm chán lắm. Để giải quyết vấn đề này, mình quan tâm đến 1 giá trị là row*col/imgCount. Tại sao lại là giá trị này? Chúng ta hãy tưởng tượng 1 ma trận với kích cỡ là row*col được lấp đầy bằng tổng số Icon là imgCount, nghĩa là trung bình mỗi Icon sẽ xuất hiện là row*col/imgCount lần. Kết hợp với việc số lần mà 1 Icon xuất hiện luôn phải là chẵn, mình rút ra số lần tối đa mà 1 Icon xuất hiện sẽ là giá trị chẵn giữa row*col/imgCount+1 hoặc row*col/imgCount+2.
Random rand = new Random(); int imgCount = 21; int max = 4; int []arr = new int[imgCount + 1]; ... int i = 0; do { int index = rand.nextInt(imgCount) + 1; if (arr[index] < max) { arr[index] += 2; for (int j = 0; j < 2; j++) { int size = listPoint.size(); int pointIndex = rand.nextInt(size); matrix[listPoint.get(pointIndex).x] [listPoint.get(pointIndex).y] = index; listPoint.remove(pointIndex); } i++; } } while (i < row * col / 2);
Tất cả phần khởi tạo ở trên mình đặt trong 1 hàm while với biến i nhận giá trị ban đầu là 0. Với mỗi lần khởi tạo ra giá trị cho 2 ô mới của ma trận, câu lệnh sẽ được chạy, và việc khởi tạo giá trị của các ô sẽ kết thúc khi ,cũng là khi chúng ta đã tạo đủ giá trị cho tất cả các ô trong ma trận của mình.
4.2. Thêm các Icon vào khối để hiển thị
Để có thể tạo ra được các icon, mình tạo 1 class mới là ButtonEvent extends từ JPanel và implements từ ActionListener trong packpage controller để xử lý event của các button được tạo ra, chính là các icon của chúng ta.Mình viết 1 hàm getIcon(int index) để lấy ra các icon theo index (vị trí) của chúng. Ở đây, mình dùng thư viện Image để lấy ra ảnh đã được lưu trong packpage icon, rồi sau đó dùng thư viện Icon để tạo ra các icon với ảnh được lấy ra cùng kích cỡ width, height có thể tùy chỉnh. Việc lấy các ảnh ra bằng index, chúng ta dùng câu lệnh
Image image = new ImageIcon(getClass().getResource( "/icon/" + index + ".png")).getImage();
Ý nghĩa của câu lệnh là chúng ta sẽ lấy ra ảnh có tên là index trong packpage icon, đó là lý do mà chúng ta đặt tên các icon là các số từ 1 đến hết mà mình đã nói từ đầu đó ^^
Sau khi lấy ra được các icon rồi, mình viết hàm addArrayButton() thực hiện việc tạo ra các button trong bảng, và setIcon cho các button được tạo ra. Chúng ta cần tạo ra đủ số button tương ứng với kích cỡ của bảng, và các icon cho mỗi button được lấy ra bằng hàm getIcon(int index) với giá trị index chính là giá trị tương ứng của ma trận tại vị trí của button đó. Bằng cách này, ma trận của chúng ta bây giờ chính thức là 1 game thu nhỏ của game Pikachu, giúp ta có thể xử lý rất nhiều thứ về thuật toán của game tại ma trận này.
package controller; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; public class ButtonEvent extends JPanel implements ActionListener { private int row; private int col; private int bound = 2; private int size = 50; private JButton[][] btn; private Controller controller; private Color backGroundColor = Color.lightGray; private MainFrame frame; public ButtonEvent(MainFrame frame, int row, int col) { this.frame = frame; chúng tôi = row; chúng tôi = col; setLayout(new GridLayout(row, col, bound, bound)); setBackground(backGroundColor); setPreferredSize(new Dimension((size + bound) * col, (size + bound) * row)); setBorder(new EmptyBorder(10, 10, 10, 10)); setAlignmentY(JPanel.CENTER_ALIGNMENT); newGame(); } public void newGame() { controller = new Controller(this.row, this.col); addArrayButton(); } private void addArrayButton() { btn = new JButton[row][col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { btn[i][j] = createButton(i + "," + j); Icon icon = getIcon(controller.getMatrix()[i][j]); btn[i][j].setIcon(icon); add(btn[i][j]); } } } private Icon getIcon(int index) { int width = 48, height = 48; Image image = new ImageIcon(getClass().getResource( "/icon/" + index + ".png")).getImage(); Icon icon = new ImageIcon(image.getScaledInstance(width, height, image.SCALE_SMOOTH)); return icon; } private JButton createButton(String action) { JButton btn = new JButton(); btn.setActionCommand(action); btn.setBorder(null); btn.addActionListener(this); return btn; } @Override public void actionPerformed(ActionEvent e) { } }
setLayout(new GridLayout(row, col, bound, bound)); Set Layout cho khối JPanel được tạo ra bằng GridLayout (sắp xếp các component thành dạng bảng) với các tham số hàng, cột và khoảng cách giữa các component theo chiều ngang và chiều dọc bằng bound=2.
setBackground(backGroundColor); Cài đặt màu nền cho khối JPanel.
setPreferredSize(new Dimension((size + bound) * col, (size + bound)* row)); Cài đặt kích cỡ của khối Panel.
setBorder(new EmptyBorder(10, 10, 10, 10)); Thêm viền bên ngoài của khối Panel.
4.3. Chạy chương trình và hiển thị các Icon
Sau khi hoàn thành 2 phần trên, mình tạo class MainFrame extends từ JFrame trong packpage controller để làm màn hình chính của game. Trong class MainFrame này, mình tạo 2 hàm createMainPanel() và createGraphicsPanel() để thêm vào các Button chứa các icon của game.
package controller; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFrame; import javax.swing.JPanel; public class MainFrame extends JFrame implements ActionListener, Runnable { private int row = 8; private int col = 8; private int width = 700; private int height = 500; private ButtonEvent graphicsPanel; private JPanel mainPanel; public MainFrame() { add(mainPanel = createMainPanel()); setTitle("Pokemon Game"); setResizable(false); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(width, height); setLocationRelativeTo(null); setVisible(true); } private JPanel createMainPanel() { JPanel panel = new JPanel(new BorderLayout()); panel.add(createGraphicsPanel(), BorderLayout.CENTER); return panel; } private JPanel createGraphicsPanel() { graphicsPanel = new ButtonEvent(this, row, col); JPanel panel = new JPanel(new GridBagLayout()); panel.setBackground(Color.gray); panel.add(graphicsPanel); return panel; } @Override public void actionPerformed(ActionEvent e) { } @Override public void run() { } }
Đặt tiêu đề cho Frame.
Cài đặt không cho phép phóng to màn hình.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Cài đặt tắt chương trình khi ấn vào dấu X ở góc phải.
setSize(width, height); Cài đặt kích cỡ của Frame hiển thị.
setLocationRelativeTo(null); Chương trình khi chạy sẽ hiển thị ở chính giữa màn hình.
Cuối cùng, chúng ta viết hàm Main để chạy chương trình.
package controller; public class Main { MainFrame frame; public Main() { frame = new MainFrame(); } public static void main(String[] args) { new Main(); } }
Sau khi hoàn thành hàm main, chương trình sẽ hiển thị được như sau:
Tạm kết
Như vậy, chúng ta đã hoàn thành việc hiển thị các Icon lên màn hình, và hoàn thành thuật toán để các Icon được hiển thị đầy đủ, ngẫu nhiên và số cặp Icon giống nhau luôn là chẵn.
– Code của mình và hình ảnh mình sử dụng: https://github.com/beloyten/daoluongduy-gmail.com