IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 修改植物大战僵尸游戏存档(Java实现版) -> 正文阅读

[Java知识库]修改植物大战僵尸游戏存档(Java实现版)

目录

一、实现思路

二、实现过程

1. 创建Java类

2. 实现读取数据方法

3. 实现修改数据方法

3.1. 修改关卡数

? ? ? ? ?3.2. 修改金币数

3.3. 解锁所有模式

3.4?解决输入错误

4. 实现写入数据方法

?三、实验测试

?四、完整代码


上次任务已经使用Hex Editor Neo工具成功修改游戏存档,具体实现探索和步骤请参考:修改植物大战僵尸游戏存档——跳关并快速实现财富自由,本次任务目的将使用java代码替换工具,实现同样的修改功能。

一、实现思路

  1. 读取数据:修改的user1.dat文件的本地路径已知,使用IO流知识读取数据并存放在程序中。
  2. 修改数据:利用控制台输入,获取用户修改意向,并根据任务的不同采取不同的修改策略。
  3. 写入数据:将修改后的数据重新写入到原文件中。

二、实现过程

1. 创建Java类

按图示创建Java工程。

?之后在创建好的Java工程src目录下创建Java类。

输入类名称就可以进行敲代码啦。如下图,定义两个全局变量,分别是可变数组userIndex,用来存放.dat文件下读取出来的数据、.dat所在的本地路径。并设为static类型,可以不用创建类对象就能使用。

2. 实现读取数据方法

有两种读取文件方式,读取文本形式使用Reader,读取二进制数据使用InputStreamFileInputStream是InputStream的一个子类。顾名思义,FileInputStream就是从文件流中读取数据。BufferedInputStream继承于FilterInputStream,提供缓冲输入流功能。缓冲输入流相对于普通输入流的优势是,它提供了一个缓冲数组,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容部分或全部返回给用户。由于从缓冲区里读取数据远比直接从物理数据源读取速度快。代码如下:

//    从二进制文件中读取数据(读取到的数据从十六进制数据自动转成十进制)
    public static void readData(){
        try
        {
            FileInputStream fis= new FileInputStream(fileName);
            BufferedInputStream br = new BufferedInputStream(fis);
            int record = -1;
            while((record = br.read()) != -1)
            {
                userIndex.add(record);  //将读到的数据添加到可变数组中(全局变量)
            }
            System.out.println("从文档中读取第一行数据显示(十进制):");
            for(int i=0; i<16; i++){
                System.out.print(userIndex.get(i) + " ");
            }
            System.out.println();
        }
        catch(Exception e)
        {
            System.out.print(e.toString());
        }
    }

?3. 实现修改数据方法

修改数据思路是:主方法中先用Scanner获取用户输入的任务类型,将用户输入数据以参数方式传给changeData方法,在方法内部判断,根据类型采取不同的修改方式。具体措施如下:

3.1. 修改关卡数

3.1.1 用Scanner获取用户输入的关卡数,得到类型为字符串,例"5-1"。

3.1.2 计算修改的十进制数(因为从文件中读取时十六进制自动转换成十进制):先用substring分别获取“-”前面和后面的数字,用变量存取(此时为字符串类型)。用valueof()方法将字符串转为数字,并用前数字*10加后数字。

3.1.3 将1.2的结果替换到表示关卡数的位置:用Hex Editor Neo表示第一行04位置(下标为04)。

 public static void changeData(String type){
        if (type.equals("1")){
            System.out.println("请输入您要改的关卡:");
            Scanner input=new Scanner(System.in);
            String level=input.nextLine();
            int firstLevel=Integer.valueOf(level.substring(0,1));
            int lastLevel=Integer.valueOf(level.substring(2,3));
            //因为从1-1开始的,5-1只需加41关即可
            int addLevel=(firstLevel-1)*10+lastLevel;
            //修改数据:关卡数在第一行04位置,即数组中下标为4
            userIndex.set(4,addLevel);
        }

?3.2. 修改金币数

?3.2.1?用Scanner获取用户输入的关卡数,得到类型为字符串,例"100000000"。

?3.2.2 计算:因为植物大战僵尸的内部机制,二进制表示是真实金币数的十分之一,因此需要将2.1结果转换为数字并除以10。文件中以十六进制存储,将除以10后的十进制数据转换成十六进制。例如"100,000,000/10d=989680h"。

?3.2.3 存储:在.dat文件中,金币数量是由08,09,0a,0b是存储位,包含8个十六进制位,因此需要将不够位数的在前面补齐。此思路用for循环,循环次数是(8-十六进制数的length)。例如"989680->00989680"。补齐之后以两位为单位,分别按低位->高位的顺序替换08->0b的值。例如"80,96,98,00"分别替换"08,09,0a,0b"位的值。代码如下:

else if (type.equals("2")){
            System.out.println("请输入您要改的金币数量:");
            Scanner input=new Scanner(System.in);
            String money=input.nextLine();
            //需要加到的金钱
            int needMoney=Integer.valueOf(money)/10;
            String HexMoney=Integer.toHexString(needMoney);
            //在十六进制数前面补0到8位
            String zero=new String();
            for (int i=0;i<8-HexMoney.length();i++){
                zero+="0";
            }
            HexMoney=zero+HexMoney;//补全的十六进制
            //最后两位,对应第一行08位置,进行替换
            int data08=Integer.valueOf(HexMoney.substring(HexMoney.length()-2));
            userIndex.set(8, Integer.parseInt(String.valueOf(data08),16));
            //倒数第3,4位,对应第一行09位置,进行替换
            int data09=Integer.valueOf(HexMoney.substring(4,6));
            userIndex.set(9, Integer.parseInt(String.valueOf(data09),16));
            //正数第3,4位,对应第一行0a位置,进行替换
            int data0a=Integer.valueOf(HexMoney.substring(2,4));
            userIndex.set(10, Integer.parseInt(String.valueOf(data0a),16));
            //正数第1,2位,对应第一行0a位置,进行替换
            int data0b=Integer.valueOf(HexMoney.substring(0,2));
            userIndex.set(11, Integer.parseInt(String.valueOf(data0b),16));
        }

3.3. 解锁所有模式

按照上次的实验,发现只需将0c位的数改为01即可达到目的。代码如下:

else if(type.equals("3")){
            //修改数据:关卡数在第一行0c位置,即数组中下标为12
            userIndex.set(12,1);
        }

3.4?解决输入错误

当输入非1-3,则提示并重新获取信息,利用递归重新进行判断。

else{
//          输入有误,重新接收数字,用递归方法修改数据
            System.out.println("输入有误,请输入1-3:");
            Scanner input=new Scanner(System.in);
            String level=input.nextLine();
            changeData(level);
            return;
        }

4. 实现写入数据方法

?利用FileOutStream写入数据,并且为完全替换,append设为false。

//   将数组以二进制写入文件中
    public static void writeData() throws IOException {
        FileOutputStream fileWriter=new FileOutputStream(fileName,false);
        for (int singleData:userIndex) {
            fileWriter.write(singleData);
        }
        //写入文件
        fileWriter.close();
    }

?三、实验测试

?1. 任务一修改关卡数为5-1:

修改关卡数为6-1:

?

?2. 任务二修改金币数量为1024:

?修改金币数量为100,000,000:

3. 任务三解锁所有模式:

?4. 其他出错检查:

?四、完整代码

import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;

public class modifyPlantsVsZombies {
    static ArrayList<Integer> userIndex=new ArrayList<>();
    static String fileName="C:\\ProgramData\\PopCap Games\\PlantsVsZombies\\userdata\\user1.dat";
    public static void main(String[] args) {
        readData();
        System.out.println("请输入任务标号(1/2/3):");
        Scanner input=new Scanner(System.in);
        String level=input.nextLine();
        changeData(level);
    }
//    从二进制文件中读取数据(在输出到控制台时十六进制数据自动转成十进制)
    public static void readData(){
        try
        {
            FileInputStream fis= new FileInputStream(fileName);
            BufferedInputStream br = new BufferedInputStream(fis);
            int record = -1;
            while((record = br.read()) != -1)
            {
                userIndex.add(record);
            }
            System.out.println("从文档中读取第一行数据显示(十进制):");
            for(int i=0; i<16; i++){
                System.out.print(userIndex.get(i) + " ");
            }
            System.out.println();
        }
        catch(Exception e)
        {
            System.out.print(e.toString());
        }
    }
//    判断任务,并根据用户输入意向进行修改
    public static void changeData(String type){
        if (type.equals("1")){
            System.out.println("请输入您要改的关卡:");
            Scanner input=new Scanner(System.in);
            String level=input.nextLine();
            int firstLevel=Integer.valueOf(level.substring(0,1));
            int lastLevel=Integer.valueOf(level.substring(2,3));
            //因为从1-1开始的,5-1只需加41关即可
            int addLevel=(firstLevel-1)*10+lastLevel;
            //修改数据:关卡数在第一行04位置,即数组中下标为4
            userIndex.set(4,addLevel);
        }else if (type.equals("2")){
            System.out.println("请输入您要改的金币数量:");
            Scanner input=new Scanner(System.in);
            String money=input.nextLine();
            //需要加到的金钱
            int needMoney=Integer.valueOf(money)/10;
            String HexMoney=Integer.toHexString(needMoney);
            //在十六进制数前面补0到8位
            String zero=new String();
            for (int i=0;i<8-HexMoney.length();i++){
                zero+="0";
            }
            HexMoney=zero+HexMoney;//补全的十六进制
            //最后两位,对应第一行08位置,进行替换
            int data08=Integer.valueOf(HexMoney.substring(HexMoney.length()-2));
            userIndex.set(8, Integer.parseInt(String.valueOf(data08),16));
            //倒数第3,4位,对应第一行09位置,进行替换
            int data09=Integer.valueOf(HexMoney.substring(4,6));
            userIndex.set(9, Integer.parseInt(String.valueOf(data09),16));
            //正数第3,4位,对应第一行0a位置,进行替换
            int data0a=Integer.valueOf(HexMoney.substring(2,4));
            userIndex.set(10, Integer.parseInt(String.valueOf(data0a),16));
            //正数第1,2位,对应第一行0a位置,进行替换
            int data0b=Integer.valueOf(HexMoney.substring(0,2));
            userIndex.set(11, Integer.parseInt(String.valueOf(data0b),16));
        }else if(type.equals("3")){
            //修改数据:关卡数在第一行0c位置,即数组中下标为12
            userIndex.set(12,1);
        }else{
//          输入有误,重新接收数字,用递归方法修改数据
            System.out.println("输入有误,请输入1-3:");
            Scanner input=new Scanner(System.in);
            String level=input.nextLine();
            changeData(level);
            return;
        }
        //修改之后输出第一行
        System.out.println("修改后第一行数据显示(十进制):");
        for(int i=0; i<16; i++){
            System.out.print(userIndex.get(i) + " ");
        }
        //将数组以二进制写入文件中
        try {
            writeData();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
//   将数组以二进制写入文件中
    public static void writeData() throws IOException {
        FileOutputStream fileWriter=new FileOutputStream(fileName,false);
        for (int singleData:userIndex) {
            fileWriter.write(singleData);
        }
        //写入文件
        fileWriter.close();
    }
}

心得

上次的手动修改使我了解到游戏中二进制的储存机制,并接触到了曾经认为遥不可及的事情。这次换代码实现,计算效率一下子提高了好多,只要编译成功,下次不需要再进行手动计算,就可以达到"一次编程,随时运行"的效果。另外,实现的过程也是让人感到乐在其中,首先将整体思路写出来,按照每步想实现的功能去查资料并实现。从IO流的应用到二进制的处理,再到字符串与数字的相互转换,这些知识点都在我心中有了更深的印记。感谢CSDN给我这次实训的机会,让我对Java又多了些热爱。劳伦斯曾说过“成功的秘诀,是在养成迅速去做的习惯,要趁着潮水涨得最高的一刹那,不但没有阻力,而且能帮助你迅速地成功”,对语言的真正掌握也只有不断地探索和实践。加油吧,少年!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-29 12:51:50  更:2021-10-29 12:52:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:18:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码