<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="ProgId" content="Word.Document">
<meta name="Generator" content="Microsoft Word 11">
<meta name="Originator" content="Microsoft Word 11">
<link rel="File-List" href="file:///C:%5CDOCUME%7E1%5Cchenpeng%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:PunctuationKerning/>
<w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
<w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
<w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SpaceForUL/>
<w:BalanceSingleByteDoubleByteWidth/>
<w:DoNotLeaveBackslashAlone/>
<w:ULTrailSpace/>
<w:DoNotExpandShiftReturn/>
<w:AdjustLineHeightInTable/>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:UseFELayout/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" LatentStyleCount="156">
</w:LatentStyles>
</xml><![endif]--><style>
<!--
/* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"/@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.5pt;
mso-bidi-font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:宋体;
mso-font-kerning:1.0pt;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;}
@page Section1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]-->
说到SLG游戏开发,无论其如何运转,里面都离不开各种数据的处理,一般来说,游戏越专业,需要处理的数据量将相对越大,类别也分得越细。
游戏离不开美工,也离不开策划,各项参数的专业划分同样是评价一款SLG游戏是否优秀的必要指标之一。所谓的好游戏仅仅画面出彩,配乐一流是绝对不够的,做“靓”很容易,做“专”则很难。
比如日本的超级机器人大战系列,自90年代初开始出现以来,截止到今天为止其中涉及的动漫超过60部,出场知名人物多达600名以上,几乎涵盖了日本所有知名机器人动画的机体(当然也有遗憾,比如机动警察)。这些角色无分善恶是各有各的fans,各有各的崇拜者。请这些“天王”出场,如果还做不好,过强或者过弱某一方,或者该出现的“华丽”技能没有出现,日本这些“ACG宅”的愤怒可是很恐怖的,正所谓“秋叶原前一声吼,东京也要抖三抖”。
对动漫人物的把握程度,对角色参数的设定,起了尤为重要的作用。
在这里鄙人不由得想起某位大神,就是SRC (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格式,实现了一种较为另类的表格式数据存储。
CSV(Comma Separated value),也叫逗号分隔值文件,是一种用来存储数据的纯文本文件格式,通常用于电子表格或数据库软件。我们打开windows记事本,随便打几个字母用“,”分割,再用excel查看,这时excel就会自动以表格方式显示这些数据。
同样对于Java中的表格数据存储,也可以采用了这种方式保存,并且利用reflect机制映射到类,看上去即直观,也比xml省心,比自己写脚本省力。
核心代码如下:
-
packageorg.loon.simple.slg.utils;
-
importjava.io.IOException;
-
importjava.lang.reflect.Array;
-
importjava.util.ArrayList;
-
importjava.util.HashMap;
-
importjava.util.Iterator;
-
importjava.util.List;
-
importjava.util.Map;
-
importjava.util.Set;
-
importjava.util.Map.Entry;
-
-
-
publicclassCSVConfigure{
-
-
-
finalstaticpublicObject[]loadPropertys(finalStringfileName,
-
finalClassclazz){
-
Object[]results=null;
-
try{
- Listproperts=CSVConfigure.loadPropertys(fileName);
-
intsize=properts.size();
- results=(Object[])Array.newInstance(clazz,size);
-
for(inti=0;i<size;i++){
- Mapproperty=(Map)properts.get(i);
- Setset=property.entrySet();
- results[i]=clazz.newInstance();
-
for(Iteratorit=set.iterator();it.hasNext();){
- Entryentry=(Entry)it.next();
- ClassUtils.beanRegister(results[i],
- (String)entry.getKey(),(String)entry.getValue());
- }
- }
-
}catch(Exceptionex){
-
thrownewRuntimeException(ex+""+fileName);
- }
-
returnresults;
- }
-
-
-
finalstaticpublicListloadPropertys(finalStringfileName){
-
Listresult=newArrayList();
-
try{
-
CSVReadercsv=newCSVReader(fileName);
- Listnames=csv.readLineAsList();
-
intlength=names.size();
-
for(;csv.ready();){
-
Mappropertys=newHashMap(length);
- String[]csvItem=csv.readLineAsArray();
-
for(inti=0;i<length;i++){
- propertys.put((String)names.get(i),csvItem[i]);
- }
- result.add(propertys);
- }
-
}catch(IOExceptione){
- e.printStackTrace();
- }
-
returnresult;
- }
- }
使用方法:
- friends=(Friend[])CSVConfigure.loadPropertys(FRIEND_FILE_NAME,
-
Friend.class);
只是一个很简单的反射,就可以将CSV表格数据注射到类上。
再说一下游戏数据的存储,一般来讲就是指游戏记录,这在Java中是最好办的。因为只要你的关键数据对象实现serializable,大可以直接将当前状态序列化到本地文件中,不过是ObjectInputStream和ObjectOutputStream的把戏罢了。
如果没有或者你不想的话,你只要将关键数据以某种格式保存(这个真是随便,能再读出来就成),然后再反馈给游戏即可。实际上我们都知道所谓读档/保存并不是时间真的重来了,而是数据被还原罢了。
用例代码:
- packageorg.loon.simple.slg.utils;
-
- importjava.io.BufferedInputStream;
- importjava.io.BufferedOutputStream;
- importjava.io.BufferedReader;
- importjava.io.ByteArrayInputStream;
- importjava.io.ByteArrayOutputStream;
- importjava.io.File;
- importjava.io.FileInputStream;
- importjava.io.FileOutputStream;
- importjava.io.IOException;
- importjava.io.InputStream;
- importjava.io.InputStreamReader;
- importjava.io.OutputStream;
- importjava.io.Reader;
- importjava.io.UnsupportedEncodingException;
- importjava.net.URLDecoder;
- importjava.net.URLEncoder;
- importjava.util.ArrayList;
- importjava.util.List;
- importjava.util.zip.GZIPInputStream;
- importjava.util.zip.GZIPOutputStream;
-
-
-
-
publicclassKeep{
-
-
privatestaticfinallongserialVersionUID=-1982090153295778606L;
-
-
finalstaticpublicStringLS=System.getProperty("line.separator","/n");
-
-
finalstaticpublicStringFS=System.getProperty("file.separator","//");
-
-
- finalstaticpublicStringaddChange(finalStrings,finalintx){
-
Stringresult=null;
-
StringBuildersbr=newStringBuilder();
-
for(inti=0;i<s.length();i++){
-
charp=(char)(s.charAt(i)+x);
- sbr.append(p);
- }
-
try{
-
result=URLEncoder.encode(sbr.toString(),"UTF-8");
-
}catch(UnsupportedEncodingExceptione){
-
thrownewRuntimeException(e);
- }
-
returnresult;
- }
-
-
-
- finalstaticpublicStringbackChange(finalStrings,finalintx){
-
Stringresult=null;
-
try{
-
result=URLDecoder.decode(s,"UTF-8");
-
}catch(UnsupportedEncodingExceptione){
-
thrownewRuntimeException(e);
- }
-
StringBuildersbr=newStringBuilder();
-
for(inti=0;i<result.length();i++){
-
charp=(char)(result.charAt(i)-x);
- sbr.append(p);
- }
-
returnsbr.toString();
- }
-
-
-
-
publicstaticbyte[]compress(finalbyte[]buffer){
-
try{
-
ByteArrayOutputStreambaos=newByteArrayOutputStream();
-
GZIPOutputStreamgzipos=newGZIPOutputStream(baos);
- gzipos.write(buffer);
- gzipos.flush();
- gzipos.close();
-
returnbaos.toByteArray();
-
}catch(IOExceptione){
-
returnnull;
- }
- }
-
-
-
-
publicstaticbyte[]uncompress(finalbyte[]buffer){
-
try{
-
GZIPInputStreamgzipis=newGZIPInputStream(
-
newByteArrayInputStream(buffer));
-
ByteArrayOutputStreambaos=newByteArrayOutputStream();
-
byte[]tmp=newbyte[8192];
-
intlen;
-
while((len=gzipis.read(tmp))>0){
- baos.write(tmp,0,len);
- }
- baos.flush();
-
returnbaos.toByteArray();
-
}catch(IOExceptione){
-
returnnull;
- }
- }
-
-
-
-
publicstaticvoidsave(finalStringfileName,finalStringmessage)throwsIOException{
-
save(newFile(fileName),newByteArrayInputStream(Keep.compress(message.getBytes())));
- }
-
-
-
-
privatestaticvoidsave(finalFilefile,finalInputStreaminput)
- throwsIOException{
- mkdirs(file);
-
BufferedOutputStreamoutput=null;
-
try{
-
intcontentLength=input.available();
-
output=newBufferedOutputStream(
-
newFileOutputStream(file,false));
-
while(contentLength-->0){
- output.write(input.read());
- }
-
}finally{
- close(input,file);
- close(output,file);
- }
- }
-
finalprivatestaticbyte[]read(finalInputStreaminputStream){
-
byte[]arrayByte=null;
-
BufferedInputStreambuffer=newBufferedInputStream(inputStream);
-
ByteArrayOutputStreambyteArrayOutputStream=newByteArrayOutputStream();
-
byte[]bytes=newbyte[8192];
-
try{
-
intread;
-
while((read=buffer.read(bytes))>=0){
- byteArrayOutputStream.write(bytes,0,read);
- }
- arrayByte=byteArrayOutputStream.toByteArray();
-
}catch(IOExceptione){
-
thrownewRuntimeException(e);
-
}finally{
-
try{
-
if(buffer!=null){
- buffer.close();
-
buffer=null;
- }
-
}catch(IOExceptione){
-
thrownewRuntimeException(e);
- }
- }
-
returnKeep.uncompress(arrayByte);
- }
-
-
-
-
publicstaticListload(finalStringfileName)throwsIOException{
-
Filefile=newFile(fileName);
-
BufferedReaderreader=newBufferedReader(newInputStreamReader(newByteArrayInputStream(Keep.read(newFileInputStream(file)))));
-
Listrecords=newArrayList();
-
Stringrecord=null;
-
try{
-
while((record=reader.readLine())!=null){
- records.add(record);
- }
-
}finally{
- close(reader,file);
- }
-
returnrecords;
- }
-
-
-
-
privatestaticvoidmkdirs(finalFilefile)throwsIOException{
- checkFile(file);
- FileparentFile=file.getParentFile();
-
if(parentFile!=null){
-
if(!parentFile.exists()&&!parentFile.mkdirs()){
-
thrownewIOException("Creatingdirectories"
-
+parentFile.getPath()+"failed.");
- }
- }
- }
-
-
privatestaticvoidcheckFile(finalFilefile)throwsIOException{
-
if(file.exists()&&!file.isFile()){
-
thrownewIOException("File"+file.getPath()
-
+"isactuallynotafile.");
- }
- }
-
-
privatestaticvoidclose(finalInputStreaminput,finalFilefile){
-
if(input!=null){
-
try{
- input.close();
-
}catch(IOExceptione){
- closingFailed(file,e);
- }
- }
- }
-
-
privatestaticvoidclose(finalOutputStreamoutput,finalFilefile){
-
if(output!=null){
-
try{
- output.close();
-
}catch(IOExceptione){
- closingFailed(file,e);
- }
- }
- }
-
-
privatestaticvoidclose(finalReaderreader,finalFilefile){
-
if(reader!=null){
-
try{
- reader.close();
-
}catch(IOExceptione){
- closingFailed(file,e);
- }
- }
- }
-
-
privatestaticvoidclosingFailed(finalFilefile,finalIOExceptione){
-
Stringmessage="Closingfile"+file.getPath()+"failed.";
-
thrownewRuntimeException(message+":"+e.getMessage());
- }
-
- }
-
导出的结果:
比如在这个示例游戏中,我将保存的数据先递增字符位数,再经过URL编码,最后gzip压缩,出来的一组鬼画符般记录文档,唯一的作用就是不让人轻易读出并修改罢了。当然这只是最简单的例子,我们完全加密的更复杂(比如玩玩DES),验证的更变态,让玩家绞尽脑汁也无法修改游戏分毫,毕竟让玩家快乐且痛苦的游戏,就是游戏制作者最大的乐趣及兴奋点啊,哈哈哈。(惊见板砖+臭鸡蛋,我闪~~~)
主菜单界面:
游戏基本界面,背景设定主角在一座城镇中,有五项基本命令可供选择。
队友雇用界面:
即酒店界面,用于寻找战友加入
物品购入界面:
商店,用于补充游戏中物品
物品装备界面:
道具装备,用于装备购入的物品
关卡选择界面:
任务选择,本示例由于没有考虑做大,所以直接将关卡做成赏金模式供玩家选择
战斗画面:
最初有过在此例复刻梦幻模拟战2的打算,但由于没有找到整套的素材,所以作罢。谁有兴趣帮兄弟找到整套素材(关键是各兵种战斗图)的话,我可以再作一个复刻梦幻2的例子。
SLG游戏入门示例及源码下载地址:http://download.csdn.net/source/809105
分享到:
相关推荐
关于绘制光标及绘制窗体响应鼠标事件的示例
JavaSLG游戏开发入门示例及其源码(源码在jar内)
python库。 资源全名:slg-dev-ops-1.6.2.tar.gz
这是一个自制的SLG的Java PC游戏用例,本利仅为游戏本身,源码将随blog更新发布,当然有兴趣的允许反编译,未加密。
python库。 资源全名:slg-dev-ops-1.12.1.tar.gz
python库。 资源全名:slg-dev-ops-1.4.1.tar.gz
资源来自pypi官网。 资源全名:slg-dev-ops-1.0.4.tar.gz
资源来自pypi官网。 资源全名:slg_dev_ops-1.6.4-py3-none-any.whl
资源分类:Python库 所属语言:Python 资源全名:slg-dev-ops-1.17.11.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
LGame-J2SE版发布过的旧例子,移植到Android环境之下,源码并没有太大变动(当然,调整为触摸屏了),算是最为基础的SLG实现,移动方式为最短距离寻径。
这是一个精简的Java版SLG入门示例(源码在jar内),仅演示了最基本的SLG游戏功能,具体请参阅博文[Java版战棋(SLG)游戏AI及寻径处理入门]。
一个J2ME SLG游戏范例,是学习SLG游戏编程的好例子,一定会收获不少 !
SLG游戏类的游戏可谓“棋盘式游戏”,如三国志2、4、5,机器人大战,梦幻模拟战等都是典型的SLG游戏。该游戏的一大特点就是:走格子。移动,攻击 范围都是以格子为攻击单位。其实SLG游戏的特点远不止这些。在这里,...
2021-2025年中国SLG类移动游戏行业调研及可持续发展战略究报告.pdf
J2ME中的SLG游戏示例代码,SLG战略实现 时间 2005年4月14日16:44 李波 小图模式 1:光标移动OK 2:滚屏OK 3:人物动作OK 4:人物移动OK 5:移动范围限定OK 6:显示菜单OK 7:多人物模式OK ...
cocos2d-x开发的手游客户端源码及资源文件,用来学习参考不错。
SLG示例源代码,基于J2ME,可以学习一下哦!
割绳子,数字游戏,俄罗斯方块,中国象棋,植物大战僵尸,按钮特效,心形进度条,赛车游戏,预测球的轨迹,愤怒的小鸟,ClippingNode,刀光效果,SLG,魂斗罗,天天过马路,橡皮擦效果,流体test,2d 光线,愤怒的小鸟2,弹球游戏,...