Java-推箱子

 

设计思路:

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();
			}
		});
 
	}
}

祝您游戏愉快,谢谢~

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值