Java實(shí)現(xiàn)經(jīng)典游戲推箱子的示例代碼
前言
《推箱子》推箱子是一個(gè)古老的游戲,目的是在訓(xùn)練你的邏輯思考能力。在一個(gè)狹小的倉(cāng)庫(kù)中,要求把木箱放到指定的位置,稍不小心就會(huì)出現(xiàn)箱子無(wú)法移動(dòng)或者通道被堵住的情況,所以需要巧妙的利用有限的空間和通道,合理安排移動(dòng)的次序和位置,才能順利的完成任務(wù)。
游戲是用java語(yǔ)言實(shí)現(xiàn),采用了swing技術(shù)進(jìn)行了界面化處理,設(shè)計(jì)思路用了面向?qū)ο笏枷搿?/p>
主要需求
控制搬運(yùn)工上下左右移動(dòng),來(lái)將箱子推到指定地點(diǎn)
主要設(shè)計(jì)
1、游戲面板生成顯示
2、地圖生成算法
3、人物移動(dòng)算法
4、播放背景音樂(lè)
5、箱子移動(dòng)算法
6、全部箱子移動(dòng)到指定位置,才算游戲過(guò)關(guān)
功能截圖
游戲開(kāi)始
移動(dòng)效果
游戲過(guò)關(guān)
代碼實(shí)現(xiàn)
核心類(lèi)
public class GameFrame extends JFrame implements ActionListener, MouseListener, KeyListener {// 實(shí)現(xiàn)動(dòng)作事件監(jiān)聽(tīng)器、鼠標(biāo)事件監(jiān)聽(tīng)器、鍵盤(pán)事件監(jiān)聽(tīng)器 // 當(dāng)前的關(guān)卡數(shù),默認(rèn)為第一關(guān),從1開(kāi)始計(jì)數(shù) private int grade = 1; // row,column記載人的位置,分別表示二維數(shù)組中的行號(hào)和列號(hào),即map[row][column]確定人的位置 private int row = 7, column = 7; // leftX,leftY記載左上角圖片的位置,避免圖片從(0,0)坐標(biāo)開(kāi)始,因?yàn)槭菆D片填充,從(0,0)開(kāi)始不行 private int leftX = 50, leftY = 50; // 記載地圖的總共有多少行、多少列 private int mapRow = 0, mapColumn = 0; // 記載屏幕窗口的寬度和高度 private int width = 0, height = 0; private boolean acceptKey = true; // 程序所需要用到的圖片 private Image pics[] = null;// 圖片數(shù)據(jù) private byte[][] map = null;// 地圖數(shù)據(jù) private ArrayList list = new ArrayList(); private SoundPlayerUtil soundPlayer;// 播放聲音工具類(lèi) /* 常量,即游戲中的資源 */ private final static int WALL = 1;// 墻 private final static int BOX = 2;// 箱子 private final static int BOX_ON_END = 3;// 放到目的地的箱子 private final static int END = 4;// 目的地 private final static int MAN_DOWN = 5;// 向下的人 private final static int MAN_LEFT = 6;// 向左的人 private final static int MAN_RIGHT = 7;// 向右的人 private final static int MAN_UP = 8;// 向上的人 private final static int GRASS = 9;// 通道 private final static int MAN_DOWN_ON_END = 10;// 站在目的地向下的人 private final static int MAN_LEFT_ON_END = 11;// 站在目的地向左的人 private final static int MAN_RIGHT_ON_END = 12;// 站在目的地向右的人 private final static int MAN_UP_ON_END = 13;// 站在目的地向上的人 private final static int MOVE_PIXEL = 30;// 表示每次移動(dòng)30像素 /** * 在構(gòu)造方法GameFrame0中,調(diào)用initMap()法來(lái)初始化本關(guān)grade游戲地圖,清空悔棋信 * 息列表list,同時(shí)播放MIDI背景音樂(lè)。 */ public GameFrame() { // 游戲窗口的一些基本設(shè)置 setTitle("推箱子游戲"); setSize(600, 600); setVisible(true); setLocation(300, 20); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container contentPane = getContentPane(); contentPane.setLayout(null); contentPane.setBackground(Color.black); // 其他設(shè)置,初始化窗口的寬度和高度賦值給width和height this.width = getWidth(); this.height = getHeight(); // 初始化圖片資源 getPics(); // 初始化地圖數(shù)據(jù) initMap(); // 注冊(cè)事件監(jiān)聽(tīng)器 setFocusable(true); addKeyListener(this); addMouseListener(this); // 播放音樂(lè) initSound(); } /** * initMap()方法的作用是初始化本關(guān)grade 游戲地圖,清空悔棋信息列表list。 調(diào)用 * getMapSizeAndPosition(方法獲取游戲區(qū)域大小及顯示游戲的左上角位置( leftX, leftY )。 */ public void initMap() { // 獲取當(dāng)前關(guān)卡的地圖數(shù)據(jù) map = MapFactory.getMap(grade); // 清除上一關(guān)保存的回退地圖數(shù)據(jù),即清空l(shuí)ist集合的內(nèi)容 list.clear(); // 初始化地圖行列數(shù)和左上角起始坐標(biāo)位置 getMapSizeAndPosition(); // 獲取角色的坐標(biāo)位置 getManPosition(); } /** * getManPosition()方法的作用是獲取工人的當(dāng)前位置(row,column)。 */ public void getManPosition() { // 即遍歷地圖數(shù)組map中存在那個(gè)值等于MANXXX(MAN_DOWN表示向下的人;MAN_UP表示向上的人)的情況,即表示該位置是人站立的位置,這個(gè)由地圖數(shù)據(jù)掃描得出 for (int i = 0; i < map.length; i++) { for (int j = 0; j < map[0].length; j++) { if (map[i][j] == MAN_DOWN || map[i][j] == MAN_DOWN_ON_END || map[i][j] == MAN_UP || map[i][j] == MAN_UP_ON_END || map[i][j] == MAN_LEFT || map[i][j] == MAN_LEFT_ON_END || map[i][j] == MAN_RIGHT || map[i][j] == MAN_RIGHT) { // 保存人的位置,i表示第幾行,j表示第幾列,而且是從0開(kāi)始的 this.row = i; this.column = j; break; } } } } /** * getMapSizeAndPosition()方法用來(lái)獲取游戲區(qū)域大小及顯示游戲的左上角位置( lefX, leftY )。 */ private void getMapSizeAndPosition() { // 初始化mapRow和mapColumn,表示地圖的行列數(shù) this.mapRow = map.length; this.mapColumn = map[0].length; // 初始化leftX和leftY,即計(jì)算左上角的位置, this.leftX = (width - map[0].length * MOVE_PIXEL) / 2; this.leftY = (height - map.length * MOVE_PIXEL) / 2; } /** * getPics()方法用來(lái)加載要顯示的圖片 */ public void getPics() { // 創(chuàng)建長(zhǎng)度為13的數(shù)組,即有十三張圖片 pics = new Image[13]; // 然后循環(huán)將每張圖片讀取保存到pics數(shù)組中 for (int i = 0; i < 13; i++) { pics[i] = Toolkit.getDefaultToolkit().getImage("src\\images\\pic_" + (i + 1) + ".png"); } } /** * 初始化播放的音樂(lè) */ public void initSound() { // 調(diào)用SoundPlayerUtil類(lèi)中的方法播放音樂(lè) soundPlayer = new SoundPlayerUtil(); soundPlayer.loadSound("src\\sounds\\music.wav"); soundPlayer.playSound(true);// 循環(huán)播放 } /** * grassOrEnd()方法判斷人所在的位置是通道GRASS還是目的地END * * @param man * @return */ public byte grassOrEnd(byte man) { if (man == MAN_DOWN_ON_END || man == MAN_LEFT_ON_END || man == MAN_RIGHT_ON_END || man == MAN_UP_ON_END) { return END; } return GRASS; } /** * 人物向上移動(dòng) */ private void moveUp() { // 如果上一位是WALL,則不能移動(dòng) if (map[row - 1][column] == WALL) { return; } // 如果上一位是BOX或BOX_ON_END,需要考慮上一位的上一位是什么情況 if (map[row - 1][column] == BOX || map[row - 1][column] == BOX_ON_END) { // 那么就需要考慮上一位的上一位情況,若上上一位是END或GRASS,則向上一步,其他情況不用處理 if (map[row - 2][column] == END || map[row - 2][column] == GRASS) { // 要保留當(dāng)前信息,以便回退上一步 Map currMap = new Map(row, column, map); list.add(currMap); byte boxTemp = (byte) ((byte) map[row - 2][column] == END ? BOX_ON_END : BOX); byte manTemp = (byte) (map[row - 1][column] == BOX ? MAN_UP : MAN_UP_ON_END); // 箱子變成temp,箱子往前移動(dòng)一步 map[row - 2][column] = boxTemp; // 人變成MAN_UP,往上走一步 map[row - 1][column] = manTemp; // 將人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) row--; } } else { // 上一位為GRASS或END,無(wú)需考慮上上一步,其他情況不用處理 if (map[row - 1][column] == GRASS || map[row - 1][column] == END) { // 保留當(dāng)前這一步的信息,以便回退上一步 Map currMap = new Map(row, column, map); list.add(currMap); byte temp = (byte) (map[row - 1][column] == END ? MAN_UP_ON_END : MAN_UP); // 人變成temp,人往上走一步 map[row - 1][column] = temp; // 人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) row--; } } } /** * 人物向下移動(dòng),其中(row,column)是當(dāng)前角色站的位置,而map[row,column]表示當(dāng)前角色 */ private void moveDown() { // 如果下一位是WALL,則不能移動(dòng) // 所以map[row+1][column]表示當(dāng)前角色的下一步,也就是下一關(guān)圖像塊 if (map[row + 1][column] == WALL) { return; } // 如果下一位是箱子BOX或放到目的地的箱子BOX_ON_END(即如果下一位是箱子,而不管是什么類(lèi)型的箱子,都可以推動(dòng)箱子),需要考慮下位的下一位是什么情況 if (map[row + 1][column] == BOX || map[row + 1][column] == BOX_ON_END) { // 那么就需要考慮下一位的下一位情況(即箱子的下一位是什么,決定著箱子是否可以向前移動(dòng)),若下下一位是目的地END或通道GRASS,則表示箱子可以向下移動(dòng)一步,其他情況不用處理 // map[row+2][column]表示箱子的下一步是什么 if (map[row + 2][column] == END || map[row + 2][column] == GRASS) { // 下面的代碼就是箱子向前移動(dòng)一步,人移動(dòng)原來(lái)箱子的位置 // 要保留當(dāng)前人和地圖信息,以便回退下一步 Map currMap = new Map(row, column, map); list.add(currMap); // 判斷箱子的下一步是否是目的地,如果是目的地,那么箱子的下一步就應(yīng)該變成BOX_ON_END(放在目的地的箱子),如果不是目的地那應(yīng)該還只是普通箱子BOX byte boxTemp = (byte) ((byte) map[row + 2][column] == END ? BOX_ON_END : BOX); // 判斷人的下一步是否是箱子 byte manTemp = (byte) (map[row + 1][column] == BOX ? MAN_DOWN : MAN_DOWN_ON_END); // 箱子變成temp,箱子往下移動(dòng)一步 map[row + 2][column] = boxTemp; // 人變成MAN_UP,往下走一步 map[row + 1][column] = manTemp; // 將人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) row++; } } else { // 執(zhí)行到這里,表示人的下一步不是箱子,那么要么是通道要么是終點(diǎn) // 下一位為GRASS或END,無(wú)需考慮下下一步,其他情況不用處理 if (map[row + 1][column] == GRASS || map[row + 1][column] == END) { // 保留當(dāng)前這一步的信息,以便回退下一步 Map currMap = new Map(row, column, map); list.add(currMap); byte temp = (byte) (map[row + 1][column] == END ? MAN_DOWN_ON_END : MAN_DOWN); // 人變成temp,人往下走一步 map[row + 1][column] = temp; // 人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) row++; } } } /** * 人物向左移動(dòng) */ private void moveLeft() { // 如果左一位是WALL,則不能移動(dòng) if (map[row][column - 1] == WALL) { return; } // 如果左一位是BOX或BOX_ON_END,需要考慮左一位的左一位是什么情況 if (map[row][column - 1] == BOX || map[row][column - 1] == BOX_ON_END) { // 那么就需要考慮左一位的左一位情況,若左左一位是END或GRASS,則向左一步,其他情況不用處理 if (map[row][column - 2] == END || map[row][column - 2] == GRASS) { // 要保留當(dāng)前信息,以便回退左一步 Map currMap = new Map(row, column, map); list.add(currMap); byte boxTemp = (byte) ((byte) map[row][column - 2] == END ? BOX_ON_END : BOX); byte manTemp = (byte) (map[row][column - 1] == BOX ? MAN_LEFT : MAN_LEFT_ON_END); // 箱子變成temp,箱子往前移動(dòng)一步 map[row][column - 2] = boxTemp; // 人變成MAN_UP,往左走一步 map[row][column - 1] = manTemp; // 將人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) column--; } } else { // 左一位為GRASS或END,無(wú)需考慮左左一步,其他情況不用處理 if (map[row][column - 1] == GRASS || map[row][column - 1] == END) { // 保留當(dāng)前這一步的信息,以便回退左一步 Map currMap = new Map(row, column, map); list.add(currMap); byte temp = (byte) (map[row][column - 1] == END ? MAN_LEFT_ON_END : MAN_LEFT); // 人變成temp,人往左走一步 map[row][column - 1] = temp; // 人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) column--; } } } /** * 人物向右移動(dòng) */ private void moveRight() { // 如果右一位是WALL,則不能移動(dòng) if (map[row][column + 1] == WALL) { return; } // 如果右一位是BOX或BOX_ON_END,需要考慮右位的右一位是什么情況 if (map[row][column + 1] == BOX || map[row][column + 1] == BOX_ON_END) { // 那么就需要考慮右一位的右一位情況,若右右一位是END或GRASS,則向右一步,其他情況不用處理 if (map[row][column + 2] == END || map[row][column + 2] == GRASS) { // 要保留當(dāng)前信息,以便回退右一步 Map currMap = new Map(row, column, map); list.add(currMap); byte boxTemp = (byte) ((byte) map[row][column + 2] == END ? BOX_ON_END : BOX); byte manTemp = (byte) (map[row][column + 1] == BOX ? MAN_RIGHT : MAN_RIGHT_ON_END); // 箱子變成temp,箱子往右移動(dòng)一步 map[row][column + 2] = boxTemp; // 人變成MAN_UP,往右走一步 map[row][column + 1] = manTemp; // 將人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) column++; } } else { // 右一位為GRASS或END,無(wú)需考慮右右一步,其他情況不用處理 if (map[row][column + 1] == GRASS || map[row][column + 1] == END) { // 保留當(dāng)前這一步的信息,以便回退右一步 Map currMap = new Map(row, column, map); list.add(currMap); byte temp = (byte) (map[row][column + 1] == END ? MAN_RIGHT_ON_END : MAN_RIGHT); // 人變成temp,人往右走一步 map[row][column + 1] = temp; // 人剛才站的地方變成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人離開(kāi)后修改人的坐標(biāo) column++; } } } /** * 驗(yàn)證玩家是否過(guò)關(guān),如果有目的地END值或人直接站在目的地則沒(méi)有成功 * * @return 如果已經(jīng)通關(guān)則返回true,否則返回false */ public boolean isFinished() { for (int i = 0; i < mapRow; i++) { for (int j = 0; j < mapColumn; j++) { if (map[i][j] == END || map[i][j] == MAN_DOWN_ON_END || map[i][j] == MAN_UP_ON_END || map[i][j] == MAN_LEFT_ON_END || map[i][j] == MAN_RIGHT_ON_END) { return false; } } } return true; } // 使用雙緩沖技術(shù)解決動(dòng)畫(huà)閃爍問(wèn)題 private Image iBuffer; private Graphics gBuffer; /** * 重寫(xiě)繪制整個(gè)游戲區(qū)域的圖形 * * @param g */ @Override public void paint(Graphics g) { if (iBuffer == null) { iBuffer = createImage(width, height); gBuffer = iBuffer.getGraphics(); } // 清空屏幕原來(lái)的繪畫(huà) gBuffer.setColor(getBackground()); gBuffer.fillRect(0, 0, width, height); for (int i = 0; i < mapRow; i++) { for (int j = 0; j < mapColumn; j++) { // 畫(huà)出地圖,i表示行數(shù),j表示列數(shù) if (map[i][j] != 0) { // 這里要減1是因?yàn)閳D片的名稱(chēng)序號(hào)不對(duì)應(yīng),應(yīng)該從0開(kāi)始,但是從1開(kāi)始的 gBuffer.drawImage(pics[map[i][j] - 1], leftX + j * MOVE_PIXEL, leftY + i * MOVE_PIXEL, 30, 30, this); } } } gBuffer.setColor(Color.RED); gBuffer.setFont(new Font("楷體_2312", Font.BOLD, 30)); gBuffer.drawString("現(xiàn)在是第", 150, 140); gBuffer.drawString(String.valueOf(grade), 310, 140); gBuffer.drawString("關(guān)", 360, 140); g.drawImage(iBuffer, 0, 0, this); /* 下面的代碼是未使用雙緩沖技術(shù)會(huì)導(dǎo)致動(dòng)畫(huà)閃爍的代碼 */ /*g.clearRect(0, 0, width, height); for (int i = 0; i < mapRow; i++) { for (int j = 0; j < mapColumn; j++) { // 畫(huà)出地圖,i表示行數(shù),j表示列數(shù) if (map[i][j] != 0) { // 這里要減1是因?yàn)閳D片的名稱(chēng)序號(hào)不對(duì)應(yīng),應(yīng)該從0開(kāi)始,但是從1開(kāi)始的 g.drawImage(pics[map[i][j] - 1], leftX + j * MOVE_PIXEL, leftY + i * MOVE_PIXEL, 30, 30, this); } } } g.setColor(Color.RED); g.setFont(new Font("楷體_2312", Font.BOLD, 30)); g.drawString("現(xiàn)在是第", 150, 140); g.drawString(String.valueOf(grade), 310, 140); g.drawString("關(guān)", 360, 140);*/ } @Override public void actionPerformed(ActionEvent e) { } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { // 當(dāng)按鍵盤(pán)上的按鍵時(shí)觸發(fā)的事件 switch (e.getKeyCode()) { case KeyEvent.VK_UP:// 上方向鍵 moveUp();// 向上移動(dòng) break; case KeyEvent.VK_DOWN:// 下方向鍵 moveDown();// 向下移動(dòng) break; case KeyEvent.VK_LEFT:// 左方向鍵 moveLeft();// 向左移動(dòng) break; case KeyEvent.VK_RIGHT:// 右方向鍵 moveRight();// 向右移動(dòng) break; } // 然后重新繪制界面 repaint(); // 在移動(dòng)完成后可能已經(jīng)通關(guān),所以需要判斷是否通關(guān) if (isFinished()) { // 禁用按鍵 acceptKey = false; // 判斷是否是最后一關(guān),如果是則直接提示,如果不是則詢(xún)問(wèn)是否要進(jìn)入下一關(guān) if (grade == MapFactory.getCount()) { JOptionPane.showMessageDialog(this, "恭喜通過(guò)最后一關(guān)!"); } else { // 提示進(jìn)入下一關(guān) String msg = "恭喜通過(guò)第" + grade + "關(guān)!??!\n是否要進(jìn)入下一關(guān)?"; int choice = JOptionPane.showConfirmDialog(null, msg, "過(guò)關(guān)", JOptionPane.YES_NO_OPTION); if (choice == 1) { System.exit(0); } else if (choice == 0) { // 進(jìn)入下一關(guān) acceptKey = true; nextGrade(); } } } } @Override public void keyReleased(KeyEvent e) { } @Override public void mouseClicked(MouseEvent e) { // MouseEvent.BUTTON3表示鼠標(biāo)右鍵 if (e.getButton() == MouseEvent.BUTTON3) { undo(); } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } /** * 返回當(dāng)前人的位置用getManX()方法和getManY()方法 * * @return */ public int getManX() { return row; } public int getManY() { return column; } /** * 返回當(dāng)前關(guān)卡數(shù) * * @return */ public int getGrade() { return grade; } /** * 返回當(dāng)前關(guān)卡的地圖信息 * * @return */ public byte[][] getMap() { return MapFactory.getMap(grade); } /** * 顯示提示信息對(duì)話框 * * @param str */ public void displayToast(String str) { JOptionPane.showMessageDialog(null, str, "提示", JOptionPane.ERROR_MESSAGE); } /** * 撤銷(xiāo)移動(dòng)操作 */ public void undo() { if (acceptKey) { if (list.size() > 0) { // 如果要撤銷(xiāo),必須要走過(guò) // 考慮用棧更合適 Map priorMap = (Map) list.get(list.size() - 1); this.map = priorMap.getMap(); this.row = priorMap.getManX(); this.column = priorMap.getManY(); repaint();// 重新畫(huà)圖 list.remove(list.size() - 1); } else { displayToast("不能再撤銷(xiāo)了!"); } } else { displayToast("此關(guān)已完成,不能撤銷(xiāo)!"); } } /** * 實(shí)現(xiàn)下一關(guān)的初始化,并且調(diào)用repaint()方法顯示游戲界面 */ public void nextGrade() { // 初始化下一關(guān)的數(shù)據(jù) if (grade >= MapFactory.getCount()) { displayToast("恭喜你完成所有關(guān)卡!"); acceptKey = false; } else { // 關(guān)卡數(shù)加1 grade++; // 初始化下一關(guān)的地圖數(shù)據(jù) initMap(); // 重新繪制畫(huà)面 repaint(); acceptKey = true; } } /** * 實(shí)現(xiàn)上一關(guān)初始化并且調(diào)用repaint()發(fā)顯示游戲界面 */ public void priorGrade() { grade--; acceptKey = true; if (grade < 0) { grade = 0; } initMap(); repaint(); } }
聲音播放類(lèi)
public class SoundPlayerUtil { public File file; public AudioInputStream stream; public AudioFormat format; DataLine.Info info; Clip clip; /** * 加載聲音文件,支持wav、mp3等聲音文件 * * @param filePath 聲音文件的路徑 */ public void loadSound(String filePath) { file = new File(filePath); try { stream = AudioSystem.getAudioInputStream(file); } catch (UnsupportedAudioFileException | IOException e) { e.printStackTrace(); } format = stream.getFormat(); } /** * 播放音樂(lè) * * @param isLoop 表示是否循環(huán)播放音樂(lè),如果傳入的是true則表示循環(huán)播放 */ public void playSound(boolean isLoop) { info = new DataLine.Info(Clip.class, format); try { clip = (Clip) AudioSystem.getLine(info); clip.open(stream); } catch (LineUnavailableException | IOException e) { e.printStackTrace(); } if (isLoop) { clip.loop(Clip.LOOP_CONTINUOUSLY);// 添加該句代碼可以循環(huán)播放 } clip.start(); } }
總結(jié)
通過(guò)此次的《推箱子》游戲?qū)崿F(xiàn),讓我對(duì)swing的相關(guān)知識(shí)有了進(jìn)一步的了解,對(duì)java這門(mén)語(yǔ)言也有了比以前更深刻的認(rèn)識(shí)。
java的一些基本語(yǔ)法,比如數(shù)據(jù)類(lèi)型、運(yùn)算符、程序流程控制和數(shù)組等,理解更加透徹。java最核心的核心就是面向?qū)ο笏枷?,?duì)于這一個(gè)概念,終于悟到了一些。
以上就是Java實(shí)現(xiàn)經(jīng)典游戲推箱子的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java推箱子的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringData JPA中@OneToMany和@ManyToOne的用法詳解
這篇文章主要介紹了SpringData JPA中@OneToMany和@ManyToOne的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10為什么程序中突然多了 200 個(gè) Dubbo-thread 線程的說(shuō)明
這篇文章主要介紹了為什么程序中突然多了 200 個(gè) Dubbo-thread 線程的說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09SpringBoot 如何自定義項(xiàng)目啟動(dòng)信息打印
這篇文章主要介紹了SpringBoot 如何自定義項(xiàng)目啟動(dòng)信息打印方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09淺談線性表的原理及簡(jiǎn)單實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇淺談線性表的原理及簡(jiǎn)單實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06深入淺析Spring-boot-starter常用依賴(lài)模塊
這篇文章主要介紹了Spring-boot-starter常用依賴(lài)模塊及spring boot的兩大優(yōu)點(diǎn),需要的朋友可以參考下2018-01-01MyBatis中基于別名typeAliases的設(shè)置
這篇文章主要介紹了MyBatis中基于別名typeAliases的設(shè)置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Java處理異常2種機(jī)制關(guān)鍵字區(qū)別解析
這篇文章主要介紹了java處理異常2種機(jī)制關(guān)鍵字區(qū)別解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01springboot新建項(xiàng)目jdk只有17/21,無(wú)法選中1.8解決辦法
最近博主也有創(chuàng)建springboot項(xiàng)目,發(fā)現(xiàn)了IntelliJ IDEA在通過(guò)Spring Initilizer初始化項(xiàng)目的時(shí)候已經(jīng)沒(méi)有java8版本的選項(xiàng)了,這里給大家總結(jié)下,這篇文章主要給大家介紹了springboot新建項(xiàng)目jdk只有17/21,無(wú)法選中1.8的解決辦法,需要的朋友可以參考下2023-12-12java HttpURLConnection 發(fā)送文件和字符串信息
這篇文章主要介紹了java HttpURLConnection 發(fā)送文件和字符串信息的相關(guān)資料,需要的朋友可以參考下2017-06-06