实现用java做一个简易版《羊了个羊》小游戏(附源代码)

您所在的位置:网站首页 给个代码 实现用java做一个简易版《羊了个羊》小游戏(附源代码)

实现用java做一个简易版《羊了个羊》小游戏(附源代码)

2023-07-29 00:44| 来源: 网络整理| 查看: 265

该项目是跟着这个b站视频一步一步写出来的,初学java有些地方我看不是很明白,但是讲解很仔细,大家可以看原视频,我没有添加背景音乐和背景图片,做出来的效果也勉勉强强。

代码已经上传到github上了,大家可以去github上直接下载代码,附上链接:点击进入github源码链接

嫌麻烦进不去github的,我直接附上HTTPS链接和SSH,自己git clone就行

HTTPS: git clone https://github.com/19138060480/Genshin-elimination-game.git

SSH: git clone [email protected]:19138060480/Genshin-elimination-game.git

先上效果图:

 因为懒得找原图,手边又刚好有原神的七元素图片,所以就用七元素做成了简易版的《原了个原》

 当元素在放满七个后会判断游戏失败,每次图片是随机的(但是可以保证能消除完)后面灰色的图片是被遮盖的图片,无法点击(指点击后不会消失),当前面覆盖的图片被点击消失后才会恢复彩色图片(即可点击状态)。

效果图就先到这里,在上源码之前先看一下我创建的包和类,不想修改乱七八糟的东西的宝子们可以跟我设置相同的包名和类名,省的麻烦。(亲测,修改后可能会出现近百个错误);

 

特别注意的是,imgs里面的图片只要命名正确就可以了,不需要原图(指可以百度),后面加Gray的图片是灰色的,我用ps一个一个把图片拖进去变成灰色你知道有多累吗?(其实也可以通过代码.......)

源码来咯:

首先是BeginGame包里面的Play:

package BeginGame; import Model.Brand; import Model.Cell; import Model.Layer; import Model.Map; import Tool.MapUtil; import javax.swing.*; import java.util.List; //测试渲染一个地图 public class Play extends JFrame { public static Map map= MapUtil.build(3); public Play(){ /*初始化窗口基本信息*/ inti(); /*渲染图层*/ List list=map.getList(); for (int i = 0; i < list.size(); i++) { renderLayer(list.get(i)); } map.compareAll(); //判定游戏开始时,所有牌是灰色还是彩色 /*自动刷新*/ autoRefresh(); //自动刷新线程 } private void renderLayer(Layer layer){ /*渲染图层 默认情况下 brand牌的左上角坐标是0,0 需要改变牌的坐标 设置布局方式,默认swing 添加组件 提供了多种布局方式 网格、流线、、、 绝对布局 */ Cell[][] cells=layer.getCells(); layer.showCell(); for (int row = 0; row < cells.length; row++) { for (int col = 0; col < cells[row].length; col++) { Brand brands1 = cells[row][col].getBrand(); int x=col*50+layer.getOffsetx(); //加上了偏移量 int y=row*50+layer.getOffsety(); //设置xy坐标 brands1.setBounds(x,y,50,50); this.getContentPane().add(brands1); } System.out.println(); } } private void autoRefresh(){ //自动刷新方法 JFrame main=this; new Thread(new Runnable() { @Override public void run() { //一直执行刷新页面 while(true){ main.repaint(); try { Thread.sleep(40); //40毫秒刷新一次 }catch (InterruptedException e){ e.printStackTrace(); } } } }).start(); } private void inti(){ this.setTitle("羊了个羊"); //标题 this.setSize(450,800); //设置窗口大小 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //关闭窗口的同时也关闭进程 /*设置绝对布局*/ this.setLayout(null); this.setBounds(0,0,450,800); this.setLocationRelativeTo(null); //窗口居中 this.setVisible(true); //窗口显示(默认关闭) } public static void main(String[] args) { new Play(); } }

 然后是Model包

Brand:

package Model; import BeginGame.Play; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; /* 游戏中的牌 */ public class Brand extends Component { //牌类 /*牌基础信息*/ private String name; //名称 private boolean isGray; //判断当前的牌是否是在牌堆下 private Image image; //正常图片 private Image grayimage; //牌堆下灰色图片 /*坐标*/ private Integer x; //代表在渲染的时候左上角的坐标 private Integer y; /*宽高度*/ private Integer width; private Integer height; /**/ private Cell cell; EliminateBox eliminateBox =new EliminateBox(); public Brand(String name){ //含name参数构造 this.name=name; /*通过name的值 对应图片目录下的图片前缀*/ this.image = Toolkit.getDefaultToolkit().getImage("imgs\\"+name+".png"); //通过name找到图片 this.grayimage=Toolkit.getDefaultToolkit().getImage("imgs\\"+name+"Gray.png"); //通过name找到灰色图片 this.isGray=false; //默认不置灰 /*设置宽高*/ this.width=50; this.height=50; /*设置默认坐标*/ this.x=0; this.y=0; this.addMouseListener(new MouseAdapter() { //鼠标监听器 @Override public void mouseClicked(MouseEvent e) { //点击鼠标 System.out.println("点击鼠标"); Brand brand=(Brand) e.getSource(); //点击后获取当前组件 强制下转型(默认是object) if (brand.getGray()){ //灰色 return; }else { /*只在页面中删除了brand对象,但是cell状态中的state和brand没有删除*/ //brand.getParent().remove(brand); //调用上层容器删除自己 一般树形结构使用这样的方式 eliminateBox.addBox(brand); /*解决问题关键是纪要删除UI当中的组件,还要删除数据模型中的数据和对应状态*/ cell.setState(0); cell.setBrand(null); Play.map.compareAll(); //涉及到map对象的共享 处理:把map对象设为静态变量 } } }); } @Override public void paint(Graphics g) { //重写Component的paint方法(绘制函数) if(this.isGray==true){ //通过控制isGray来控制图片的灰色和彩色 //绘制灰色图片 g.drawImage(this.grayimage,this.x,this.y,null); }else { //绘制正常图片 g.drawImage(this.image,this.x,this.y,null); } } /* set/get */ public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isGray() { return isGray; } public void setGray(boolean gray) { isGray = gray; } public boolean getGray(){ return isGray; } public Image getImage() { return image; } public void setImage(Image image) { this.image = image; } public Image getGrayimage() { return grayimage; } public void setGrayimage(Image grayimage) { this.grayimage = grayimage; } public Cell getCell() { return cell; } public void setCell(Cell cell) { this.cell = cell; }

Cell:

package Model; /* 单元格类 有两种状态, 0:无牌,1:有牌; */ public class Cell { private Integer state; //0、1 private Brand brand; /* get/set方法 */ public Integer getState() { return state; } public void setState(Integer state) { this.state = state; } public Brand getBrand() { return brand; } public void setBrand(Brand brand) { this.brand = brand; } } EliminateBox: package Model; import javax.swing.*; import java.util.*; import java.util.Map; import java.util.stream.Collectors; public class EliminateBox { //消除区域 private static List Box=new ArrayList(); //存放消除牌的数据 /*迭代器清空集合方法*/ void deleteByBrandName(String name){ Iterator iterator = Box.iterator(); while (iterator.hasNext()){ //如果有下一个值 Brand next=iterator.next(); //获取下一个值 if (next.getName().equals(name)){ next.getParent().remove(next); iterator.remove(); } } } public void addBox(Brand brand){ //添加到消除区方法 Box.add(brand); /*牌的排序(根据名称)*/ Box.sort(Comparator.comparing(Brand::getName)); /*消除算法*/ Map map= Box.stream().collect(Collectors.groupingBy(Brand::getName));//获取牌的名称 Set key=map.keySet(); for (String s:key){ List brands=map.get(s); if (brands.size()==3){ deleteByBrandName(s); //调用迭代器消除方法 break; } } paint(); //调用方法 绘制到消除区 over(brand);//调用方法 判断游戏结束 } void paint(){ //绘制到消除区 for (int i = 0; i < Box.size(); i++) { Brand brand = Box.get(i); int x=i*brand.getWidth()+10; brand.setBounds(x,600,50,50); } } /*消除方法*/ void over(Brand brand){ if (Box.size()>=7){ //判断游戏结束 JOptionPane.showMessageDialog(brand,"游戏失败"); System.exit(0); } } }

Layer:

package Model; import java.util.Random; /* 图层类 二维表格 */ public class Layer { private Integer offsetx; /*设置偏移量*/ //x轴 private Integer offsety; //偏移量 y轴 private Integer rowNum; //有多少行 (行数) private Integer colNum; //有多少列 (列数) private Integer capacity; //当前图层能最多容纳的牌数量 最大容量 private Integer size; //图层 目前有多少牌 当牌添加的时候,需要改变值、当牌减少的时候,也需要改变值 private Layer parent; //上一层图层对象 private Cell[][] cells =null; public Layer(Integer rowNum, Integer colNum) throws Exception{ //构造函数,传递参数为行号和列号(因为其他属性都可以通过行号列号知道) this.rowNum = rowNum; this.colNum = colNum; this.capacity= this.rowNum * this.colNum; //容量为行数×列数 if(this.capacity%3!=0){ throw new Exception("容量不是3的倍数"); } this.cells=new Cell[this.rowNum][this.colNum]; //因为传递的是行号和列号,所以可以通过行号和列号创建对象. this.size=0; //默认为零 this.offsetx=new Random().nextInt(100); this.offsety=new Random().nextInt(100); //用随机数设置偏移量 } public void showCell(){ for (int row = 0; row < cells.length; row++) { for (int col = 0; col < cells[row].length; col++) { Brand brands1= cells[row][col].getBrand(); System.out.print(brands1.getName()+"-"); } System.out.println(); } } /* get/set方法 */ public Layer getParent() { return parent; } public void setParent(Layer parent) { this.parent = parent; } public Integer getOffsety() { return offsety; } public void setOffsety(Integer offsety) { this.offsety = offsety; } public Integer getOffsetx() { return offsetx; } public void setOffsetx(Integer offsetx) { this.offsetx = offsetx; } public Integer getRowNum() { return rowNum; } public void setRowNum(Integer rowNum) { this.rowNum = rowNum; } public Integer getColNum() { return colNum; } public void setColNum(Integer colNum) { this.colNum = colNum; } public Integer getCapacity() { return capacity; } public void setCapacity(Integer capacity) { this.capacity = capacity; } public Integer getSize() { return size; } public void setSize(Integer size) { this.size = size; } public Cell[][] getCells() { return cells; } public void setCells(Cell[][] cells) { this.cells = cells; } }

Map:

package Model; import Tool.MapUtil; import java.util.ArrayList; import java.util.List; //图层 public class Map { private Integer floorHeight; //层高 有几个图层 private List list=new ArrayList(); //存放图层数据 /* set/get */ public Integer getFloorHeight() { return floorHeight; } public void setFloorHeight(Integer floorHeight) { this.floorHeight = floorHeight; } public List getList() { return list; } public void setList(List list) { this.list = list; } /*判断当前map中所有牌是否置灰*/ public void compareAll(){ System.out.println("map.compareAll"); //i=0是最顶层layer,不需要判断 for (int i = 1; i < list.size(); i++) { Layer layer=list.get(i); Cell[][] cells=layer.getCells(); for (int row = 0; row < cells.length; row++) { for (int col = 0; col < cells[row].length; col++) { Cell cell=cells[row][col]; //先拿到单元格对象 if (cell.getState()==1){ Brand brand = cell.getBrand(); //有牌取牌 boolean result=MapUtil.compare(brand,layer.getParent()); brand.setGray(result); } } } } } }

然后是Tool工具包:

BrandUtil:

package Tool; import Model.Brand; import java.util.Random; /* 工具类 提供 创建牌相关的一些公共方法 */ public class BrandUtil { public static Random random =new Random(); public static String[] brandNames= {"风","岩","雷","草","水","火","冰"}; //牌名数组 public static String getBrandName(){ //随机获取一个牌的名称 int a=random.nextInt(brandNames.length); return brandNames[a]; } //创建随机牌 public static Brand[] buildBrands(Integer capcity){ //需要参数(数组大小) Brand brands[]=new Brand[capcity]; for (int i = 0; i < brands.length; i=i+3) { String randomBrandName=getBrandName(); //每次循环获取一个随机牌名称 Brand brand1=new Brand(randomBrandName); //名称传递,创建新的对象 Brand brand2=new Brand(randomBrandName); Brand brand3=new Brand(randomBrandName); //创建三个相同的对象,方便删除牌 brands[i]=brand1; brands[i+1]=brand2; brands[i+2]=brand3; } for (int i = 0; i < brands.length; i++) { //当前位置A的变量拿到 Brand brandA = brands[i]; //随机交换位置 int randomIndex=random.nextInt(brands.length); Brand brandB=brands[randomIndex]; Brand temp=brandA; brands[i]= brandB; brands[randomIndex]=temp; //交换 } return brands; } }

LayerUtil:

package Tool; import Model.Brand; import Model.Cell; import Model.Layer; public class LayerUtil { public static Layer build(Integer rowNum, Integer colNum) { Layer layer = null; try { layer = new Layer(rowNum, colNum); //容量需要为3的倍数,不然下面for循环因为i=i+3时,数组越界会报错 } catch (Exception e) { e.printStackTrace(); } Brand[] brands=BrandUtil.buildBrands(layer.getCapacity()); Cell cells[][] = layer.getCells(); int flag=0; for (int row = 0; row < cells.length; row++) { for (int col = 0; col < cells[row].length; col++) { // System.out.println(row+"-"+col); Brand brands1=brands[flag++]; Cell cell = new Cell(); //初始化单元格对象 cell.setState(1); cell.setBrand(brands1); //单元格对象找到我们牌 brands1.setCell(cell); //牌反向找到单元格对象, 互相链式关系 cells[row][col] = cell; //把之前空的图层设置了值 } } return layer; } }

MapUtil:

package Tool; import Model.Brand; import Model.Cell; import Model.Layer; import Model.Map; import java.awt.*; public class MapUtil { public static Map build(Integer floorHeight){ Map map=new Map(); map.setFloorHeight(floorHeight); Layer layer1= LayerUtil.build(3,5); Layer layer2= LayerUtil.build(9,4); Layer layer3= LayerUtil.build(6,4); Layer layer4= LayerUtil.build(6,9); Layer layer5= LayerUtil.build(3,3); Layer layer6= LayerUtil.build(10,9); Layer layer7= LayerUtil.build(3,8); Layer layer8= LayerUtil.build(9,6); Layer layer9= LayerUtil.build(6,9); Layer layer10= LayerUtil.build(6,12); Layer layer11= LayerUtil.build(6,5); Layer layer12= LayerUtil.build(4,9); Layer layer13= LayerUtil.build(5,9); Layer layer14= LayerUtil.build(7,9); Layer layer15= LayerUtil.build(9,9); Layer layer16= LayerUtil.build(2,9); Layer layer17= LayerUtil.build(5,9); Layer layer18= LayerUtil.build(4,9); layer1.setParent(null); //parent为null时已经是最后一层了 是循环递归结束的条件 layer2.setParent(layer1); layer3.setParent(layer2); //用链式关系把图层锁起来 layer4.setParent(layer3); layer5.setParent(layer4); layer6.setParent(layer5); layer7.setParent(layer6); layer8.setParent(layer7); layer9.setParent(layer8); layer10.setParent(layer9); layer11.setParent(layer10); layer12.setParent(layer11); layer13.setParent(layer12); layer14.setParent(layer13); layer15.setParent(layer14); layer16.setParent(layer15); layer17.setParent(layer16); layer18.setParent(layer17); map.getList().add(layer1); map.getList().add(layer2); map.getList().add(layer3); map.getList().add(layer4); map.getList().add(layer5); map.getList().add(layer6); map.getList().add(layer7); map.getList().add(layer8); map.getList().add(layer9); map.getList().add(layer10); map.getList().add(layer11); map.getList().add(layer12); map.getList().add(layer13); map.getList().add(layer14); map.getList().add(layer15); map.getList().add(layer16); map.getList().add(layer17); map.getList().add(layer18); return map; } public static boolean compare(Brand brand, Layer layer){ //判断当前牌和某一图层所有牌是否有矩阵交集,ture表示有交集,显示灰色,false表示没有交集,显示正常牌 Cell cells[][]=layer.getCells(); for (int row = 0; row < cells.length; row++) { for (int col = 0; col < cells[row].length; col++) { //如果当前单元格为空,cell不用比较 Cell cell=cells[row][col]; if(cell.getState()==1){ //单元格有牌,可以比较 Rectangle temp=cell.getBrand().getBounds(); Rectangle rect=brand.getBounds(); boolean result=rect.intersects(temp); //布尔类型判断是否有交集 if (result){ //有交集说明被上层牌盖住了 return result; //判定结束,结束方法 } } } System.out.println(); } /*如果跳出了上面的循环,说明都没有交集,需要和更上层进行对比*/ if (layer.getParent()!=null){ return compare(brand,layer.getParent()); //递归判定 }else{ //如果getparent等于null,说明已经到最顶层了 return false; } } }

好了只用这些就能完整的运行啦,细心的人可能发现了我没有发Test包里的东西 ,因为那只是用来做测试的!!!不过如果想要的话私聊我,我看看能不能把整个压缩包发给你.......

我这上面注释写的应该还算清楚,应该不难理解吧,不过为了以防万一,我还是说一下一些关键可修改的地方

首先是MapUtil类里面的,这个包是不是看到很多重复的代码块(不是为了凑代码行数!!)

这是为了创建不同的图层,这个游戏可以理解为有很多图层叠在一起,然后这里就是设置图层的个数,每创建一组就多一层图层。

 这一行是设置图层的长rowNum和宽colNum的 (注意长和宽的乘积一定要是3的倍数,最简单的方法就是其中一个是3或者3的倍数,不然会报错,因为在LayerUtil类里设置了捕获异常,捕获的是BrandUtil类里,因为Brand对象是三个三个创建的,如果不是三的倍数会出现数组越界)

 这一行是为了让后一个图层把上一层图层联系起来,层与层之间互相关联,比如这个图就是layer3与layer2锁在一起,让layer3的父层为layer2,如果要新添加图层的话,新添加的图层也需要把上一层设置为父层。

 这一条代码是为了让图层显示出来,如果没有这一行,你的图层将不会渲染到游戏里,add括号内写哪一层就渲染哪一层。

这三条语句可以看为一个整体,如果要添加或者删除图层的话,只需要修改对应的这三条语句就可以了。

然后是BrandUtil类里

 brandNames数组里是你的图片名称,你可以随意修改(前提是找得到图片),图片在imgs文件夹下,和Total_class是同级的,注意你也要创建一个imgs文件夹来存放图片,不然就进入brand类里面,把这个imgs改成你文件的名字

特别说一下,设置的图层偏移量是在Play类里面,写的有注释,可以自行查找也可以不改,还有就是每个图层的长宽比不要太大,不然会出现你不想看到的结果(指bug)。

 其他的有注释,能看懂的应该都能看懂,看不懂的那我也没办法,照抄就好了。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3