设计思路:
1、地图的绘制
2、添加角色
3、移动箱子
4、游戏状态显示
5、人推箱子
6、背景图片的设计
*添加了右键点击事件
可以随意更换背景图片
其他功能随后更新
代码:
四个类:
package my;
import java.awt.AWTEvent;
import java.awt.Image;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MyFrame extends JFrame
{
MyPanel root=new MyPanel();
String filePath;//用来表示图片路径
JPopupMenu popup=new JPopupMenu(); //右键弹出式菜单
public MyFrame(String title)
{
super(title);
this.setContentPane(root);
root.setLayout(null);
//右键菜单
popup.add( createMenuItem("通知.png", "reSet","重置游戏"));
popup.add( createMenuItem("ic_search.png", "bgChange","更换背景"));
popup.add( createMenuItem("ic_saveas.png","fileSave","保存"));
popup.addSeparator();
popup.add( createMenuItem("ic_help.png", "fileHelp","帮助"));
//初始化背景图片
try {
Image image=ImageIO.read(new File("images/bg2.jpg"));
root.setBgImage(image);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
root.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(e.getButton()==MouseEvent.BUTTON3)
popup.show(e.getComponent(), e.getX(), e.getY());
}
});
}
//设置背景图片
private void setBg()
{
Image image;
try {
image = ImageIO.read(new File(getPicture()));
root.setBgImage(image);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//启动图片选择框
private String getPicture()
{
//创建一个文件选择器
JFileChooser chooser=new JFileChooser();
chooser.setDialogTitle("选择背景图片");
chooser.setCurrentDirectory(new File("D:/")); //初始化为D盘
//文件名后缀过滤器
FileNameExtensionFilter filter=new FileNameExtensionFilter("图片文件", "jpg","jpeg","png");
chooser.setFileFilter(filter);
//显示对话框
int ret=chooser.showOpenDialog(this);
//获取用户选择的结果
if(ret==JFileChooser.APPROVE_OPTION);
{
//结果为已经存在一个文件
File file=chooser.getSelectedFile();
filePath=file.getAbsolutePath();
}
return filePath;
}
protected JMenuItem createMenuItem(String iceName,String action,String text)
{
JMenuItem item=new JMenuItem(text); //名字
item.setActionCommand(action); //设置命令
item.addActionListener(actionListener);
if(iceName!=null)
{
String imagePath="/icons/"+iceName;
URL imageURL=getClass().getResource(imagePath);
item.setIcon(new ImageIcon(imageURL));
}
return item;
}
//创建一个监听器
//注意:actionListener是类的属性
private ActionListener actionListener=new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String action=e.getActionCommand();
//当是打开命令时,再弹出一个窗口
if(action.equals("bgChange"))
{
setBg();
}
if(action.equals("reSet"))
{
reset();
}
if(action.equals("fileSave"))
{
save2();
}
if(action.equals("fileHelp"))
{
help2();
}
}
};
private void reset()
{
JOptionPane.showMessageDialog(this, "操作已经完成!祝您游戏愉快");
}
//保存
private void save2()
{
JOptionPane.showMessageDialog(this, "已保存!");
}
//没帮助
private void help2()
{
JOptionPane.showMessageDialog(this, "此游戏创建于2019-08-13 20:33,随着知识的学习,作者会不断更新,谢谢~");
}
}
package my;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MyPanel extends JPanel
{
Game game = new Game();
Image bgImage;
Rectangle area ; // 中间可玩区域 (正方形 )
Rectangle[][] grid ; // 每个单元格
Image icChild, icBox, icTarget; // 角色图标
String display = ""; // 状态提示
public MyPanel()
{
this.setFocusable(true); // 允许输入
this.enableEvents(KeyEvent.MOUSE_EVENT_MASK);
this.enableEvents(KeyEvent.KEY_EVENT_MASK);
// 加载角色图标
try {
icChild = ImageIO.read(getClass().getResource("/icons/ic_child.png"));
icBox = ImageIO.read(getClass().getResource("/icons/ic_box.png"));
icTarget = ImageIO.read(getClass().getResource("/icons/ic_target.png"));
}catch(Exception e)
{
e.printStackTrace();
}
}
@Override
protected void processMouseEvent(MouseEvent e)
{
if(e.getID() == MouseEvent.MOUSE_CLICKED)
{
this.repaint();
}
super.processMouseEvent(e);
}
@Override
protected void processKeyEvent(KeyEvent e)
{
if(e.getID() == KeyEvent.KEY_PRESSED)
{
int code = e.getKeyCode();
int dx=0, dy = 0;
// 响应上、下、左、右键
if(code == KeyEvent.VK_UP)
dy = -1;
else if(code == KeyEvent.VK_DOWN)
dy = 1;
else if(code == KeyEvent.VK_LEFT)
dx = -1;
else if(code == KeyEvent.VK_RIGHT)
dx = 1;
display = "";
if(game.canMove(dx, dy))
{
game.move(dx, dy);
}else
{
display = "不能移动!前方有障碍物或墙壁!";
System.out.println("不能移动!前方有障碍物或墙壁!");
}
if( game.getStatus() == 100)
{
display = "游戏结束,恭喜通关!";
}
repaint();
}
super.processKeyEvent(e);
}
public void setBgImage(Image image)
{
this.bgImage = image;
this.repaint();
}
// 计算与测量:得到网格数据
private void calculate()
{
int width = getWidth();
int height = getHeight();
// System.out.println("width,height: "+ width + "," + height);
int NN = game.NN;
grid = new Rectangle[NN][NN];
// 中间取一个正方形
int unit = 20; // 每一个小格的尺寸
int size = unit * NN;
int centerX = (width - size)/2;
int centerY = (height -size)/2; // 中心点
area = new Rectangle(centerX, centerY, size, size);
// 计算出每个单元格
for(int row =0; row<NN; row++) // 行
{
for(int col=0; col<NN; col++)
{
int x = (int) ( area.x + col * unit);
int y = (int) ( area.y + row * unit);
grid[row][col] = new Rectangle(x,y,unit,unit);
//grid[row][col].grow(-2, -2); // 缩一点
}
}
}
@Override
protected void paintComponent(Graphics g)
{
int width = getWidth();
int height = getHeight();
Graphics2D g2d = (Graphics2D) g;
g2d.clearRect(0, 0, width, height);
// 平滑绘制 ( 反锯齿 )
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(0xE1E1E1));
g2d.fillRect(0, 0, width, height);
// 绘制背景
if(bgImage != null)
{
g2d.drawImage(bgImage, 0, 0, width, height, null);
g2d.setPaint(new Color(255,255,255, 150)); //半透明遮罩
g2d.fillRect(0, 0, width, height);
}
calculate();
// 两种颜色:焦点色 与 无焦点状态
Color focusColor = new Color(0xC1CDCD);
Color darkColor = new Color(0xAAAAAA);
// 绘制场地
g2d.setPaint(Color.WHITE);
g2d.fill(area);
if(this.hasFocus())
g2d.setPaint(focusColor);
else
g2d.setPaint(darkColor);
// 绘制角色
int NN = game.NN;
for(int i=0; i<NN; i++)
{
for(int k=0; k<NN; k++)
{
Rectangle r = grid[i][k];
Game.Cell cell = game.getCell(i, k);
// 绘制障碍
if(cell.type == Game.Role.STONE)
{
Rectangle r2 = new Rectangle(r);
r2.grow(-1, -1);
g2d.fill(r2);
}
// 绘制角色图标
Image icon = null;
if(cell.type == Game.Role.CHILD) icon = icChild;
if(cell.type == Game.Role.BOX) icon = icBox;
if(cell.type == Game.Role.TARGET) icon = icTarget;
if(icon != null)
{
g2d.drawImage(icon, r.x, r.y, r.width,r.height,null);
}
}
}
// 状态提示
if(display != null)
{
g2d.setFont(g2d.getFont().deriveFont(20.0f));
FontMetrics fm = g2d.getFontMetrics(g2d.getFont());
int fontSize = fm.getHeight(); // 字高
int textWidth = fm.stringWidth(display);
g2d.setPaint(new Color(0x333333));
g2d.drawString(display, (width - textWidth)/2, fontSize + 50);
}
}
}
package my;
public class Game
{
//规格
public int NN=15;
//角色:空,小孩,箱子,障碍物,目标
public enum Role{EMPTY,CHILD,BOX,STONE,TARGET};
//网格数据/二维Cell对象/类型
public Cell[][] grid=new Cell[NN][NN];
//用来记录所在位置
Cell box;
Cell child;
//游戏状态
private int status=0;//0进行中,100,通关
//单元的的定义(每个单元格可以为空,也可以是一个角色)
public static class Cell
{
int row;
int col;
Role type=Role.EMPTY;
}
public Game()
{
initMap();
}
//初始化地图
public void initMap()
{
//创建地图
for(int row=0;row<NN;row++)
{
for(int col=0;col<NN;col++)
{
grid[row][col]=new Cell();
grid[row][col].row=row;
grid[row][col].col=col;
}
}
//设置围墙
for(int row=0; row<NN; row ++)
{
for(int col=0; col<NN; col ++)
{
if(row == 0 || row == NN-1 || col==0 || col==NN-1)
{
grid[row][col].type = Role.STONE;
}
}
}
//设置目的地
grid[3][3].type=Role.TARGET;
//设置箱子
grid[6][7].type=Role.BOX;
box=grid[6][7];
//设置孩子
grid[2][1].type=Role.CHILD;
child=grid[2][1];
//场地中的障碍物
grid[7][5].type=Role.STONE;
grid[5][7].type=Role.STONE;
grid[3][11].type=Role.STONE;
grid[10][8].type=Role.STONE;
}
//获取一个位置
public Cell getCell(int row,int col)
{
return grid[row][col];
}
//计算下一步的位置:dx,水平方向移动几格.......
public Cell next(Cell current,int dx,int dy)
{
int nextRow=current.row+dy;
int nextCol=current.col+dx;
return getCell(nextRow, nextCol);
}
// 探测是否可以移动
public boolean canMove(int dx, int dy)
{
if(status == 100) return false; // 都通关了,就不让再玩了
Cell nextCell = next(child,dx, dy); //小孩的前方位置
if(nextCell.type == Role.EMPTY || nextCell.type == Role.TARGET)
{
//前方为空
return true;
}
//前方为箱子
else
if(nextCell.type==Role.BOX)
{
//前方为箱子的话,判断箱子的前方可否移动
Cell next2=next(nextCell,dx,dy); //障碍物的前方
if(next2.type == Role.EMPTY || next2.type == Role.TARGET)
{
//前方为空
return true;
}
}
return false;
}
// 移动 (相对位置)
public void move(int dx, int dy)
{
Cell nextCell = next(child, dx, dy); // 小孩的前方位置
if( nextCell.type == Role.EMPTY || nextCell.type == Role.TARGET)
{
// 移动小孩
nextCell.type = Role.CHILD;
child.type = Role.EMPTY;
child = nextCell;
}
if( nextCell.type == Role.BOX)
{
// 前方为障碍物
Cell next2 = next(nextCell, dx, dy); // 障碍物的前方
Role next2Type = next2.type;
if(next2Type == Role.EMPTY || next2Type == Role.TARGET)
{
// 先移动箱子、再移动小孩
next2.type = Role.BOX;
box.type = Role.EMPTY;
box = next2;
nextCell.type = Role.CHILD;
child.type = Role.EMPTY;
child = nextCell;
if(next2Type == Role.TARGET)
{
status = 100;
}
}
}
System.out.printf("Child (%d,%d) Box (%d,%d)\n", child.row , child.col , box.row , box.col);
}
public int getStatus()
{
return status;
}
}
package my;
import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Demo
{
private static void createGUI()
{
// JFrame指一个窗口,构造方法的参数为窗口标题
// 语法:因为MyFrame是JFrame的子类,所以可以这么写
JFrame frame = new MyFrame("Js推箱子");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置窗口的其他参数,如窗口大小
frame.setSize(800, 500);
// 显示窗口
frame.setVisible(true);
}
public static void main(String[] args)
{
//设置界面样式 Look And Feel
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run()
{
createGUI();
}
});
}
}