我有一款咪咕游戏总是支付失败,总是移动失败。它总是要占手机内存。

我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?
来源:互联网
责任编辑:李平字体:
红米4x手机怎样插卡红米Note4X怎么插卡?红米Note4X是小米又一款千元强机,以超强的续航能力受到了用...然后稍微用力一顶即可弹出SM卡槽,我们将手机SIM卡放入卡槽,然后再装入手机即可,具...红米4x手机背面有一个按钮,它有什么用处红米4x手机背面,有一个圆形凹下去的,差不多有一个一毛钱硬币大小!这是指纹识别模组的所在区域!希望有用!红米4x手机下载的软件什么会移不到存储卡呢?安卓系统为了系统的运行的更稳定所以不允许软件装到内存卡了只能安装到手机内存中比如音乐视频照片这些较大的文件是可以放到内存卡的红米4x有足够的内存让你安装...我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?(图2)我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?(图4)我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?(图8)我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?(图10)我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?(图12)我是红米4x手机啊,如图所示,点击安装出现失败了啊?是什么游戏呢?(图14)
红米4x手机壳怎么打开正确的手机开后盖方法:开盖时首先必须要有一个力的支点,然后给后盖一个开盖的向上受力点。开盖的步骤是:1、左手抓住手机上部,不要用力只是稳住手机2、右手操作手机下...防抓取,好心游戏网提供内容,请查看原文。用户回答1:红米4x手机如何和电脑一起上网同时连接一个WiFi网络就可以防抓取,好心游戏网提供内容,请查看原文。
说明你有重复安装,再其他应用里下载安装就可以了
红米4X手机GPS无缘无故自动开后台运行软件就这样!防抓取,好心游戏网提供内容,请查看原文。相关解决方法如下:小米2s跟红米4x哪部手机玩游戏性能更好非要二选一,当然是后者红米4x更好。准确点说都不强,都差。屏幕上4x是720p,高配4是1080p,还是能看出差别的。最重要的是cpu上4x只有骁龙435一款,防抓取,好心游戏网提供内容,请查看原文。
红米4X手机怎么加软件不明白你所说的加载是什么意思,如果是想安装软件的话可以到小米应用商店里面去搜索下载,下载后会自动安装的,安装好就可以使用了。防抓取,好心游戏网提供内容,请查看原文。您好,您可以在您的电脑上安装pc套件,然后连上您的手机,选择软件页面,搜索您想要使用的软件,然后点击安装即可;
您也可以使用您的手机浏览器浏览软件的官网,到软件下载页...红米4x手机如何装入手机卡SIM卡安装方法步骤:1.首先取出包装盒中的SIM卡针,然后垂直插入红米Note4X机身左侧...是安装在卡托标有字的一面。3.将SIM卡安装到卡托中后,再将卡托正面朝上,推防抓取,好心游戏网提供内容,请查看原文。
我的红米4为什么识别不了SIM卡答:无法识别sim卡,查看是什么原因造成的并解决:1、查看手机卡槽或者sim卡有没有损坏:可以插入其他手机卡尝试,再将手机本身的sim卡放到其他手机上看看,如果是卡槽损防抓取,好心游戏网提供内容,请查看原文。&&& 进入"设置"--"关于手机"--"版本号"或"内核版本",连续快速点击"版本... 电脑中的 豌 豆 荚会自动在网上搜索并安装适合你手机的驱动,在手机弹出的USB选项中...我手机是红米4,我恢复了出厂设置,可还是不行,怎...答:现在根本就没有红米4手机,刚发售到红米3,哪来的红米4防抓取,好心游戏网提供内容,请查看原文。
急急。买的红米4,丢了,找回来了但他不给,怎么确...问:急急。买的红米4,丢了,找回来了但他不给,怎么确定这红米4是我的(没...答:你好,你可以拿出你的手机盒,看手机和背面的手机序列号,然后对比手防抓取,好心游戏网提供内容,请查看原文。亲,关于您的手机下载安装应用失败,小编建议您尝试以下方法:
手机仅支持 APK 格式的... 才能正常安装。进入"设置"界面,点击"安全",勾选"未知来源"复选框,然后重新安装该应用...我才买的红米4打不出去电话,怎么回事答:建议按一下方法进行排查一下:①是否正确的插入了SIM卡。②是否插入了错误的SIM卡,如标准版插入电信SIM卡等。③进入硬件检测查看SIM卡是否工作正常(拨号界面防抓取,好心游戏网提供内容,请查看原文。
为什么我手机打不出电话也接不了电话,我手机是红米4答:你的手机是否设置了“勿扰模式”,这样就会出现你说的情况,可以在你的手机设置里修改回来。手机可能系统出现了问题,建议备份后恢复出厂设置,若不行,找售防抓取,好心游戏网提供内容,请查看原文。是系统版本问题啊,我有过的,要刷稳定版的系统,别尝鲜..如图所示,我点击哪个啊?都不管用啊!我是红米4手...答:点击右上角那个叉子,图里面已经提示你了,你没有手机券,不能兑换,所以只好退出了。防抓取,好心游戏网提供内容,请查看原文。
有谁知道我的红米4屏幕是哪个牌子的答:有说,不过根据红米4贴吧已购买的用户反馈的消息,大多用的是天马屏幕和富士康屏幕,都是国产。屏幕其实可以放心,八九百手机的屏幕素质都差不多,比不上两三千的,但也不会防抓取,好心游戏网提供内容,请查看原文。点击下载⑶存储卡兼容性方面解决方案:将待安装程序转移到手机内存再安装,安装位置依然自定.二、证书过期为什么部分S603rd程序安装会出现"证书过期"呢?因为一些程序使...我的红米4经常死机了呢,不知道咋回事答:手机经常死机,经刷机无效,即为硬件问题,只能送修解决。若为偶然几次死机,可参考下面死机故障原因分析:1、不只是红米手机有死机现象,其他品牌Android系统的手防抓取,好心游戏网提供内容,请查看原文。
我是红米4的手机,手机一来电就无法显示电话号码我...答:对方使用通话软件刻意抹去了号码信息。如何实现这种效果,只要手机频段不在电信、移动、联通或者其他国际手机运营商的运营范围内,显示的就是未知号码。防抓取,好心游戏网提供内容,请查看原文。影响软件运行,建议大型游戏或程序安装到TF卡中,小的系统程序可以安装到手机内存中... 点击&已安装的程序&进入,移动到SD卡。
3、其它地方下载的程序,通过手机...为什么我的红米Note4没有关于手机答:MIUI8最新系统版本,没有关于手机的选项,改为我的设备了,打开设置,第一行就是我的设备,里面内容和原来的关于手机是一样的防抓取,好心游戏网提供内容,请查看原文。
防抓取,好心游戏网提供内容,请查看原文。内购插件不是万能的,一些特殊的可以到网上查存档
也可以试试最新的iapfree2.0分谁,adc340移速出鞋才400,荆轲出门就400,还没等跑呢,已经输了。没有位移adc350。荆轲出鞋你想跑都跑不了。现在荆轲有的出那个脱离战斗加60移速那个鞋。没法玩。不是技术不行,是先天压制。防抓取,好心游戏网提供内容,请查看原文。
早在去年,新年后不再破解游戏和转载破解资源,三大妈全面转型,要发展成为集卖正版,出攻略的综合性网站。此事件起因,是因一家日本公司发给三大妈的警告信(函)引起,具体过程是三大妈破解(转载)了《三国志13防抓取,好心游戏网提供内容,请查看原文。同事大型游戏运行的次数较少没必要放在手机内存上占用空间。
极品飞车数据包和安装程序不分先后,都装好后才能玩。
他说的对的。
1.可以安装在tf卡上,手机内存东西多了...不会啊,我媳妇有时候安慰我还会送我皮肤呢。玩游戏嘛,每个人理解不一样。有的人觉得浪费,有的人觉得划算不贵,我觉得在能接受的范围里面都是可以的。其实这里面最耗钱的是水晶和符文,其余的不算贵。不过这游戏最防抓取,好心游戏网提供内容,请查看原文。
我遇到最尴尬的一件事就是差点失去了我的第一次。当时正在包夜,一个女的从我身边走过,看着她火辣的身材加上黑丝皮裙就没忍住一直盯着看,想看她做哪台机,谁知她突然转头和我对视五秒钟,然后问我看什么。我鬼使神防抓取,好心游戏网提供内容,请查看原文。这可能你下载的游戏是更新之前的,说以一打开就会出现过你这样的问题,我也试过,你打开泡泡的客户端进去下载个就新版就行了。今天我要说的是关于本人的一个故事,一个关于《魔兽世界》JJC的故事个人认为魔兽世界PVP做的算是非常平衡了,首先天赋百花齐放,百家争鸣。部落最良心的地方就是不会出现土豪吊打潘康恼庵智榭龀鱿郑灰闶址雷ト。眯挠蜗吠峁┠谌荩氩榭丛摹
应该是我的世界好玩,添加一些mod,光影材质,动态光影,add-ons,皮肤,披风之类的。迷你世界的mod,皮肤,披风,add-ons,光影材质,动态光影都没有,而且这些有些要钱,里面的物品还要等级解防抓取,好心游戏网提供内容,请查看原文。手机是7个数字;;好一点的手机是8位数;;数越大表示手机能运行游戏文件的大小;;你下载512KB以下的游戏;如果是7位数;你就下载256KB以下的游戏;;下载放到内存卡里选择安装...小伙苦战195分钟获胜,后台却没有战绩,找客服理论无果只好以跳楼相逼。很多玩家放弃LOL转战王者荣耀,就是因为手机游戏时间短,一把只要十几二十分钟。而今天要说了这位玩家足足玩了195分钟王者荣耀,手机防抓取,好心游戏网提供内容,请查看原文。
1.饥荒饥荒主人公威尔逊是个实验失败的科学家,一次实验时打开了收音机,收音机却传给他禁忌的知识,他造出了时空穿越器,启动后却不小心被传到了饥荒的时代。每个地图都会随机生成一个麦斯威尔的传送门,通过十五防抓取,好心游戏网提供内容,请查看原文。答:一般是可用内存不足,而部分常驻内存的进程不服从IOS的内存回收机制。这种情况在越狱的机器上比较常见,特别是安装了很多cydia里面的常驻后台插件以后。简单的方法就是备份一下你的程序和数据,然后重刷系统,再有选择的安装插件来测试;复杂的...谢谢小秘书邀请(????)王者荣耀玩猴子用什么名字?个人认为玩猴子不一定非要去用与猴子相关的名字,既然题主就是有这样的需要,我绞尽脑汁想到了几个我个人认为还不错的名字。吃我一棒放屁都暴击齐天如果感觉只有文字很单调的话可以适当添加一些符号????????????????????????ζ?????????????????ζ?????????????n?????????????⊙●○①◎Θ⊙¤I★☆防抓取,好心游戏网提供内容,请查看原文。
《迷你世界》抄袭《Minecraft》是事实,有买《Minecraft》的版权的话,为什么《迷你世界》官方至今没把版权证明拿出来?《迷你世界》的皮肤人设极渣,还收费!艹!那么渣的皮肤也收费!《迷你世界防抓取,好心游戏网提供内容,请查看原文。答:个人觉得根据自己喜好,从系统上来讲: 一、 安卓系统,自由开放,一般的软件和应用都可以安装! 系统可以自由刷机,不受限制! 二、 苹果系统,安全稳定,运行比较流畅,系统安全高,软件安装需要许可 系统刷机麻烦,越狱后风险较高。 综上所述...肯定迷你...话不多说大家都清楚吧……抄袭mc它还挺有理.一堆借口什么mc有枪吗?有什么公主床吗?不愧可以说是一款小学生玩的游戏呀??公主床这些的...mc不需要?还有minidog说,mc画质太差,全是方的,我不确定它们智商知不知道材质包和mod这个东西但是,我敢确定mc比它们迷你那不方不圆的好多了!因为一款沙盒游戏“方”,才是主要元素!它们连图标都抄袭我们籽民大大的.还有建筑....下面??是防抓取,好心游戏网提供内容,请查看原文。
大学的时候,班级一共三十个人,能组两个队伍5vs5,各种讨论战术,各种谁都不服。现在登上游戏,满满一页好友只有两三个在游戏中加的不认识的人在线,久久不显示正在游戏中。以前去网吧,爆满的网吧里玩其他游戏防抓取,好心游戏网提供内容,请查看原文。答:更新后应该不会提示了…如果还有删除重新安装。要想逼格高最重要的一点是:走别人没走过的路叔本华曾说过这样一句话:有才之人,能击中别人无法击中的目标;天才,能击中别人连看都看不到的目标。Talenthitsatargetnooneelsecanhi防抓取,好心游戏网提供内容,请查看原文。
以前玩大话最早是在05年,现在十多年了,那时候开始还买点卡,后来自己能跑200后,一直自己跑200挣点卡钱,一直也没冲过什么钱,直到他妈的有一次端午节任务,说出来是好事,但是塞翁失马焉知非福,我得了一防抓取,好心游戏网提供内容,请查看原文。答:在电脑上登陆官网主页,点击上部的下载按键,然后选择手机型号版本,进入后在这个页面先下载最新版系统包,然后在这个页面点击刷机教程,选择线刷方法,在教程里下载刷机工具miflash安装到电脑上,在电脑上修复系统。如果需要获取root权...当然是选贵的....如果是只送一个的话……荣耀水晶与王者水晶兑换的最好。芈月:大秦宣太后(用了红桃皇后代替一下....)小乔:天鹅之梦钟无艳:海滩丽影孙尚香:杀手不太冷(没找到图.....)韩信:教廷特使(首先你要有韩信)再下面就是贵哒了荆轲:暗夜猫娘鲁班:电玩小子墨子:龙骑士项羽:苍穹之光不过谁会送你皮肤呢……防抓取,好心游戏网提供内容,请查看原文。
在这个困的睁不开眼得中午,你把我拉了过来,算了,说正题。支持那个游戏,说实话,我支持最开始,国外的我的世界,被网易一代理,作为一名学生党,哪有钱买啊,别说我穷,我真的掏不出来这45块钱,所以说,支持最防抓取,好心游戏网提供内容,请查看原文。答:你好!这个应该是你路由器信号穿墙能力不行,建议购买使用更好的路由器,又或者使用WIFI信号放大器。我觉得应该是李白第一,露娜第二,貂蝉第三把。李白是新买的,买完了立马配了一个千年之狐,感觉帅炸了,赶紧去秀,我已经预见到我就是下一个剑仙,我仿佛看到了我刷大抢龙拿五杀了,结果――0-5。嗯?我的打开方防抓取,好心游戏网提供内容,请查看原文。
首先得看你在哪里,比如:1你在亚洲中国等地那你最先思考的是应该躲在哪里,毕竟这里禁枪人口又太密集,好一点的刀具也没多少,况且咱们又不是啥主角什么的出门就能捡个三棱军刺的,但是菜刀之流的千万别要拿,那玩防抓取,好心游戏网提供内容,请查看原文。答:不用管 手机过温会自动降频的。只要不是很烫手就没事。一如果是在游戏里打架的话那肯定MC赢咯,MC就是不用MOD不用指令不开创造,仗着人多也能把迷你狗们打到喊爹吧,适合打架的MOD我看非无尽贪婪莫属,无尽套穿满后不会再受到任何伤害,剑的伤害是∞,也就是说防抓取,好心游戏网提供内容,请查看原文。
首先王者荣耀是属于一个推塔游戏再到团战游戏,而不是各打各的。实事证明车队打排位上分比起单排上分容易2.5倍,车队的胜率也比单排多19%左右。今天聊一下很多玩家都会遇到的情况。如果团灭敌方之后,是集合推防抓取,好心游戏网提供内容,请查看原文。问:红米4和红米4x哪个性能好点,玩游戏不卡,哪个比较好看,我是一个学生。感谢邀请,本人先说明一下,我的世界创始于2009年,迷你创建于啥时候?2015年!说minecraft抄袭垃圾迷你的,咋TM想的你!要你这么说Notch从2009年穿越到2015年抄袭迷你,再跑回去,防抓取,好心游戏网提供内容,请查看原文。答:红米4的高配比红米4X高配,CPU对比 高通骁龙430/骁龙625(64位八核) 高通骁龙435(四核) 红米4占优势。 屏幕规格 5英寸0x1080 5英寸 红米4和红米4X 标配一样,但是高配的话,红米4比红米4X分辨率高。 价格上相差100元,你...谢邀。首先说一下王者荣耀的评分系统,根据你的击杀数,被杀数,助攻数还有参团率等一系列因素给你的评分。首先这个分数在有些情况下是很不合理的。举个栗子,李元芳打野很强,抢大龙小龙很快,偷到主宰对团队的贡献很大吧,但是在最后评分无法体现。通常两边正常打不送不放水的情况下两波主宰会推掉对面两三座塔甚至更多,但是这在评分上没有体现。所以分数只是一个参考,高分并不代表厉害,低分也并不代表很坑,我用猴子在劣势的防抓取,好心游戏网提供内容,请查看原文。
大司马――我的梦想是开一家真皮网咖,本名韩金龙,是斗鱼直播平台旗下的一名签约主播。主播的内容当然是英雄联盟。直播时间段固定在每天下午三点到晚上八点,周三固定休息。其他时间段没特殊情况一般都会播。你是李防抓取,好心游戏网提供内容,请查看原文。问:红米4x手机提示有风险啊?风险是安装猎豹浏览器就不风险了,可我的手机...那我们就来谈谈王者荣耀1v1模式厉害的英雄????(? ̄??? ̄??)1、不知火舞火舞一套技能几乎是可以直接秒人的,特别是二技CD短,伤害高,还会减速,而且六段位连跳,可以直接让人吐血,但到了后期,能防抓取,好心游戏网提供内容,请查看原文。答:可以不用理它的,套路来的wot属于比较冷门的类型,但好制作比较精良,虽然根据游戏性的需求做了点妥协,但还是有一定的真实度的,但“黄金五九”之类的做法还是有点反胃。毕竟wot的题材和操作门槛没办法让绝大部分人适应(虽然已经很简防抓取,好心游戏网提供内容,请查看原文。
今天是全中国和全高考生的大日子,那就是高考。对于高考想必很多人都是紧张的,尤其是家长和考生,三年来的努力都在7、8、9三日里体现了,在此小编也祝各位能够取得一个好成绩,上自己理想的大学。对于考试紧张压防抓取,好心游戏网提供内容,请查看原文。答:是移动换购活动的红米4x吗。手机本身无问题,可能是网页的事,你刷新一下,还是不行换个手机重新点。我也有过这种情况,如果是前期对线的话能打赢他的ADC的确不多,女警,奥巴马和他有的一拼。女警超远射程可以有很好的消耗效果,而且清兵特快,一旦推进了你的塔内,在你方塔下放三角阵或者八字,一字型夹子,那你补兵都不好补,只有防抓取,好心游戏网提供内容,请查看原文。
首先是你自己把自己玩累了,我就是把它当游戏玩,本来就是娱乐,当自己过于执着一段代码,而不是娱乐,交友,怎么都会累。我就是仅仅当做娱乐,每天两小时,刷刷世界,打打战场等等。其次魔兽是退步好多,但是我敢说防抓取,好心游戏网提供内容,请查看原文。答:你还没有下载呢,不用卸,别点下载,不用管它。玩了5年的起凡,不知道有没有人知道这个游戏。当时我还是小学的时候就比较火了(我08年6年级)。初一才开始到这个游戏。那个时候全班的男生百分之50都玩起凡。每天下课就聚在一起聊游戏。什么昨天我拿了两个m防抓取,好心游戏网提供内容,请查看原文。红米4X手机怎样将后盖打开插卡该手机为一体机不能开后盖请注意手机左侧(没有按键的一侧)有一个小孔用取卡针或者曲别针插进去顶出卡托&将手机卡放在卡托上再将卡托插回手机里就可以了红米4x手机壳怎么打开正确的手机开后盖方法:开盖时首先必须要有一个力的支点,然后给后盖一个开盖的向上受力点。开盖的步骤是:1、左手抓住手机上部,不要用力只是稳住手机2、右手操作手机下...红米4x手机如何和电脑一起上网同时连接一个WiFi网络就可以为您准备的好内容:
最新添加资讯
24小时热门资讯
Copyright © 2004- All Rights Reserved. 好心游戏网 版权所有
京ICP备号-1 京公网安备02号尊敬的用户您好!因系统升级,暂时无法访问,给您带来的不便我们感到万分抱歉。论坛开放时间将另行通知,感谢您的理解与支持!
10 秒后自动跳转页面3058人阅读
在信息社会中,手机及其他无线设备越来越多的走进普通百姓的工作和生活,随着信息网络化的不断进展,手机及其他无线设备上网络势在必行。但是传统手机存在以下弊端:
1.& 传统手机出厂时均由硬件厂商固化程序,程序不能增加、删除,有了错误也不能更新、修改,若要增加新功能必须另换一部手机。
2.& 传统手机访问互联网是通过WAP(Wireless Application Protocal),所有网络资源必须接通网络才能在线访问,非常耗时、费用亦很高。
而Java技术在无线应用方面的优势非常明显:
1.& 应用程序可按需下载,而不是购买由硬件商提供的套件,可升级空间大。
2.& Java技术提供了一个类库,它使的应用开发商可以创建更为直觉、丰富的用户界面(GUI);
3.& Java技术使网络带宽的应用更为有效,因为应用程序可以下载到器件上,并在本地运行,仅仅是在连接到服务器时才会占用网络带宽。
基于以上分析,Java手机将是未来手机的发展方向,是业界的热点。
虽然 Java 已经被用到许多企业级软体上,可是其实骨子里面还是非常适合用在嵌入式系统之中。Java平台演进到Java2后,Java平台分别针对不同领域的需求被分成四个版本,亦即J2EE、J2SE、J2ME以及JavaCard。其中J2ME定位在消费性电子产品的应用上。这个版本针对资源有限的电子消费产品的需求精简核心类库,并提供了模块化的架构让不同类型产品能够随时增加支持的能力。这个版本的应用层面相当广泛,会是未来Java平台发展的重点项目。
J2ME在1999年的JavaOne开发人员大会上初次亮相,它的目标是面向智能无线设备和小型计算机设备的开发人员。J2ME的一个关键优点是,J2ME与所有支持Java的设备都是兼容的。支持Java的设备就是任何运行Java虚拟机器的计算机。Motorola、Nokia等生产厂商都生产支持Java的设备。、
J2ME平台是由配置(Configuration)和简表(Profile)构成的。配置是提供给最大范围设备使用的最小类库集合,在配置中同时包含Java虚拟机。简表是针对一系列设备
提供的开发包集合。在J2ME中还有一个重要的概念是可选包(Optional Package),它是针对特定设备提供的类库,比如某些设备是支持蓝牙的,针对此功能J2ME中制定了JSR82(Bluetooth API)提供了对蓝牙的支持。
目前,J2ME中有两个最主要的配置,分别是Connected Limited Devices Configuration(CLDC)和Connected Devices Configuration(CDC)。
作为第一个面对小型设备的Java应用开发规范,CLDC是由包括Nokia,Motorola和Siemens在内的18家全球知名公司共同协商完成的。CLDC是J2ME核心配置中的一个,可以支持一个或多个profile。其目标主要面向小型的、网络连接速度慢、能源有限(主要是电池供电)且资源有限的设备,如手机、PDA等。
而CDC则是主要用于运算能力相对较佳、在电力供应上相对比较充足的嵌入式装置 (比方说冷气机、电冰箱、电视机机顶盒 (set-top box))
&&& 一个手机游戏应该具有以下特征:
易于学习: 既然手机游戏面向的是普通消费者而不是计算机专家,那么他们不可能深入的学习游戏技巧。消费者不会花几个小时去研究一个3元的手动操作的游戏。保持游戏的简单是最基本的要求。
可中断性: 多任务处理是手机生活方式的基本特征。手机用户常常在任务(如等一个电子邮件或者等车)之间有一小段时间。而游戏、日历管理、通讯和工作数据访问使用的是同一个设备。所以一个好的手机游戏应该提供短时间的娱乐功能,并且允许用户在游戏和工作模式之间顺利切换。
基于订阅:手机游戏的盈利成功取决于他们巨大的使用量。一开始开发和设计每个游戏都是昂贵的。如果一个手机游戏开发者要赢利的话,重要的是:同一个游戏引擎,多个标题,基本的故事情节类似。基于订阅的游戏是不断产生收入的最好方法。
丰富的社会交互: 不管一个游戏设计得多好,只要玩家找到了它的根本模式或者玩完了所有的游戏路径很快就会厌烦这个游戏。对于一个基于订阅的游戏,重要的是与别的玩家合作以增强所玩游戏的智力和随机性。在今天纷繁复杂的多玩家游戏中具有丰富社会交互的游戏证明是成功的。
利用手机技术的优点: 巨额的手机技术研发费用都花在提高设备和网络的可用性和可靠性上面。因此,手机设备硬件和网络协议与桌面/控制台世界(如全球定位系统(GPS)扩展、条形码扫描仪、和短消息服务(SMS)/多媒体信息服务(MMS)通讯)有着非常大的差别。好的手机游戏应该利用那些更新的设备特征和网络基础设备的优点。
在抗战中,由国民政府领导的中国空军是所有国民党军队中抗战最为彻底,也最为英勇的部队,虽然开战之初力量悬殊,但是面对穷凶极恶的日本侵略者,他们毫不畏惧,视死如归,全力以赴投身到民族救亡的伟业中去,用自己的鲜血和生命谱写了中华民族最为豪迈的诗篇。自一九三二年二月五日“一·二八”事件始,至一九四五年八月十四日止,抗战期间,共出动飞机一千一百二十八批,八千八百四十七架次,击落敌机五百二十九架,击伤敌机一百一十架,炸毁敌机二百二十七架。同时,中国空军空战中一共牺牲空勤人员六百六十一名。
我至今仍然清楚的记得,在抗日战争即世界反法西斯战争胜利50周年的时候,我在一本描述抗战空军的书里第一次看到阎海文烈士那年青的面孔时所带来的震撼,第一次看到高志航、沈崇海等空军烈士的事迹时所带来的感动,第一次听说碧山空战时的无奈。
时至今日,已经很少有人能够记得在中国的天空献身的抗日英雄们,我只能引用下面这句话来表达我的心情:“你们的名字无人知晓,你们的业绩与世长存! ”
我的这款游戏取名为《览桥风光》,以纪念从览桥中央航校走出的英雄们。
引言和第一章中介绍了手机在无线应用方向的当今概况,J2ME的相关内容,分析了J2ME在手机软件开发中起的重要作用,描述了本论文的相关背景。
开发环境及相关技术的介绍
操作系统:Microsoft Windows XP
程序语言:Java 2
开 发 包:Java(TM) 2 Standard Edition (5.0)
&&&&&&& Sun Micro. J2ME&& Wireless Tool Kit 2.2
IDE:&&& Eclipse 3.01
1. 平台无关性
Java引进虚拟机原理,并运行于虚拟机,实现不同平台之间的Java接口。Java的数据类型与机器无关。
Java的编程类似C++,但舍弃了C++的指针对存储器地址的直接操作,程序运行时,内存由操作系统分配,这样可以避免病毒通过指针入侵系统。它提供了安全管理器,防止程序的非法访问。
3. 面向对象
&&& Java吸收了C++面向对象的概念,将数据封装于类中,实现了程序的简洁性和便于维护性,使程序代码可以只需一次编译就可反复利用。
Java建立在TCP/IP网络平台上,提供了用HTTP和FTP协议传送和接收信息的库函数,使用其相关技术可以十分方便的构建分布式应用系统。
Java致力与检查程序在编译和运行时的错误,并自动回收内存,减少了内存出错的可能性。Java取消了C语言的结构、指针、#define语句、多重继承、goto语句、操作符、重载等不易被掌握的特性,提供垃圾收集器自动回收不用的内存空间。
&&& Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括 Java 开发工具(Java Development Tools,JDT)。
虽然大多数用户很乐于将 Eclipse 当作 Java IDE 来使用,但 Eclipse 的目标不仅限于此。Eclipse 还包括插件开发环境(Plug-in Development Environment,PDE),这个组件主要针对希望扩展 Eclipse 的软件开发人员,因为它允许他们构建与 Eclipse 环境无缝集成的工具。由于 Eclipse 中的每样东西都是插件,对于给 Eclipse 提供插件,以及给用户提供一致和统一的集成开发环境而言,所有工具开发人员都具有同等的发挥场所。
这种平等和一致性并不仅限于 Java 开发工具。尽管 Eclipse 是使用 Java 语言开发的,但它的用途并不限于 Java 语言;例如,支持诸如 C/C++、COBOL 和 Eiffel 等编程语言的插件已经可用,或预计会推出。Eclipse 框架还可用来作为与软件开发无关的其他应用程序类型的基础,比如内容管理系统。Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。
WTK(Wireless Tool Kit)是Sun公司针对J2ME推出的用于手机和Palm等移动设备的开发包,是除手机厂商的专用开发包外唯一的手机模拟器开发包。它通用性高,开发出的应用程序可保证能运行在大部分设备上,而不像专用厂商具有一定的不兼容性。虽然它没有强大的功能和完善的调试手段,但它提供运行模拟器的最基本组件,是其他IDE需集成采用的必备元素。
手机中负责调配程序运行资源的管理后台是Java Application Manager。它所使用的传输媒体可以是红外线、网络、以及其他可用来传输的媒体。Java Application Manager 会从网络上下载代表该Application Suite 的JAR 档,接着在手机上安裝此MIDlet Suite,然后在手机开始执行该应用程序。
第二章介绍了Java语言的特点、本程序的开发环境及其相关工具的原理和使用。
程序结构、思想和相关技术
1.& 游戏程序是一项精度要求很高的程序系统,因为其代码利用率很高。一个实时运行的最终作品,每秒都会运行成千上万行程序,绘图事件、键盘事件都会以极高的频率在后台等待响应,若有丝毫的差别都将很容易导致程序在运行不久后可能出现严重错误,甚至死循环。因此,其逻辑设计应当相当严谨,需将所有可能发生的事件及意外情况考虑在设计中。
2.& 游戏中为了美观,适用性强,可能需要采用外部文件引入的图片贴图,有关贴图,在MIDP2.0中提供了用于增强游戏功能的game包,使得解决静态或动态、画面背景、屏幕刷新的双缓冲等都有较好的解决方案。
3. 玩家飞机的运行可以通过键盘响应事件控制,但敌方则因为是自动运行,就需要有一定的智能性;敌人飞机的运行算法也要进行相关的设置,已免游戏过于简单。
4.对于双方发射的子弹应该赋予不同的速度,同时,程序应该设定敌人飞机的子弹不与敌人的飞机进行碰撞检测,已增加游戏的可玩性。
5. 双方的飞机在前进时也需要考虑到是否碰撞到对方飞机,以免重叠运行,造成许多物理上不可能的情况,缺乏真实感。每一次刷新页面、每前进一步都需要进行相关的碰撞检测。
6.为了增加界面的美观,在程序中添加了白云。由于手机屏幕大小有限,所以白云的数量和出现的位置要经过相关的设置,才能实现白云不规则出现的效果。
7.& 游戏的地图不可能通过绘图来解决。否则,不仅难于控制和处理过多的元素,也会因过多的大型图片而不能限制程序的大小,失去手机上程序的原则和Java的优势。
8.& Java是基于虚拟机的半解释型编译系统,其执行效率较C++等完全编译后的程序会低很多,程序如果不进行精简和优化,将可能导致运行的不流畅。除开发过程中对结构上的控制、变量的使用、算法的优化等优化外,还可以使用混淆器(Obfuscator)进行程序打包后的优化。
9.& 游戏的结束、开始、动态信息画面作为构成一个程序都是必不可少的重要部分。良好的用户界面更是吸引用户的硬指标,相关的美术构图和人性化设置也需要有一定的考虑。
以上相关技术细节和整体流程将分别在以下小节阐述。
(Destroyed)
StartApp()
DestroyApp()
呼叫MIDlet的构造函数
DestroyApp()
PauseApp()
图3-1& MIDlet的流程
MIDlet suite是MIDP应用程序的最小单位,JAM负责将手机内的MIDlet suite以图形化的方式呈现,让用户能够选取欲执行的MIDlet suite,一旦选取了某个MIDlet suite,操作系统就会激活KVM执行里面的MIDlet。MIDlet及相关的支持类组成了MIDP应用程序的实际内容。而
每个MIDlet都必须继承javax.microedition.midlet.MIDlet这个抽象类。在MIDP规范中定义了MIDlet的生命周期,以及可以存在的三种状态,包括Paused、Active以及Destroyed,每一个MIDlet在任何时刻只可能处于其中的一个状态。这三种状态的转换关系如图3-1所示:MIDlet有三个状态,分别是pause、active和destroyed。在启动一个MIDlet的时
候,应用管理软件会首先创建一个MIDlet实例并使得他处于pause状态,当startApp()方法被调用的时候MIDlet进入active状态,也就是所说的运行状态。在active状态调用destroyApp(boolean unconditional)或者pauseApp()方法可以使得MIDlet进入destroyed或者pause状态。值得一提的是destroyApp(boolean unconditional)方法,事实上,当destroyApp()方法被调用的时候,AMS通知MIDlet进入destroyed状态。在destroyed状态的MIDlet必须释放了所有的资源,并且保存了数据。如果unconditional为false的时候,MIDlet可以在接到通知后抛出MIDletStateChangeException而保持在当前状态,如果设置为true的话,则必须立即进入destroyed状态。
本程序采用面向对象的设计模式,对游戏中的所有物体赋予对象的概念和属性。运行程序后允许用户选择执行选项菜单,在开始游戏后将先从外部文件载入地图文件,对背景的所有物体进行绘图。在主程序运行的线程中,画面刷新将以一定的频率采用双缓冲技术对屏幕重绘,实时反映整个游戏的进行状态。
游戏开始后先绘制地图,并将各个对象实例化。在主程序运行的线程中,游戏中所有的对象都应该运行在同一个线程下。当敌人或者用户的子弹达到射程范围后,并不删除子弹对象,而是使用setVisable(false)使其不能显示,当用户或敌人在次发射子弹时,只需使用setVisable(true)设置成可以显示即可。在屏幕重绘的主程序中,将在每次的循环中判断若干事件,以便程序进入相关的分支执行相关的反应代码。如:玩家剩余飞机数是为0、敌人、玩家飞机是否被击中、屏幕上相关信息的绘制等。
程序为需要完成独立功能的模块设置了单独的类。lzhhdm类继承自Midlet,gameScrenn类、MenuScreen类继承自GameCanvas,mybullets继承自Sprite类。载入程序后首先启动的是程序介绍的信息画面。点击ok后调用MenuScreen类实现菜单。
如果选择进入游戏,则调用gameScreen类,并且中止MenuScreen类中的线程运行,已提高运行速度。
Mybullets类为玩家子弹类。
为了能有程序开发人员控制接口的外观和行为,需要使用大量的初级用户接口类,尤其在游戏程序中,几乎完全依赖的就是Canvas抽象类进行绘图。从程序开发的观点看,Canvas类可与高级Screen类交互,程序可在需要时在Canvas中掺入高级类的组件。Canvas提供了键盘事件、指点杆事件(如果设备支持),并定义了允许将键盘按键映射为游戏控制键的函数。键盘事件由键代码指定,但这样控制游戏会导致缺乏通用性,并不是每个设备的键盘布局都适合游戏的操作。应当将键代码转换为游戏键的代码,以便硬件开发商能定义他们自己的游戏键布局。
Graphics类提供了简单的2D绘图功能。它具有24位深度色彩的绘制能力,以三原色分别各占一个字节表示其颜色。程序只能在paint()函数中使用Graphics绘制,GameCanvas可调用getGraphics()函数直接绘制在缓冲区上,可以在任何时间请求传输到前台。其对象会被传给Canvas的paint()函数,以便最终显示。
在没有MIDP2.0前,进行游戏绘图一般需要手动编程使用双缓冲。需要在paint()方法内将所想要画的图形画在一张预先准备好的背景上,等所有绘图操作都完成后再将背景的数据拷贝到实际的屏幕上。Image类提供了一个建立背景的静态方法createImage(int width, int height),再利用getGraphics()方法取得属于这个背景的Graphics对象,所进行的绘图操作都会作用在背景上,等到全部的绘图操作完成后,再调用drawImage()方法将背景的数据复制到实际显示的屏幕上。
这样的技术在绘制动画时特别有用。绘制动画时经常需要不断地更新画面,而更新画面的操作就是先将屏幕以fillRect()的方式清除,再将下一张图片画在屏幕上,然而反复的清除及重绘会造成屏幕的闪烁现象(flicker),因此使用双重缓冲的好处就是在背景进行这个清除及重绘的操作,再将完成的绘图拷贝到屏幕上,由于用户看不到清除的操作,因此就不会出现闪烁的现象了。不过在某些MIDP的实现上已经加上了双重缓冲的支持,因此在处理前应先利用Canvas类的isDoubleBuffer()方法来判断。
&&& J2ME的流行促进几个运营商和制造商开发了一些支持游戏的类,但是,这却造成了游戏缺乏可移植性的问题,例如,很难将使用Siemens的Sprite类的游戏移植到Nokia上。
&&& 在MIDP2.0版本发布后,这些游戏移植性问题初步得到了解决。MIDP2.0新加入了
GameCanvas、Sprite、Layer、LayerManager、TiledLayer五个与游戏开发相关的类。其中 Layer类一般不会直接用到。
&&& Game类的出现不仅降低了错误出现的几率,也使游戏代码变的更小,因为开发者不需要自己编写象Sprite这种例子。下面将简要介绍Game类。
&& &GameCanvas类继承自Canvas,所以具有Canvas所具有的功能,还额外增加了一些便于游戏设计的功能。比如: GameCanvas类直接提供了getKeyStates(),使程序员可以在同一个线程自己侦测按键的状态。GameCanvas类提供了flushGraphics()的功能,实现了双缓冲技术。
&&& 所谓的Sprite,就是画面上独立移动的图形。
Sprite类是继承自Layer的用于存储多桢的基本可视元素。不同的frame可交相显示,构成动态的效果。图片可翻转、颠倒、由一个主角图片就可以方便的得到所有方向的显示状态,相比原先只能使用Canvas绘图,需要将所有方向的主角图象都绘制在png图象中简化了许多。Sprite也可以从整合的图象中读图,读图时将把大图分解为若干等宽等高的小图。每个小图按照其排列顺序有相应的序号,在程序中调用其序号,就可以绘制出相应的图片。本程序中的双方飞机、子弹、白云都由Sprite继承得到。
LayerManager提供控制整体画面层的控制。它包括了一系列自动获取了代号和位置的层,简化了各层加入游戏画面的过程,提供了自动排序和绘制的能力。
LayerManager存储了一个层的列表,新的层可以用函数附加、删除和插入。层的序号相当于坐标的Z轴,0层表示最接近用户视觉,层数越高,离用户越远。层号总是连续的,即使有中间的层被移除,其他层的序号会作相应的调整以保持整体的完整性。LM中的View Window控制着与LM相对坐标的可视区域。改变View Window的位置可以制造出滚动屏幕的效果。
TiledLayer是有一组图象格元素组成的整块虚拟图象。该类使不需要高分辨率的图象就能创建大幅图面成为可能。这项技术通常应用在2D游戏平台的滚动背景的绘图。一块整图可被分割成等大小的图象格,每块格有其对应的序号,按照行列递增。多块小格可由大块同时替换组合而模拟动态的背景,这不需要逐块替换所有的静态图象格而显得非常方便。
PNG(Portable Network Graphics)格式是MIDlet唯一支持的图象格式,PNG具体格式由PNG Specification,Version 1.0定义的。PNG格式提供透明背景的图象,这对绘制游戏画面和被操纵主角极有帮助。飞机之间或与白云碰撞时就不会因为背景有特定的颜色,显示出的效果像贴上的图片而缺乏真实感,物体之间轻微重叠时最上层图片也不会覆盖超过其有效象素外的部分。
PNG格式图片中包含许多定义其图片特性的冗余部分(Chunks)。这些代码包含在每一个单独的png格式图象中,然而如果将多个png图象合并在一张幅面稍大一些的整图中,多个chunks就可以得到精简,图片的大小可以得到控制。使用Image类中的createImage函数可从整图中分割出所需要的元素。在Game包中的TiledLayer和Sprite类都整合了这样的功能。本程序中的地图元素都集成在一张beijing.png图片中,实现了方便的管理和程序体积的精简。
&&& GameCanvas提供getKeyStates函数可获取当前键盘上的信息。将以位的形式返回键盘上所有键的按与释放的状态,当bit为1时,按键就是被按下的状态,为0时则为释放状态。只需要此一个函数的返回值就可以返回所有键的状态。这保证了快速的按键和释放也会被循环所捕捉。同时,这样的机制也可检测到几个键同时按下的状态,从而提供斜向运行等相应功能(本程序没有实现斜上运行功能)。
&&& 程序运行时应该对玩家飞机是否飞出屏幕的范围进行检测,如果飞出屏幕,就应该重新设定玩家飞机的位置。
&&& 玩家飞机被击中后,为了平衡游戏的可玩性,玩家飞机将有短暂时间无敌,即不进行碰撞检测,同时在屏幕右上角显示无敌时间。
&&& 根据游戏设定,敌人飞机。不能与玩家飞机重合,则他每走一步都需要检测一下是否与玩家飞机碰撞。Sprite类中提供了collidesWith函数,用于判断是否与某个Sprite、TiledLayer、Image的对象有图象上的重合(即游戏中的碰撞)。同理,还需要检测玩家子弹与敌机、敌机与玩家子弹是否碰撞。如果发生碰撞,将相关精灵图片替换为爆炸图片。
敌人飞机需要具有一定的智能性,以便对玩家攻击,使游戏具有一定的可玩性。敌人可以在适当时候转向或者开炮火,同时,程序应该检测敌机是否飞出了界外。
在普通敌机中,有一组敌机的其中一架具有跟踪功能,其原理为:当其进入屏幕后,根据玩家飞机的X、Y坐标不断调整自己的X、Y坐标,已达成跟踪的效果。由于线程的关系,敌机器的改变方向有时并不是实时的,这就可以使玩家有躲开撞击的可能,增强了游戏的可玩性。
在游戏进行中出现的大型飞机,由于其不可能立即被击落,所以应该设置其的运行方法,理论上讲还是根据玩家飞机的坐标,但是,在此设置一个标志位,使得敌人在取的玩家位置后即开始玩家方向运动,这期间,将不执行取得玩家飞机位置重设飞行方向的步骤。这样做,即防止了大飞机变成跟踪飞机,又使得大飞机的运行具有不确定性。
在关尾出现的BOSS,其在屏幕上方左右移动并发射子弹。实际上,此时BOSS应该通过玩家在游戏运行中的习惯性的运行方向,使用遗传算法,来动态判断玩家下一步的运行方向,并且指挥普通飞机出现在预测的位置上。可惜由于时间关系没有实现。
&&& 玩家的子弹是个精灵数组,有9个元素,表示玩家一次最多可以发射3组9发子弹,对于一个完整的游戏来讲,应该根据关卡的不同而给予玩家不同的飞机,飞机性能的差别在于子弹的射程不同。由于本游戏仅有一关,所以子弹速度设定的差别没有体现出来。
&&& 当玩家一次发射了3组子弹,而这3组子弹并没有消失时,玩家将无法发射子弹。
&&& 使用每组子弹的第一发作为与敌人进行碰撞检测的精灵,同时相关的标志位也设在第一发子弹中。如果玩家子弹与敌机相撞,则敌机消失时,子弹精灵的图片替换为爆炸图片,直到第二次发射该组子弹时,才将图片替换为子弹图片。
手机内存空间小,所以在程序设计时应该注意以下几点,以尽量减少内存的使用:
&&& (1)尽量缩短命名的长度。在应用程序内,对于所建立的类、接口、方法及变量名而言,都需要赋予一个识别的名称,所命名的名称每多一个字符就会在类文件内多产生一个字节,对于一个较复杂的应用程序而言就会增加为数不小的数据量。所有这些可以借助混淆器来帮助实现
&&& (2)所有代码写为一个类。
&&& (3)只使用一个线程。
&&& (4)尽量不使用静态变量。
&&& (5)将PNG图片合并成一张,减少图形数据的大小。
将PNG格式的小分辨率图象合并在一张大的高分辨率图象中,由于减少了头文件的大小,将比合并前的总大小减少许多。
Wireless Tool Kit提供了许多在运行时监视运行状态的工具。 包括内存状况的检测(手机上的内存空间十分有限,必须时刻关注机载内存是否大于程序所能使用到的最大可能的内存空间),网络状况的检测,运行函数的跟踪等。内存检测器是内存跟踪测试随时间变化的调试器。其中,允许强制垃圾回收(Garbage Collection)。由于Java语言中,不像许多其他的如C++语言,不需要指定回收函数中特定不使用的资源,资源回收机制将自动清空无效变量占用的空间。在程序运行中也可以调用System类的gc()函数手动收回废弃的内存。
Java 语言并没有完全编译成二进制可执行文件,编译出的.class文件是一种介于源程序和二进制之间的一中基于半解释的字节码,需要虚拟机来执行。它包括了所有的信息。然而这样会导致.class很容易被反编译为源代码,从而不能保护作者的知识成果。目前流行的如decode,JAD等反编译工具可以以很快的速度生成源文件。如果不加以施行有效的措施,将造成严重的后果。
由此引入混淆器的概念。混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,如果缺乏相应的函数名指示和程序注释,即使被反编译,也将难以阅读。
&&& 混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的减少变量、函数的命名长度的关系,编译后也会从.class文件中减少这些冗余的信息。混淆后,体积大约能减少25%,这对当前费用较贵的无线网络传输是有一定意义的。
第三章中介绍了程序的流程、相关技术的思想及其在本程序中的应用。对游戏基本算法等做了详细叙述。具体算法的代码实现和详细流程将在下章介绍。
程序分析和具体实现
每个MIDlet程序都必须有一个主类,该类必须继承自MIDlet。它控制着整个程序的运行,并且可以通过相应函数从程序描述文件中获取相关的信息。该类中拥有可以管理程序的创建、开始、暂停(手机中很可能有正在运行程序却突然来电的情况,这时应进入暂停状态。)、结束的函数。本程序主类为lzhhdm,并实现接口CommandLIstener。
首先显示的是游戏的背景介绍(图4-1),为此,在类lzhhdm定义Form类对象a,在startApp()函数中判断isSplash是否为真,如果为真的话,将创建Form类的实例a,并且调用append()方法在表单上放置StringItem类的实例以显示游戏背景信息。使用语句ok=new &Command(&ok&,Command.OK,1);实例化Command类对象ok。调用addCommand()命令建立ok命令与Form之间的关联,调用setCommandListener()命令使Form与CommandListener建立关联。调用Displayable的
图4-1游戏背景介绍&&&&&&&&&&&&&&&&&&
&& seturrent()函数显示背景介绍窗口。
&&&& 当玩家点击ok后将调用display.setCurrent(menuscreen)&&
以显示游戏菜单menuscreen(图4-2)。&
&&& 类menuscreen继承自Canvas类,并实现接口Runnable
和CommandListener。在类menuscreen中定义了lowColor和
highColor、highBGColor三个整型变量及布尔型变量co。其
中lowColor赋值为0x000000FF,代表兰色,higColor赋值为
0x00FF0000,代表红色,highBGColor赋值为0x00CCCCCC,代表
图4-2 游戏的菜单
兰灰色,即背景条。当玩家按住上或下键时,在函数keyPressed
(int code)中的整型变量menuIndex相应的减1或加1,相应的,在paint()函数中会根据menuIndex绘制选项是否被选中。在函数run()中,如果co为真,则不停的repaint(),设置co的意义在于,当进入游戏主画面后,co赋值为false,以终止绘制选项的repaint(),提高游戏速度。&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&
&&& 当移动选项条到某项,并点击ok时,在commandAction()方法中根据 menuIndex&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
pzbzover==0
玩家被击落了吗 ?
玩家是否还有机会?
返回主界面
图4-4 gameScreen类主要关系流程图
的值判断选择了哪个选项,列如当选择“关于”时,将调用lzhhdm类中的renwuShow()方法以显示”关于”界面(图4-3),在renwuShow()方法中,Form类对象a=null,表示清空Form,并重新调用用append()方法在表单上放置StringItem类的实例以显示游戏关于信息,“帮助“界面的显示与”关于“界面相同,只不过调用的是helpShow()方法。
&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
图4-3关于界面
在介绍游戏主类gameScreen类之前,应该先简要说明一下玩家子弹类mybullets类,实际上,mybullets类是应该删除的,其要实现的功能应该放在gameScreen类中,但是由于设计游戏的过程也是一个学习的过程,而在当时,我并没有意识到这一点。&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
类继承自Sprite类,以实现玩家子弹的相关功能。首先,创建子弹状态数组private int[][] bullets,其中,[i][0]代表子弹的X坐标,[i][1]代表子弹的Y坐标,[i][2]代表子弹Y方向速度,[i][3]代表子弹存活状态(由于此类是在早期设计的,而之后子弹存活状态使用了子弹射程作为标志位,所以其并没有起到作用)。类中定义的方法setfirstposition()起到定义玩家子弹发射坐标的作用(此方法在设计时起到的作用是消除每按一次开火玩家子弹位置就重新定位这个BUG,但是,这个BUG完全可以用设置标志位的方法消除)。方法newposition()实现的功能为更新玩家的子弹位置,并且检测玩家子弹与普通敌人的碰撞及记录玩家战果(更新子弹位置的功能可以由使用move()加设置标志位的方法取代;由于设计这个类的时候并没有考虑到添加BOSS等,所以在此检测碰撞,但添加BOOS等功能后,此处的检测完全可以和飞机对飞机等的碰撞检测封装在同一个方法中)。
mybullets类在gameScreen中建立了对象数组huokebullet[9],代表玩家所能发射的9发子弹。
&&& gameScreen类是游戏的主类,决定着敌人何时出现,控制着敌人出现的方法,判断敌人及玩家是否被击中等。它运行在独立的线程中,以恒定的频率刷新画面。本程序设置为1/20秒。其主逻辑如图4-4所示。&&&&&
类所实现的功能
gameScreen类要实现地图的滚动、敌人飞机的相关属性、玩家的相关属性等功能。
gameScreen类包括了LayerManager,这样所有静态和动态的图象都不需要手动刷新,只需要在LayerManager中加入所有的需要控制的精灵,在统一由LayerManager刷新即可, 因此,在gameScreen中创建LayerManager的对象lm,并在构造函数中实例子化。
其他精灵类的对象如敌人飞机、玩家飞机、玩家飞机的子弹、敌人的子弹、BOSS及BOSS所属的子弹都需在gameScreen()类中建立相应的对象,并在构造喊数中实例化,且由lm.appned()方法添加到LayerManager类对象lm中。
地图的创建
&& 由于手机存储空间的限制,不可能将整张地图完整地存储在手机中,为了节约空间,往往提出地图中相同的图片组成一张PNG格式的图片,然后象拼图一样拼出地图来,专业的游戏设计者往往自己写一个地图编辑器,以使拼图过程不是那么痛苦。
创建地图就需要使用TiledLayer。TiledLayer指的是由一块一块类似用瓷砖拼凑起来的画面。地图实际即为TiledLayer的一个对象。先利用TiledLayer的构造函数建立TiledLayer,根据构造函数的参数可以给定Cell数组 的大小,并且地图图片切割成等尺寸的画面,并调用setCell()设置具体的图象格内容。地图
图4-5 地图
图片如图4-5所示。
&&& 因此,创建一个返回TtiledLayer的方法createBackGround(),以便在gameScreen()的构造函数中调用。在方法中,定义整型数组map1[]以存储Cell的索引值。并使用tiledLayer.setCell(column,row,map1[i])设定TtiledLayer的内容,以形成地图。其中i的值由循环for(int i=0;i&map1.i++)取得,column由语句column=i%15取得、行由row=(i-column)/15取得。
&&& 画出地图后,由lm.append()将地图添加到LayerManager类对象lm中。由于地图位于Layer的最低层,即离用户视线最远的层,所以Tiledlayer最后一个被添加到lm中。
地图的移动&&
&& &根据游戏的设定,游戏中地图是向下移动的,实现此功能的方法如下:
&&& 首先,在使用createBackGround()函数创建地图数组时,用(row+1)*16-getHeight()&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
语句对整型变量row2赋值,其中row+1代表地图有多少列,16为地图片的高度,而减去getHeight()是因为要留出一个屏幕的可视区域,由于J2ME规定坐标系中下方向为正,所以使用语句y1=-row2将row2的数值变为负数。
&&&&&&&&&&&&&&&&&& &&&&&&y1=y1+1;
&&&&&&&&&&&&&&&&&& View Window&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& 向下移动&&&&&&&&&&&&&&
& (0,0)&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& &&&&&&&&图4-6&
&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& 其次,render()函数中,使用lm.setViewWindow(0,0,getWidth(),getHeight()+10000)设定可视区域的范围,(0,0)表示View Window的起始坐标,(getWidth() ,getHeight()+10000)&
使用lm.paint(g,0,y1)决定
View& Window从屏幕的哪里画起。
在run()函数中的while(conti)中,
使用语句y1=y1+1使得每次绘图都使
地图下移1个象素。(参考图4-6)
类的构造函数
gameScreen类的构造函数要将游戏中出现的所有精灵都实例化,实际上,这种方法
严重的占用了内存,但在当时,我并没有意识到这一点。
由于敌人要求不停的出现,但是不可能设置过多的精灵,解决的办法是设定6个Sprite类对象j0、j1、j2及jbullet1、jbullet1、jbullet2,分别代表三架敌机及其配属的子弹。所以在gameScreen类的构造函数分配这6个Sprite类的存储空间,并且使用new Sprite(Image img, int width,int height)实例化这6个类变量。同关尾cboss与游戏进行中的大飞机其他的Sprite类对象都需要使用相同的方法实例化。同样处于节约内存的考虑,sboss与cboss同用3个Sprite类对象bossbullet0,1,2。
&&& 在构造函数中,定义boolean型变量conti=true。conti的作用在于控制是否进行游戏画面的重绘及其他需要在画面重绘前进行的运算。
&&& 在构造函数中,将mybullets类里的no和score初始化,现在看来no的初始化没有必要,但是score的初始化是必须的,因为这个变量存储着玩家每次游戏的成绩,如果不在此进行初始化,则玩家重新开始游戏后score并不归0。
关于commandAction()方法
每个创建Command实例的J2ME的应用程序也必须创建实现CommandListener接口的实例。每当用户通过commandAction()方法的方式与命令进行交互的时候,就会通过CommandLIstener.所以实现CommandListener的类必须实现commandAction()方法。
在commandAction()方法中,使用getabel()方法获取命令的标签。如果getLabel()=“暂停”时,表示玩家点击了暂停键,此时,conti赋值为false,游戏画面的绘制及游戏相关的运算暂停,并且,使用removeCommand(c)语句将“暂停”移除,使用addCommand(new Command(&继续&,Command.OK,2));将”继续“按纽”添加进来。当玩家点击“继续“时,conti赋值为true,并且,一定要调用start()方法,否则继续功能不可用。必须调用start()方法的原因是:J2ME的线程已stop()方法拿掉,如果想停止线程的运做,就必须依靠一个旗标(flag),在本程序中,flag就是boolean型变量conti。所以一旦此标识变量被设为false,那么while(conti)循环就会结束,线程也会跟着结束。当用户按下“继续”的时候,start()将重新产生一个线程继续执行相关的运算和画面绘制。
当玩家通关时或者任务失败时,将显示相应信息,并使用上面的方法将“暂停”键变为“返回”键盘,当点击“返回”键时,将返回主菜单选项,调用类lzhhdm里的方法menuscreensecond(),在此方法中,实例化一个MenuScreen类对象,并且使选项“新游戏”改变为”重新开始“(图4-7)。完成此项功能的语句子为MenuScreen.mainmenu[0]=”重新开始”。当选择”重新开始“时,使用gamescreen=new gameScreen(this)将使所有变量重新被初始化,如地图的绘制、敌人出现位置的重置、敌人的数量、玩家飞机的当前位置等。使用gamescreen.start()重新开始程序的循环。
类对象的碰撞检测及相关属性
&&& 游戏进行中,即在while(conti){ }中,需要进行玩家飞
机、子弹与敌机及敌机子弹与玩家飞机的碰撞检测,即使用函
数collidesWith(Sprite,boolean)。由于设计的问题,玩家发
射的子弹与普通敌机的碰撞检测被写在了mybullets类中,并
且只检测第一发子弹是否与敌人相碰撞,如果碰撞为真时,则
使用setVisible(false)函数将敌机隐藏,使用setImage()函
数将子弹精灵的三张图片置换为爆炸图片( 图4-8 )。当敌人剩
余飞机消失后,即所有的敌人都飞出了屏幕后,使用函数
setVisible(true)将敌机重新设置为可见。在按“开火”键时,使用setImage()函数将huokebullets重新设定为子弹图片(每次击落敌机后屏幕上的爆炸效果有3团,并且按“开火”后爆炸图片就消失了,实际上setVisavle(false)的应该是子弹数组,而对敌人精灵使用setImage(),这样效果会好一些)。
敌机与玩家的碰撞检测原理同上,都是使用的collidesWith()函数,遗憾的是,我在写这段代码的时候,并没有考虑设置玩家有4次机会,所以对敌人飞机setVisable(fasle)了,而将玩家的飞机换成了爆炸图片,之后,添加了玩家4次机会这个功能,由于玩家被击落后会重新从屏幕下方进入屏幕,所以爆炸的图片一闪而过,效果不是很好。
玩家4次游戏机会的实现方法&&&&&&&&
&& &根据游戏设置,玩家在每关中有共四次机会,当玩家飞机被击中或撞击爆炸后,程序首先检测整型变量playerno的值,并根据playerno的值决定屏幕右上角所画玩家飞机标志的数量(参考图4-8),playerno的初始值设为3,因为碰撞后才减1,所以玩家共有4次机会,当playerno&0时,游戏结束,同时将变量pver赋值为1,render()或renderboss()函数中,over=1代表在屏幕上GAMEOVER等相关信息,同时,将整型变量inputno赋植为1,以使手机的方向键失效,以消除玩家可以控制爆炸图像移动这个BUG。同时整型变量pzbz赋植为1,以消除玩家爆炸图像继续与敌人进行碰撞检测这个BUG。
&&& 当playerno&0时,碰撞后,将变量planert赋值为1,在之后的if(planert==1)判断语句中,重新设定玩家飞机的图片和可视状态,同时使用setPosition()函数设定玩家非的位置在屏幕下方。设定pzbz=1,即不检测碰撞,玩家有短暂时间无敌,无敌时间由屏幕右上角进度条表示。设定inputno=1,即飞入屏幕的过程中手机键盘是不可以用的。设置planert=2,即以上这些设置只执行一便。
&&&& 在if(planert==2)判断语句中,使用语句move(
0,-2)使飞机自己向上运动,使用if(c1.getY()&(
planepo-24))判断飞机是否到达屏幕最下方(planepo
是屏幕下边缘的坐标),如条件为真,则将inputno
设置为1,表示键盘可用,将planert赋值为3,使
其不再执行以上各步。
&input()函数的作用是检测用户的输入。
首先使用if(inputno==0)判断用户的输入是否
被禁止,如为真,则用户输入不被禁止。
图4-8 游戏界面
其次,调用getKeyStates()查询按键的状态。
当玩家按方向键时,玩家飞机就向不同的方向运行,这需要使用c1.move(int x,int y)函数,当玩家控制飞机向左或右飞时,需要使c1.setFrame()函数改变飞机的图形(参见图4-7,此时飞机右飞)。同时,还需要判断飞机是否飞出屏幕,如,当飞机右飞时,用if(c1.getX()&(getWidth()-c1.getWidth()))
语句判断(getWith()为屏幕的宽度,c1.getWidth()为玩家飞机c1的宽度),如果条件为真,则使用c1.setPosition((getWidth()-c1.getWidth()),c1.getY())语句将飞机设置在紧靠屏幕右边的位置。上、下、左的设置原理同上。
&&& 语句if((keystate&LEFT_PRESSED)==0)的作用是消除左、右飞后在上、下飞时飞机的形态不变的BUG。如果为真,则执行语句c1.setFrame(0),表示只要左键松开飞机的形态都是平飞。
根据游戏设定,玩家一次最多只能发三组子弹,并且子弹有射程限制(在类mybullets中使用整型变量no表示),而当玩家按下“开火“键时,即if((keystate&FIRE_PRESSED)!=0)中判断条件为真时,首先执行循环语句for(int i=0;i&=6;i=i+3),即检测3组子弹中每组的第一发,即0,3,6。其次,检测huokebullet[i].no是否等于1,当等于1时使用语句for( int z=i;z&i+3;z++)初始化该组子弹中的3发子弹,而设置子弹位置的函数应该在if(huokebullet[i].no==1)语句外设置,因为当初设计的时候mybullets类里的函数写成了一次设置三组子弹的形式。
huokebullet[z].no=huokebullet[z].bulletheight赋予子弹射程。当程序循环运行时no--,当一次发射了三组子弹后,只有某一组子弹消失,即no等于1后才能继续发射子弹。
现在看来,玩家发射子弹的设置是完全失败的,降低了效率。
和renderboss()
在方法render()过程中,除了要重绘飞机、地图、子弹外还要在上方绘制关卡信息、战果、玩家飞机数、及无敌状态时的无敌时间、大飞机生命条等。
首先使用lm.setViewWindow()和lm.paint()设定可视范围ViewWindow和从哪里画起(见4.3.3)。
其次,使用g.drawString()绘制屏幕上方的关卡信息、战绩、玩家剩余生命标志。
drawString()中使用String.valueOf(huokebullet[0].rscore()+huokebullet[3].
rscore()+huokebullet[6].rscore())返回玩家成绩score的字符串表示。
其中根据playerno的值绘出玩家的飞机标志数(应该有更好方法,但是没有想到 )当每次刷新绘图页面时,应使用GameCanvas的flushGraphics()将屏幕后台的缓冲区内的图像刷新到前台来(flushGraphics()应该写在render(){ }的最后)。
renderboss()方法重绘的是关尾的精灵cboss、相关信息等,与render()的区别在与于函数lm.paint(g,0,0),起始坐标是不可变的,即,关尾的地图背景是不可变的。实际上,renderboss()是完全不需要的,只要在render()函数中设置相关标志位就可以解决关尾的绘图问题。
玩家飞机的生命标志使用drawImage()就可以绘制在屏幕上了。
& &&根据游戏设定,当y1=-1000时,会出现如图4-8
所示的飞机(sboss),当玩家击落他后,屏幕会显示“
援军到达“,并且玩家剩余飞机数加1。
&&& 使用 if((y1==-1000)&&(sbz==0)){ }设定sboss的
初始位置,根据游戏设定,sboos从屏幕上方倒飞入屏幕,
所以sboss设定的初始位置(50,planepoup-65),其中
planepoup为屏幕上边缘的标志位。
最后,要将sbz赋值为1,消除sboos不停设置初始位置的BUG。
&&& 当sboss飞入屏幕后,将sbz赋值为2,以执行下面
的if(sbz==2)语句。
& &&在判断语句if(sbz==2)里,将根据玩家的位置自动飞
行。首先,根据玩家飞机的位置对sbmove赋值,当c1在sboos的上、下、左、右时,其对应的值为1、2、3、4在这4个if语句中,要设置标志位(smovebz==0)。设置这个
标志位的目的是防止sboos根据c1的位置不停的改变运行状态,即防止sboos成为跟踪飞机。当sboos根据c1的位置改变一次运行方向后,smovebz赋值为1,即不检测c1
的位置。只有sboss运行到屏幕的边缘时,才将smovebz重新赋值为0,使其可以再次通过c1的位置决定sboos的运行方向。
当玩家子弹击中sboss后,使用sboss.setFrame(1),此时飞机变红,在本次repaint结束前,使用sboss.setFrame(0)使飞机变为本来颜色,而程序设定每1/20秒画一次,由此得到飞机被击中后变色的效果。(参见图4-10)。
&&& sboos会根据玩家飞机的位置发射子弹,根据游戏设置,当玩家在其上方、左方、右方时,sboss一次发射1发子弹,而玩家飞机在其下方时,sboss一次发射3发子弹。&&&&&&&&&&&&&&&&&&&&&&&&
&&& sboss与cboss共用3发子弹,因为当sboss出现时,离关尾还远,所以,为了提高效率,采用这种方法。
&&& 如果sboos被击落后,使用函数setVisable(false)将bossbullet0、bossbullet1、bossbullet2设置为不见,使用sboss.setImage()函数将sboos的图片设置为爆炸图片。同时,玩家生命标志playerno加1,sbz赋值为-1,使得sboos无法发射子弹,sbpzbz赋值为1,使得玩家的子弹不与sboos进行碰撞检测。
&&& 同时在屏幕中使用drawString()绘制“援军到达”四个字,随着屏幕的运动,爆炸图片逐渐进入屏幕下方,当sboos.getY()&palnepo,通过改变标志位的值使得drawSteing()不在执行,四字消失。
&&& 如果玩家被击落后并没有点“返回“,而此时,背景会一直运动到关尾,考虑到其与关尾BOSS共用3发子弹,如sboos不消失,将会出现子弹乱飞的情况。所以,如果判断语句if((sboss.getY()==getHeight()))为真,则表示离地图的终点只有一个屏幕的距离时,sbz赋值为-1、sbpzbz赋值为1(含义上面已经说明)。同时调用sboss.move(0,-3),使sboos快速飞出屏幕,直到判断语句if(sboss.getY()&-65)为真时,调用下面的函数setVisable(false),使得sboos不可见。
&& &普通敌人是指游戏中不断出现的兰色飞机。
&&& 首先在程序中首先定义了aik、aip两个Random()类对象,ai和aipp两个整型变量。程序中使用switch(ai)语句判断下一次的飞机出现情况,为了达到不重复出现的效果,使用语句ai=aik.nextInt()%4(同样应该在构造函数中放置此语句和aipp=aip.nextInt() % 5,以使每次游戏开始的时候敌人飞机的出现顺序是不固定的),以随机出现0,1,2,3四个整数(代表着飞机的四种出现情况)。
& &&情况1:使用 aipp=aip.nextInt()%5取得随机数aipp,根据下面三条语句设置飞机的出现位置:j0.setPosition(100-aipp*30,planepoup+24);
&& &&&&&&&j1.setPosition(100,planepoup);
&& &&&&&&&j2.setPosition(100+aipp*30,planepoup-24);;
将getHeight()/8赋给整型变量kkk,每次循环kkk-1,当kkk&=1时飞机转向,当aipp&0时,飞机向左下方运行,使用语句setFrame(0)、move(-3,3)达成向左下方运动的效果。当aipp&0时,向右下方运动,实现方法同上。
&&& 情况2:初始位置设置方法同情况1。当kkk〈0时,飞机掉头向上飞,其中setFrame(3),
move(-4,0)。
&&& 情况3:初始位置设置方法同情况1。当kkk〈0时,飞机只向左转。设置情况3的原因是在更多的随机位置出现敌机。
&&& 情况4:初始位置设置方法同情况1。但其中的飞机j1具有跟踪能力,其实现方法如下:使用2个if语句if(j1.getX()&c1.getX())、if(j1.getX()&c1.getX())判断J1在c1的左或右侧,并且实时根据判断情况使用setFrame()和move()改变飞机的形态,使用语句
if((j1.getX()&c1.getX())&&((j1.getX()+48)&c1.getX())&&(j1.getY()&c1.getY()))判断c1是否在j1的下方,当c1在j1的下方时,发射子弹jbullet1。
&&&& 以上四种情况的最后,都将使用函数nextInt()产生ai,aipp的值。
&&&& 设置整型数组jb[4],对应着4种出现情况的标志位。
&&&& 如,执行情况1,首先执行判断语句if(jb[0]==1),在此语句中,首先使用setVisable (true)函数将敌人飞机设置为可见的,并根据上次运行的qipp的值设置敌人飞机的初始位置最后,jb[0]赋值为2。
&&& 接着执行判断语句if(jb[0]==2),在此语句中,首先使用move()函数使飞机向下运动,同时kkk减1,当kkk&=0时,飞机转向,此时,根据aipp的正负判断飞机向哪边转向。当飞机飞出屏幕时,jb[0]赋值为3。
&&& 需要注意的一点是,当取得ai的数值时,一定要写上这条语句:jb[ai]=1;因为当4种情况都出现一便的时候,标志位jb[]里的数值都将变为3,如果不将其重新赋值为1,敌人飞机将只能出现4次。
&&& 其他3种情况也大致如此。
&&& 普通敌人是否发射子弹由以下语句if(((j1.getX()&=c1.getX()-18)||((j2.getX() -6)&=c1.getX()))&(jbz==0)),即c1在j1左侧18象素范围内或j2左侧6象素范围时,j0、j1、j2一起发射子弹,jbz=1,表示在这组子弹消失前敌人不发射子弹。
&& &如果jpb的值为0,则判断语句if(jpb==0)里的move()语句将一直执行下去。
&&& 之后,还需要对每发子弹于玩家飞机进行碰撞检测,如果碰撞,则将碰撞的这发子弹设置为不可见。
&&&为了游戏界面更加美观,程序中设定了精灵数组cloud[i]来表示白云,由于白云应该在所有飞机的上方,即cloud[i]应该最早被append()到LayerManager中,或者使用insert (cloud[],0)在索引数值0处插入Layer,本程序采用了第一种方法,即在gameScreen类的构造函数中按游戏设置的顺序使用lm.append()加入到LayerManager之中。
&&& 程序中设定白云数为5。首先设置白云的初始位置,其语句如下:
cloud[0].setPosition(25,planepoup-(65));
cloud[1].setPosition(80,planepoup-(140));
cloud[2].setPosition(112,planepoup-(90));
cloud[3].setPosition(175,planepoup-(200));
cloud[4].setPosition(223,planepoup-(70));
其原理为:将屏幕的X数轴和Y数轴各分成5份,即在X轴的5个范围内每个范围出现一朵白云,Y轴的每个范围内也只能出现一朵。所以的白云的起始位置在每次游戏开始时是固定的。
白云位置设定后,使用move(0,1)使白云移动,由于白云初始位置设定在屏幕的不同区域内,故其移动出屏幕的先后顺序是不同的,使用if(cloud[].getY()&planepo)判断白云是否飞出屏幕。如果为真则使用cloud[].setPosition(cloudposition*40,planepoup)设置白云的位置,其中,cloudposition=aicloud.nextInt()%5,aicloud为Random()类对象。乘以40表示其在X轴出现的范围是多少,cloud[0]、cloud[1]、cloud[2]、cloud[3]、
cloud[4]乘以的值分别为40,30、55、15、22。以达成白云的随机出现效果。
&&& 关尾处飞机在屏幕上方横向移动,而背景地图不动,所以使用renderboss()重绘屏幕,其中,paint(g,0,0)表示屏幕绘制点在坐标轴(0,0)处。BOSS生命进度条由以下语句绘制:
g.setColor(255,0,0);
&&&&&&&&&& &&&&&&&& g.fillRect(2,2,60,5);//生命进度条背静红
&&&&&&&&&& &&&&&&&& g.setColor(255,255,255);
&&&&&&&&&& &&&&&&&& g.fillRect(2,2,bosslife,5);//生命进度条前景白
其中bosslife记录着BOSS的生命值,其初始值为0,当玩家每击中一次BOSS,其值加5,,即化出白色进度条,当bosslife==60时,表示过关,除玩家飞机与子弹外的其他Sprite均使用setVisable(false)使其不在显示,同样的pzbz要赋予1,以消除玩家飞机还能与敌人碰撞的BUG。
&&& 如果cboss.getX()&0,则表示其在屏幕左方出界,应改为右飞。同理如果cboss.getX()
&(getWidth()-cboss.getWidth()),则表示其在屏幕右方出界,应改为左飞。
在飞机横向飞行中,使用以下语句判断飞机是否开火:
if(((cboss.getX()&=c1.getX()-10)||(cboss.getX()&=c1.getX()+60))&&(jbsz==0))
当每发一组子弹后,jbsz=1,则飞机无法开火,知道子弹
飞出屏幕,jbsz才重新设定为0。而((cboss.getX()&=
c1.getX()-10)||(cboss.getX()&=c1.getX()+60)表示当
玩家飞机处于BOSS的左右各10个象素的范围内时。BOSS
开火。关尾参见图4-10。
第四章中按照相应的步骤描述了所有关键类的具体算
图4-10关尾
法实现,引用了相关函数进行了具体流程的解释,并对原
理稍复杂的函数做了详细的分析。对游戏有关的各运行面也做了展示。
&& &使用Eclipse完成代码的调试之后,需要使用WTK生成包(即jar和jad文件),其过程如下:首先,使用WTK的新建项目功能建立一个新项目,要求与Eclipse工作区下的项目名称、MIDlet类名相同(图5-1)。
&& 新建项目后,将Eclipse工作区下的.java文件拷入src文件夹,将.class文件拷入class文件夹(需要新建),将pic文件夹拷入res文件夹,点击生成,如一切正常,将如图片5-2所示。
之后,选择项目-包-生成包。如图5-3所示。
生成的jar和jad文件存储在lzhhdm/bin目录下。
运行Motorola SDK v4.2 for J2ME,使用MOTOA760手机模拟器进行测试。参考图5-4。点击Lanuch按纽,进入如图5-5的界面,即可以进行游戏测试了。
& &测试的过程,实际上就是找不同的同学玩这款游戏,以期望发现BUG。实际上,几乎每一版本都会产生很多BUG。&&&&&&&&&
几乎每一个计算机程序都会有这样
那样的不足,尤其是未经过精心维护的
非商业软件。即使是作为操作系统的各
种版本的Windows也时常会发生许多类
型的错误和漏洞。本游戏程序对于初涉
此领域的毕业设计课题来说,尤其在开
始初期,感觉逻辑复杂,难以控制,因
此产生了大量BUG,其中一些BUG还没有
解决,所有发现的BUG如下:
1.玩家子弹出现顺序问题;
2.玩家飞机爆炸后仍然可以控制爆
炸图片;&&&&&&&&&
3.当过关后仍然会发生碰撞;
4.当玩家击落可奖人飞机的同时玩
家被击落,并且此为玩家的最后
一架飞机,虽然显示援军到达,但
游戏仍然结束。
5.有某组飞机在飞机被击中后仍能发射子弹;
6.sboos左侧子弹发射后不停在原位置刷新问题;
7.& 游戏运行一段时间后变的很卡;
&&& 其中,1、2、3、4条BUG已经解决(方法已在第4章相关位置进行了说明)。4、5、6没有解决,其中,4、5、6三条如果有足够的时间可以解决。第7条以现有水平无法解决,因为出现这种情况的原因估计是内存的问题,而由于水平的关系,现在的代码变量过多,并且效率低下,有很多重复的地方,解决的方法只能是在水平提高的情况下重写整个程序。
经过汇总测试人员的建议,本游戏应该完善的功能如下
1. 由于每按一次开火,就会对玩家子弹的精灵数组进行一次循环检查,使得本运行效率就不高的KVM运行异常缓慢。即使刷屏没有间隔也不会提高速度;
&&& 2. 最好有接宝物的设置,增强可玩性;
&&& 3. 由于没由合适的图片,使得敌人设置单一;
&&& 4. 地图本应由外部文件读入,但设计初期并没有掌握这项技术;
&&& 5. 手机游戏最好只有一个类,而我却有4个;
&&& 7. 没有添加成绩记录,即英雄榜;
&&& 6. 最大的遗憾,敌人不够智能化。
&&& 希望不远的将来,我能够有能力对这个游戏进行重写,以解决BUG、完善功能。
&& &&本程序设计实现了手机上以J2ME为平台的飞行射击游戏的开发,敌人运行的方式由程序进行控制,具有一定的可玩性和复杂性。经过了细心的调试和排错解决了绝大部分的问题。
&但是我的水平实在有限,在第5章列举的众多BUG和遗憾就可以看出这一点来,但我相信,随着时间的推移,个人水平的增长,我一定会重写这个程序,使其更加完善,
&& 这款游戏作为我的毕业设计,是本人目前做过的最有意义的程序,这期间对J2ME的学习,使我又回到了初学PASCAL的时候。
本科期间做过很多课程设计,大多规模很小。在数据库、各种应用软件和游戏中,我仍觉得对游戏的设计有极大的热情。因为其各个模块间的联系十分紧密,代码重复执行率高,当经过无数次的调试、修改后,能最终看到成品,有无比自豪的心情。大学期间做过图书馆管理程序等简单的数据库管理系统的课程设计,思想大致相似,变化范围有限,没有太多自己可发挥的余地。大家作品的最终结果都离不开同一个模式。相比一些数据库软件,游戏的设计有很多人情色彩和艺术思想的发挥,正式商业的软件的人性化界面和各个游戏间迥异的结构每每会让人有去开发的冲动。
&&& 学习J2ME的困难远远超出了想象,在设计初期,为了解决地图的滚动、玩家飞机如何不飞出上下边界两个问题竟然花费了数天的时间。很多相关的技术,如需要使用到的线程、Game包的新功能、高级、低级图形界面的使用、贴图等,每一项都需要花一定的时间去掌握和熟悉。更为困难的是,J2ME为一种刚出现仅几年的新技术,国内的参考资料非常少,仅有的几本也停留在简单的介绍阶段。台湾的王森写了本较好的书,给了我很大的帮助,但对设计该游戏来说,仍只够入门。
&&&& 幸运的是,互联网上有那么多无私的人,由Jason Lam著,Deaboway Chou译的电子书《J2ME&Gaming》给了我很大的帮助,作者、译者的辛勤劳动的成果免费放在网上由大家下载,是开源精神的完美体现。
首先感谢我的指导老师马慧彬副教授,她在我的毕业设计过程中提出了指导性的方案和架构,并指引我阅读相关的资料和书籍,使我在不熟悉的领域中仍能迅速掌握新兴的技术。
感谢黄明旭、包明辉同学对游戏进行测试,感谢包明辉同学对游戏相关图片的修改。
感谢答辩组对本毕业设计的考核,如果可以得到专家的认可将对我的学习和工作给予极大的鼓励。你们客观的评价和建议我将牢记在心,在今后的发展中扬长避短,更加努力的严格要求自己。
[1]Joshua Bloce著. 潘爱民译. Effective Java中文版.2004年7月第4版. 机械工业出版社.
[2]Bruce Eckel.侯捷译.Java编程思想. 2005年3月第1版. 机械工业出版社出版社
[3]王森著.Java手机/PDA程序设计入门.2005年2月第3版.电子工业出版社.
[4]James Keogh著.潘颖王磊译.J2ME开发大全.2004年2月第1版清华大学出版社.
[5]Ian Sommerville著.程成等译.软件工程.2003年1月第1版.机械工业出版社.
[6]Jason Lam著.Deabo way Chou译 J2ME&Gaming 2004年末
[7]陈立伟 张克非 黎秀红著.精通JAVA手机游戏与应用程序设计.中国青年出版社.
[8]飞思科技产品研发中心.精通Jbuilder9.电子工业出版社.2004年
[9]微型爪哇人.Java手机程序开发.中国铁道出版社,2003年
[10]Frand M.Carrano,Janet J.Prichard&.著&韩志宏&译.数据抽象和问题求解——
JAVA语言描述.清华大学出版社2005年4月
[11]袁海燕 王文涛著.JAVA实用程序设计100例.人民邮电出版社.2005年5月
[12]Jonathan Knudsen.What's New in the J2ME Wireless Toolkit 2. 22004年4月
import javax.microedition.midlet.MID
import javax.microedition.midlet.MIDletStateChangeE
import javax.microedition.lcdui.*;
public class lzhhdm extends MIDlet implements CommandListener {
&&&&&&& public D
&&&&&& private Image splashL
&&&&&& private boolean isSplash=
&&&&&&& public F
&&&&&&& private A
&&&&&&& private MenuS
&&&&&&& private gameS
&&&&&&& private Command ok,
&&&&&&& private byte[] byteInputD
&&&&&& public lzhhdm()
&&&&&& protected void startApp() throws MIDletStateChangeException {
&&&&&& display=Display.getDisplay(this);
&&&&&& menuscreen=new MenuScreen(this);
&&&&&& if(isSplash)
&&&&&& {& a=
&&&&&&&&&&&&& a=new Form(&览桥风光V1.0&);
&&&&&&&&&&&&& ok=new Command(&ok&,Command.OK,1);
&&&&&& &&& a.append(new StringItem(null,&.....&));
&&&&&&&&&&&&& a.addCommand(ok);
&&&&&&&&&&&&& a.setCommandListener(this);
&&&&&& &&& display.setCurrent(a);&
&&&&&& protected void menuscreenShow()
&&&&&&&&&&&&& display.setCurrent(menuscreen);
&&&&&& protected void menuscreensecond() {
&&&&&&&&&&&&&
&&&&&&&&&&&&& menuscreen=new MenuScreen(this);
&&&&&&&&&&&&& MenuScreen.mainmenu[0]=&重新开始&;//玩完一遍或挂了后在玩一遍 菜单第一项改为 重新开始
&&&&&&&&&&&&& display.setCurrent(menuscreen);
&&&&&&&&&&&&& }
&&&&&& protected void pauseApp() {}
&&&&&& protected void destroyApp(boolean arg0) throws MIDletStateChangeException {&&
&&&&&& protected void helShow()
&&&&&& {& a=
&&&&&&&&&&&&& a=new Form(&览桥风光V1.0&);
&&&&&&&&&&&&& back=new Command(&返回&,Command.BACK,1);
&&&&&& &&& a.append(new StringItem(null,&操作方式:上 2 下 8 左 4 右 6 开火 5&));
&&&&&& &&& a.append(new StringItem(null,&弹药数:一次最多打三组&));
&&&&&&&&&&&&& a.addCommand(ok);
&&&&&&&&&&&&& a.setCommandListener(this);
&&&&&& &&& display.setCurrent(a);
&&&&&& protected void renwuShow()
&&&&&&&&&&&&& a=&&&
&&&&&&&&&&&&& a=new Form(&览桥风光V1.0&);
&&&&&&&&&&&&& back=new Command(&返回&,Command.BACK,1);
&&&&&& &&& a.append(new StringItem(null,&游戏名称:览桥风光&));
&&&&&& &&& a.append(new StringItem(null,&版本号:V1.00&));
&&&&&& &&& a.append(new StringItem(null,&制作者:信息电子技术学院01计算机5班 刘泽华 学号:7&));
&&&&&&&&&&&&& a.addCommand(ok);
&&&&&&&&&&&&& a.setCommandListener(this);
&&&&&& &&& display.setCurrent(a);
&&&&&& protected void gameShow()
&&&&&& {&& try{
&&&&&&&&&&&&& gamescreen=
&&&&&&&&&&&&& gamescreen=new gameScreen(this);
&&&&&&&&&&&&&
&&&&&&&&&&&&& gamescreen.start();
&&&&&&&&&&&&&&&&&&&& display.setCurrent(gamescreen);
&&&&&&&&&&&&& gamescreen.conti=
&&&&&& }catch(Exception exp)
&&&&&& System.out.println(&dfg&);
&&&&&& public void commandAction(Command arg0, Displayable arg1) {
&&&&&&&&&&&&& a=
&&&&&&&&&&&&&
&&&&&&&&&&&&& this.menuscreenShow();
import javax.microedition.lcdui.*;
public class MenuScreen extends Canvas& implements Runnable,CommandListener
&Font lowfont=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_PLAIN,Font.SIZE_MEDIUM);
&&&&&& & Font highfont=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_BOLD,Font.SIZE_MEDIUM);
&&&&&& &int lowColor=0x000000FF;
&&&&&& &int highColor=0x00FF0000;
&&&&&& &int highBGColor=0x00CCCCCC;
&&&&&& &int startH
&&&&&& &int spacing=highfont.getHeight()/2;
&&&&&& public& static String[] mainmenu={&?????·&,&°??ú&,&????&};
&&&&&& &int menuI
&&&&&& Thread menuT
&&&&&& private Command ok=new Command(&ok&,Command.OK,1);
&&&&&& public MenuScreen(lzhhdm midlet)
&&&&&& {&&&& this.midlet=
&&&&&&&&&&&&& width=getWidth();
&&&&&&&&&&&&& height=getHeight();
&&&&&&&&&&&&& startHeight=(highfont.getHeight()*mainmenu.length)+((mainmenu.length-1)*spacing);
&&&&&&&&&&&&& startHeight=(height-startHeight)/2;
&&&&&&&&&&&&& menuIndex=0;
&&&&&&&&&&&&& addCommand(ok);
&&&&&&&&&&&&& &setCommandListener(this);&&&&&&
&&&&&&&&&&&&& menuThread =new Thread(this);
&&&&&&&&&&&&& menuThread.start();
&&&&&&&&&&&&& co=
&&&&&& public void run()
&&&&&&&&&&&&& while(co)
&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&& repaint();
&&&&&&&&&&&&& }
&&&&&& public void paint(Graphics g)
&&&&&&&&&&&&& g.setColor(0x00FFFFFF);
&&&&&&&&&&&&& g.fillRect(0,0,width,height);
&&&&&&&&&&&&& for(int i=0;i&mainmenu.i++)
&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&& if(i==menuIndex)
&&&&&&&&&&&&&&&&&&&& {&
&&&&&&&&&&&&&&&&&&&&&&&&&&& g.setColor(highBGColor);
&&&&&&&&&&&&&&&&&&&&&&&&&&& g.fillRect(0,startHeight+(i*highfont.getHeight())+spacing,width,highfont.getHeight());
&&&&&&&&&&&&&&&&&&&&&&&&&&& g.setFont(highfont);
&&&&&&&&&&&&&&&&&&&&&&&&&&& g.setColor(highColor);&&&&&& g.drawString(mainmenu[i],(width-highfont.stringWidth(mainmenu[i]))/2,startHeight+(i*highfont.getHeight())+spacing,20);
&&&&&&&&&&&&&&&&&&&& }else
&&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&& g.setFont(lowfont);
&&&&&&&&&&&&&&&&&&&&&&&&&&& g.setColor(lowColor);
&&&&&&&&&&&&&&&&&&&& &&&&&& g.drawString(mainmenu[i],(width-lowfont.stringWidth(mainmenu[i]))/2,startHeight+(i*highfont.getHeight())+spacing,20);
&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&& }
&&&&&& public void keyPressed(int code)
&&&&&&&&&&&&& if(getGameAction(code)==Canvas.UP&&menuIndex-1&=0)
&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&& menuIndex--;
&&&&&&&&&&&&& }
&&&&&&&&&&&&& else if(getGameAction(code)==Canvas.DOWN&&menuIndex+1&mainmenu.length)
&&&&&&&&&&&&& {
&&&&&&&&&}

我要回帖

更多关于 中国第一款网络游戏 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信