赞
踩
具体的可查看
Java-黄金矿工(一)
Java-黄金矿工(二)
Java-黄金矿工
①服务端与客户端通讯,互相发送各个状态,以达到相对同步;
②共3个界面:服务端、客户端、游戏界面;
③倒计时结束,根据双方的金钱进行判断输赢。
首先在publicmain中新建变量:state_miner1和state_miner2,分别表示矿工1和矿工2的状态:
public static int state_miner1 = 0, state_miner2 = 0;
然后新建Miner.java:
public class Miner {//矿工 public static int money1 = 0,money2 = 0;//矿工1和2的钱 public static int state1 = 1,state2 = 1;//矿工1和2的状态,3种状态 private Image minerState1 = Toolkit.getDefaultToolkit().getImage("imgs/minerState1.jpg"); private Image minerState2 = Toolkit.getDefaultToolkit().getImage("imgs/minerState2.jpg"); private Image minerState3 = Toolkit.getDefaultToolkit().getImage("imgs/minerState3.gif"); //状态1:普通状态,手在上,没有放线 //状态2:放线状态,手在下,正在放线 //状态3:是个动图,这个里面好像看不了,是抓住金块后,往上拉 void paintSelf(Graphics g){ if (publicMeans.isServer){ if (state1 == 1){ g.drawImage(minerState1,372,51,null); } else if (state1 == 2) {//矿工也变了 g.drawImage(minerState2,372,51,null); } else if (state1 == 3) { g.drawImage(minerState3,372,51,null); } if (state2 == 1){ g.drawImage(minerState1,495,51,null); } else if (state2 == 2) { g.drawImage(minerState2,495,51,null); } else if (state2 == 3) { g.drawImage(minerState3,495,51,null); } } else{ if (publicMeans.state_miner1 == 1){ g.drawImage(minerState1,372,51,null); } else if (publicMeans.state_miner1 == 2) { g.drawImage(minerState2,372,51,null); } else if (publicMeans.state_miner1 == 3) { g.drawImage(minerState3,372,51,null); } if (publicMeans.state_miner2 == 1){ g.drawImage(minerState1,495,51,null); } else if (publicMeans.state_miner2 == 2) { g.drawImage(minerState2,495,51,null); } else if (publicMeans.state_miner2 == 3) { g.drawImage(minerState3,495,51,null); } } } }
import java.awt.*; public class Object {//这里是新建一个类,代表金块,下面是金子的属性,坐标,尺寸,图片,价值就是钱,还有flag标志 public int x,y;//坐标 public int width,height;//尺寸 public Image img;//图片 public int money = 0; public int flag;//0=能移动 1=被矿工1抓住 2=被矿工2抓住 3=抓取完成被扔出 void paintSelf(Graphics g){ g.drawImage(img,x,y,null); } public Rectangle getRec(){ return new Rectangle(x,y,width,height); } public static Image bigGold = Toolkit.getDefaultToolkit().getImage("imgs/bigGold.png"); public static Image middleGold = Toolkit.getDefaultToolkit().getImage("imgs/middleGold.png"); public static Image smallGold = Toolkit.getDefaultToolkit().getImage("imgs/smallGold.png"); } class BigGold extends Object{//大金块继承上面的金块类 BigGold(){//Math.random()是[0,1]的随机数 //金块位置:地下的下半部分x∈[0,852],y∈[420,598] //横坐标 852=985-133:985是窗口宽度,133是金块宽度,坐标是指左上角坐标,所以金块坐标不能超过985-133 //如果超过了,就会超出画面 //纵坐标同理 int a = (int)(Math.random()*852); int b = (int)(Math.random()*178+420);//纵坐标 719-121=598 598/2=299 719-299=420 598-420=178 int c = 133;//宽度 int d = 121;//高度 this.x = a; this.y = b; this.width = c; this.height = d; this.img = Toolkit.getDefaultToolkit().getImage("imgs/bigGold.png"); this.flag = 0;//初始为0,代表金块可以被抓取 this.money = 120;//大金子价值120元 } } //下面的中等金块和小金子同理 class MiddleGold extends Object{ MiddleGold(){ //金块位置:地下的下半部分x∈[0,913],y∈[151,653] int a = (int)(Math.random()*913);//横坐标 985-72=913 int b = (int)(Math.random()*477+176);//纵坐标 719-66=653 653-176=477 int c = 72;//宽度 int d = 66;//高度 this.x = a; this.y = b; this.width = c; this.height = d; this.img = Toolkit.getDefaultToolkit().getImage("imgs/middleGold.png"); this.flag = 0; this.money = 60;//中金子60元 } } class SmallGold extends Object{ SmallGold(){ //金块位置:地下的下半部分x∈[0,961],y∈[151,697] int a = (int)(Math.random()*961);//横坐标 985-24=961 int b = (int)(Math.random()*521+176);//纵坐标 719-22=697 697-176=521 int c = 24;//宽度 int d = 22;//高度 this.x = a; this.y = b; this.width = c; this.height = d; this.img = Toolkit.getDefaultToolkit().getImage("imgs/smallGold.png"); this.flag = 0; this.money = 20;//小金子20元 } }
import java.awt.*; public class Line {//线 GameFrame frame; Line(GameFrame frame){this.frame = frame;} //判断线是否触碰到金块,若触碰到,则线的状态为3(抓取收回),金块的状态为1/2(被矿工1或2抓住) //只有在金块的状态为0的情况下,金块才可以被抓取 void logic(){ for(Object obj:this.frame.objectList){//遍历金子 if (obj.flag == 0){//如果线的末端坐标碰到金子了 此时线的状态为1(抓取状态)时才可以抓到金子 if (endX1 > obj.x && endX1 < obj.x + obj.width && endY1 > obj.y && endY1 < obj.y + obj.height && Line.state1 == 1){ state1 = 3;//就改线的状态 抓取收回=3 obj.flag = 1;//改金子的状态 1:被矿工1抓住 } if (endX2 > obj.x && endX2 < obj.x + obj.width && endY2 > obj.y && endY2 < obj.y + obj.height && Line.state2 == 1){ state2 = 3; obj.flag = 2;//这里是矿工2抓住 } } } } public static int x1 = 410,y1 = 117,endX1,endY1;//矿工1的起点坐标和终点坐标 public static int x2 = 530,y2 = 117,endX2,endY2;//矿工2的起点坐标和终点坐标 public static double length1 = 50, length2 = 50;//线长 public static double angle1 = 0.9, angle2 = 0.1;//角度,与x轴的夹角 public static int dir1 = -1, dir2 = 1;//方向:顺时针=1 逆时针=-1 public static int state1 = 0, state2 = 0;//线的状态:摇摆=0 抓取=1 收回(未抓到)=2 抓取收回=3 void paintSelf(Graphics g){ if (publicMeans.isServer){ logic();//看这个方法 一直重绘,一直重绘 g.setColor(new Color(51,51,51));//线的颜色 switch (state1){ case 0://摇摆(线与x轴的角度发生变化),此时就是状态0 if (angle1 < 0.1) { dir1 = 1; } else if (angle1 > 0.9) { dir1 = -1; } angle1 += 0.005 * dir1;//角度每次都变化一点点,因为画面一直在重绘,就是repaint lines1(g);//看这个,这会就是画好线了,只要是线的状态是0,就一直在摇摆 break; case 1://抓取(线变长),如果线的末端坐标在窗体内,则继续延长 状态1,去抓取,线延长 现在就去抓取了 endX1 = (int)(x1 + length1 * Math.cos(angle1 * Math.PI)); endY1 = (int)(y1 + length1 * Math.sin(angle1 * Math.PI)); if (endX1>0 && endX1<985 && endY1<719){//这里的985*719是窗口大小,如果末端坐标没有到达窗口边缘,就会一直延长 length1 += 10; lines1(g);//画线 } else{ state1 = 2; }//如果到达窗口边缘了,就收回,即状态2,没有抓到的收回线 break; case 2://收回(线变短) 没有抓到金块 Miner.state1 = 3;//此时矿工状态变为3,拉回的动态图 if (length1 > 50){//为什么>50,因为线的初始长度是50,线的状态为0时,线长一直是50在摇摆 length1 -= 10;//线长度减小 lines1(g);//画线 } else{ state1 = 0; Miner.state1 = 1; }//如果到了50,就改变线的状态为0,摇摆状态,同时改变矿工的状态为1,普通状态 break; case 3://抓取收回(线变短,令金块的位置=线的末端坐标,这样可以使金块跟着线走) //状态3,抓到金块了,线收回,被抓到的金块的坐标也跟着变化 if (length1 > 50){//一样,线长>50就一直往回收,去看金块类,回到线这里 for(Object obj:this.frame.objectList){//遍历刚才存储的金块集合 if (obj.flag == 1){//金块状态是1,代表金块被矿工1抓住 Miner.state1 = 3;//矿工1要往上拉,矿工1的状态变成3,动图的那个 if(obj.width == 133){//如果金块的宽是133,代表是大金子 obj.x = endX1 - 66;//就把大金子的坐标放在线的末端,为什么要-66,线的末端要拉住金子的中间部分 obj.y = endY1; length1 -= 0.5;//大金子比较重,所以线收的比较慢,线的长度也要减小的小一点 lines1(g);//画线 } else if(obj.width == 72){ obj.x = endX1 - 36; obj.y = endY1; length1 -= 1;//这里是中金子,线回收的比大金子快 lines1(g);//画线 } else if (obj.width == 24) { obj.x = endX1 - 12; obj.y = endY1; length1 -= 1.2;//这里是小金子,线回收的比中金子快 lines1(g);//画线 } //如果length小于初始长度了,则把金块扔出去,即更改金块的坐标为画面外 //同时修改金块的状态为3(金块抓取完成被扔出) //同时修改线的状态0(摇摆) if(length1 <= 50){//回收的过程中,检测到length<50了, obj.x = -150; obj.y = -150;//金子坐标放在画面外 obj.flag = 3;//金子状态改为3=抓取完成被扔出 state1 = 0;//线的状态为0,摇摆 Miner.state1 = 1;//矿工1的状态变为1,普通状态 Miner.money1 += obj.money;//把钱添加到矿工1的钱里面 } } } } break; } switch (state2){//这里是线2 基本和线1一样 case 0: if (angle2 < 0.1) { dir2 = 1; } else if (angle2 > 0.9) { dir2 = -1; } angle2 += 0.005 * dir2; lines2(g); break; case 1: endX2 = (int)(x2 + length2 * Math.cos(angle2 * Math.PI)); endY2 = (int)(y2 + length2 * Math.sin(angle2 * Math.PI)); if (endX2>0 && endX2<985 && endY2<719){ length2 += 10; lines2(g); } else{ state2 = 2; } break; case 2: Miner.state2 = 3; if (length2 > 50){ length2 -= 10; lines2(g); } else{ state2 = 0; Miner.state2 = 1; } break; case 3: if (length2 > 50){ Miner.state2 = 3; for(Object obj:this.frame.objectList){ if (obj.flag == 2){ if (obj.width == 133){ obj.x = endX2 - 66; obj.y = endY2; length2 -= 0.5; lines2(g); } else if(obj.width == 72){ obj.x = endX2 - 36; obj.y = endY2; length2 -= 1; lines2(g); } else if(obj.width == 24){ obj.x = endX2 - 12; obj.y = endY2; length2 -= 0.8; lines2(g); } if (length2 <= 50){ obj.x = -150; obj.y = -150; obj.flag = 3; state2 = 0; Miner.state2 = 1; Miner.money2 += obj.money; } } } } break; } } else{ g.drawLine(x1,y1,publicMeans.endX1,publicMeans.endY1); g.drawLine(x1-1,y1,publicMeans.endX1-1,publicMeans.endY1); g.drawImage(hook,(int)(x1+publicMeans.length1*Math.cos(publicMeans.angle1*Math.PI)-10), (int)(y1+publicMeans.length1*Math.sin(publicMeans.angle1*Math.PI)-10),null); g.drawLine(x2,y2,publicMeans.endX2,publicMeans.endY2); g.drawLine(x2-1,y2,publicMeans.endX2-1,publicMeans.endY2); g.drawImage(hook,(int)(x2+publicMeans.length2*Math.cos(publicMeans.angle2*Math.PI)-10), (int)(y2+publicMeans.length2*Math.sin(publicMeans.angle2*Math.PI)-10),null); } } private Image hook = Toolkit.getDefaultToolkit().getImage("imgs/hookBall.png"); void lines1(Graphics g){//获取末端坐标,矿工1的线 endX1 = (int)(x1 + length1 * Math.cos(angle1 * Math.PI)); endY1 = (int)(y1 + length1 * Math.sin(angle1 * Math.PI));//获取到了线的末端坐标,下面就是画线了 //两句g.drawLine为了加粗线 g.drawLine(x1,y1,endX1,endY1); g.drawLine(x1-1,y1,endX1-1,endY1); //画粉色小球,小球大小是20*20 g.drawImage(hook,(int)(x1+length1*Math.cos(angle1*Math.PI)-10),(int)(y1+length1*Math.sin(angle1*Math.PI)-10),null); } void lines2(Graphics g){//画线2的,就是矿工2的线 endX2 = (int)(x2 + length2 * Math.cos(angle2 * Math.PI)); endY2 = (int)(y2 + length2 * Math.sin(angle2 * Math.PI)); g.drawLine(x2,y2,endX2,endY2); g.drawLine(x2-1,y2,endX2-1,endY2); g.drawImage(hook,(int)(x2+length2*Math.cos(angle2*Math.PI)-10),(int)(y2+length2*Math.sin(angle2*Math.PI)-10),null); } }
import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class Hook { private BufferedImage hook1,hook2; { try { hook1 = ImageIO.read(new File("imgs\\hook.png")); hook2 = ImageIO.read(new File("imgs\\hook.png")); } catch (IOException e) { throw new RuntimeException(e); } } int w = hook1.getWidth(); int h = hook1.getHeight(); public void paintSelf1(Graphics g) { hookMain(g,hook1,Line.endX1,Line.endY1,Line.angle1); } public void paintSelf2(Graphics g){ hookMain(g,hook2,Line.endX2,Line.endY2,Line.angle2); } private void hookMain(Graphics g,BufferedImage hook,int x,int y,double angle){ Graphics2D g2 = (Graphics2D)g; g2.translate(x - 22,y); g2.rotate(angle,w >> 1,h >> 1); g2.drawImage(hook,0,0,w,h,0,0,w,h,null); g2.translate(-x + 22,-y); } }
public class Bg {//背景类 Image bgUp = Toolkit.getDefaultToolkit().getImage("imgs/Up.jpg");//上方 Image bgDown = Toolkit.getDefaultToolkit().getImage("imgs/down.jpg");//下方 void paintSelf(Graphics g){ g.drawImage(bgUp,0,30,null);//(0,30)在窗口里面的坐标 g.drawImage(bgDown,0,151,null);//在窗口里面的坐标 g.setColor(new Color(143,112,1));//设置字体颜色 g.setFont(new Font("幼圆",Font.BOLD,20));//设置字体“幼圆”,加粗,字号20 //下面是写金钱和倒计时的 if (publicMeans.isServer){//服务端就直接写Miner.money的 g.drawString("金钱:" + Miner.money1,275,60); g.drawString("金钱:" + Miner.money2,609,60);//495+114=609 g.setFont(new Font("幼圆",Font.BOLD,20));//倒计时的字体 g.drawString("时间:" + GameFrame.ss + "秒",800,60);//服务端就直接调用那个ss } else {//客户端就写publicMeans里面的 g.drawString("金钱:" + publicMeans.money1,275,60); g.drawString("金钱:" + publicMeans.money2,609,60);//495+114=609 g.setFont(new Font("幼圆",Font.BOLD,20)); g.drawString("时间:" + publicMeans.timeSs + "秒",800,60); } } }
import javax.swing.*; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; public class GameFrame extends JFrame {//新建界面 //这个画面是用paint画的 Bg bg = new Bg();//背景类 Miner miner = new Miner();//矿工 Line line = new Line(this);//线,这个东西比较多 end Image canvasImage; BigGold bigGold;//大金块 MiddleGold middleGold;//中等金块 SmallGold smallGold;//小金子 boolean isOverlap = false; List<Object> objectList = new ArrayList<>();//存储金块、石块 private void CreateGold()//这个是把创建金子放在了方法里面 {//新建list集合,放置金子 //这里我随便设的,大金子最多5个,中金子最多8个,小金子最多10个 for (int i = 0; i < 5; i++){ bigGold = new BigGold();//新建大金子 for(Object obj:objectList){//需要遍历集合里的所有金块 if (bigGold.getRec().intersects(obj.getRec())){//这个是判断两个金块有没有重叠 isOverlap = true;//如果有重叠了,就isOverlap=true break;//跳出 } } //遍历完成后,没有发现重叠,就把金子放到集合里面 if (!isOverlap){objectList.add(bigGold);} else{isOverlap = false;}//重置这个isOverlap,因为下面的中金子和小金子还要用它 } for(int i = 0; i < 8; i++){ middleGold = new MiddleGold(); for(Object obj:objectList){ if (middleGold.getRec().intersects(obj.getRec())){ isOverlap = true; break; } } if (!isOverlap) {objectList.add(middleGold);} else{isOverlap = false;} } for(int i = 0; i < 10; i++){ smallGold = new SmallGold(); for(Object obj:objectList){ if (smallGold.getRec().intersects(obj.getRec())){ isOverlap = true; break; } } if (!isOverlap) {objectList.add(smallGold);} else{isOverlap = false;} } //这里的中金子和小金子一样,和大金子一样 } private boolean isFirst = true; //倒计时 private static int time = 60;//秒 private static int num = 0;//新建一个int变量,记录一下金子集合也就是objectList里面有几个被抓完扔出了 void launch(){//publicMeans.isServer在一开始就已经判断过了 this.setVisible(true);//窗口是否可见 this.setBounds(publicMeans.GameWinX,publicMeans.GameWinY,publicMeans.GameWinW,publicMeans.GameWinH); //如果是服务端,就设置服务端的窗口标题为"黄金矿工联机版(server)" if (publicMeans.isServer){this.setTitle("黄金矿工联机版(server)");} //如果是客户端,就为"黄金矿工联机版(client)" else {this.setTitle("黄金矿工联机版(client)");} this.setResizable(false);//窗口不能更改大小 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);//关闭窗口的方法 //EXIT_ON_CLOSE是关闭整个进程,DISPOSE_ON_CLOSE只关闭当前界面,DO_NOTHING_ON_CLOSE不能关闭 //然后是按键,↓,e.getKeyCode() == 40,这里的40指的就是↓键 addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { //首先,在服务端摁↓,直接,改变线的状态,0摇摆变为1放线,矿工状态1手在上变为2手在下 //这里摁完后,状态改变了 if (publicMeans.isServer && Line.state1 == 0 && e.getKeyCode() == 40) {Line.state1 = 1; Miner.state1 = 2;} //看客户端,在客户端摁↓,客户端想服务端发送"keys:40;" if (!publicMeans.isServer && publicMeans.state_line2 == 0 && e.getKeyCode() == 40) { Client.Send("keys:" + 40 + ";");//这里是客户端,要根据publicMeans里线2的状态判断 } } }); if (publicMeans.isServer){timer();} //timer();//调用刚才写的那个方法 CreateGold();//创造金子 因为把创造金子的代码放进这个方法里面了,所以需要调用执行 String message = ""; while (true){//先看这里,这里是个死循环,代表一直在重绘 //在死循环里判断isEnd是否为true if (publicMeans.isEnd){ //如果为true,则表示游戏结束 publicMeans.isEnd = false;//重置一下这个变量,防止再次开始游戏时有bug //跳出之前需要判断一下赢家+刷新数据 JudgeWinner();//判断赢家 IniData();//刷新数据 Close();//关闭界面 break;//跳出循环 } if (publicMeans.isServer){ //这里是服务端 我这里写了两套变量 //这一行,判断刚才那个变量是否为40,若是,就代表客户端摁了↓,改变矿工2的状态和线的状态,然后把这个变量置为0 //因为如果不置为0,这个循环会一直进来,矿工2和线的状态一直是这样,所以要置为0 if (publicMeans.clientKey == 40){Line.state2 = 1;Miner.state2 = 2;publicMeans.clientKey = 0;} repaint();//重绘 UpdateThis();//更新第一套 //下面的if就是判断第一套和第二套有什么不一样 //有不一样的就放进message里面,并且加上说明 比如上次是1,这次是2 //比如第一个,矿工1的状态不一样了,就把 "miner1:2;" 这一段添加到message中 //数据格式"miner1:0;miner2:0;" 注意这个分号 if (state_miner1 != Last_state_miner1){message += "miner1:" + state_miner1 + ";";} if (state_miner2 != Last_state_miner2){message += "miner2:" + state_miner2 + ";";} if (state_line1 != Last_state_line1 || endX1 != Last_endX1 || endY1 != Last_endY1 || length1 != Last_length1 || dir1 != Last_dir1){ message += "line1:" + Line.state1 + " " + Line.endX1 + " " + Line.endY1 + " " + Line.angle1 + " " + Line.length1 + " " + Line.dir1 + ";"; } if (state_line2 != Last_state_line2 || endX2 != Last_endX2 || endY2 != Last_endY2 || length2 != Last_length2 || dir2 != Last_dir2){ message += "line2:" + Line.state2 + " " + Line.endX2 + " " + Line.endY2 + " " + Line.angle2 + " " + Line.length2 + " " + Line.dir2 + ";"; } if (money1 != Last_money1){message += "money1:" + money1 + ";";} if (money2 != Last_money2){message += "money2:" + money2 + ";";} //现在准备给客户端传值,传倒计时 if (timeSs != Last_timeSs){message += "time:" + timeSs + ";";}//现在已经把倒计时添加到message里面了 //看这里,这里用isFirst,是为了让if里面的语句走一次 //因为首先要把objectList里面的金子都发给客户端,让客户端去画 //然后不能每次都发送所有的,因为金子不是一直都在变化的,只有被抓取后金子才会改变 if (isFirst){ for (Object obj:objectList){ message += "firstGold:" + obj.x + " " + obj.y + " " + obj.width + ";"; } isFirst = false; } for (int i = 0; i < Last_gold.size(); i++){ //这里本来是应该走被注释掉的代码,但是还不知道为什么有bug,就是不会进入if语句 //现在也能正常运行 message += "gold:" + i + " " + gold.get(i).x + " " + gold.get(i).y + " " + gold.get(i).flag + ";"; // if (gold.get(i).x != Last_gold.get(i).x || gold.get(i).y != Last_gold.get(i).y || gold.get(i).flag != Last_gold.get(i).flag){ // message += "gold:" + i + " " + gold.get(i).x + " " + gold.get(i).y + " " + gold.get(i).flag + ";"; // System.out.println("gold:" + i + " " + gold.get(i).x + " " + gold.get(i).y + " " + gold.get(i).flag); // } } //以上就是把改变的数据放在message中 Server.Send(message);//这个就是刚才写的“发送” 这里一起发送 然后客户端去解析 message = ""; UpdateLast();//运行完1遍后更新第二套 //为什么?因为要根据这两套变量判断有哪些数据发生变化了,如果发生变化了,就把它们放进一个字符串里,最后发送给客户端 //客户端读取并解析这些变量,并展示到客户端的界面上 //所以说服务端的数据和客户端的数据是两套数据 //服务端需要一直把变化的数据发给客户端 //这里是在一直循环的,我们可以在这里实时检测金子有没有被抓完 //如果金子的flag=3,代表金子被抓完丢掉了 if (!isFirst){ for (Object obj:objectList){ if (obj.flag == 3){num++;} } if (num == objectList.size()){ //如果num=集合里的金子数量,表示所有的金子都被抓住扔出了 Server.Send("游戏结束");//告诉客户端游戏结束了 去解析一下 publicMeans.isEnd = true; timer.cancel();//关闭倒计时的那个定时器 } num = 0;//重置一下num,要不num会一直加 } } else { repaint();//重绘 } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public static String winner = "null"; public static void JudgeWinner(){ //判断赢家 if (publicMeans.isServer){ //服务端就直接通过Miner.money判断 if (Miner.money1 > Miner.money2){ winner = "玩家1获胜。"; } else if (Miner.money1 < Miner.money2) { winner = "玩家2获胜。"; } else { winner = "平手。"; } Server.textArea.append("游戏结束," + winner + "\r\n");//打印到服务端的文本框中 } else { //客户端就需要判断publicMeans里面的变量 if (publicMeans.money1 > publicMeans.money2){ winner = "玩家1获胜。"; } else if (publicMeans.money1 < publicMeans.money2) { winner = "玩家2获胜。"; } else { winner = "平手。"; } Client.textArea.append("游戏结束," + winner + "\r\n");//打印到客户端的文本框中 } } //刷新数据,如果不刷新数据,再次点击开始游戏时,画面会出现问题 public void IniData(){ Miner.state1 = 1;Miner.state2 = 1;Miner.money1 = 0;Miner.money2 = 0; objectList.clear(); Line.state1 = 0;Line.length1 = 50;Line.angle1 = 0.9;Line.dir1 = -1; Line.state2 = 0;Line.length2 = 50;Line.angle2 = 0.1;Line.dir2 = 1; gold.clear(); Last_state_miner1 = Integer.MAX_VALUE; Last_state_miner2 = Integer.MAX_VALUE; Last_state_line1 = Integer.MAX_VALUE; Last_endX1 = Integer.MAX_VALUE; Last_endY1 = Integer.MAX_VALUE; Last_dir1 = Integer.MAX_VALUE; Last_state_line2 = Integer.MAX_VALUE; Last_endX2 = Integer.MAX_VALUE; Last_endY2 = Integer.MAX_VALUE; Last_dir2 = Integer.MAX_VALUE; Last_angle1 = Double.MAX_VALUE; Last_length1 = Double.MAX_VALUE; Last_angle2 = Double.MAX_VALUE; Last_length2 = Double.MAX_VALUE; Last_gold.clear(); Last_money1 = Integer.MAX_VALUE; Last_money2 = Integer.MAX_VALUE; Last_timeSs = Integer.MAX_VALUE; publicMeans.gold.clear(); publicMeans.timeSs = -1; time = 60; isFirst = true; num = 0; } //新建一个关闭窗口的方法,需要的时候直接调用就可以 public void Close(){ this.setVisible(false); this.dispose(); Server.btBegin.setEnabled(true); } //现在判断游戏是否结束 :1.倒计时结束 2.金子被抓完 public static int ss; private static Timer timer = null;//timer是定时器 private static void timer(){ timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { time--; ss = time % 60;//ss就是剩余时间 if (ss == 0){ //如果ss=0了,说明倒计时结束,游戏结束 就是这里 Server.Send("游戏结束"); publicMeans.isEnd = true; timer.cancel();//停止这个定时器 } } },0,1000);//1000是指1000ms毫秒,也就是1秒执行1次 } @Override public void paint(Graphics g) {//绘制画面 刚才的repaint是一直走的这个paint方法 canvasImage = this.createImage(985,719);//这里是新建一个画布,把所有的东西放在上面 Graphics gCanvasImage = canvasImage.getGraphics(); bg.paintSelf(gCanvasImage);//把背景放在上面 miner.paintSelf(gCanvasImage);//矿工 line.paintSelf(gCanvasImage);//线 //金子 这里的金子绘制,服务端就直接用objectList if (publicMeans.isServer){ for (Object obj:objectList){ obj.paintSelf(gCanvasImage); } } else {//客户端就使用publicMeans.gold for (Object obj:publicMeans.gold){ obj.paintSelf(gCanvasImage); } } g.drawImage(canvasImage,0,0,null);//把画布画出来 } //第1套 public static int state_miner1 = 0, state_miner2 = 0; public static int state_line1 = 0, endX1 = 0, endY1 = 0, dir1 = -1; public static int state_line2 = 0, endX2 = 0, endY2 = 0, dir2 = 1; public static double angle1 = 0.9, length1 = 50; public static double angle2 = 0.1, length2 = 50; public static List<Object> gold = new ArrayList<>(); public static int money1 = 0, money2 = 0; public static int timeSs = 0; //第2套 public static int Last_state_miner1 = Integer.MAX_VALUE, Last_state_miner2 = Integer.MAX_VALUE; public static int Last_state_line1 = Integer.MAX_VALUE, Last_endX1 = Integer.MAX_VALUE, Last_endY1 = Integer.MAX_VALUE, Last_dir1 = Integer.MAX_VALUE; public static int Last_state_line2 = Integer.MAX_VALUE, Last_endX2 = Integer.MAX_VALUE, Last_endY2 = Integer.MAX_VALUE, Last_dir2 = Integer.MAX_VALUE; public static double Last_angle1 = Double.MAX_VALUE, Last_length1 = Double.MAX_VALUE; public static double Last_angle2 = Double.MAX_VALUE, Last_length2 = Double.MAX_VALUE; public static List<Object> Last_gold = new ArrayList<>(); public static int Last_money1 = Integer.MAX_VALUE, Last_money2 = Integer.MAX_VALUE; public static int Last_timeSs = Integer.MAX_VALUE;//这里把last的初始值设置为int的最大值 //因为在第一次进入界面时,肯定要把所有的数据发送给客户端一遍,然后再发送变化的值 private void UpdateThis(){ //是把当前的所有状态(矿工、线、钱和金子)都更新到第一套变量里面 这一次的数据 state_miner1 = Miner.state1; state_miner2 = Miner.state2; state_line1 = Line.state1; endX1 = Line.endX1; endY1 = Line.endY1; dir1 = Line.dir1; state_line2 = Line.state2; endX2 = Line.endX2; endY2 = Line.endY2; dir2 = Line.dir2; angle1 = Line.angle1; length1 = Line.length1; angle2 = Line.angle2; length2 = Line.length2; money1 = Miner.money1; money2 = Miner.money2; timeSs = ss; gold.clear(); for (Object obj:objectList){gold.add(obj);} } private void UpdateLast(){ //这里是把第一套更新到第二套里面 Last是指上一次的数据 Last_state_miner1 = state_miner1; Last_state_miner2 = state_miner2; Last_state_line1 = state_line1; Last_endX1 = endX1; Last_endY1 = endY1; Last_dir1 = dir1; Last_state_line2 = state_line2; Last_endX2 = endX2; Last_endY2 = endY2; Last_dir2 = dir2; Last_angle1 = angle1; Last_length1 = length1; Last_angle2 = angle2; Last_length2 = length2; Last_money1 = money1; Last_money2 = money2; Last_timeSs = timeSs; Last_gold.clear(); for (Object obj1:gold){Last_gold.add(obj1);} } }
import java.io.*; import java.net.Socket; public class ServerThread extends Thread{//extends Thread创建服务端线程 private Socket socket = null; //public ServerThread(Socket socket){this.socket = socket;} //接收来自客户端信息的相关变量 public InputStream is = null; public InputStreamReader isr = null; public static BufferedReader br = null; public static String info = null; //向客户端发送信息的相关变量 public OutputStream os = null; public PrintWriter pw = null; @Override public void run() {//刚才的线程开启后,自动执行run try{ socket = Server.serverSocket.accept();//等待客户端连接,若没有连接,就会一直在这一行代码等着,若连接了,就会下一步 publicMeans.isServer = true;//表示这个窗口是服务端 publicMeans.isConn = true;//这里表示客户端连接了,所以把isConn置为true Server.textArea.append("连接成功。\r\n");//把这句话添加到textArea中 os = socket.getOutputStream(); pw = new PrintWriter(os);//这两个是向客户端发送信息的相关变量 is = socket.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr);//这三个事接收客户端信息的变量 while(true){//这里使用死循环,是因为要一直监视客户端有没有发过来信息 while((info = br.readLine()) != null){//刚才的"keys:40;"就来这里了 //br.readLine()就是读取客户端发过来的信息,br.readLine()读取一行,然后使用while((info = br.readLine()) != null) //读取发过来的所有信息 Analysis();//解析客户端发过来的信息 } } }catch (Exception e){} } private static String[] message = null; public static void Analysis(){//解析客户端发来的信息 message = info.split(";"); for (int i = 0; i < message.length; i++){ if (message[i].startsWith("keys:")){ publicMeans.clientKey = 40;//然后把这个变量改变 } } } }
import java.io.*; import java.net.Socket; public class ServerThread extends Thread{//extends Thread创建服务端线程 private Socket socket = null; //public ServerThread(Socket socket){this.socket = socket;} //接收来自客户端信息的相关变量 public InputStream is = null; public InputStreamReader isr = null; public static BufferedReader br = null; public static String info = null; //向客户端发送信息的相关变量 public OutputStream os = null; public PrintWriter pw = null; @Override public void run() {//刚才的线程开启后,自动执行run try{ socket = Server.serverSocket.accept();//等待客户端连接,若没有连接,就会一直在这一行代码等着,若连接了,就会下一步 publicMeans.isServer = true;//表示这个窗口是服务端 publicMeans.isConn = true;//这里表示客户端连接了,所以把isConn置为true Server.textArea.append("连接成功。\r\n");//把这句话添加到textArea中 os = socket.getOutputStream(); pw = new PrintWriter(os);//这两个是向客户端发送信息的相关变量 is = socket.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr);//这三个事接收客户端信息的变量 while(true){//这里使用死循环,是因为要一直监视客户端有没有发过来信息 while((info = br.readLine()) != null){//刚才的"keys:40;"就来这里了 //br.readLine()就是读取客户端发过来的信息,br.readLine()读取一行,然后使用while((info = br.readLine()) != null) //读取发过来的所有信息 Analysis();//解析客户端发过来的信息 } } }catch (Exception e){} } private static String[] message = null; public static void Analysis(){//解析客户端发来的信息 message = info.split(";"); for (int i = 0; i < message.length; i++){ if (message[i].startsWith("keys:")){ publicMeans.clientKey = 40;//然后把这个变量改变 } } } }
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.Socket; public class Client extends JFrame { public static JTextArea textArea = new JTextArea(5,10); private static JScrollPane scrollPane; private static JLabel labelIP = new JLabel("IP:"); private static JTextField textIP = new JTextField("127.0.0.1",10); private static JLabel labelPort = new JLabel("端口号:"); private static JTextField textPort = new JTextField("8088",10); public static JButton btConn = new JButton("连接"); void launch(){ this.setVisible(true); this.setSize(500,500); this.setLocationRelativeTo(null);//窗口位置:居中 this.setTitle("黄金矿工联机版(client)"); this.setResizable(false); setLayout(null);//设置布局 setDefaultCloseOperation(EXIT_ON_CLOSE); //textArea.setOpaque(false);//透明 textArea.setForeground(Color.black); textArea.setBackground(Color.white); textArea.setFont(new Font("幼圆",Font.BOLD,15)); textArea.setEnabled(false);//只读 textArea.setBounds(0,0,500,200); scrollPane = new JScrollPane(textArea); scrollPane.setBounds(0,0,500,200); //"IP:" labelIP.setFont(new Font("幼圆",Font.PLAIN,15)); labelIP.setBounds(145,250,100,20); //输入IP地址的文本框 textIP.setFont(new Font("幼圆",Font.PLAIN,15)); textIP.setBounds(238,250,100,20); //“端口:” labelPort.setFont(new Font("幼圆",Font.PLAIN,15)); labelPort.setBounds(145,300,100,20); //输入端口号的文本框 textPort.setFont(new Font("幼圆",Font.PLAIN,15)); textPort.setBounds(238,300,100,20); //连接按钮 btConn.setFont(new Font("幼圆",Font.PLAIN,15)); btConn.setBounds(200,350,100,30); btConn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //比如“ 123 ”,加了.trim就会得到“123” publicMeans.ip = textIP.getText().trim();//获取输入的IP,就是textIP里面的 .trim()的意思是删除文本框里面内容前后的空格 publicMeans.port = Integer.parseInt(textPort.getText().trim());//因为port是int类型,所以要使用Integer.parseInt把string转为int BuildClient();//点击连接按钮后,去创建客户端 } }); this.add(scrollPane); this.add(labelIP); this.add(textIP); this.add(labelPort); this.add(textPort); this.add(btConn); } public static void main(String[] args){ Client client = new Client(); client.launch(); } private static Socket socket; private static ClientThread thread; public static void BuildClient(){//创建客户端 try{ thread = new ClientThread(socket);//跟刚才一样,创建一个客户端线程 thread.start(); }catch (Exception ignored){} } //客户发送信息时引用 public static void Send(String message){ thread.pw.write(message + "\r\n"); thread.pw.flush(); } //关闭客户端时引用 还有这个,暂时还没有用,但是最好可以加上 //在关闭客户端时调用这个方法,主动把socket和thread相关变量关掉 public void ShutDown(){ try{ if(thread.is != null){thread.is.close();} if(thread.isr != null){thread.isr.close();} if(thread.br != null){thread.br.close();} if(thread.os != null){thread.os.close();} if(thread.pw != null){thread.pw.close();} if(socket != null){socket.close();} }catch (Exception ignored){} } }
import java.io.*; import java.net.Socket; public class ClientThread extends Thread{//创建客户端线程 private Socket socket; public ClientThread(Socket socket){this.socket = socket;} //接收来自服务端信息的相关变量 public InputStream is = null; public InputStreamReader isr = null; public BufferedReader br = null; private static String info = null, infoAll = null; //向服务端发送信息的相关变量 public OutputStream os = null; public PrintWriter pw = null; OpenThread openThread; @Override public void run() {//线程开始,自动运行 try{ socket = new Socket(publicMeans.ip,publicMeans.port);//服务端的ip地址和端口号 这里的ip和port也就是刚才文本框里输入的 publicMeans.isServer = false;//如果成功进入到这一步,则代表此窗口是客户端窗口 publicMeans.isConn = true;//连接成功 Client.textArea.append("连接成功。\r\n");//"\r\n"的意思是换行 Client.btConn.setEnabled(false);//禁用客户端的连接按钮 os = socket.getOutputStream(); pw = new PrintWriter(os); is = socket.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr);//这里就是客户端接收的地方 while(true){//这里使用死循环,是因为要一直监视服务端有没有发过来信息 //刚才在服务端里面,开始游戏的时候服务端向客户端发送了“开始游戏”,这里解析 while((info = br.readLine()) != null){ if (info.startsWith("开始游戏")){ Client.textArea.append("开始游戏。\r\n"); openThread = new OpenThread(); openThread.start();//这个OpenThread就是刚才新建的线程,当客户端收到开始游戏时,进入到游戏界面 } else if (info.startsWith("游戏结束")) { publicMeans.isEnd = true; System.out.println(3); openThread.gameFrame.Close();//调用线程里的gameFrame,gameFrame是游戏界面,调用它的Close方法,关闭界面 } else { Analysis();//解析服务端发过来的内容 } } }//跟服务端一个意思 }catch (Exception e){ e.printStackTrace(); } } private static String[] message = null; private static String[] messageTemp = null; private static Object obj; public static void Analysis(){//"miner1:0;miner2:0;" message = info.split(";");//首先以分号为间隔分组,放到message数组中 miner1:0 miner2:0 for (int i = 0; i < message.length; i++){//然后循环message数组 此时message[0]=miner1:0 message[1]=miner2:0 //进入判断 //比如第一个if 判断message[0]是不是以"miner1"开头的,miner1:0,是,就进入,把publicMeans里的变量置为这个接收到的数据 //因为接收的数据是string格式的,所以使用Integer.parseInt转为int格式 if (message[i].startsWith("miner1:")) {publicMeans.state_miner1 = Integer.parseInt(message[i].substring(7));}//miner1:0 else if (message[i].startsWith("miner2:")){publicMeans.state_miner2 = Integer.parseInt(message[i].substring(7));} else if (message[i].startsWith("line1:")){ messageTemp = message[i].substring(6).split(" "); publicMeans.state_line1 = Integer.parseInt(messageTemp[0]); publicMeans.endX1 = Integer.parseInt(messageTemp[1]); publicMeans.endY1 = Integer.parseInt(messageTemp[2]); //这里需要的数据angle1是double格式的,所以使用Double.parseDouble把string转为double publicMeans.angle1 = Double.parseDouble(messageTemp[3]); publicMeans.length1 = Double.parseDouble(messageTemp[4]); publicMeans.dir1 = Integer.parseInt(messageTemp[5]); } else if (message[i].startsWith("line2:")){ messageTemp = message[i].substring(6).split(" "); publicMeans.state_line2 = Integer.parseInt(messageTemp[0]); publicMeans.endX2 = Integer.parseInt(messageTemp[1]); publicMeans.endY2 = Integer.parseInt(messageTemp[2]); publicMeans.angle2 = Double.parseDouble(messageTemp[3]); publicMeans.length2 = Double.parseDouble(messageTemp[4]); publicMeans.dir2 = Integer.parseInt(messageTemp[5]); } else if (message[i].startsWith("money1:")){publicMeans.money1 = Integer.parseInt(message[i].substring(7));} else if (message[i].startsWith("money2:")){publicMeans.money2 = Integer.parseInt(message[i].substring(7));} else if (message[i].startsWith("gold:")){ messageTemp = message[i].substring(5).split(" "); if (publicMeans.gold.size() == 0){continue;} publicMeans.gold.get(Integer.parseInt(messageTemp[0])).x = Integer.parseInt(messageTemp[1]); publicMeans.gold.get(Integer.parseInt(messageTemp[0])).y = Integer.parseInt(messageTemp[2]); publicMeans.gold.get(Integer.parseInt(messageTemp[0])).flag = Integer.parseInt(messageTemp[3]); } else if (message[i].startsWith("time:")){//传过来的是"time:8" 我们只需要把8赋值给publicMeans.timeSs publicMeans.timeSs = Integer.parseInt(message[i].substring(5)); //这里的substring就是从第五位开始截取 第0位t 1=i 2=m 3=e 4=: 5=8 所以括号里面写5 } else if (message[i].startsWith("firstGold:")){ messageTemp = message[i].substring(10).split(" "); switch (messageTemp[2]){ case "133": obj = new BigGold(); break; case "72": obj = new MiddleGold(); break; case "24": obj = new SmallGold(); break; default:break; } obj.x = Integer.parseInt(messageTemp[0]); obj.y = Integer.parseInt(messageTemp[1]); publicMeans.gold.add(obj); } else {} } } }
public class OpenThread extends Thread{//在准备好进入游戏界面时,开启这个线程
public GameFrame gameFrame;
@Override
public void run() {
gameFrame = new GameFrame();
gameFrame.launch();
}
}
import java.awt.*; import java.awt.geom.AffineTransform; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; public class publicMeans { public static boolean isServer = false;//记录此程序是服务端还是客户端,服务端:true;客户端:false public static boolean isConn = false;//记录是否连接成功 public static boolean isEnd = false;//表示游戏是否结束 private static int screenW = (int)Toolkit.getDefaultToolkit().getScreenSize().width; private static int screenH = (int)Toolkit.getDefaultToolkit().getScreenSize().height; // private static GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); // private static AffineTransform tx = gc.getDefaultTransform(); // public static double uiScaleX = tx.getScaleX(); // public static double uiScaleY = tx.getScaleY(); public static int GameWinW = 985; public static int GameWinH = 719; public static int ChatW = 375; public static int ChatH = 719; //聊天窗口在左,游戏窗口在右 public static int ChatX = screenW/2-(GameWinW+ChatW)/2; public static int ChatY = screenH/2-ChatH/2; public static int GameWinX = ChatX + ChatW; public static int GameWinY = ChatY; //游戏窗口在左,聊天窗口在右 // public static int GameWinX = screenW/2-(GameWinW+ChatW)/2; // public static int GameWinY = screenH/2-GameWinH/2; // public static int ChatX = GameWinX + GameWinW; // public static int ChatY = GameWinY; public static String ip = null; public static int port = 0; //以下就是客户端所需要的数据,客户端根据以下数据进行画面重绘 public static int state_miner1 = 0, state_miner2 = 0; public static int state_line1 = 0, endX1 = 0, endY1 = 0, dir1 = -1; public static int state_line2 = 0, endX2 = 0, endY2 = 0, dir2 = 1; public static double angle1 = 0.9, length1 = 50; public static double angle2 = 0.1, length2 = 50; //public static Object gold = new Object(); public static List<Object> gold = new ArrayList<>(); public static int money1 = 0, money2 = 0; public static int timeSs = -1;//这个用来记录倒计时,是客户端引用的 public static int clientKey = 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。