码迷,mamicode.com
首页 > 其他好文 > 详细

推箱子

时间:2020-04-05 13:49:32      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:mapr   click   print   xtend   wstring   i++   tor   finish   tool   

难点

逻辑判断当前地图的状态(注意数组越界问题), 根据这个状态, 对数组的值进行修改, 然后调用 repaint() -> paint() 来将图形绘制出来.

举一反三

实际上, 步骤1,2 完全可以用在 连连看中. 而且连连看不需要撤销功能, 所以不需要保存之前的图形的样子.

而连连看的主程序在实现逻辑上会有区别, 另外, 连连看在鼠标事件中会有应用, 点了哪个图片等等.

步骤:

1. 创建初始化界面(地图) {可共用} MapFactory.java

package com.leon.movebox;

public class MapFactory {
    /**
     * 
     */
    static byte map[][][] = {
        /*
         *  0 表示空白, 什么都不用画, 不参与到游戏中
         *  WALL = 1, BOX = 2, BOXONEND = 3, END = 4,
         *  MANDOWN = 5, MANLEFT = 6, MANRIGHT = 7, MANUP = 8, 
         *  GRASS = 9, MANDOWNONEND = 10, MANLEFTONEND = 11, MANRIGHTONEND = 12,
         *  MANUPONEND = 13;
         * */
        {
            // map[0]
            {0, 0, 1, 1, 1, 0, 0, 0},
            {0, 0, 1, 4, 1, 0, 0, 0},
            {0, 0, 1, 9, 1, 1, 1, 1},
            {1, 1, 1, 2, 9, 2, 4, 1},
            {1, 4, 9, 2, 5, 1, 1, 1},
            {1, 1, 1, 1, 2, 1, 0, 0},
            {0, 0, 0, 1, 4, 1, 0, 0},
            {0, 0, 0, 1, 1, 1, 0, 0},
        },
        {
            // map[1]
            {1, 1, 1, 1, 1, 0, 0, 0, 0},
            {1, 9, 9, 5, 1, 0, 0, 0, 0},
            {1, 9, 2, 2, 1, 0, 1, 1, 1},
            {1, 9, 2, 9, 1, 0, 1, 4, 1},
            {1, 1, 1, 9, 1, 1, 1, 4, 1},
            {0, 1, 1, 9, 9, 9, 9, 4, 1},
            {0, 1, 9, 9, 9, 1, 9, 9, 1},
            {0, 1, 9, 9, 9, 1, 1, 1, 1},
            {0, 1, 1, 1, 1, 1, 0, 0, 0},
        },
    };
    // count 当前有多少关
    static int count = map.length;
    public static byte[][] getMap(int grade) {
        byte temp[][];
        if (grade >= 0 && grade < count)
            // 指针, 并非真正 copy
            temp = map[grade];
        else
            temp = map[0];
        int row = temp.length;
        int column = temp[0].length;
        byte[][] result = new byte[row][column];
        // 真正 copy
        for (int i = 0; i < row; i++)
            for (int j = 0; j < column; j++)
                result[i][j] = temp[i][j];
        return result;
    }
    public static int getCount() {
        return count;
    }
}

 

2. 初始化声音 {可共用} Sound.java

package com.leon.movebox;

import java.io.File;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;

public class Sound {
    
    private String path = new String("musics/");
    private String file = new String("nor.mid");
    private Sequence seq;
    private Sequencer midi;
    private boolean sign;
    
    public void loadSound() {
        try {
            // 打开 MIDI 文件
            seq = MidiSystem.getSequence(new File(path+file));
            // 建立音频序列
            midi = MidiSystem.getSequencer();
            // 打开音频序列
            midi.open();
            // 读取即将播放的音频序列
            midi.setSequence(seq);
            // 播放音乐
            midi.start();
            midi.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        sign = true;
    }
    
    public void mystop() {
        midi.stop();
        midi.close();
        sign = false;
    }
    
    public boolean isPlay() {
        return sign;
    }
    
    public void setMusic(String e) {
        file = e;
    }
    
}

 

3. 记录当前的地图的状态

package com.leon.movebox;

/**
 * save the currently map status
 * @author Leon
 *
 */
public class Map {
    int manX = 0;
    int manY = 0;
    byte map[][];
    int grade;
    
    public Map(int manX, int manY, byte[][] map) {
        this.manX = manX;
        this.manY = manY;
        int row = map.length;
        int column = map[0].length;
        byte temp[][] = new byte[row][column];
        for (int i = 0; i < row; i++)
            for (int j = 0; j < column; j++)
                temp[i][j] = map[i][j];
        this.map = temp;
    }
    
    public Map(int manX, int manY, byte[][] map, int grade) {
        this(manX, manY, map);
        this.grade = grade;
    }
    
    public int getManX() {
        return manX;
    }
    
    public int getManY() {
        return manY;
    }
    
    public byte[][] getMap() {
        return this.map;
    }
    
    public int getGrade() {
        return grade;
    }
}

 

4. 主程序(还需要再调整, 当前有 Bug) (设计到 上, 下, 左, 右 移动, 即根据当前的状态更改数组的状态, 进而更改图片)

package com.leon.movebox;

import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class GameFrame extends JFrame implements ActionListener, MouseListener, KeyListener{

    // 游戏关卡
    // row, column 记载人的行号和列号
    // leftX, leftY 记载图片左上角的位置
    private int grade = 0;    
    private int row = 7; 
    private int column = 7;
    private int leftX = 0;
    private int leftY = 0;
    private int mapRow = 0;
    private int mapColumn = 0;
    // 记载屏幕的宽 和 高
    private int width = 0;
    private int height = 0;
    private boolean acceptKey = true;
    private Image pic[] = null;
    private byte[][] map = null;
    // 为了悔棋, 回退步骤
    private ArrayList list = new ArrayList();
    Sound sound;
    final byte WALL = 1, BOX = 2, BOXONEND = 3, END = 4,
        MANDOWN = 5, MANLEFT = 6, MANRIGHT = 7, MANUP = 8, 
        GRASS = 9, MANDOWNONEND = 10, MANLEFTONEND = 11, MANRIGHTONEND = 12,
        MANUPONEND = 13;
            
    public GameFrame() {
        super("推箱子游戏音乐版");
        setSize(600, 600);
        setVisible(true);
        setResizable(false);
        setLocation(300, 20);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container cont = getContentPane();
        cont.setLayout(null);
        cont.setBackground(Color.black);
        getPic();
        width = this.getWidth();
        height = this.getHeight();
        this.setFocusable(true);
        initMap();
        this.addKeyListener(this);
        this.addMouseListener(this);
        sound = new Sound();
        sound.loadSound();
    }
    
    public void initMap() {
        map = getMap(grade);
        list.clear();
        getMapSizeAndPosition();
        getManPosition();
    }
    
    public void getMapSizeAndPosition() {
        mapRow = map.length;
        mapColumn = map[0].length;
        // 找到起始图片位置, 相当于留出边界
        leftX = (width - map[0].length * 30) / 2;
        leftY = (height - map.length * 30) / 2;
        System.out.println(leftX);
        System.out.println(leftY);
        System.out.println(mapRow);
        System.out.println(mapColumn);
    }
    
    public void getManPosition() {
        for (int i = 0; i < map.length; i++) 
            for (int j = 0; j < map[0].length; j++)
                if (map[i][j] == MANDOWN || map[i][j] == MANDOWNONEND
                    || map[i][j] == MANUP || map[i][j] == MANUPONEND
                    || map[i][j] == MANLEFT || map[i][j] == MANLEFTONEND
                    || map[i][j] == MANRIGHT || map[i][j] == MANRIGHTONEND) {
                    row = i;
                    column = j;
                    break;
                }
    }    
    
    // 初始化地图
    public byte[][] getMap(int grade) {
        return MapFactory.getMap(grade);
    }
    
    // 加载图片
    public void getPic() {
        pic = new Image[14];
        for (int i = 0; i < 13; i++) {
            pic[i] = Toolkit.getDefaultToolkit().getImage("images/pic" + i + ".JPG");
        }
    }
    
    // 判断人所在的位置, 是grass 还是 end
    public byte grassOrEnd(byte man) {
        byte result = GRASS;
        if (man == MANDOWNONEND || man == MANLEFTONEND
            || man == MANRIGHTONEND || man == MANUPONEND)
            result = END;
        return result;
    }
    
    // 这个函数命名成 paint, 就会自动调用
    public void paint(Graphics g) {
        for (int i = 0; i < mapRow; i++)
            for (int j = 0; j < mapColumn; j++) {
                // 画出地图, i 代表行数, j 代表列数
                if (map[i][j] != 0)
                    g.drawImage(pic[map[i][j]], leftX + j*30, leftY + i*30, this);
            }
//        g.setColor(Color.RED);
//        g.setFont(new Font("楷体_2312", Font.BOLD, 30));
//        g.drawString("现在是第", 150, 140);
//        g.drawString(String.valueOf(grade+1), 310, 140);
//        g.drawString("关", 360, 140);
    }
    
    public int getManX() {
        return row;
    }
    
    public int getManY() {
        return column;
    }
    
    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] == MANDOWNONEND
                    || map[i][j] == MANUPONEND || map[i][j] == MANLEFTONEND
                    || map[i][j] == MANRIGHTONEND)
                    return false;
        return true;
    }

    private void moveUp() {
        // 上一步 p1 为 wall
        if (map[row-1][column] == WALL)
            return;
        // 如果 p1 是 BOX, BOXONEND, 须考虑 p2
        if (map[row-1][column] == BOX || map[row-1][column] == BOXONEND) {
            if (map[row-2][column] == END || map[row-2][column] == GRASS) {
                Map currMap = new Map(row, column, map);
                list.add(currMap);
                byte boxTemp = map[row-2][column] == END? BOXONEND: BOX;
                byte manTemp = map[row-1][column] == BOX? MANUP: MANUPONEND;
                // 箱子变成 temp, 箱子往前一步
                map[row-2][column] = boxTemp;
                // 人变成MANUP, 往上走一步
                map[row-1][column] = manTemp;
                // 人刚才站的地方编程 GRASS 或者 END
                map[row][column] = grassOrEnd(map[row][column]);
                // 人离开后, 修改人的坐标
                row--;
            }
        } else {
            // 上一位是 GRASS, END 无需考虑 p2, 其他情况不用处理
            if (map[row-1][column] == GRASS || map[row-1][column] == END) {
                Map currMap = new Map(row, column, map);
                list.add(currMap);
                byte temp = map[row-1][column] == END?MANUPONEND: MANUP;
                // 人变成 temp, 人往上走一步
                map[row-1][column] = temp;
                // 人刚才站的地方编程 GRASS 或者 END
                map[row][column] = grassOrEnd(map[row][column]);
                // 人离开后修改人的坐标
                row--;
            }
        }
    }
    
    private void moveDown() {
        // 下一步 p1 为 wall
        if (map[row+1][column] == WALL)
            return;
        // 如果 p1 是 BOX, BOXONEND, 须考虑 p2
        if (map[row+1][column] == BOX || map[row+1][column] == BOXONEND) {
            if (map[row+2][column] == END || map[row+2][column] == GRASS) {
                Map currMap = new Map(row, column, map);
                list.add(currMap);
                byte boxTemp = map[row+2][column] == END? BOXONEND: BOX;
                byte manTemp = map[row+1][column] == BOX? MANUP: MANUPONEND;
                // 箱子变成 temp, 箱子往前一步
                map[row+2][column] = boxTemp;
                // 人变成MANUP, 往下走一步
                map[row+1][column] = manTemp;
                // 人刚才站的地方编程 GRASS 或者 END
                map[row][column] = grassOrEnd(map[row][column]);
                // 人离开后, 修改人的坐标
                row--;
            }
        } else {
            // 下一位是 GRASS, END 无需考虑 p2, 其他情况不用处理
            if (map[row+1][column] == GRASS || map[row+1][column] == END) {
                Map currMap = new Map(row, column, map);
                list.add(currMap);
                byte temp = map[row+1][column] == END?MANUPONEND: MANUP;
                // 人变成 temp, 人往下走一步
                map[row+1][column] = temp;
                // 人刚才站的地方编程 GRASS 或者 END
                map[row][column] = grassOrEnd(map[row][column]);
                // 人离开后修改人的坐标
                row--;
            }
        }
    }
    
    private void moveLeft() {
        // 左一步 p1 为 wall
                if (map[row][column-1] == WALL)
                    return;
                // 如果 p1 是 BOX, BOXONEND, 须考虑 p2
                if (map[row][column-1] == BOX || map[row][column-1] == BOXONEND) {
                    if (map[row][column-2] == END || map[row][column-2] == GRASS) {
                        Map currMap = new Map(row, column, map);
                        list.add(currMap);
                        byte boxTemp = map[row][column-2] == END? BOXONEND: BOX;
                        byte manTemp = map[row][column-1] == BOX? MANUP: MANUPONEND;
                        // 箱子变成 temp, 箱子往前一步
                        map[row][column-2] = boxTemp;
                        // 人变成MANUP, 往下走一步
                        map[row][column-1] = manTemp;
                        // 人刚才站的地方编程 GRASS 或者 END
                        map[row][column] = grassOrEnd(map[row][column]);
                        // 人离开后, 修改人的坐标
                        row--;
                    }
                } else {
                    // 下一位是 GRASS, END 无需考虑 p2, 其他情况不用处理
                    if (map[row][column-1] == GRASS || map[row][column-1] == END) {
                        Map currMap = new Map(row, column, map);
                        list.add(currMap);
                        byte temp = map[row][column-1] == END?MANUPONEND: MANUP;
                        // 人变成 temp, 人往下走一步
                        map[row][column-1] = temp;
                        // 人刚才站的地方编程 GRASS 或者 END
                        map[row][column] = grassOrEnd(map[row][column]);
                        // 人离开后修改人的坐标
                        row--;
                    }
                }
    }
    
    private void moveRight() {
        // 左一步 p1 为 wall
                if (map[row][column+1] == WALL)
                    return;
                // 如果 p1 是 BOX, BOXONEND, 须考虑 p2
                if (map[row][column+1] == BOX || map[row][column+1] == BOXONEND) {
                    if (map[row][column+2] == END || map[row][column+2] == GRASS) {
                        Map currMap = new Map(row, column, map);
                        list.add(currMap);
                        byte boxTemp = map[row][column+2] == END? BOXONEND: BOX;
                        byte manTemp = map[row][column+1] == BOX? MANUP: MANUPONEND;
                        // 箱子变成 temp, 箱子往前一步
                        map[row][column+2] = boxTemp;
                        // 人变成MANUP, 往下走一步
                        map[row][column+1] = manTemp;
                        // 人刚才站的地方编程 GRASS 或者 END
                        map[row][column] = grassOrEnd(map[row][column]);
                        // 人离开后, 修改人的坐标
                        row--;
                    }
                } else {
                    // 下一位是 GRASS, END 无需考虑 p2, 其他情况不用处理
                    if (map[row][column+1] == GRASS || map[row][column+1] == END) {
                        Map currMap = new Map(row, column, map);
                        list.add(currMap);
                        byte temp = map[row][column+1] == END?MANUPONEND: MANUP;
                        // 人变成 temp, 人往下走一步
                        map[row][column+1] = temp;
                        // 人刚才站的地方编程 GRASS 或者 END
                        map[row][column] = grassOrEnd(map[row][column]);
                        // 人离开后修改人的坐标
                        row--;
                    }
                }
    }
    
    public int getGrade() {
        return grade;
    }
    
    public void displayToast(String str) {
        JOptionPane.showMessageDialog(null, str, "提示", JOptionPane.ERROR_MESSAGE);
    }
    
    public void undo() {
        if (acceptKey) {
            // 撤销
            if (list.size() > 0) {
                // 若要撤销, 必须走过
                Map priorMap = (Map) list.get(list.size() - 1);
                map = priorMap.getMap();
                row = priorMap.getManX();
                column = priorMap.getManY();
                repaint();
                list.remove(list.size() - 1);
            } else
                displayToast("不能再撤销!");
        } else {
            displayToast("此关已经完成, 不能撤销!");
        }
    }
    
    public void nextGrade() {
        if (grade >= MapFactory.getCount() - 1) {
            displayToast("恭喜你完成所有关卡");
            acceptKey = false;
        } else {
            grade++;
            initMap();
            repaint();
            acceptKey = true;
        }
    }
    
    public void priorGrade() {
        grade--;
        acceptKey = true;
        if (grade < 0)
            grade = 0;
        initMap();
        repaint();
    }
    
    @Override
    public void mouseClicked(MouseEvent e) {
        // 右键撤销移动
        if (e.getButton() == MouseEvent.BUTTON3) {
            undo();
        }    
        
    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_UP ) {
            moveUp();
        }
        if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
            moveDown();
        }
        if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
            moveLeft();
        }
        if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
            moveRight();
        }
        repaint();
        if (isFinished()) {
            acceptKey = false;
            if (grade == 2) {
                JOptionPane.showMessageDialog(this, "恭喜通过最后一关");
            } else {
                // 提示进入下一关
                String msg = "恭喜您通过第" + grade + "关!!!\n 是否进入下一关?";
                int type = JOptionPane.YES_NO_OPTION;
                String title = "过关";
                int choice = 0;
                choice = JOptionPane.showConfirmDialog(null, msg, title, type);
                if (choice == 1)
                    System.exit(0);
                else if (choice == 0) {
                    acceptKey = true;
                    nextGrade();
                }
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        
    }

    public static void main(String[] args) {
        new GameFrame();

    }
}

 

推箱子

标签:mapr   click   print   xtend   wstring   i++   tor   finish   tool   

原文地址:https://www.cnblogs.com/moveofgod/p/12636644.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!