In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article will explain in detail how to use Java to achieve classic game push boxes. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.
Main design
1. Game panel generation display
2. Map generation algorithm
3. Character movement algorithm
4. Play background music
5. Box moving algorithm
6. Only when all the boxes are moved to the designated position can the game be counted as a pass.
Function screenshot
The game begins.
Moving effect
The game passes.
The code implements the core classes public class GameFrame extends JFrame implements ActionListener, MouseListener, KeyListener {/ / to implement the number of levels for action event listeners, mouse event listeners, keyboard event listeners / / current levels. Default is the first level. Count private int grade = 1 starting from 1. / / row,column records the position of the person, representing the line number and column number in the two-dimensional array respectively, that is, map [row] [column] determines the position of the person private int row = 7, column = 7; / / leftX,leftY records the position of the picture in the upper left corner to avoid starting from (0L0) coordinates, because it is a picture fill, private int leftX = 50, leftY = 50 is not allowed from (0P0). / / record the total number of rows and columns of the map private int mapRow = 0, mapColumn = 0; / / record the width and height of the screen window private int width = 0, height = 0; private boolean acceptKey = true; / / the picture needed by the program private Image pics [] = null;// picture data private byte [] map = null;// map data private ArrayList list = new ArrayList () Private SoundPlayerUtil soundPlayer;// playback sound tool class / * constant, that is, resources in the game * / private final static int WALL = 1 role private final static int BOX / wall private final static int MAN_DOWN = 2 beat / box private final static int BOX_ON_END = 3 private final static int END / box put to destination private final static int END = 4 position / destination private final static int MAN_DOWN = 5 / / downward person private final static int MAN_LEFT = 6 Sigma / people to the left private final static int MAN_RIGHT = 7 / person to the right private final static int MAN_UP = 8 / person private final static int GRASS = 9 / Channel private final static int MAN_DOWN_ON_END = 10 / person standing at the destination private final static int MAN_LEFT_ON_END = 11 / / people who are standing to the left of the destination private final static int MAN_RIGHT_ON_END = 12 / those who are standing to the right of the destination private final static int MAN_UP_ON_END = 13 / those who are standing up at the destination private final static int MOVE_PIXEL = 30 / / indicates that each move is 30 pixels / * in the construction method GameFrame0, call the initMap () method to initialize the local grade game map, clear the regret chess message list list, and play MIDI background music at the same time. * / public GameFrame () {/ / some basic settings of the game window setTitle ("push box game"); setSize (600,600); setVisible (true); setLocation (300,20); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); Container contentPane = getContentPane (); contentPane.setLayout (null); contentPane.setBackground (Color.black) / / other settings, the width and height of the initialization window are assigned to width and height this.width = getWidth (); this.height = getHeight (); / / initialize image resources getPics (); / / initialize map data initMap (); / / register event listeners setFocusable (true); addKeyListener (this) The function of the addMouseListener (this); / / play music initSound ();} / * initMap () method is to initialize the local grade game map and clear the list of repentance information list. Call * getMapSizeAndPosition (method to get the size of the game area and display the position of the upper left corner of the game (leftX, leftY). * / public void initMap () {/ / get the map data of the current level map = MapFactory.getMap (grade); / / clear the fallback map data saved in the previous level, that is, clear the contents of the list collection list.clear (); / / initialize the number of rows and rows of the map and the starting coordinate position of the upper left corner getMapSizeAndPosition () / / get the coordinate position of the character getManPosition (); the function of the} / * getManPosition () method is to obtain the worker's current position (row,column). * / public void getManPosition () {/ / that is, in the traversal map array map, the value equals to MANXXX (MAN_DOWN for downward person; MAN_UP for upward person), which means that the position is the position where the person is standing. The for (int I = 0; I) is obtained from the map data scan.
< 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开始的 this.row = i; this.column = j; break; } } } } /** * getMapSizeAndPosition()方法用来获取游戏区域大小及显示游戏的左上角位置( lefX, leftY )。 */ private void getMapSizeAndPosition() { // 初始化mapRow和mapColumn,表示地图的行列数 this.mapRow = map.length; this.mapColumn = map[0].length; // 初始化leftX和leftY,即计算左上角的位置, this.leftX = (width - map[0].length * MOVE_PIXEL) / 2; this.leftY = (height - map.length * MOVE_PIXEL) / 2; } /** * getPics()方法用来加载要显示的图片 */ public void getPics() { // 创建长度为13的数组,即有十三张图片 pics = new Image[13]; // 然后循环将每张图片读取保存到pics数组中 for (int i = 0; i < 13; i++) { pics[i] = Toolkit.getDefaultToolkit().getImage("src\\images\\pic_" + (i + 1) + ".png"); } } /** * 初始化播放的音乐 */ public void initSound() { // 调用SoundPlayerUtil类中的方法播放音乐 soundPlayer = new SoundPlayerUtil(); soundPlayer.loadSound("src\\sounds\\music.wav"); soundPlayer.playSound(true);// 循环播放 } /** * 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; } /** * 人物向上移动 */ private void moveUp() { // 如果上一位是WALL,则不能移动 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) { // 要保留当前信息,以便回退上一步 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,箱子往前移动一步 map[row - 2][column] = boxTemp; // 人变成MAN_UP,往上走一步 map[row - 1][column] = manTemp; // 将人刚才站的地方变成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人离开后修改人的坐标 row--; } } else { // 上一位为GRASS或END,无需考虑上上一步,其他情况不用处理 if (map[row - 1][column] == GRASS || map[row - 1][column] == END) { // 保留当前这一步的信息,以便回退上一步 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]); // 人离开后修改人的坐标 row--; } } } /** * 人物向下移动,其中(row,column)是当前角色站的位置,而map[row,column]表示当前角色 */ private void moveDown() { // 如果下一位是WALL,则不能移动 // 所以map[row+1][column]表示当前角色的下一步,也就是下一关图像块 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,则表示箱子可以向下移动一步,其他情况不用处理 // map[row+2][column]表示箱子的下一步是什么 if (map[row + 2][column] == END || map[row + 2][column] == GRASS) { // 下面的代码就是箱子向前移动一步,人移动原来箱子的位置 // 要保留当前人和地图信息,以便回退下一步 Map currMap = new Map(row, column, map); list.add(currMap); // 判断箱子的下一步是否是目的地,如果是目的地,那么箱子的下一步就应该变成BOX_ON_END(放在目的地的箱子),如果不是目的地那应该还只是普通箱子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,箱子往下移动一步 map[row + 2][column] = boxTemp; // 人变成MAN_UP,往下走一步 map[row + 1][column] = manTemp; // 将人刚才站的地方变成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人离开后修改人的坐标 row++; } } else { // 执行到这里,表示人的下一步不是箱子,那么要么是通道要么是终点 // 下一位为GRASS或END,无需考虑下下一步,其他情况不用处理 if (map[row + 1][column] == GRASS || map[row + 1][column] == END) { // 保留当前这一步的信息,以便回退下一步 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]); // 人离开后修改人的坐标 row++; } } } /** * 人物向左移动 */ private void moveLeft() { // 如果左一位是WALL,则不能移动 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) { // 要保留当前信息,以便回退左一步 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,箱子往前移动一步 map[row][column - 2] = boxTemp; // 人变成MAN_UP,往左走一步 map[row][column - 1] = manTemp; // 将人刚才站的地方变成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人离开后修改人的坐标 column--; } } else { // 左一位为GRASS或END,无需考虑左左一步,其他情况不用处理 if (map[row][column - 1] == GRASS || map[row][column - 1] == END) { // 保留当前这一步的信息,以便回退左一步 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]); // 人离开后修改人的坐标 column--; } } } /** * 人物向右移动 */ private void moveRight() { // 如果右一位是WALL,则不能移动 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) { // 要保留当前信息,以便回退右一步 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,箱子往右移动一步 map[row][column + 2] = boxTemp; // 人变成MAN_UP,往右走一步 map[row][column + 1] = manTemp; // 将人刚才站的地方变成GRASS或者END map[row][column] = grassOrEnd(map[row][column]); // 人离开后修改人的坐标 column++; } } else { // 右一位为GRASS或END,无需考虑右右一步,其他情况不用处理 if (map[row][column + 1] == GRASS || map[row][column + 1] == END) { // 保留当前这一步的信息,以便回退右一步 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]); // 人离开后修改人的坐标 column++; } } } /** * 验证玩家是否过关,如果有目的地END值或人直接站在目的地则没有成功 * * @return 如果已经通关则返回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; } // 使用双缓冲技术解决动画闪烁问题 private Image iBuffer; private Graphics gBuffer; /** * 重写绘制整个游戏区域的图形 * * @param g */ @Override public void paint(Graphics g) { if (iBuffer == null) { iBuffer = createImage(width, height); gBuffer = iBuffer.getGraphics(); } // 清空屏幕原来的绘画 gBuffer.setColor(getBackground()); gBuffer.fillRect(0, 0, width, height); for (int i = 0; i < mapRow; i++) { for (int j = 0; j < mapColumn; j++) { // 画出地图,i表示行数,j表示列数 if (map[i][j] != 0) { // 这里要减1是因为图片的名称序号不对应,应该从0开始,但是从1开始的 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("现在是第", 150, 140); gBuffer.drawString(String.valueOf(grade), 310, 140); gBuffer.drawString("关", 360, 140); g.drawImage(iBuffer, 0, 0, this); /* 下面的代码是未使用双缓冲技术会导致动画闪烁的代码 */ /*g.clearRect(0, 0, width, height); for (int i = 0; i < mapRow; i++) { for (int j = 0; j < mapColumn; j++) { // 画出地图,i表示行数,j表示列数 if (map[i][j] != 0) { // 这里要减1是因为图片的名称序号不对应,应该从0开始,但是从1开始的 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("现在是第", 150, 140); g.drawString(String.valueOf(grade), 310, 140); g.drawString("关", 360, 140);*/ } @Override public void actionPerformed(ActionEvent e) { } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { // 当按键盘上的按键时触发的事件 switch (e.getKeyCode()) { case KeyEvent.VK_UP:// 上方向键 moveUp();// 向上移动 break; case KeyEvent.VK_DOWN:// 下方向键 moveDown();// 向下移动 break; case KeyEvent.VK_LEFT:// 左方向键 moveLeft();// 向左移动 break; case KeyEvent.VK_RIGHT:// 右方向键 moveRight();// 向右移动 break; } // 然后重新绘制界面 repaint(); // 在移动完成后可能已经通关,所以需要判断是否通关 if (isFinished()) { // 禁用按键 acceptKey = false; // 判断是否是最后一关,如果是则直接提示,如果不是则询问是否要进入下一关 if (grade == MapFactory.getCount()) { JOptionPane.showMessageDialog(this, "恭喜通过最后一关!"); } else { // 提示进入下一关 String msg = "恭喜通过第" + grade + "关!!!\n是否要进入下一关?"; int choice = JOptionPane.showConfirmDialog(null, msg, "过关", JOptionPane.YES_NO_OPTION); if (choice == 1) { System.exit(0); } else if (choice == 0) { // 进入下一关 acceptKey = true; nextGrade(); } } } } @Override public void keyReleased(KeyEvent e) { } @Override public void mouseClicked(MouseEvent e) { // MouseEvent.BUTTON3表示鼠标右键 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) { } /** * 返回当前人的位置用getManX()方法和getManY()方法 * * @return */ public int getManX() { return row; } public int getManY() { return column; } /** * 返回当前关卡数 * * @return */ public int getGrade() { return grade; } /** * 返回当前关卡的地图信息 * * @return */ public byte[][] getMap() { return MapFactory.getMap(grade); } /** * 显示提示信息对话框 * * @param str */ public void displayToast(String str) { JOptionPane.showMessageDialog(null, str, "提示", JOptionPane.ERROR_MESSAGE); } /** * 撤销移动操作 */ public void undo() { if (acceptKey) { if (list.size() >0) {/ / if you want to undo, you must walk / / consider using a stack more appropriate Map priorMap = (Map) list.get (list.size ()-1); this.map = priorMap.getMap (); this.row = priorMap.getManX (); this.column = priorMap.getManY () Repaint (); / / redraw list.remove (list.size ()-1);} else {displayToast ("can't be undone!") ;}} else {displayToast ("this pass has been completed and cannot be undone!") ;}} / * initialize the next level, and call the repaint () method to display the game interface * / public void nextGrade () {/ / initialize the next level data if (grade > = MapFactory.getCount ()) {displayToast ("Congratulations on completing all levels!") ; acceptKey = false;} else {/ / checkpoints plus 1 grade++; / / initialize the map data initMap () for the next level; / / redraw the screen repaint (); acceptKey = true }} / * to initialize the previous level and call repaint () to send and display the game interface * / public void priorGrade () {grade--; acceptKey = true; if (grade < 0) {grade = 0;} initMap (); repaint ();}} sound playback class public class SoundPlayerUtil {public File file Public AudioInputStream stream; public AudioFormat format; DataLine.Info info; Clip clip; / * load sound files and support the path of wav, mp3 and other sound files * * @ param filePath sound files * / public void loadSound (String filePath) {file = new File (filePath); try {stream = AudioSystem.getAudioInputStream (file) } catch (UnsupportedAudioFileException | IOException e) {e.printStackTrace ();} format = stream.getFormat ();} / * * play music * * @ param isLoop indicates whether to play music in a loop. If true is passed, it means to play music in a loop * / 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); / / add this code to loop} clip.start () }} this is the end of the article on "how to use Java to realize the push box of classic games". I hope the above content can be helpful to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.