关于倒腾我制作的夜影长空游戏的随笔。

2 须道菩提一剑斩天 4小时前 62次点击

起因其实挺简单,最开始就是想把《夜影长空》这个工程重新弄起来,结果真正动手以后才发现,这东西根本不是简单改几个界面那么回事。最早拿到工程的时候,APK最大的问题就是闪退,而且不是那种点某个按钮偶尔闪一下的小问题,而是有时候安装、启动、进入某个界面、点某个菜单都会直接退出,甚至前面修好了一个地方,后面又会冒出来另一个问题。最开始怀疑的是签名,因为Android如果APK签名不对,安装阶段就可能直接报错,所以先检查APK的签名、重新签名、重新对齐这些东西,结果发现签名本身并不是主要原因。后来又怀疑是不是服务器节点的问题,因为之前给游戏加过服务器登录、账号同步之类的东西,加完以后游戏就开始不稳定,尤其是登录和启动阶段特别容易出问题,于是把服务器相关的东西拆出来测试,甚至尝试去掉服务器逻辑单独跑,结果发现并不是简单删掉服务器就能解决,说明问题已经深入到了程序本身的初始化和界面逻辑里面。接下来就开始真正往APK里面扒,能看到的东西先全部拆出来,包括资源、Manifest、DEX、Smali、字符串、布局以及各种初始化代码。因为原工程并不是一个可以直接拿来重新编译的干净源码工程,所以很多东西反编译出来以后已经不是原作者写代码时的样子了,类名、变量名、局部变量、控制流都可能发生变化,有些代码甚至只能根据调用关系反推原本想干什么。这个阶段最麻烦的地方就是“能看懂”和“能重新编译”是两回事,反编译工具可以把DEX还原成接近Java的代码,也可以拆成Smali,但重新编译的时候,寄存器数量、方法签名、资源ID、依赖关系、异常处理、字节码版本,只要有一个地方对不上,就可能重新打包失败。也正因为这样,后面没有一味地死磕某一份反编译出来的Java代码,而是逐步把真正需要的逻辑重新整理成可以稳定构建的工程。闪退问题也不是只找到一个“罪魁祸首”,最开始有几类问题混在一起。第一类是初始化阶段的问题,也就是Activity启动以后,某些对象还没有初始化就被调用,或者某个资源、控件、配置项为空,代码却直接使用,导致NullPointerException一类的问题。第二类是菜单逻辑的问题,有些菜单项看起来存在,但实际上没有真正实现功能,点击以后直接走到了一个空处理分支,甚至某些地方把“没有实现”错误地处理成了退出当前Activity,于是用户看到的效果就是“点一下就闪退”。第三类是手势处理的问题,原来的触摸事件没有把单指、双指和多指真正分开,某些情况下双指操作会被单指逻辑再次处理,导致同一个事件触发两套代码,菜单返回、云游、移动等功能就可能出现非常奇怪的行为。第四类就是构建环境本身的问题,有些时候并不是代码改错,而是构建工具版本不匹配,或者资源编译、DEX转换、签名阶段出了问题,最后生成的APK虽然存在,但是运行时却表现异常。于是后面开始重新搭构建环境,这个过程本身也挺折腾,因为一开始工作区基本就是一个空环境,想直接构建APK根本没有完整的Android SDK,需要的东西不是一个JAR就能解决,而是一整套工具链。首先是Android SDK Command-line Tools,它里面最关键的东西之一就是sdkmanager,可以用它管理Android SDK的软件包。后来又补了Android SDK Platform 35,因为最终的工程需要以API 35作为编译平台;Android官方的Android 15 SDK配置也明确要求在SDK Platforms里面安装Android SDK Platform 35,并在SDK Tools里面安装Build Tools 35的最新35.x.x版本。Command-line Tools当时用的是commandlinetools-linux-15859902_latest.zip,这个版本也能在Android官方的下载页面查到,官方地址就是https://developer.android.com/studio/。然后就是Android⁠� SDK Platform 35,也就是构建Android 15 API 35程序所需要的平台包,官方明确说明如果要访问Android 15 API,就需要把compileSdk设置成35,并安装Android SDK Platform 35,我们当时保存的是platform-35_r02.zip,这个文件后来也专门保留下来了。这里需要特别说明,Platform 35和Build Tools不是一个东西,Platform主要提供对应Android API的平台文件和编译所需的Android系统接口,而Build Tools里面才是实际参与资源编译、APK签名等工作的那套工具。Build Tools当时使用的是35.0.1,因为我们后面采用的是比较直接的构建方式,不完全依赖传统Gradle流程,而是直接调用Android工具链里面的组件。Android官方文档也明确说明Android SDK Build Tools是构建Android应用所需要的组件,其中就包括AAPT2和apksigner等工具,官方工具页面就是https://developer.android.com/tools。我们保存的是build-tools_r35.0.1_linux.zip,以后如果构建环境被清空,恢复这个包就可以把35.0.1的Build⁠� Tools重新放回来。这个工具里面最重要的几个东西就是AAPT2、D8、zipalign和apksigner,AAPT2负责处理Android资源,把XML、图片、资源表等东西编译成Android运行时能够识别的二进制资源;D8负责把Java字节码转换成DEX;zipalign负责对APK进行最终的字节对齐;apksigner负责给APK签名并检查签名是否有效。Platform-Tools也补上了,里面最常用的就是ADB,ADB主要负责电脑和Android设备之间的调试、安装、启动、查看设备状态等工作,Android官方Platform-Tools地址是https://developer.android.com/tools/releases/platform-tools。Java环境也补齐了,因为没有Java,很多Android构建工具根本没办法正常运行,我们后来保留了JDK⁠� 17作为这个工程的稳定运行环境,而不是随便拿一个最新Java版本硬套,这样做的原因很简单,构建环境最怕的就是今天能编,明天换个JDK就不能编,所以宁愿把版本固定下来。最后整个环境被整理成一个恢复包,里面不只是放几个ZIP,还加入了版本说明、恢复检查脚本以及SHA-256校验信息,这样以后即使当前工作区没了,也可以拿自己的备份重新搭,而不是每次都重新猜缺哪个组件。构建环境稳定以后,才真正开始处理游戏本身,首先重新整理了登录和注册,注册成功以后账号信息需要保存在应用自己的数据区域里,登录时检查输入的账号和密码是否存在,如果不存在就直接提示“登录失败,您输入的账号或密码不存在”,而不是进入一个半成品状态,注册成功后账号信息继续保留,设置里面增加退出登录,退出以后下次进入必须重新输入账号密码,而不是自动偷偷登录上一次账号。玩家数据方面也考虑了本地保存和后续同步的结构,目标不是把数据散乱地写在几个临时文件里,而是给玩家建立一个统一的数据结构,后面再接云同步。然后开始处理菜单,菜单原来最大的毛病之一就是“看起来什么都有,实际上点进去不是没反应就是直接退出”,所以后来重新定义菜单行为,真正有功能的项目进入对应功能,暂时没有实现的项目不能乱跳、不能退出游戏、不能触发其他功能,最安全的行为就是不触发任何东西。特别是“返回游戏菜单”这个地方,之前就出现过双指操作以后点击返回游戏菜单直接闪退的问题,所以这个返回逻辑后来单独处理,不能再让它落入默认退出分支。整个菜单也按照游戏实际操作习惯重新规划,不再把所有东西塞在一个平面界面里,而是做成可以上下浏览的菜单结构,因为这是一个市长、经营、云游、修炼一类的游戏,菜单未来会越来越多,所以从一开始就得把菜单导航结构做好,否则以后加几十个功能以后会彻底乱掉。音量系统也重新考虑,音乐音量和音效音量不能只是摆两个数字在那里装样子,而应该是真正能够控制声音,比如浏览到“音乐音量”,左滑就是减少,右滑就是增加,每次变化5格;浏览到“音效音量”,也是左滑减少、右滑增加,每次5格,并且音效音量调整以后,脚步声、菜单音效、障碍物音效等都应该跟着当前音效音量变化,而不是改了一个数字却什么都不变。音乐系统暂时不急着做,因为现在的重点是先把所有游戏玩法和菜单功能搭起来,等核心玩法完成以后再统一处理背景音乐、场景音乐、音乐音量以及淡入淡出这些东西。地图系统则是后面逐步建立起来的,地图不是一张只能看不能动的图片,而是一个真正的网格,玩家有横坐标和纵坐标,比如初始位置是0,0,向右走一格就是1,0,向左走一格就是-1,0,向前或者向后同样改变对应坐标,地图本身也有名称,比如“师门领地”,所以玩家在师门领地的0,0位置,正确的朗读格式就是“师门领地。0。0。”,走到其他位置就朗读对应的坐标,但是后来发现如果每走一步就TTS读一次坐标,体验会非常烦,所以这个规则又重新改了,移动的时候不再朗读坐标,不朗读地图名,只播放对应的移动音效;只有玩家用单指点击下半屏的时候,才读取当前地图名称和横纵坐标,也就是说,走路是走路,查询位置是查询位置,两件事情彻底分开。脚步音效也专门重新整理过,当时有三种木质声音,每个压缩包里面都有9个文件,规则不是“把三个压缩包里的27个文件全部混起来随机”,而是严格按照音效组随机,使用第一组,就只能从第一组的9个文件里面随机;使用第二组,就只能从第二组9个文件随机;使用第三组,就只能从第三组9个文件随机,这样不同材质的脚步声不会乱串,每走一步只播放一次对应的脚步声音,不再同时朗读一堆文字。撞墙音效当时还没有确定,所以暂时设为空,撞墙以后不播放撞墙声音,也不朗读任何东西;撞墙之后重新移动,同样不会因为撞墙状态产生额外TTS。手势系统是另一个重点,因为整个游戏是给触摸操作设计的,所以不能用一个简单的“手指按下就执行”来糊弄,单指就是单指,双指就是双指,多指就是多指,单指负责普通浏览、菜单操作和地图移动,双指负责特定的返回、云游或者菜单快捷操作,没有定义功能的多指操作必须什么都不触发,不能自动降级成单指操作。之前之所以出现“某些双指操作点返回游戏菜单就闪退”,本质上就是事件分发没有严格区分,后来就把手势识别作为独立的一层处理,让触摸事件先判断到底来了几根手指,再决定交给哪个功能,这样做虽然代码多一点,但比所有事件混在一起安全得多。另外还有双击时间的问题,之前有一个500毫秒和10毫秒之间的讨论,最后明确区分了两个概念,双击判定时间和滑动响应时间不是一个东西,双击不能因为追求快速滑动就直接改成10毫秒,否则正常人根本点不出双击,真正需要非常快的是滑动后的响应,所以滑动操作尽量在极短时间内反馈,这个地方后来也重新整理,避免因为一个参数同时承担两个完全不同的职责,导致菜单和地图操作互相影响。在这些基础东西稳定以后,开始把游戏逻辑往菜单里面填,比如修炼、突破、锁妖塔、师门修炼、土地、建筑、徒弟任务、战斗模式等,都不能只是一个“点一下显示暂无功能”的摆设,现在的思路是先把这些功能做成能运行的基础玩法,每个功能都有自己的状态、数据和返回路径,之后再慢慢扩展成完整系统,比如修炼可以有当前修为、修炼次数、突破条件;土地可以有土地数量、建筑、收益;徒弟任务可以有任务状态、完成状态和奖励;锁妖塔可以有层数和战斗结果;战斗模式可以先做基础战斗逻辑,以后再加入属性、技能、敌人AI和掉落,这样以后继续扩展的时候,不需要把整个工程重新推倒。整个过程中其实还踩过一个很典型的坑,就是“构建成功”和“游戏正确”完全是两件事情,一个APK能够生成,并不代表里面的代码一定没问题;反过来,一个工程代码本身没问题,如果AAPT2、D8、SDK、JDK或者签名工具版本不对,也可能根本生成不了APK,所以后来每次构建都不只是看“有没有APK”,而是把流程拆成资源编译、Java编译、DEX转换、APK打包、zipalign、签名和签名验证,只有这些步骤都通过,才算真正的构建成功。最后也把构建环境单独打包保存,目的就是以后不要再出现“代码已经修好了,但是突然没有构建工具,只能重新找一堆ZIP”的情况。目前这个工程算是从最开始的“能不能启动”阶段,慢慢进入“怎么把游戏做好”的阶段,最早的问题是APK闪退,后来开始解决启动、登录、注册、菜单、手势、地图、音效、构建环境,最后终于把基础框架跑起来,现在最大的变化不是单纯多了几个菜单,而是整个工程开始有了比较明确的层次,底层负责输入和手势,中间负责菜单和游戏状态,再往下是地图、玩家数据、音效、TTS以及以后要加入的战斗、经营、任务系统,最外层才是Android界面,这样以后就算再加几十个功能,也不至于所有代码全部塞进一个Activity里面互相打架。构建工具这边也已经整理成以后可以反复使用的固定组合,Command-line Tools官方地址是https://developer.android.com/studio/,Platform-Tools官方地址是https://developer.android.com/tools/releases/platform-tools,Android⁠� 15和API 35 SDK配置说明是https://developer.android.com/about/versions/15/setup-sdk,Android⁠� SDK工具总页面是https://developer.android.com/tools,其中Command-line⁠� Tools负责提供sdkmanager等命令行工具,官方说明它可以用来查看、安装、更新和卸载SDK软件包;Build Tools则是实际构建Android应用所必需的组件,Platform-Tools主要提供ADB和fastboot等工具,Android 15对应API 35,所以我们的Platform 35也不是随便选的,而是和工程的compileSdk版本对应起来的。最后结果就是,《夜影长空》已经不再是最开始那个一碰就闪退、菜单点一下就退出、手势混在一起、走一步就疯狂TTS、构建环境还经常缺工具的半成品了,现在已经有了一套能够稳定恢复的Android构建环境,有固定的SDK Platform 35、Build Tools 35.0.1、Platform-Tools、Command-line Tools和JDK,有能够重新构建APK的完整链路;游戏方面已经把登录注册、退出登录、菜单结构、基础游戏入口、地图网格、坐标、脚步音效、TTS查询、单指双指多指手势这些核心框架搭起来了,后面真正要做的就不是天天救火,而是开始往里面塞游戏内容,把菜单里的修炼、战斗、城市建设、土地、建筑、徒弟、任务、资源、经济系统一个一个做实,再回头继续扩地图,让地图不只是“能走”,而是真正成为整个游戏世界。等这些东西全部完成以后,再统一处理背景音乐、剧情、更多音效、存档、云同步以及更完整的服务器系统。这样一路下来,最开始看起来像一堆互相打架的代码和闪退问题,最后慢慢被整理成了一套能继续往下开发的游戏工程。

共 1 条评论
须道菩提一剑斩天 [楼主] 4小时前
0 
我们官方的qq群。762479032
添加一条新评论

登录后可以发表评论 去登录