前言
如今的游戏已经成为世界上最大的娱乐休闲项目之一,游戏市场规模持续增长,潜力巨大,我国政府一向以来都特别鼓励游戏产业的发展,特别是我国当地的游戏产业,扶持力度连年加大,由此可见,我国对游戏产业的重视程度。该坦克大战游戏是对红白机经典90坦克大战的延续,对于80后,90后来说,都是童年里最宝贵的回忆,而80后,90后恰好占据着当今游戏人群的主体,对于他们来说,该坦克大战游戏不仅可以减轻人们的社会压力,放松身心,也可以回味小时候玩红白机游戏的疯狂时光,又不会沉迷于游戏,老少咸宜,能够更好地体验游戏的乐趣。
《坦克大战联机版》游戏以坦克战斗为主题,用java语言实现,采用了swing技术进行了界面化处理,设计思路用了面向对象思想。
主要需求
该坦克大战选择使用以往的游戏规矩。服务器端创建并设置一个主机,客户端申请连接加入,若其IP输入判断无误,载入地图关卡并开始游戏,在游戏界面中,会实时显示敌方坦克数量和玩家坦克的生命数量及分数。敌方坦克自行移动和打出子弹,玩家通过敲击键盘来操控自己坦克的动作并打出子弹,子弹无法打中相同阵营的坦克,当两方阵营的子弹相交时会相互抵消,打中对方坦克时会产生爆炸效果,中途可以暂停、发送信息,玩家坦克吃掉超级武器后会赋予其特殊的功能,在游戏地图界面中还同时游戏中还包含了通信功能。如果取得了胜利,会显示“你过关了!”,如果失败了,则系统给出“GAME OEVR!还想再玩一次吗?(y/n)”的提示,如果玩家双方都选择继续游戏,则游戏重新加载并开始,不然结束并退出游戏界面。
主要设计
1、基地的设计:
 base类定义了几个变量,通过构造器初始化了基地的变量参数,使用g.drawImage()方法设置一幅图片来代表基地,通过public void move(){}来处理基地受到铁墙防护时的变化,使用if()判断语句判断铁墙的保护时间。游戏的核心重点自然就是基地了,一旦基地被毁,则玩家失败,游戏结束。游戏面板是游戏程序的关键,这里使用了方法paintComponent(Graphics g)来进行建立并设置其属性。
2、敌方坦克的设计:
 enemy类设置了敌方坦克的共同属性,并根据不同外形的坦克设置了不同的属性,如椭圆形的坦克的移动速度会比较快,拥有多层颜色坦克的生命力与其拥有的颜色数量一样,利用随机函数Math.random()*4随机生成一个随机值,并转换成整形数值,将此值赋给变量direction来作为敌方坦克生成时的方向,再将Math.random()*200生成的随机值转换成整形数值,赋予变量interval来作为生成时的时间间隔,并且设置了地方坦克的移动周期,在一个周期内将会朝着相同的方向继续移动,并设置了其发射子弹的遂进行。而在特殊属性中,分别设置了敌方坦克的的火力、速度、图标等属性,再用方法draw(Graphics g){}向地图中加入敌方坦克。
3、河道、草坪的设计:
 grass类继承了Actor接口,通过grass类构造器定义了草坪的x,y坐标和矩形边界以及图标,通过public void draw(Graphics g) {}方法绘制了草坪。游戏双方坦克及其子弹可以自由通过草坪。
4、墙与铁墙的设计:
 该模块通过new Rectangle(int x,int y,int width,int height)完成了一个矩形的创建,然后将其具体值赋给变量数组border[数组索引]生成了墙。坐标x和y为绘制矩形时的起始点,width,height分别为矩形绘制的宽和高。通过构造器定义普通墙和铁墙的矩形边界和图标。
5、界面窗口的创建:
 再该模块中,在ServerView类的构造器中用super()方法调用父类构造器设置窗口题目为“坦克大战”,使用JButton(String)定义了六个(退出、帮助、发送、暂停/继续、建立主机和隐藏)鼠标点击事件(即所谓的按钮),JTextField定义文本框,并将其设置为不可编辑。使用new drawingPanel()和setBackground(Color c)创建一个面板并设置背景颜色,再通过setBounds()和setLayout()方法定义了页面的大小并将页面布局定义为空。通过add()方法向页面添加按钮和文本框。使用setColor(Color c)方法设置面板颜色为指定颜色,再通过继承自java.awt.Graphics类中的drawString(String,int,int)方法向面板添加并输出当前关数及剩余敌人数,通过if判断语句进行判断,如果消灭坦克数量大于敌方坦克数量则输出胜利场景。
6、子弹功能设计:
 该模块用setColor()方法设置子弹颜色为浅灰色,使用g.fillRect(int,int,int,int)方法设置子弹水平或垂直发射时的形状,子弹和什么东西相交通过if()判断语句和equals()方法来鉴定,然后再处理相交时子弹和其他对象的属性变化。
7、坦克功能设计:
 坦克吃掉了什么特殊武器图标通过if()判断语句和equals()方法来鉴定,如果吃到TNT图标,则已经出现了的敌方坦克全部被炸毁;如果吃到坦克图标,玩家坦克加一条生命;如果吃到五角星图标,则提升玩家坦克子弹火力并且速度加快,可以打破铁墙;若是头盔图标,则玩家坦克获得防护盾且免疫敌方子弹;如果吃到铁墙图标,则基地由普通墙变为铁墙,如果吃到钟表图标,则时间停止,所有敌方坦克静止。
8、服务器设计:
 在ServerModel类,实现了ActionListener接口,具备了监听功能。创建了一些连接变量和游戏变量,设置了布尔类型的服务器状态变量,使用构造器完成了消息队列信息的设置,使用createServer(){}方法建立主机,当布尔变量serverCreated的值为true时,主机创建成功,还设置了一个端口号,用try{}catch{}语句处理代码执行时发生的异常,并给出错误提示,服务器通过accept()方法与客户端建立连接,当端口号没有被其他应用程序占用并IP地址正确,则成功完成连接,载入游戏,如若不然,就会显示相应的错误提示。使用addMessage()在屏幕上显示消息,使用removeMessage()方法删除屏幕上的消息,通过addActor()和remove()方法完成了向地图中增添新的物体对象和清除已经不存在了的物体对象的操作。
功能截图
启动服务端和客户端
 
连接主机成功:
 
 帮助提示:
 
游戏界面:
 
代码实现
ServerModel
import java.net.*;
import java.io.*;
import java.awt.event.*;
import java.awt.*;
public class ServerModel implements ActionListener{
	//视图参考
	public ServerView view;
	//连接变量
	public ServerSocket serverSocket;
	public Socket clientSocket;
	public PrintWriter out;
	public BufferedReader in;
	public String inputLine, outputLine;
	//服务器状态
	public boolean serverCreated;
	public boolean clientConnected;
	public boolean gameStarted;
	public boolean gamePaused;
	public boolean gameOver;
	public boolean serverVoteYes, serverVoteNo;
	public boolean clientVoteYes, clientVoteNo;
	public boolean pausePressed;
	//游戏消息
	public String[] messageQueue;
	public int messageIndex;
	public String playerTypedMessage = "";
	//实际的游戏在这个线程上运行,而主线程监听用户的输入
	public Ticker t;
	public Image[] textures;
	//游戏变量
	public static int gameFlow;
	public Actor[] actors;
	public player P1;   //由服务器玩家控制的坦克
	public player P2;   //有客户端玩家控制的坦克
	public ServerModel(ServerView thisview){
		view = thisview;
		messageQueue = new String[8];
		view.mainPanel.messageQueue = messageQueue;
		addMessage("欢迎来到坦克大战主机端!  请点击\"建立主机\"按钮开始游戏" );
		t = new Ticker(1000);
		t.addActionListener(this);
	}
	public void createServer(){
 		addMessage("正在建立主机(端口9999)");
 		try {
			serverSocket = new ServerSocket(9999);
        	serverCreated = true;
        } catch (Exception e) {
			addMessage("无法建立主机,请确认端口9999没有被别的程序使用");
			System.out.println(e);
			t.stop();
			return;
        }
		addMessage("建立完成,等待玩家连接");
        try {
		   clientSocket = serverSocket.accept();
	       clientConnected = true;
	    	out = new PrintWriter(clientSocket.getOutputStream(), true);
		    in = new BufferedReader(new InputStreamReader(
				clientSocket.getInputStream()));
	    } catch (Exception e) {
			addMessage("连接中出现错误,请重新建立主机");
			serverCreated = false;
			clientConnected = false;
			t.stop();
			//当发生错误,摧毁一切已创建的
			try{
				serverSocket.close();
				clientSocket.close();
				out.close();
				in.close();
			}catch(Exception ex){}
			return;
        }
		view.messageField.setEnabled(true);
		addMessage("玩家已连接上,开始载入游戏");
		//一旦客户端连接,然后告诉客户端开始加载游戏
		 out.println("L1;");
		//加载游戏
		textures = new Image[88];
		for(int i = 1; i < textures.length+1; i++)
			textures[i-1] = Toolkit.getDefaultToolkit().getImage("image\\" + i + ".jpg");
		//设置第一关
		actors = new Actor[400];
		level.loadLevel(this);
		P1 = new player("1P", this);
		addActor(P1);
		P2 = new player("2P", this);
		addActor(P2);
		gameStarted = true;
		view.mainPanel.actors = actors;
		view.mainPanel.gameStarted = true;
	addMessage("载入完毕,游戏开始了!");
	}
	public void actionPerformed(ActionEvent e){
		createServer();
		//如果程序未能创建服务器,则什么也不做
		if(!serverCreated)
			return;
		//游戏逻辑回路,
		try{
			while((inputLine = in.readLine()) != null){
				//处理客户反馈消息
				feedbackHandler.handleInstruction(this, inputLine);
				outputLine = "";
				if(!gamePaused)
					gameFlow++;
				if(pausePressed){
					if(!gamePaused){
						outputLine+= "x0;";
					}else{
						outputLine+= "x1;";
					}
					pausePressed = false;
				}
				if(gameOver || (P1.life == 0 && P2.life == 0)){
					if(P1.freezed != 1)
						outputLine+="a;";
					if((P1.freezed != 1 || messageIndex == 1) && serverVoteYes){
						addMessage("等待用户端玩家的回应...");
					}
					if(P1.freezed != 1 || messageIndex == 0){
							addMessage("GAME OVER !  想再玩一次吗 ( y / n ) ?");
					}
					gameOver =  true;
					P1.freezed = 1;
					P2.freezed = 1;
					if(serverVoteNo && !serverVoteYes)
						System.exit(0);
					if(serverVoteYes){
						outputLine+="j;";
						if(clientVoteYes){
							addMessage("用户端玩家决定再玩一次,游戏重新开始了...");
							//重新启动游戏
							P1 = new player("1P", this);
							P2 = new player("2P", this);
							level.reset();
							level.loadLevel(this);
							gameOver = false;
							serverVoteYes = false;
							clientVoteYes = false;
							serverVoteNo = false;
							enemy.freezedMoment = 0;
							enemy.freezedTime = 0;
							gameFlow = 0;
							//告诉客户端程序重新启动游戏
							outputLine+="L1;";
						}
					}
				}
				if(level.deathCount == 20 &&  !gameOver){
					level.winningCount++;
					if(level.winningCount == 120){
						P1.freezed = 1;
						P2.freezed = 1;
					}
					if(level.winningCount == 470){
						if(P1.life > 0)
							P1.reset();
						if(P2.life > 0)
							P2.reset();
						level.loadLevel(this);
						//告诉客户端程序加载下一关
						outputLine+="L" +(1 +  (level.currentLevel-1)%8) + ";";
					}
					if(level.winningCount  == 500){
						P1.freezed = 0;
						P2.freezed = 0;
						level.deathCount = 0;
						level.winningCount = 0;
					}
				}
				//大量生产敌人坦克
				if(!gamePaused)
					level.spawnEnemy(this);
				for(int i = 0; i < actors.length; i++){
					if(actors[i] != null)
						actors[i].move();
				}
				//从消息队列中删除一个消息每10秒,(如果有的话)
				if(gameFlow%300 == 0)
					removeMessage();
				//将玩家、关卡的信息写入输出行
				outputLine+="p" + level.enemyLeft + "," + level.currentLevel + "," + P1.life + "," + P1.scores + "," +  P2.life + "," + P2.scores +";";
				outputLine+="g" + level.winningCount + ";";
				//将玩家类型信息写入输出行
				if(!playerTypedMessage.equals("")){
					outputLine+=playerTypedMessage;
					playerTypedMessage = "";
				}
				//将最后的指令字符串发送到客户端程序
				out.println(outputLine);
				//调用视图重绘本身
				view.mainPanel.repaint();
				//如果玩家切换到对话框模式,则停止所有坦克动作
				if(!view.mainPanel.hasFocus()){
					P1.moveLeft = false;
					P1.moveUp = false;
					P1.moveDown = false;
					P1.moveRight = false;
					P1.fire = false;
				}
				Thread.sleep(30);
			}
		}catch(Exception ex){
			ex.printStackTrace();
			view.messageField.setEnabled(false);
			serverVoteYes= false;
			serverVoteNo = false;
			clientVoteYes = false;
			serverCreated = false;
			gameStarted = false;
			gameOver = false;
			gameFlow = 0;
			enemy.freezedTime = 0;
			enemy.freezedMoment = 0;
			view.mainPanel.gameStarted = false;
			t.stop();
			addMessage("玩家退出了,请重新建立主机");
			//当发生错误在游戏中,摧毁任何东西,包括游戏的变量
			try{
				out.close();
				in.close();
				clientSocket.close();
        		serverSocket.close();
			}catch(Exception exc){}
			//破坏游戏数据
			P1 = null;
			P2 = null;
			level.reset();
		}
	}
	//添加游戏对象(如坦克,子弹等..)到游戏系统
	public void addActor(Actor actor){
		for(int i = 0; i < actors.length; i ++ )
			if(actors[i] == null){
				actors[i] = actor;
				break;
			}
	}
	//从游戏系统中移除游戏对象
	public void removeActor(Actor actor){
			for(int i = 0; i < actors.length; i ++ )
					if(actors[i] == actor){
						actors[i] = null;
						break;
			}
	}
	//在屏幕上显示一行消息
	public void addMessage(String message){
		if(messageIndex < 8){
			messageQueue[messageIndex] = message;
			messageIndex++;
		}
		else{
			for(int  i = 0; i < 7; i++)
				messageQueue[i] = messageQueue[i+1];
			messageQueue[7] = message;
		}
		//调用视图重绘屏幕如果游戏有没有开始
		if(!gameStarted)
			view.mainPanel.repaint();
	}
	//删除屏幕上最早的信息
	public void removeMessage(){
		if(messageIndex == 0)
			return;
		messageIndex--;
		for(int  i = 0; i < messageIndex; i++)
			messageQueue[i] = messageQueue[i+1];
		messageQueue[messageIndex] = null;
		//调用视图重绘屏幕如果比赛还没开始
		if(!gameStarted)
			view.mainPanel.repaint();
	}
}
ServerView
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//这个类表示服务器的图形界面
public class ServerView extends JFrame{
	public drawingPanel mainPanel;
	public JButton createServer, exit, pauseAndResume, help, hiddenButton;
	public JTextField messageField;
	public JButton sendMessage;
	public ServerControler controler;
	public ServerModel model;
	public ServerView(){
		super("坦克大战");
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) { }
		getContentPane().setLayout(null);
		//制作动画绘制的主面板
		mainPanel = new drawingPanel();
		mainPanel.setLayout(null);
		mainPanel.setBounds(0,  22, 679, 605);
		mainPanel.setBackground(new Color(128, 64, 0));
		messageField = new JTextField();
		messageField.setBounds(0,519, 560,22);
		messageField.setEnabled(false);
		sendMessage = new JButton("发送");
		sendMessage.setBounds(570,518, 62,24);
		sendMessage.setFocusable(false);
		mainPanel.add(messageField);
		mainPanel.add(sendMessage);
		getContentPane().add(mainPanel);
		mainPanel.setFocusable(true);
		//制作选项按钮
		createServer = new JButton("建立主机");
		createServer.setBounds(0, 0,120,22);
		getContentPane().add(createServer);
		createServer.setFocusable(false);
		pauseAndResume = new JButton("暂停/继续");
		pauseAndResume.setBounds(120, 0,120,22);
		getContentPane().add(pauseAndResume);
		pauseAndResume.setFocusable(false);
		help = new JButton("帮助");
		help.setBounds(240, 0,120,22);
		getContentPane().add(help);
		help.setFocusable(false);
		exit = new JButton("退出");
		exit.setBounds(360, 0,120,22);
		getContentPane().add(exit);
		exit.setFocusable(false);
		//设置主框架
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(150, 130, 640, 590);
    	setVisible(true);
    	setResizable( false );
		//设置服务器模式
		model = new ServerModel(this);
		//设置服务器控制器
		controler = new ServerControler(this, model);
	}
	public static void main(String[] args){
		new ServerView();
	}
}
总结
通过此次的《坦克大战联机版》游戏实现,让我对swing的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。
java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。
源码获取
可关注博主后,私聊博主免费获取
 需要技术指导,写项目程序,等更多服务请联系博主
今天是持续写作的第 29 / 100 天。
可以关注我,点赞我、评论我、收藏我啦。
