在Recorder类中,增加一个Vector集合,用来接收从MyPanel类中传入的enemyTanks集合,在记录时遍历集合,将还存活的敌人坦克的方向和坐标逐一取出并保存
Recorder类:增加属性enemyTanks、增加方法setEnemyTanks、修改keepRecord方法:
//定义Vector,指向MyPanel对象的敌人坦克的Vector
private static Vector<EnemyTank> enemyTanks = null;
public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
Recorder.enemyTanks = enemyTanks;
}
public static void keepRecord() {
try {
bw = new BufferedWriter(new FileWriter(recordFile));
bw.write(allEnemyTankNum + "\n");
//遍历敌人坦克的Vector,根据情况保存即可
for (int i = 0; i < enemyTanks.size(); i++) {
//取出敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
if (enemyTank.isLive) {//虽然被击中的坦克对象已经被删除了,但是还是建议判断一下
//保存该enemyTank信息
String record = enemyTank.getX()+" "+enemyTank.getY()+" "+enemyTank.getDirect();
//写入到文件中
bw.write(record+"\n");
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在MyPanel类中的MyPanel方法,调用Recorder的静态方法setEnemyTanks,将敌人坦克的集合enemyTanks传到Recorder类中

ps:引用类型传递的是地址,地址不会变化,因此可以获取到集合的最新的状态
关闭时:
记录状态:
将每个敌人信息恢复(读取)成Node对象,再放到vector里面去,通过Node的vector去初始化敌人坦克的位置和方向
新建一个Node类:
package li.TankGame.version06;
/**
* @author 李
* @version 6.0
* 一个Node对象表示一个敌人坦克的信息
*/
public class Node {
private int x ;
private int y ;
private int direct ;
public Node(int x, int y, int direct) {
this.x = x;
this.y = y;
this.direct = direct;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
}
在Recorder类中:
创建一个BufferedReader对象:
private static BufferedReader br = null;//输入处理流
定义一个Node的Vector对象,用于保存敌人的信息node:
//定义一个Node的Vector对象,用于保存敌人的信息node
private static Vector<Node> nodes = new Vector<>();
增加getNodesAndEnemyTankRec方法,用于读取recordFile,恢复相关信息:
//增加一个方法,用于读取recordFile,恢复相关信息
//该方法在点击继续上局的时候调用
public static Vector<Node> getNodesAndEnemyTankRec() {
try {
br = new BufferedReader(new FileReader(recordFile));
//读取上局击毁坦克数量
allEnemyTankNum = Integer.parseInt(br.readLine());
//循环读取文件,生成nodes集合
String line = "";
while ((line = br.readLine()) != null) {
//用空格将每一行的数据分割,分割完的字符数组里面存储了一组敌方坦克的x,y,direct
String[] xyd = line.split(" ");
//将字符串转为int类型,赋值给node对象
Node node = new Node(Integer.parseInt(xyd[0]),
Integer.parseInt(xyd[1]), Integer.parseInt(xyd[2]));
//将该node对象放到nodes集合中
nodes.add(node);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return nodes;
}
在MyPanel类中:
定义一个存放Node对象的Vector,用于恢复敌人坦克的坐标和方向:
//定义一个存放Node对象的Vector,用于恢复敌人坦克的坐标和方向
Vector<Node> nodes = new Vector<>();
修改MyPanel方法,修改了方法传入的参数String key;
在方法里面调用了getNodesAndEnemyTankRec,将其返回的nodes集合传给MyPanel类的nodes的集合;
使用switch,根据输入的key判断是新开一局还是接着上一局游戏;
public MyPanel(String key) {
nodes = Recorder.getNodesAndEnemyTankRec();
//将MyPanel对象的enemyTanks 设置给Recorder的enemyTanks
Recorder.setEnemyTanks(enemyTanks);
hero = new Hero(400, 200);//初始化自己的坦克
//hero.setSpeed(5); //改变坦克的速度
switch (key){
case "1": //开新游戏
Recorder.setAllEnemyTankNum(0);//重设击毁敌方坦克数目
//初始化敌人的坦克
for (int i = 0; i < enemyTankNum; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
//将enemyTanks集合设置给 enemyTank
enemyTank.setEnemyTanks(enemyTanks);
//初始化敌人坦克方向向下
enemyTank.setDirect(2);
//启动敌人坦克线程,让他动起来
new Thread(enemyTank).start();
//给该enemyTank加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
//将该子弹加入到enemyTank的Vector集合中
enemyTank.shots.add(shot);
//启动 shot对象
new Thread(shot).start();
//将设置好的的敌人坦克放入到集合中
enemyTanks.add(enemyTank);
}
break;
case "2": //继续上局游戏
//初始化敌人的坦克
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
//将enemyTanks集合设置给 enemyTank
enemyTank.setEnemyTanks(enemyTanks);
//初始化敌人坦克方向向下
enemyTank.setDirect(node.getDirect());
//启动敌人坦克线程,让他动起来
new Thread(enemyTank).start();
//给该enemyTank加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
//将该子弹加入到enemyTank的Vector集合中
enemyTank.shots.add(shot);
//启动 shot对象
new Thread(shot).start();
//将设置好的的敌人坦克放入到集合中
enemyTanks.add(enemyTank);
}
break;
default:
System.out.println("输入有误");
}
//初始化图片对象
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb1.png"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb2.png"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb3.png"));
}
在TankGame06类中新建一个Scanner对象:
static Scanner scanner = new Scanner(System.in);
修改TankGame06构造器,是在控制台输入的选择传到MyPanel构造器中:
public TankGame06() {
System.out.println("请输入选择:\n" + "1:新游戏 2:继续上局");
String key = scanner.next();
mp = new MyPanel(key);
//将mp放入到Thread,并启动
Thread thread = new Thread(mp);
thread.start();
this.add(mp);//把面板(就是游戏的绘图区域)添加进来
this.setSize(950, 600);//设置大小
this.addKeyListener(mp);//让JFrame监听mp的键盘事件
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击窗口的叉时停止运行
this.setVisible(true);//设置显示
//在JFrame中增加相应关闭窗口的处理
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Recorder.keepRecord();
System.exit(0);
}
});
}
退出时:
继续上局:
ps:这里截图不及时,实际上恢复的位置与上局一致
坦克大战7.0版
增加功能:
新建一个播放音乐的类
在网上找到相关音乐的.wav文件(注意一定要是wav,自己改的缀有可能会出现不能播放的情况),将其粘贴到项目的src文件的根目录下面
新建一个播放音乐的类
package li.TankGame.version07;
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
public class AePlayWave extends Thread {
private String filename;
public AePlayWave(String wavfile) { //构造器 , 指定文件
filename = wavfile;
}
public void run() {
File soundFile = new File(filename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (Exception e) {
e.printStackTrace();
return;
}
auline.start();
int nBytesRead = 0;
//这是缓冲
byte[] abData = new byte[512];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
在MyPanel类中的构造器MyPanel中,在最后一行启动线程
//这里播放指定的音乐
new AePlayWave("src\\111.wav").start();
把Recorder类中的记录文件修改为:保存到src目录下

在还没有文件记录的时候,如果我们选择“继续上局”游戏的话,就会出现异常。因为文件中没有记录,MyPanel中的nodes集合也就得不到数据,会出现一个敌人坦克都没有的情况:
在Recorder类中增加getRecordFile方法:
//返回记录文件的路径
public static String getRecordFile() {
return recordFile;
}
在MyPanel类中的MyPanel方法的最开始,添加判断方法:
先判断记录文件是否存在,如果存在就正常执行,若不存在,就提示只能开新新游戏,将 key 置为 1
//先判断记录文件是否存在,如果存在就正常执行,若不存在,就提示只能开新新游戏,将 key 置为 1
File file = new File(Recorder.getRecordFile());
if (file.exists()) {
nodes = Recorder.getNodesAndEnemyTankRec();
} else {
System.out.println("没有存档记录,只能开启新游戏!");
key = "1";
}

顺便把子弹类中子弹位置的提示信息删除:

运行截图:
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵