Java多人联机游戏(飞机大战)

飞机大战源码及素材

一、引言

应本学期Java课程大作业要求,建立可联机游戏项目。于是便编写了这个游戏。
关于这款游戏,其想法来源于传统的雷霆战机,然后对这类游戏进行了改造,对其玩法经行了补充。其玩法分为单人、双人、联机模式;在单机单人或双人模式中,由一人控制英雄机,“wsad”键位实现上下左右移动操作、“空格”进行射击,英雄机功能为经行射击攻击,并且为导弹的主要载体。另一人可以控制僚机,通过鼠标移动控制,僚机体积小用鼠标控制,这意味着可以更加灵活的在枪林弹雨中穿梭,其功能是辅助英雄机、提供进攻与防御的支持。僚机的设定中其不能射击攻击,由于英雄机击杀敌机后,会掉落金币,僚机用于拾取这些金币,游戏的初始设定为10金币可以,可以换取英雄机一条命;20金币可以释放大型导弹产生大范围的攻击,但金币在僚机上,需要当僚机与英雄机相重合时可进行这类操作。注意:僚机血量不能回复,且当血量达到上限时(初始设定:英雄机血量为3;僚机血量为5)不能进行加血操作。敌机方面,会从任意位置、任意刷新三种不同种类敌机,(不同敌机移动速度不同,小的敌机移速较快,中等适中,大的则慢)。状态栏设置在上部,左上角显示的是击杀数(当英雄机或僚机撞到敌机是会击杀敌机,但会损失血量)与金币数;右上角显示英雄机与僚机血量。当英雄机阵亡后游戏结束,“enter”键可以重返战场,当数据会初始化。联机模式就是可以在不同的端口同时运行该游戏经行竞技,然后可以经行数据的交互,击杀数高者为胜者。

二、游戏框架与类

1、类图

2.类






三、代码实现

App

在整个工程开始之前,由于我们需要实现游戏图形化,所以我们需要把图像导入,为了避免导入图片时不用重复操作,这也就需要我们有一个导入图片的工具,我就新建了一个App类。
首先我们要了解Java中的表示图片的类是BufferedImage,我们就要定义一个BufferedImage的方法用以调用图片(getImg()),通过IO流读取到相应图片,在将图片导入。搭建一个反射框架来执行待操作。

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class App {//读取指定位置上的图片//加static的目的://static特点:公用的,所有对象,可以直接通过类名调用(不需要再调用对象)public static BufferedImage getImg(String path){//加载图片//Java中的IO流,输送数据的管道//输入输出流//这里利用反射,提前构造好框架//App.class 找到App类的路径//getResource()获取资源try {BufferedImage img = ImageIO.read(App.class.getResource(path));//如果找到图片,就将图片返回return img;} catch (IOException e){//catch 如果找不到图片,就会捕获找不到图片的原因e.printStackTrace();}return null;}
}

有了图形导入工具以后,我们就可以开始进行游戏中对象类的编写了。我们的游戏是飞机大战,其中元素对象为:英雄机、僚机、敌机、子弹、导弹、金币。这些类都有一定的特性。于是,我们创建一个关于这些飞行物的一个超类(flyObject),由这些子类来继承。

flyObject

这个超类中需要放一些共用的变量,该飞行物的所在的位置坐标(横纵坐标),以及该飞行物的高度与宽度,以及飞行物的图片。

import java.awt.image.BufferedImage;
public class flyObject {//飞行物的图片BufferedImage img ;//飞行物的横坐标int x;//飞行物的纵坐标int y;//飞行物的宽度int w;//飞行物的高度int h;}

Hero

定义完飞行物超类后我们就可以将这些对象类一一编写出来。英雄机,这里我们需要做的就是导入英雄机的图片并获取图片的长高。用以确定英雄机的初始位置。另外,我们要新增英雄机血量参数,并为其编写上下左右的移动方法。

public class Hero extends flyObject {int hp;public Hero(){//确定游戏开始时,英雄机显示的图片img = App.getImg("/img/hero.png");//确定英雄机的大小//使用图片的大小,作为飞机的大小w=img.getWidth();h=img.getHeight();//使用横纵坐标、确定英雄机在游戏开始时显示的位置x=175;y=650-h;hp = 3;//英雄机的初始血量}//向上移动public void moveUp(){if(y>=50)y -= 50;}//向下移动public void moveDown(){if(y<=530)y += 50;}//向左移动public void moveLeft(){if(x>=25)x -=50;}//向右移动public  void moveRight(){if(x<=335)x += 50;}}

Wingman

僚机类与英雄机类相似,但由于其是通过鼠标移动,所以需要将鼠标的位置参数传给僚机图片的正中央位置的参数,所以要新建一个含参方法moveToMouse(int mx int my)其中的参数就为鼠标的位置参数。而且由于僚机功能的原因,当他登上英雄机时才能进行兑换金币用以补血与使用导弹的操作,我们还需要一个方法(meet)去判定来哦及是否与英雄机重合。

public class Wingman extends flyObject{int hp;public Wingman(){img = App.getImg("/img/wingman.png");w=img.getWidth();h=img.getHeight();x=300;y=600-h;hp = 5;}public void moveToMouse(int mx, int my){x = mx-w/2;//将鼠标居于僚机正中y = my-h/2;//将鼠标居于僚机正中}/*** 检测是否达到加血要求*/public boolean meet(Hero hero) {boolean meetH = x <= hero.x + hero.w && x >= hero.x - w && y <= hero.y + hero.h && y >= hero.y - h;return meetH;}
}

Enemy

敌机类中,我设置的有三种不同类型的敌机,分为大、中、小,我们要分别随机的刷入敌机种类与随机生成位置,并且不同的飞机类型拥有不同的飞行速度,我采取的方法是设置1-3标签,然后随机在1-3中抽取,对图片也同样进行编号,速度的表示用一定大的数减去标签数与适配值的积。于是,飞机越大,标签值越大,速度也就越慢。我们还要将速度这一参量体现在飞机的移动中。并且,我们还要设置敌机的碰撞条件判定。
Java画板绘图时采取的坐标系如下:

范围判定如下:

飞行物的位置坐标是取其图片的左上角,所以当敌机位置横坐标小于等于飞行物横坐标与飞行物宽度之和,且大于等于飞行物的位置横坐标与敌机宽度之差;敌机位置纵坐标小于等于飞行物位置纵坐标与其高度之和,敌机位置纵坐标大于等于飞行物位置纵坐标与敌机的高度之差的时候,判定为碰撞。
所以我们用写作:x <= f.x + f.w && x >= f.x - w && y <= f.y + f.h && y >= f.y - h
然后,因为敌机与子弹、英雄机、僚机相撞均会毁坏,所以我们要将该方法进行重写。

import java.util.Random;
public class Enemy extends flyObject {int speed;//设置速度public Enemy() {//定义随机数的类Random rd = new Random();//生成一个随机数来选取图片int index = rd.nextInt(3) + 1;//确定敌机显示的图片img = App.getImg("/img/enemy" + index + ".png");//确定敌机的大小w = img.getWidth();h = img.getHeight();//确定敌机的位置//nextInt(num),表示在[0,num)之间随机生成一个正数x = rd.nextInt(480 - w);y = -h;//设置速度speed = 20 - index * 5;//飞机越大,速度越慢}/*** 敌机移动的方法*/public void move() {y += speed;}/*** 碰撞检测*/public boolean shootBy(Bullet b) {boolean hit = x <= b.x + b.w && x >= b.x - w && y <= b.y + b.h && y >= b.y - h;return hit;}/*** 装到英雄机*/public boolean hitBy(Hero he) {boolean hitH = x <= he.x + he.w && x >= he.x - w && y <= he.y + he.h && y >= he.y-h;return hitH;}public boolean hitBy(Wingman he) {boolean hitH = x <= he.x + he.w && x >= he.x - w && y <= he.y + he.h && y >= he.y-h;return hitH;}
}

Money、Bomb和Bullet

有了刚刚几个类的基础,这几个类也是如法炮制的,只是需要注意的是Money类需要编写一个判定僚机拾取的方法,那么这几个类就留给读者自行练习用吧。

GameFrame

在对象类完成以后,我们继而需要做出游戏窗口的边框与面板,GameFrame类继承JFrame,再在构造函数里经行一些基础属性的设置

import javax.swing.*;
public class GameFrame extends JFrame {public GameFrame(){//设置标题 方法源于JFrame类setTitle("飞机大战");//设置大小  setSize(宽度,高度)setSize(480,700);//设置居中显示  null表示相对与屏幕左上角居中setLocationRelativeTo(null);//设置不允许玩家改变界面大小setResizable(false);//设置默认的关闭选项//关闭窗体时推出程序setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}

我们再这里也加入main函数,并创建窗体对象与面板对象,并将面板加入到窗体中。

public static void main(String[] args) {//创建窗体对象:调用窗体的构造方法,制作窗体GameFrame frame = new GameFrame();//创建面板对象:调用面板的构造方法,制作面板GamePanel panel =new GamePanel(frame);//方便在面板中添加键盘监听器//调用启动游戏的方法panel.startGame();//将面板加入到窗体中frame.add(panel);//显示窗体 true 显示, false 隐藏frame.setVisible(true);}
}

GamePanel

GamePanel是游戏面板类,也是承建游戏机制逻辑的主体。首先我们要将对象创建进来,因为敌机,子弹和金币需要不断刷新多个实例,所以我们给这几个类创建链表。我们还要创建线程,在线程里,执行相应方法,然后就是书写方法。创建鼠标键盘适配器,然后再写监听方法。并定义画笔,将背景,状态栏及对象绘制出来。这是大致的流程。

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;/*** Java中的游戏面板: JPanel* 自定义游戏面板* 1、写一个类,继承JPanel* 2、写一个构造方法,初始化(确定)面板的属性** 画图片的步骤:* 1、在类中定义图片,并取名* 2、在构造方法中,调用工具初始化图片* 3、在画图方法,paint中,画图片*/
public class GamePanel extends JPanel {//1、定义背景图BufferedImage bg;//背景图//创建英雄机Hero hero = new Hero();//创建僚机Wingman wingman = new Wingman();//创建导弹Bomb bomb = new Bomb();//    //创建敌机
//    Enemy enemy = new Enemy();//创建敌机的集合List<Enemy> ens = new ArrayList<Enemy>();//<Enemy>为范型规定为Enemy//创建子弹集List<Bullet> bul = new ArrayList<Bullet>();//创建金币集List<Money> mon = new ArrayList<Money>();//定义金币数int score=0;//定义击杀量int num=0;//设置游戏开关boolean gameover;//游戏开始时gameover为falseboolean wingmanDie;boolean bombHoo=false;boolean bombRun=false;/*** 开始游戏的方法*/public void startGame(){//创建并启动一个线程,控制游戏场景中物体活动(木偶,皮影)//固定格式//new Tread(){public void run(){...线程需要做的...}}.star();new Thread(){public void run(){//要一直做某事,写一个死循环,让游戏一直运行while(true){if(!gameover) {//调用敌机入场的方法enemyEnter();//调用让敌机移动的方法enemyMove();//这里设置为按空格射击
//                        //发射子弹
//                        shoot();//让子弹飞bulletMove();//判断子弹是否击中敌机shootEnemy();//判断僚机是否捡到金币catchMoney();//让金币飞moneyMove();//判断敌机是否撞到了英雄机hit();//导弹启动if(bombRun){BombRUN();}//每执行一次,休息一会//线程休眠 sleep(毫秒数)}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//重绘,刷新画布repaint();}}}.start();}/*** 导弹启动*/protected void BombRUN(){bomb.run();if(!bombHoo && bomb.y>=250){for(int i=0;i<ens.size();i++) {Enemy en = ens.get(i);int x = en.x;int y = en.y;//1、敌机死亡(消失:从敌机集合中删除)ens.remove(en);//生成金币Money m = new Money(x, y);mon.add(m);//击杀数加一num += 1;}bombHoo=true;bombRun=false;}if(bombHoo){Random rd = new Random();bomb.x= rd.nextInt(480 - bomb.w);bomb.y = -bomb.h;}bombHoo=false;}/*** 检测敌机是否撞到英雄机*/protected void hit(){//遍历敌机for(int i=0;i<ens.size();i++){//获取敌机Enemy e=ens.get(i);//如果敌机被英雄机撞到if(e.hitBy(hero)){int ensx=e.x;int ensy=e.y;//1、删除敌机ens.remove(e);//2、英雄机血量减少hero.hp--;//3、生成金币Money m = new Money(ensx,ensy);mon.add(m);//4.击杀数加一num+=1;//5、当英雄机血量清零是游戏结束if(hero.hp<=0){gameover = true;}}if(e.hitBy(wingman) && !wingmanDie){//1、删除敌机ens.remove(e);//2、英雄机血量减少wingman.hp--;//3、增加分数score+=1;//4、增加击杀数num+=1;//5、当英雄机血量清零是游戏结束if(wingman.hp<=0){wingmanDie=true;}}}}/*** 检测僚机是否捡到金币*/protected  void catchMoney(){//遍历每一个金币,将金币与僚机经行位置比较for(int i=0;i<mon.size();i++){//获取该敌机Money m = mon.get(i);//判断该子弹是否击中敌机if(m.catchBy(wingman)){//如果金币被僚机捡到//1、金币死亡(消失:从敌机集合中删除)mon.remove(m);//2、分数加一score+=1;}}}/*** 检测子弹是否集中敌机*/protected void shootEnemy(){//遍历所有的敌机,不知道是哪一个子弹大到了飞机所以要遍历for(int i=0;i<bul.size();i++){//获取每一个子弹Bullet b = bul.get(i);//每拿一颗子弹,就判断一下这颗炸弹是否击中敌机ko(b);}}/***判断子弹是否击中敌机*/private void ko(Bullet b){//遍历每一个敌机,将子弹与敌机经行位置比较for(int i=0;i<ens.size();i++){//获取该敌机Enemy e = ens.get(i);//判断该子弹是否击中敌机if(e.shootBy(b)){//如果敌机被子弹击中//记录死亡位置int x=e.x;int y=e.y;//1、敌机死亡(消失:从敌机集合中删除)ens.remove(e);//2、删除子弹bul.remove(b);//生成金币Money m = new Money(x,y);mon.add(m);//击杀数加一num+=1;}}}/*** 让子弹飞*/protected  void bulletMove(){//遍历所有子弹for(int i=0; i<bul.size();i++){//获取每一个子弹Bullet bullet = bul.get(i);//让子弹飞bullet.move();}}/*** 让金币飞*/protected  void moneyMove(){for(int i=0; i<mon.size();i++){//获取每一个子弹Money money = mon.get(i);//让子弹飞money.move();}}/*** 发射子弹的方法*/int bulletNum = 0;//计数器记录shoot方法执行次数protected void shoot(){bulletNum++;if(bulletNum>=5 ) {//创建子弹Bullet bullet1 = new Bullet(hero.x, hero.y);//将子弹加入子弹集bul.add(bullet1);//加入双排子弹//创建子弹Bullet bullet2 = new Bullet(hero.x+72, hero.y);//将子弹加入子弹集bul.add(bullet2);//创建子弹
//            Bullet bullet3 = new Bullet(hero.x+36, hero.y-20);
//            //将子弹加入子弹集
//            bul.add(bullet3);bulletNum = 0;}}/*** 敌机移动的方法*/protected void enemyMove(){//遍历所有的敌机for(int i=0;i<ens.size();i++){//获取每一个敌机Enemy en =ens.get(i);//敌机移动en.move();}}/*** 敌机入场的方法* 因为此方法在死循环中调用的,所以该方法会一直重复运行* 因为敌机数量刷新的太快,我们让执行n次enemyEnter()方法,才创建一个敌机*/int index= 0 ;//记录方法执行的次数protected void enemyEnter(){//记录执行次数index ++;if(index>=15) {//1、创建敌机Enemy en = new Enemy();//2、将敌机加入到敌机集合中ens.add(en);//将index清零index = 0;}}/*** 返回分数与击杀数的函数* @param frame* @return*/public int returnScore(){final int score = this.score;return score;}public int returnNum(){return num;}public GamePanel(GameFrame frame){//设置背景setBackground(Color.GRAY);//初始化图片bg = App.getImg("/img/background.png");//使用鼠标监听器(固定格式)//1、创建鼠标适配器MouseAdapter adapter = new MouseAdapter() {//2、确定需要监听的鼠标事件// 鼠标的事件//  mouseMoved() 监听鼠标移动事件//  mouseClick() 监听鼠标单击事件//  mousePressed() 监听鼠标按下去的事件//  mouseEntered() 监听鼠标移入游戏界面事件//  mouseExited() 监听鼠标移出游戏界面事件// MouseEvent 鼠标的事件,记录鼠标做的事情@Overridepublic void mouseClicked(MouseEvent e){if(score>=10 && !gameover && !wingmanDie && wingman.meet(hero) && hero.hp<3 && e.getButton()==e.BUTTON1){score-=10;hero.hp+=1;}if(score>=20 && !gameover && !wingmanDie && wingman.meet(hero) && e.getButton()==e.BUTTON3){bombRun = true;score-=20;}}@Overridepublic void mouseMoved(MouseEvent e) {//当鼠标在游戏界面中移动时,会触发的方法//让英雄机跟着鼠标一起移动//让英雄的横纵坐标等于鼠标的横纵坐标//获取鼠标的横纵坐标int mx = e.getX();//鼠标的横坐标int my = e.getY();//鼠标的纵坐标//如果游戏没有结束if(!gameover && !wingmanDie) {//让英雄机移动到鼠标的位置上(英雄机的行为,可以在英雄机中定义移动到鼠标的方法)wingman.moveToMouse(mx, my);}//这里需要注意://要刷新页面,将英雄机绘制到新的位置上//重新调用paint方法repaint();}};//将适配器加入到监听器中addMouseListener(adapter);addMouseMotionListener(adapter);//使用键盘监听器(固定格式)//1、创建键盘适配器KeyAdapter kd = new KeyAdapter() {//2、确定需要监听的键盘事件@Overridepublic void keyPressed (KeyEvent e) {//当按下键盘的按键时,会触发的方法//监听键盘的按键//每一个键盘的按键都对应的有一数字//获取键盘上按键的数字int keyCode = e.getKeyCode();//如果按了上键if(!gameover){if(keyCode==KeyEvent.VK_W){//英雄机向上移动hero.moveUp();}else if(keyCode==KeyEvent.VK_S){//英雄机向下移动hero.moveDown();}else if(keyCode==KeyEvent.VK_A){//英雄机向左移动hero.moveLeft();}else if(keyCode==KeyEvent.VK_D){//英雄机向右移动hero.moveRight();}else if(keyCode==KeyEvent.VK_SPACE){shoot();}}else if(gameover){if(keyCode==KeyEvent.VK_ENTER){//重新开始游戏hero = new Hero();wingman = new Wingman();//重置游戏开关gameover = false;score=0;num=0;ens.clear();bul.clear();mon.clear();repaint();}}//重绘repaint();}};//3、将适配器加入到窗体的监听器中frame.addKeyListener(kd);}/*** 专用画图方法* Graphics g 画笔* paint 方法的写法, 先打一个paint出来,然后再按键盘Alt+?*/@Overridepublic void paint(Graphics g) {super.paint(g);//画图片//g.drawImage(图片,图片的横坐标,图片的纵坐标,null)//横纵坐标,是设置图片左上角的坐标
//        o———————————————>x
//        |
//        |
//        |
//        |
//        |
//        |y
//         java的坐标g.drawImage(bg, 0, 0,null);g.drawImage(bg,480,0,null);//画图片时,如果不加宽度和高度,画的是原图的大小//g.drawImage(图片,图片的横坐标,图片的纵坐标,图片的宽度,图片的高度,null);//上面操作是在画背景的时候改变图片大小//画英雄机//g.drawImage(图片,图片的横坐标,图片的纵坐标,图片的宽度,图片的高度,null);g.drawImage(hero.img,hero.x,hero.y,hero.w,hero.h,null);//画僚机if(!wingmanDie){g.drawImage(wingman.img,wingman.x,wingman.y,wingman.w,wingman.h,null);}//画导弹if(!bombHoo && bombRun){g.drawImage(bomb.img,bomb.x,bomb.y,bomb.w,bomb.h,null);}//画敌机//在paint中画图是有顺序的,先画的会被后画的覆盖//遍历敌机集合,画出所有的敌机for(int i=0;i<ens.size();i++) {//获取每个敌机Enemy e = ens.get(i);g.drawImage(e.img, e.x, e.y, e.w, e.h, null);}//画子弹for(int i=0;i<bul.size();i++){//获取一个子弹Bullet bullet = bul.get(i);g.drawImage(bullet.img,bullet.x,bullet.y,bullet.w,bullet.h,null);}//画金币for(int i=0;i<mon.size();i++){//获取一个子弹Money money = mon.get(i);g.drawImage(money.img,money.x,money.y,money.w,money.h,null);}//画分数g.setColor(Color.white);g.setFont(new Font("楷体",Font.BOLD,30));g.drawString("金币数:"+score,10,30);g.drawString("击杀数:"+num,10,55);g.setColor(Color.red);g.setFont(new Font("楷体",Font.BOLD,15));g.drawString("英雄血量:",220,25);g.drawString("僚机血量:",220,50);//画英雄机的血量for(int i = 0;i<hero.hp;i++){g.drawImage(hero.img,300+i*35,5,30,30,null);}//画僚机血量for(int i = 0;i<wingman.hp;i++){g.drawImage(wingman.img,300+i*35,30,30,30,null);}//当游戏结束时,画出GameOverif(gameover) {g.setColor(Color.red);g.setFont(new Font("楷体", Font.BOLD, 35));g.drawString("Game Over", 20, 300);g.setFont(new Font("楷体",Font.BOLD,20));g.drawString("按下enter,让你重返战场",20,350);}}
}

多人联机的实现

使用Socket实现联机,要分别建立服务端(Server)与客户端(Client),并分别建立监听,发送方法

Server

import code.GameFrame;
import code.GamePanel;
import org.json.simple.JSONObject;import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class Server {public static void main(String[] args){try {System.out.println("Socket 准备就绪...");ServerSocket serverSocket = new ServerSocket(9999);while (true){Socket socket = serverSocket.accept();new Thread(new Server_listen(socket)).start();new Thread(new Server_send(socket)).start();}}catch (Exception e){e.printStackTrace();}}}
class Server_listen implements Runnable {private Socket socket;Server_listen(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());while (true)System.out.println(ois.readObject());} catch (Exception e) {e.printStackTrace();} finally {try {socket.close();} catch (Exception e) {e.printStackTrace();}}}
}class Server_send implements Runnable{private Socket socket;Server_send(Socket socket){this.socket = socket;}@Overridepublic void run() {try {ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());Scanner scanner = new Scanner(System.in);
//            while (true){//创建窗体对象:调用窗体的构造方法,制作窗体GameFrame frame = new GameFrame();//创建面板对象:调用面板的构造方法,制作面板GamePanel panel = new GamePanel(frame);//方便在面板中添加键盘监听器//调用启动游戏的方法panel.startGame();//将面板加入到窗体中frame.add(panel);//显示窗体 true 显示, false 隐藏frame.setVisible(true);while (true) {int score = panel.returnScore();int num = panel.returnNum();JSONObject object = new JSONObject();object.put("敌方分数:",score);object.put("敌方击杀数:",num);oos.writeObject(object);oos.flush();}//            }}catch (Exception e){e.printStackTrace();}}}

Client

import code.GameFrame;
import code.GamePanel;
import org.json.simple.JSONObject;import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {private static Socket socket;public static boolean connection_state = false;public static void main(String[] args){while (!connection_state) {connect();try {Thread.sleep(3000);}catch (Exception e){e.printStackTrace();}}}private static void connect(){try {socket = new Socket("Server的ip", 9999);connection_state = true;ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());new Thread(new Client_listen(socket,ois)).start();new Thread(new Client_send(socket,oos)).start();
//            new Thread(new Client_heart(socket,oos)).start();}catch (Exception e){e.printStackTrace();connection_state = false;}}public static void reconnect(){while (!connection_state){System.out.println("正在尝试重新链接.....");connect();try {Thread.sleep(3000);}catch (Exception e){e.printStackTrace();}}}
}class Client_listen implements Runnable{private Socket socket;private ObjectInputStream ois;Client_listen(Socket socket,ObjectInputStream ois){this.socket = socket;this.ois = ois;}@Overridepublic void run() {try {while (true){System.out.println(ois.readObject());}}catch (Exception e){e.printStackTrace();}}
}class Client_send implements Runnable{private Socket socket;private ObjectOutputStream oos;Client_send(Socket socket, ObjectOutputStream oos){this.socket = socket;this.oos = oos;}@Overridepublic void run() {try {Scanner scanner = new Scanner(System.in);
//            while (true){//创建窗体对象:调用窗体的构造方法,制作窗体GameFrame frame = new GameFrame();//创建面板对象:调用面板的构造方法,制作面板GamePanel panel =new GamePanel(frame);//方便在面板中添加键盘监听器//调用启动游戏的方法panel.startGame();//将面板加入到窗体中frame.add(panel);//显示窗体 true 显示, false 隐藏frame.setVisible(true);while (true){int score = panel.returnScore();int num = panel.returnNum();JSONObject object = new JSONObject();object.put("敌方分数:",score);object.put("敌方击杀数:",num);oos.writeObject(object);oos.flush();}
//            }}catch (Exception e){e.printStackTrace();try {socket.close();Client.connection_state = false;Client.reconnect();}catch (Exception ee){ee.printStackTrace();}}}
}
这就是该游戏的全部内容,游戏素材可以在网上搜索,这里也提供一份全套资源(含源码和素材)飞机大战源码及素材

从头开始实现Java多人联机游戏(飞机大战)源码粘贴即用相关推荐

  1. 小甲鱼python小游戏“飞机大战”源码素材

    话不多说,链接奉上. 百度网盘链接: https://pan.baidu.com/s/1KkmCqCBJ2Jq_IrewovYPAQ 提取码:43av 注:需下载Python pygame包 下载方式 ...

  2. java毕业设计网页小游戏交流论坛源码+lw文档+mybatis+系统+mysql数据库+调试

    java毕业设计网页小游戏交流论坛源码+lw文档+mybatis+系统+mysql数据库+调试 java毕业设计网页小游戏交流论坛源码+lw文档+mybatis+系统+mysql数据库+调试 本源码技 ...

  3. 基于VC++实现游戏潜艇大战源码,让您体会C/C++的魅力

    VC++编写的原汁原味的潜艇大战源码,这是一个国外VC++高手编写的潜艇大战,其玩法和界面效果均和windows电脑中自带的潜艇大战十分相似,从编译情况来看,游戏开发时未使用第三方控件,在VC6环境下 ...

  4. 基于VC++实现游戏潜艇大战源码,潜艇大战一触即发

    C++编写的原汁原味的潜艇大战源码,这是一个国外VC++高手编写的潜艇大战,其玩法和界面效果均和windows电脑中自带的潜艇大战十分相似,从编译情况来看,游戏开发时未使用第三方控件,在VC6环境下, ...

  5. Java实现五子棋小游戏(附源码)

    今天给大家分享一个用java写的小游戏--<五子棋> (完整代码可在[资源下载]目录查看) . 推荐学习专栏: Java基础学习专栏:[Java]基础篇 Java进阶学习专栏:[Java] ...

  6. 重温经典:Python版飞机大战源码 神器 玩游戏就玩自己开发的

    目录 导语 正文 一.环境安装 二.我方飞机 三.敌方飞机 四.控制键盘移动 五.检测子弹碰撞 六.效果图 总结 免费源码领取处: 往期文章推荐-- Python从入门到实战-- 绘图Turtle系列 ...

  7. java飞机大战子弹怎么修改_java改版飞机大战源码

    [实例简介] 利用java写的飞机大战,有BOSS 导弹,散射子弹,追踪弹,清屏技能,爆炸效果等等.适合用来练习面向对象: [实例截图] [核心代码] 4692cf8f-6049-4755-a40a- ...

  8. python3飞机大战源码及源码使用教程(让小白做出第一个小游戏)

    python3飞机大战 一.源代码使用教程及环境配置 1.环境配置 打开pycharm,进入file,打开settings 打开project interpreter,点击右上方 + 号 搜索pyga ...

  9. java 坦克重叠_Java实现支持双黑两人激战的 坦克大战源码(经典游戏)

    写这个游戏已经有一段时间了,一直在实现各种新功能,从最开始的地图上只有坦克,发子弹还是一个大问题到现在可以两个人一起玩,还是花了不少心思的,现在坦克的速度更快,电脑坦克也不会撞墙.虽然游戏性没有经典坦 ...

  10. java模拟回合制游戏大小姐_[源码和文档分享]基于java的RPG回合制游戏

    一.工作积累总结 1.1 简介 该项目是一个回合制RPG游戏,讲述了动物主角对抗人类,自逃出动物园开始,一路与人类对抗,提升能力,并寻找新队友组成团体,逼得人类不得不与之谈判,最终与人类达成了和平协议 ...

最新文章

  1. es mysql延迟_ES 近实时搜索 更新延迟问题
  2. leetcode 40. 组合总和 II 思考分析
  3. MySQL——数据库和表的增删改查
  4. BitMEX联合创始人:以比特币为首的加密货币综合体是防范恶性通货膨胀的最佳对冲
  5. mimics能导出什么格式_mimics教程
  6. 图表背后的秘密 | 技术指标讲解:唐奇安通道
  7. 数据分析达到精准营销的路径分析
  8. 概率与数理统计学习总结四---连续型随机变量及其概率密度
  9. android测试内存的软件下载,AndroBench p10内存门app下载
  10. html关于页内样式,HTML的页内样式演示案例
  11. 2022-04-01每日刷题打卡
  12. ActiveMQ学习(二)——MQ的工作原理
  13. 金工如何运用计算机思维,金工的实习心得体会
  14. 容器类:QVector、QList、QSet、QMap使用
  15. python安全之Pickle反序列化漏洞学习。
  16. ExtJS面板的使用(Ext.Panle、Ext.TabPanel、Ext.Viewport)
  17. 小程序收集箱:批量调节图像曝光度、锐利度、对比度、亮度的demo
  18. 数据可视化大屏设计尺寸怎么定?
  19. Riak Core Guide 1
  20. python picklable

热门文章

  1. Dingoapi的使用
  2. 高德足迹地图在哪里_高德地图怎么点亮城市 足迹地图查看方法
  3. word自动更正关闭_如何在OS X中关闭自动更正文本替换
  4. .htaccess wp博客 静态网页 永久链接一步步来
  5. Magisk使用记录
  6. jena mysql_使用Jena将本体存入MySQL
  7. 计算机配置很不错但是卡,高手告诉你win10电脑明明配置很好却卡顿的详尽处理手法...
  8. mac系统下,vm虚拟机打不开/dev/vmmon,如何解决?
  9. 微信小程相对图片路径_微信小程序中图片绝对定位(背景图片)的方法
  10. 使用file.delete删除文件不起作用解决办法