<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Java 推箱子 > 原文: [https://zetcode.com/tutorials/javagamestutorial/sokoban/](https://zetcode.com/tutorials/javagamestutorial/sokoban/) 在 Java 2D 游戲教程的這一部分中,我們將創建 Java 推箱子游戲克隆。 源代碼和圖像可以在作者的 Github [Java-Sokoban-Game](https://github.com/janbodnar/Java-Sokoban-Game) 存儲庫中找到。 ## 推箱子 推箱子是另一個經典的電腦游戲。 它由 Imabayashi Hiroyuki 于 1980 年創建。 推箱子是日語的倉庫管理員。 玩家在迷宮周圍推箱子。 目的是將所有盒子放置在指定的位置。 ## Java 推箱子游戲的開發 我們使用光標鍵控制推箱子對象。 我們也可以按 `R` 鍵重新啟動電平。 將所有行李放在目的地區域后,游戲結束。 我們在窗口的左上角繪制`"Completed"`字符串。 `Board.java` ```java package com.zetcode; import java.awt.Color; import java.awt.Graphics; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import javax.swing.JPanel; public class Board extends JPanel { private final int OFFSET = 30; private final int SPACE = 20; private final int LEFT_COLLISION = 1; private final int RIGHT_COLLISION = 2; private final int TOP_COLLISION = 3; private final int BOTTOM_COLLISION = 4; private ArrayList<Wall> walls; private ArrayList<Baggage> baggs; private ArrayList<Area> areas; private Player soko; private int w = 0; private int h = 0; private boolean isCompleted = false; private String level = " ######\n" + " ## #\n" + " ##$ #\n" + " #### $##\n" + " ## $ $ #\n" + "#### # ## # ######\n" + "## # ## ##### ..#\n" + "## $ $ ..#\n" + "###### ### #@## ..#\n" + " ## #########\n" + " ########\n"; public Board() { initBoard(); } private void initBoard() { addKeyListener(new TAdapter()); setFocusable(true); initWorld(); } public int getBoardWidth() { return this.w; } public int getBoardHeight() { return this.h; } private void initWorld() { walls = new ArrayList<>(); baggs = new ArrayList<>(); areas = new ArrayList<>(); int x = OFFSET; int y = OFFSET; Wall wall; Baggage b; Area a; for (int i = 0; i < level.length(); i++) { char item = level.charAt(i); switch (item) { case '\n': y += SPACE; if (this.w < x) { this.w = x; } x = OFFSET; break; case '#': wall = new Wall(x, y); walls.add(wall); x += SPACE; break; case '$': b = new Baggage(x, y); baggs.add(b); x += SPACE; break; case '.': a = new Area(x, y); areas.add(a); x += SPACE; break; case '@': soko = new Player(x, y); x += SPACE; break; case ' ': x += SPACE; break; default: break; } h = y; } } private void buildWorld(Graphics g) { g.setColor(new Color(250, 240, 170)); g.fillRect(0, 0, this.getWidth(), this.getHeight()); ArrayList<Actor> world = new ArrayList<>(); world.addAll(walls); world.addAll(areas); world.addAll(baggs); world.add(soko); for (int i = 0; i < world.size(); i++) { Actor item = world.get(i); if (item instanceof Player || item instanceof Baggage) { g.drawImage(item.getImage(), item.x() + 2, item.y() + 2, this); } else { g.drawImage(item.getImage(), item.x(), item.y(), this); } if (isCompleted) { g.setColor(new Color(0, 0, 0)); g.drawString("Completed", 25, 20); } } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); buildWorld(g); } private class TAdapter extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { if (isCompleted) { return; } int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_LEFT: if (checkWallCollision(soko, LEFT_COLLISION)) { return; } if (checkBagCollision(LEFT_COLLISION)) { return; } soko.move(-SPACE, 0); break; case KeyEvent.VK_RIGHT: if (checkWallCollision(soko, RIGHT_COLLISION)) { return; } if (checkBagCollision(RIGHT_COLLISION)) { return; } soko.move(SPACE, 0); break; case KeyEvent.VK_UP: if (checkWallCollision(soko, TOP_COLLISION)) { return; } if (checkBagCollision(TOP_COLLISION)) { return; } soko.move(0, -SPACE); break; case KeyEvent.VK_DOWN: if (checkWallCollision(soko, BOTTOM_COLLISION)) { return; } if (checkBagCollision(BOTTOM_COLLISION)) { return; } soko.move(0, SPACE); break; case KeyEvent.VK_R: restartLevel(); break; default: break; } repaint(); } } private boolean checkWallCollision(Actor actor, int type) { switch (type) { case LEFT_COLLISION: for (int i = 0; i < walls.size(); i++) { Wall wall = walls.get(i); if (actor.isLeftCollision(wall)) { return true; } } return false; case RIGHT_COLLISION: for (int i = 0; i < walls.size(); i++) { Wall wall = walls.get(i); if (actor.isRightCollision(wall)) { return true; } } return false; case TOP_COLLISION: for (int i = 0; i < walls.size(); i++) { Wall wall = walls.get(i); if (actor.isTopCollision(wall)) { return true; } } return false; case BOTTOM_COLLISION: for (int i = 0; i < walls.size(); i++) { Wall wall = walls.get(i); if (actor.isBottomCollision(wall)) { return true; } } return false; default: break; } return false; } private boolean checkBagCollision(int type) { switch (type) { case LEFT_COLLISION: for (int i = 0; i < baggs.size(); i++) { Baggage bag = baggs.get(i); if (soko.isLeftCollision(bag)) { for (int j = 0; j < baggs.size(); j++) { Baggage item = baggs.get(j); if (!bag.equals(item)) { if (bag.isLeftCollision(item)) { return true; } } if (checkWallCollision(bag, LEFT_COLLISION)) { return true; } } bag.move(-SPACE, 0); isCompleted(); } } return false; case RIGHT_COLLISION: for (int i = 0; i < baggs.size(); i++) { Baggage bag = baggs.get(i); if (soko.isRightCollision(bag)) { for (int j = 0; j < baggs.size(); j++) { Baggage item = baggs.get(j); if (!bag.equals(item)) { if (bag.isRightCollision(item)) { return true; } } if (checkWallCollision(bag, RIGHT_COLLISION)) { return true; } } bag.move(SPACE, 0); isCompleted(); } } return false; case TOP_COLLISION: for (int i = 0; i < baggs.size(); i++) { Baggage bag = baggs.get(i); if (soko.isTopCollision(bag)) { for (int j = 0; j < baggs.size(); j++) { Baggage item = baggs.get(j); if (!bag.equals(item)) { if (bag.isTopCollision(item)) { return true; } } if (checkWallCollision(bag, TOP_COLLISION)) { return true; } } bag.move(0, -SPACE); isCompleted(); } } return false; case BOTTOM_COLLISION: for (int i = 0; i < baggs.size(); i++) { Baggage bag = baggs.get(i); if (soko.isBottomCollision(bag)) { for (int j = 0; j < baggs.size(); j++) { Baggage item = baggs.get(j); if (!bag.equals(item)) { if (bag.isBottomCollision(item)) { return true; } } if (checkWallCollision(bag,BOTTOM_COLLISION)) { return true; } } bag.move(0, SPACE); isCompleted(); } } break; default: break; } return false; } public void isCompleted() { int nOfBags = baggs.size(); int finishedBags = 0; for (int i = 0; i < nOfBags; i++) { Baggage bag = baggs.get(i); for (int j = 0; j < nOfBags; j++) { Area area = areas.get(j); if (bag.x() == area.x() && bag.y() == area.y()) { finishedBags += 1; } } } if (finishedBags == nOfBags) { isCompleted = true; repaint(); } } public void restartLevel() { areas.clear(); baggs.clear(); walls.clear(); initWorld(); if (isCompleted) { isCompleted = false; } } } ``` 游戲簡化了。 它僅提供非常基本的功能。 該代碼比容易理解。 游戲只有一個關卡。 ```java private final int OFFSET = 30; private final int SPACE = 20; private final int LEFT_COLLISION = 1; private final int RIGHT_COLLISION = 2; private final int TOP_COLLISION = 3; private final int BOTTOM_COLLISION = 4; ``` 墻圖片大小為`20x20`像素。 這反映了`SPACE`常數。 `OFFSET`是窗口邊界和游戲世界之間的距離。 有四種類型的碰撞。 每個數字都由一個數字常數表示。 ```java private ArrayList<Wall> walls; private ArrayList<Baggage> baggs; private ArrayList<Area> areas; ``` 墻壁,行李和區域是特殊的容器,可容納游戲的所有墻壁,行李和區域。 ```java private String level = " ######\n" + " ## #\n" + " ##$ #\n" + " #### $##\n" + " ## $ $ #\n" + "#### # ## # ######\n" + "## # ## ##### ..#\n" + "## $ $ ..#\n" + "###### ### #@## ..#\n" + " ## #########\n" + " ########\n"; ``` 這是游戲的水平。 除空格外,還有五個字符。 井號(`#`)代表墻。 美元(`$`)表示要移動的框。 點(`.`)字符表示我們必須移動框的位置。 at 字符(`@`)是推箱子。 最后,換行符(`\n`)開始了世界的新行。 ```java private void initWorld() { walls = new ArrayList<>(); baggs = new ArrayList<>(); areas = new ArrayList<>(); int x = OFFSET; int y = OFFSET; ... ``` `initWorld()`方法啟動游戲世界。 它遍歷級別字符串并填充上述列表。 ```java case '$': b = new Baggage(x, y); baggs.add(b); x += SPACE; break; ``` 對于美元字符,我們創建一個`Baggage`對象。 該對象將附加到行李列表。 x 變量相應增加。 ```java private void buildWorld(Graphics g) { ... ``` `buildWorld()`方法在窗口上繪制游戲世界。 ```java ArrayList<Actor> world = new ArrayList<>(); world.addAll(walls); world.addAll(areas); world.addAll(baggs); world.add(soko); ``` 我們創建一個包含游戲所有對象的世界列表。 ```java for (int i = 0; i < world.size(); i++) { Actor item = world.get(i); if (item instanceof Player || item instanceof Baggage) { g.drawImage(item.getImage(), item.x() + 2, item.y() + 2, this); } else { g.drawImage(item.getImage(), item.x(), item.y(), this); } ... } ``` 我們遍歷世界容器并繪制對象。 播放器和行李圖像稍小。 我們在其坐標上添加 2px 以使其居中。 ```java if (isCompleted) { g.setColor(new Color(0, 0, 0)); g.drawString("Completed", 25, 20); } ``` 如果完成該級別,則在窗口的左上角繪制`"Completed"`。 ```java case KeyEvent.VK_LEFT: if (checkWallCollision(soko, LEFT_COLLISION)) { return; } if (checkBagCollision(LEFT_COLLISION)) { return; } soko.move(-SPACE, 0); break; ``` 在`keyPressed()`方法內部,我們檢查了按下了哪些鍵。 我們用光標鍵控制推箱子對象。 如果按左光標鍵,我們將檢查推箱子是否與墻壁或行李相撞。 如果沒有,我們將推箱子向左移動。 ```java case KeyEvent.VK_R: restartLevel(); break; ``` 如果按`R`鍵,我們將重新啟動該級別。 ```java case LEFT_COLLISION: for (int i = 0; i < walls.size(); i++) { Wall wall = walls.get(i); if (actor.isLeftCollision(wall)) { return true; } } return false; ``` 創建`checkWallCollision()`方法以確保推箱子或行李不會通過墻壁。 有四種類型的碰撞。 上面幾行檢查是否有左碰撞。 ```java private boolean checkBagCollision(int type) { ... } ``` `checkBagCollision()`涉及更多。 行李可能會與墻壁,推箱子或其他行李發生碰撞。 僅當行李與推箱子碰撞且不與其他行李或墻壁碰撞時,才可以移動行李。 搬運行李時,該通過調用`isCompleted()`方法檢查水平是否已完成。 ```java for (int i = 0; i < nOfBags; i++) { Baggage bag = baggs.get(i); for (int j = 0; j < nOfBags; j++) { Area area = areas.get(j); if (bag.x() == area.x() && bag.y() == area.y()) { finishedBags += 1; } } } ``` `isCompleted()`方法檢查級別是否完成。 我們得到行李數。 我們比較所有行李和目的地區域的 x 和 y 坐標。 ```java if (finishedBags == nOfBags) { isCompleted = true; repaint(); } ``` 當`finishedBags`變量等于游戲中的行李數時,游戲結束。 ```java private void restartLevel() { areas.clear(); baggs.clear(); walls.clear(); initWorld(); if (isCompleted) { isCompleted = false; } } ``` 如果我們做了一些不好的動作,我們可以重新啟動關卡。 我們從列表中刪除所有對象,然后再次啟動世界。 `isCompleted`變量設置為`false`。 `Actor.java` ```java package com.zetcode; import java.awt.Image; public class Actor { private final int SPACE = 20; private int x; private int y; private Image image; public Actor(int x, int y) { this.x = x; this.y = y; } public Image getImage() { return image; } public void setImage(Image img) { image = img; } public int x() { return x; } public int y() { return y; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public boolean isLeftCollision(Actor actor) { return x() - SPACE == actor.x() && y() == actor.y(); } public boolean isRightCollision(Actor actor) { return x() + SPACE == actor.x() && y() == actor.y(); } public boolean isTopCollision(Actor actor) { return y() - SPACE == actor.y() && x() == actor.x(); } public boolean isBottomCollision(Actor actor) { return y() + SPACE == actor.y() && x() == actor.x(); } } ``` 這是`Actor`類。 該類是游戲中其他演員的基礎類。 它封裝了推箱子游戲中對象的基本功能。 ```java public boolean isLeftCollision(Actor actor) { return x() - SPACE == actor.x() && y() == actor.y(); } ``` 此方法檢查演員是否與左側的另一個演員(墻壁,行李,推箱子)相撞。 `Wall.java` ```java package com.zetcode; import java.awt.Image; import javax.swing.ImageIcon; public class Wall extends Actor { private Image image; public Wall(int x, int y) { super(x, y); initWall(); } private void initWall() { ImageIcon iicon = new ImageIcon("src/resources/wall.png"); image = iicon.getImage(); setImage(image); } } ``` 這是`Wall`類。 它繼承自`Actor`類。 構建后,它將從資源中加載墻圖像。 `Player.java` ```java package com.zetcode; import java.awt.Image; import javax.swing.ImageIcon; public class Player extends Actor { public Player(int x, int y) { super(x, y); initPlayer(); } private void initPlayer() { ImageIcon iicon = new ImageIcon("src/resources/sokoban.png"); Image image = iicon.getImage(); setImage(image); } public void move(int x, int y) { int dx = x() + x; int dy = y() + y; setX(dx); setY(dy); } } ``` 這是`Player`類。 ```java public void move(int x, int y) { int dx = x() + x; int dy = y() + y; setX(dx); setY(dy); } ``` `move()`方法將對象移動到世界內部。 `Baggage.java` ```java package com.zetcode; import java.awt.Image; import javax.swing.ImageIcon; public class Baggage extends Actor { public Baggage(int x, int y) { super(x, y); initBaggage(); } private void initBaggage() { ImageIcon iicon = new ImageIcon("src/resources/baggage.png"); Image image = iicon.getImage(); setImage(image); } public void move(int x, int y) { int dx = x() + x; int dy = y() + y; setX(dx); setY(dy); } } ``` 這是`Baggage`對象的類。 該對象是可移動的,因此也具有`move()`方法。 `Area.java` ```java package com.zetcode; import java.awt.Image; import javax.swing.ImageIcon; public class Area extends Actor { public Area(int x, int y) { super(x, y); initArea(); } private void initArea() { ImageIcon iicon = new ImageIcon("src/resources/area.png"); Image image = iicon.getImage(); setImage(image); } } ``` 這是`Area`類。 這是我們嘗試放置行李的對象。 `Sokoban.java` ```java package com.zetcode; import java.awt.EventQueue; import javax.swing.JFrame; public class Sokoban extends JFrame { private final int OFFSET = 30; public Sokoban() { initUI(); } private void initUI() { Board board = new Board(); add(board); setTitle("Sokoban"); setSize(board.getBoardWidth() + OFFSET, board.getBoardHeight() + 2 * OFFSET); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); } public static void main(String[] args) { EventQueue.invokeLater(() -> { Sokoban game = new Sokoban(); game.setVisible(true); }); } } ``` 這是主要的類。 ![Sokoban](https://img.kancloud.cn/b4/21/b4214cacb349378bbb0c42cd64fd90b5_460x310.jpg) 圖:推箱子 這是推箱子游戲。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看