博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java版SLG游戏开发入门 2 --数据的读取及保存
阅读量:2200 次
发布时间:2019-05-03

本文共 10882 字,大约阅读时间需要 36 分钟。

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!

                 

  说到SLG游戏开发,无论其如何运转,里面都离不开各种数据的处理,一般来说,游戏越专业,需要处理的数据量将相对越大,类别也分得越细。

 

  游戏离不开美工,也离不开策划,各项参数的专业划分同样是评价一款SLG游戏是否优秀的必要指标之一。所谓的好游戏仅仅画面出彩,配乐一流是绝对不够的,做“靓”很容易,做“专”则很难。

 

  比如日本的超级机器人大战系列,自90年代初开始出现以来,截止到今天为止其中涉及的动漫超过60部,出场知名人物多达600名以上,几乎涵盖了日本所有知名机器人动画的机体(当然也有遗憾,比如机动警察)。这些角色无分善恶是各有各的fans,各有各的崇拜者。请这些“天王”出场,如果还做不好,过强或者过弱某一方,或者该出现的“华丽”技能没有出现,日本这些“ACG宅”的愤怒可是很恐怖的,正所谓“秋叶原前一声吼,东京也要抖三抖”。

 

  对动漫人物的把握程度,对角色参数的设定,起了尤为重要的作用。

 

  在这里鄙人不由得想起某位大神,就是 (Simulation RPG Construction)的作者鬼子Kei。这家伙从90年代末就用VB5.0开始制作SRC这个机战的同人制作工具,而我这辈子读的第一段程序代码,也正是某杂志随盘附录的SRC0.6版及其源码,当时我连VB是什么都不知道,彻底的读天书,于是才买书钻研VB……一晃10年,VB6.0我都已放下很久,他居然还在更新SRC,而且还是使用VB5开发,我不由惊叹鬼子的勤奋还有专注。10年工夫,我是也不信Kei不会用更简便的工具来制作SRC的,但是他却没有,硬是把VB5这个现在很多人用都没用过的古董级工具(实际上我也没用过|||)做出一款亚洲知名的机战同人开发工具来,10年来此人网站流量累计超过1690万,而且我也真的见过很多同人爱好者的SLG游戏是采用SRC开发。日本人真是恐怖,居然有人能甘心钻研VB5如此之久,如果把这种劲头用在工作上,想想我都不寒而栗,有这样的恒心这样弃而不舍的精神,在亚洲中国最大的潜在对手始终非日本莫属……咳咳,扯远了。

 SRC运行画面,运行需要VB5运行库,并日文Windows环境。(或者先用AppLocale转内码,再转日文脚本乱码后载入)

 

  通常来讲,我们不太可能将各种游戏数据硬编码到程序中,这样既不利于测试,也不方便重用,总需要一个外部文件作为存储介质。这时的选择其实很多,在Java游戏开发中我们即可以使用xml这类现有的规范格式,也可以干脆如SRC般自己定义脚本,或者将少量数据利用properties存储。

 

  就我个人认为,自己订制游戏脚本格式从长远看是最可取的,以后的同类项目方便重用,也不容易被他人盗取数据。而xml虽然有很多现成的组件可用,但是处理复杂业务时就没有自己的脚本用着方便,而且当数据很少时也有些杀鸡用牛刀的感觉。至于properties,存取单键值的数据固然很方便,但是对于表格类的数据,即使很简单也不适用,至少不直观了。

 

  在本例中我所采用的,是一种更为偷懒的方式,并不归属于以上所说,而是的利用csv格式,实现了一种较为另类的表格式数据存储。

 

   CSVComma Separated value),也叫逗号分隔值文件,是一种用来存储数据的纯文本文件格式,通常用于电子表格或数据库软件。我们打开windows记事本,随便打几个字母用“,”分割,再用excel查看,这时excel就会自动以表格方式显示这些数据。

 

 

 

  同样对于Java中的表格数据存储,也可以采用了这种方式保存,并且利用reflect机制映射到类,看上去即直观,也比xml省心,比自己写脚本省力。

  核心代码如下:

  1. package org.loon.simple.slg.utils;
  2. import java.io.IOException;
  3. import java.lang.reflect.Array;
  4. import java.util.ArrayList;
  5. import java.util.HashMap;
  6. import java.util.Iterator;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Set;
  10. import java.util.Map.Entry;
  11. /**
  12.  * Copyright 2008
  13.  * 
  14.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  15.  * use this file except in compliance with the License. You may obtain a copy of
  16.  * the License at
  17.  * 
  18.  * http://www.apache.org/licenses/LICENSE-2.0
  19.  * 
  20.  * Unless required by applicable law or agreed to in writing, software
  21.  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  22.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  23.  * License for the specific language governing permissions and limitations under
  24.  * the License.
  25.  * 
  26.  * @project loonframework
  27.  * @author chenpeng
  28.  * @email:ceponline@yahoo.com.cn
  29.  * @version 0.1
  30.  */
  31. public class CSVConfigure {
  32.     /**
  33.      * 载入CSV数据后转化为指定类的Object[]
  34.      * 
  35.      * @param fileName
  36.      * @param clazz
  37.      * @return
  38.      */
  39.     final static public Object[] loadPropertys(final String fileName,
  40.             final Class clazz) {
  41.         Object[] results = null;
  42.         try {
  43.             List properts = CSVConfigure.loadPropertys(fileName);
  44.             int size = properts.size();
  45.             results = (Object[]) Array.newInstance(clazz, size);
  46.             for (int i = 0; i < size; i++) {
  47.                 Map property = (Map) properts.get(i);
  48.                 Set set = property.entrySet();
  49.                 results[i] = clazz.newInstance();
  50.                 for (Iterator it = set.iterator(); it.hasNext();) {
  51.                     Entry entry = (Entry) it.next();
  52.                     ClassUtils.beanRegister(results[i],
  53.                             (String) entry.getKey(), (String) entry.getValue());
  54.                 }
  55.             }
  56.         } catch (Exception ex) {
  57.             throw new RuntimeException(ex+" "+fileName);
  58.         }
  59.         return results;
  60.     }
  61.     /**
  62.      * 载入CSV数据到List
  63.      * 
  64.      * @param fileName
  65.      * @return
  66.      */
  67.     final static public List loadPropertys(final String fileName) {
  68.         List result = new ArrayList();
  69.         try {
  70.             CSVReader csv = new CSVReader(fileName);
  71.             List names = csv.readLineAsList();
  72.             int length = names.size();
  73.             for (; csv.ready();) {
  74.                 Map propertys = new HashMap(length);
  75.                 String[] csvItem = csv.readLineAsArray();
  76.                 for (int i = 0; i < length; i++) {
  77.                     propertys.put((String) names.get(i), csvItem[i]);
  78.                 }
  79.                 result.add(propertys);
  80.             }
  81.         } catch (IOException e) {
  82.             e.printStackTrace();
  83.         }
  84.         return result;
  85.     }
  86. }

  使用方法:

  1. friends = (Friend[]) CSVConfigure.loadPropertys(FRIEND_FILE_NAME,
  2.                 Friend.class);
   只是一个很简单的反射,就可以将CSV表格数据注射到类上。

 

   再说一下游戏数据的存储,一般来讲就是指游戏记录,这在Java中是最好办的。因为只要你的关键数据对象实现serializable,大可以直接将当前状态序列化到本地文件中,不过是ObjectInputStreamObjectOutputStream的把戏罢了。

 

  如果没有或者你不想的话,你只要将关键数据以某种格式保存(这个真是随便,能再读出来就成),然后再反馈给游戏即可。实际上我们都知道所谓读档/保存并不是时间真的重来了,而是数据被还原罢了。

  用例代码:

  1. package org.loon.simple.slg.utils;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.BufferedReader;
  5. import java.io.ByteArrayInputStream;
  6. import java.io.ByteArrayOutputStream;
  7. import java.io.File;
  8. import java.io.FileInputStream;
  9. import java.io.FileOutputStream;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.InputStreamReader;
  13. import java.io.OutputStream;
  14. import java.io.Reader;
  15. import java.io.UnsupportedEncodingException;
  16. import java.net.URLDecoder;
  17. import java.net.URLEncoder;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import java.util.zip.GZIPInputStream;
  21. import java.util.zip.GZIPOutputStream;
  22. /**
  23.  * 
  24.  * Copyright 2008 
  25.  *
  26.  * Licensed under the Apache License, Version 2.0 (the "License");
  27.  * you may not use this file except in compliance with the License.
  28.  * You may obtain a copy of the License at
  29.  *
  30.  * http://www.apache.org/licenses/LICENSE-2.0
  31.  *
  32.  * Unless required by applicable law or agreed to in writing, software
  33.  * distributed under the License is distributed on an "AS IS" BASIS,
  34.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  35.  * either express or implied. See the License for the specific language
  36.  * governing permissions and limitations under the License.
  37.  *
  38.  * @project loonframework
  39.  * @author chenpeng  
  40.  * @email:ceponline@yahoo.com.cn 
  41.  * @version 0.1
  42.  */
  43. public class Keep {
  44.     private static final long serialVersionUID = -1982090153295778606L;
  45.     final static public String LS = System.getProperty("line.separator""/n");
  46.     final static public String FS = System.getProperty("file.separator""//");
  47.     
  48.     /**
  49.      * 增位变更指定字符串(混淆记录用)
  50.      * 
  51.      * @param s
  52.      * @param x
  53.      * @return
  54.      */
  55.     final static public String addChange(final String s, final int x) {
  56.         String result = null;
  57.         StringBuilder sbr = new StringBuilder();
  58.         for (int i = 0; i < s.length(); i++) {
  59.             char p = (char) (s.charAt(i) + x);
  60.             sbr.append(p);
  61.         }
  62.         try {
  63.             result = URLEncoder.encode(sbr.toString(),"UTF-8");
  64.         } catch (UnsupportedEncodingException e) {
  65.             throw new RuntimeException(e);
  66.         }
  67.         return result;
  68.     }
  69.     /**
  70.      * 减位变更指定字符串(混淆记录用)
  71.      * 
  72.      * @param s
  73.      * @param x
  74.      * @return
  75.      */
  76.     final static public String backChange(final String s, final int x) {
  77.         String result = null;
  78.         try {
  79.             result = URLDecoder.decode(s,"UTF-8");
  80.         } catch (UnsupportedEncodingException e) {
  81.             throw new RuntimeException(e);
  82.         }
  83.         StringBuilder sbr = new StringBuilder();
  84.         for (int i = 0; i < result.length(); i++) {
  85.             char p = (char) (result.charAt(i) - x);
  86.             sbr.append(p);
  87.         }
  88.         return sbr.toString();
  89.     }
  90.     
  91.     /**
  92.      * 压缩byte[]
  93.      * 
  94.      * @param buffer
  95.      * @return
  96.      */
  97.     public static byte[] compress(final byte[] buffer) {
  98.         try {
  99.             ByteArrayOutputStream baos = new ByteArrayOutputStream();
  100.             GZIPOutputStream gzipos = new GZIPOutputStream(baos);
  101.             gzipos.write(buffer);
  102.             gzipos.flush();
  103.             gzipos.close();
  104.             return baos.toByteArray();
  105.         } catch (IOException e) {
  106.             return null;
  107.         }
  108.     }
  109.     /**
  110.      * 压缩byte[]
  111.      * 
  112.      * @param buffer
  113.      * @return
  114.      */
  115.     public static byte[] uncompress(final byte[] buffer) {
  116.         try {
  117.             GZIPInputStream gzipis = new GZIPInputStream(
  118.                     new ByteArrayInputStream(buffer));
  119.             ByteArrayOutputStream baos = new ByteArrayOutputStream();
  120.             byte[] tmp = new byte[8192];
  121.             int len;
  122.             while ((len = gzipis.read(tmp)) > 0) {
  123.                 baos.write(tmp, 0, len);
  124.             }
  125.             baos.flush();
  126.             return baos.toByteArray();
  127.         } catch (IOException e) {
  128.             return null;
  129.         }
  130.     }
  131.     /**
  132.      * 保存游戏记录
  133.      * 
  134.      * @param file
  135.      * @param bytes
  136.      * @throws IOException
  137.      */
  138.     public static void save(final String fileName,final String message) throws IOException {
  139.         save(new File(fileName), new ByteArrayInputStream(Keep.compress(message.getBytes())));
  140.     }
  141.     /**
  142.      * 保存记录到文件
  143.      * 
  144.      * @param file
  145.      * @param input
  146.      * @throws IOException
  147.      */
  148.     private static void save(final File file,final InputStream input)
  149.             throws IOException {
  150.         mkdirs(file);
  151.         BufferedOutputStream output = null;
  152.         try {
  153.             int contentLength = input.available();
  154.             output = new BufferedOutputStream(
  155.                     new FileOutputStream(file, false));
  156.             while (contentLength-- > 0) {
  157.                 output.write(input.read());
  158.             }
  159.         } finally {
  160.             close(input, file);
  161.             close(output, file);
  162.         }
  163.     }
  164.     
  165.     final private static byte[] read(final InputStream inputStream) {
  166.         byte[] arrayByte = null;
  167.         BufferedInputStream buffer = new BufferedInputStream(inputStream);
  168.         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  169.         byte[] bytes = new byte[8192];
  170.         try {
  171.             int read;
  172.             while ((read = buffer.read(bytes)) >= 0) {
  173.                 byteArrayOutputStream.write(bytes, 0, read);
  174.             }
  175.             arrayByte = byteArrayOutputStream.toByteArray();
  176.         } catch (IOException e) {
  177.             throw new RuntimeException(e);
  178.         } finally {
  179.             try {
  180.                 if (buffer != null) {
  181.                     buffer.close();
  182.                     buffer = null;
  183.                 }
  184.             } catch (IOException e) {
  185.                 throw new RuntimeException(e);
  186.             }
  187.         }
  188.         return Keep.uncompress(arrayByte);
  189.     }
  190.     /**
  191.      * 读取记录到list
  192.      * 
  193.      * @param fileName
  194.      * @return
  195.      * @throws IOException
  196.      */
  197.     public static List load(final String fileName) throws IOException {
  198.         File file = new File(fileName);
  199.         BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(Keep.read(new FileInputStream(file)))));
  200.         List records = new ArrayList();
  201.         String record = null;
  202.         try {
  203.             while ((record = reader.readLine()) != null) {
  204.                 records.add(record);
  205.             }
  206.         } finally {
  207.             close(reader, file);
  208.         }
  209.         return records;
  210.     }
  211.     /**
  212.      * 创建文件夹
  213.      * 
  214.      * @param file
  215.      * @throws IOException
  216.      */
  217.     private static void mkdirs(final File file) throws IOException {
  218.         checkFile(file);
  219.         File parentFile = file.getParentFile();
  220.         if (parentFile != null) {
  221.             if (!parentFile.exists() && !parentFile.mkdirs()) {
  222.                 throw new IOException("Creating directories "
  223.                         + parentFile.getPath() + " failed.");
  224.             }
  225.         }
  226.     }
  227.     private static void checkFile(final File file) throws IOException {
  228.         if (file.exists() && !file.isFile()) {
  229.             throw new IOException("File " + file.getPath()
  230.                     + " is actually not a file.");
  231.         }
  232.     }
  233.     private static void close(final InputStream input,final File file) {
  234.         if (input != null) {
  235.             try {
  236.                 input.close();
  237.             } catch (IOException e) {
  238.                 closingFailed(file, e);
  239.             }
  240.         }
  241.     }
  242.     private static void close(final OutputStream output,final File file) {
  243.         if (output != null) {
  244.             try {
  245.                 output.close();
  246.             } catch (IOException e) {
  247.                 closingFailed(file, e);
  248.             }
  249.         }
  250.     }
  251.     private static void close(final Reader reader,final File file) {
  252.         if (reader != null) {
  253.             try {
  254.                 reader.close();
  255.             } catch (IOException e) {
  256.                 closingFailed(file, e);
  257.             }
  258.         }
  259.     }
  260.     private static void closingFailed(final File file,final IOException e) {
  261.         String message = "Closing file " + file.getPath() + " failed.";
  262.         throw new RuntimeException(message + ":" + e.getMessage());
  263.     }
  264. }

导出的结果:

 

  比如在这个示例游戏中,我将保存的数据先递增字符位数,再经过URL编码,最后gzip压缩,出来的一组鬼画符般记录文档,唯一的作用就是不让人轻易读出并修改罢了。当然这只是最简单的例子,我们完全加密的更复杂(比如玩玩DES),验证的更变态,让玩家也无法修改游戏分毫,毕竟让玩家快乐且痛苦的游戏,就是游戏制作者最大的乐趣及兴奋点啊,哈哈哈。(惊见板砖+臭鸡蛋,我闪~~~

主菜单界面:

  游戏基本界面,背景设定主角在一座城镇中,有五项基本命令可供选择。
 
  队友雇用界面:
  即酒店界面,用于寻找战友加入
 
  物品购入界面: 
  商店,用于补充游戏中物品
 
  物品装备界面:
  道具装备,用于装备购入的物品
 
  关卡选择界面:  
  任务选择,本示例由于没有考虑做大,所以直接将关卡做成赏金模式供玩家选择
  
   战斗画面:
   最初有过在此例复刻梦幻模拟战2的打算,但由于没有找到整套的素材,所以作罢。谁有兴趣帮兄弟找到整套素材(关键是各兵种战斗图)的话,我可以再作一个复刻梦幻2的例子。
 
  

           

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!

你可能感兴趣的文章
机器学习中常用评估指标汇总
查看>>
什么是 ROC AUC
查看>>
Bagging 简述
查看>>
详解 Stacking 的 python 实现
查看>>
简述极大似然估计
查看>>
用线性判别分析 LDA 降维
查看>>
用 Doc2Vec 得到文档/段落/句子的向量表达
查看>>
使聊天机器人具有个性
查看>>
使聊天机器人的对话更有营养
查看>>
一个 tflearn 情感分析小例子
查看>>
attention 机制入门
查看>>
手把手用 IntelliJ IDEA 和 SBT 创建 scala 项目
查看>>
GAN 的 keras 实现
查看>>
AI 在 marketing 上的应用
查看>>
Logistic regression 为什么用 sigmoid ?
查看>>
Logistic Regression 为什么用极大似然函数
查看>>
SVM 的核函数选择和调参
查看>>
LightGBM 如何调参
查看>>
用 TensorFlow.js 在浏览器中训练神经网络
查看>>
cs230 深度学习 Lecture 2 编程作业: Logistic Regression with a Neural Network mindset
查看>>