下载 App

开发者日志 #5 —— 把一只猫送上手机

修改于10/2028 浏览综合
先交代状态,免得你觉得我在吹:包能出来、签名有效、能在安卓上装起来、能玩到结局;但"在真机上跑多少帧"这件事,我到今天还是答不上来。 我手上一路没有安卓实体机,最后是用 Android 官方模拟器(AVD)把这段补上的——它能回答"到底动得起来吗",回答不了"在一台 1500 块钱的手机上是什么感觉"。这两个问题的区别,我在第三节里会一条条划清楚。

一、导出一个安卓包,到底缺什么

Godot 的安卓导出和你想象的"点一下导出"差得很远。它要的是一条完整的工具链,缺一环就停:
① JDK 17。 Godot 用它跑 apksigner 和 zipalign 来签名和优化包。Temurin 17(Adoptium)就行。
② Android SDK,并且要有对的具体组件。 光有 SDK 目录不够,必须装了 platforms;android-34 和 build-tools;34.0.0。
③ Godot 4.7 的安卓导出模版。 官方只发一个 .tpz 压缩包,你要解压到 %APPDATA%\Godot\export_templates\4.7.stable\ 下面。
三样我都装到了 D:\toolchain\ 下,没有装进系统目录。
实际的安装顺序和耗时:
步骤遇到什么耗时
Godot 4.7 导出模版(1.22GB)官方源(GitHub 资产 CDN)被限速到 3KB/s,等于没有速度换源后 265s
JDK 17(Temurin)Adoptium 官方 API 被墙,连不上换清华 TUNA 镜像
Android cmdline-toolsdl.google.com 用 .NET 的下载方式直接失败换 curl -4 --tlsv1.2 --http1.1,7.1MB/s
sdkmanager 装组件许可协议没接受,组件被静默跳过管道喂 40 个 y
模版那 1.22GB 是最折磨的一关。GitHub 的资产 CDN 在我这个网络环境下只有 3KB/s——按那个速度要下四天。我试了 ghproxy.net,被限流到 3KB/s;最后用 gh-proxy.com 拿到 4.4MB/s,265 秒下完。
Android SDK 那部分也踩了个坑:sdkmanager 会先要你接受许可,不接受就静默跳过你要求的组件——命令跑完了,返回码也是 0,但东西根本没装。得把 40 个 y 管道喂进去。
另外 dl.google.com 用 .NET 的 Invoke-WebRequest 会直接失败(连 TLS 握手都过不去),换成 curl.exe -4 --tlsv1.2 --http1.1 才有 7.1MB/s。

之前就踩过的两个小坑

这次装的时候又遇到了,跟安卓本身无关,跟装东西的环境有关:
  • winget 不可用,所以"一行命令装 JDK"这条路一开始就是断的;
  • chocolatey 的社区源被代理屏蔽,另一条自动装的路也断了。
所以对我来说,实际可行的大概只剩下"手动下载 + 解压 + 配环境变量"这一条。

二、导出这一步本身

工具链齐了之后,导出命令其实只有一条:
powershell
& $godot --headless --path $root --export-release 'Android' $out
结果:Android 端 15 秒左右出一个 35.5 MB 的 APK(今晚重出的那份是 37,253,516 字节)。Windows 端 7.2 秒,104 MB exe + 7.0 MB pck。
⚠ 写到这里我去 build/ 下看了一眼文件时间,才发现Windows 那份还是 10-04 出的, 而安卓这份是今晚刚出的。也就是说我下面所有关于"包里对不对"的结论,只对安卓成立。 一个绿色的检查结果,指向的可能不是你以为的那个产物——这个坑我在这篇里要讲三遍, 因为我自己栽了三次。
签名用的是自己配的 release keystore,不是 debug keystore——keytool 生成的,CN=Scent City。apksigner verify 确认 v2 + v3 两套签名方案都过。

但"命令跑通"和"包是对的"是两回事

这里有个我一开始完全没想到的坑,值得单独拎出来讲。
包导出成功了,体积也正常,我以为完事了。直到我把 APK 当 zip 解开看了一眼内部结构,才发现:
  • 游戏里真正在用的 5 首 BGM,一首都没进包;
  • 反倒是 13.5MB 完全没被任何脚本引用的音频,和 4.8MB 早就标了"已弃用"的 AI 曲子,全都在包里。
第一反应是"导入没跑完",于是清空 .godot/imported/ 强制重导入。结果 Godot 甩给我一条我一直没当回事的报错:
ERROR: Failed to decode mp3 file. Make sure it is a valid mp3 audio file.
我又去看文件头:
bgm_p_daylight.mp3  52 49 46 46 6c 0c 7e 00 57 41 46 45   ← "RIFF"… "WAVE"
RIFF 是 WAV 的魔数。这五个文件根本不是 MP3,是 WAV 套了个 .mp3 的扩展名。
原因在生成脚本里,一行的事:
python
with wave.open(p, "wb") as w: # 写的是 WAV ... save("bgm_p_daylight.mp3", st) # 存成了 .mp3
Godot 看到 .mp3 扩展名,走 MP3 解码器去解 RIFF 数据,必然失败,于是 .mp3str 产物从来没生成过。从头到尾没有任何人报过"文件坏了",Godot 只是安静地少放了几首歌进包。
改名成 .wav、同步改 audio_director.gd 里 5 处引用之后,重导入,5 个 .sample 全部生成,解包复验 bgm_p_*.sample 数量为 5。
这件事我后怕了很久。 如果我没有去解包看一眼,这个游戏会安安静静地带着一个"5 首 BGM"的宣传语、实际上全程无声地发出去,而控制台上那行报错早就被我当噪音跳过去了。
顺带清掉的死资源还有:5 个源文件已删、.import 还留着的孤儿文件(因为 export_filter="all_resources",孤儿 .import 也会把对应的旧资源塞进包),以及一个已经被移到 archive/ 的目录——注意 exclude_filter 只管导出不管导入,想让 Godot 连碰都不碰,得在目录里放一个 .gdignore。
同一类坑后来又抓到一次:约 14.9MB 的 AI 原始设定图以零引用的形式躺在 APK 里,只因为它们还留在 assets/ 下。同一个教训交了两遍学费:export_filter="all_resources" 会把"还在仓库里但没人用"的东西一并打包。

三、上了安卓之后发生的事

先划清楚这一节哪些是测出来的、哪些仍然空着,因为我不想让你(也不想让我自己)把模拟器当成手机。
测试环境:Android 官方模拟器 AVD scent_phone(pixel_6 配置,x86_64,Android 15 / API 35,2400×1080 横屏,-gpu host)。不是实体机。 装的是 build/ScentCity.apk,release 签名那份。

3.1 它动得起来了

这是本篇我最想写的一条,因为在此之前它一直是悬着的。
v0.4 的全部输入是 Input.is_key_pressed(KEY_*) 和 keycode 轮询——手机上没有任何触摸输入,APK 能装、能开,但你点屏幕不会有任何反应。它是个能启动的幻灯片。这件事我一直知道,一直往后退,退到最后才动手补触控层。
补完之后,在安卓上实测:
  • 开局菜单能点进去(选猫、切画质、点「开始流浪生活」都响应);
  • 虚拟摇杆真的能让猫走:在左半屏按下并向右拖 4 秒,画面整体向左平移 126 屏幕像素(拿两张截图做水平互相关找的最优位移;对齐时平均像素差 8.0,不对齐时 16.0——差一倍,说明这个平移是真的,不是噪声);
  • 右侧常驻按钮、点按交互、事件日志、HUD 全部正常:截图里满屏的猫(近十只)头顶名字和情绪气泡都读得出来,清洁工拿着扫帚在街面上走;
  • 整条结局链在安卓上跑通了:收养邀约弹出 → 点「跟她回家」→ CG 全屏播放(无黑边、无拉伸)→ 结局卡收场。
顺带一个我自己的测量教训,说清楚免得误导人:第一次点「开始流浪生活」我没点动,换了三种发事件的方式都没反应。我差点把它写成"安卓上零时长的 tap 事件不生效"——那是错的。真实原因是我在拿肉眼从截图上估按钮坐标,估偏了一百多像素;改用程序扫出那颗黄色按钮的实际包围盒(中心 1198, 978)之后,普通 input tap 一次就进去了。"点不动"是我的量法坏了,不是触控层坏了。 这种时候先怀疑自己的尺,别急着给游戏定罪。
切后台再回来也验了:按 HOME 退到后台 12 秒再拉回前台,进程号没变(3641 → 3641),世界还在原样(第 18 天 15:00、领地版图还开着、猫各在各的),logcat 里没有 FATAL / SIGSEGV / ANR。这条对 TapPlay 的稳定性判定是硬指标,现在至少是"有证据的应该没问题"。

3.2 在安卓上抓到一个一直在的 bug:震动权限根本没声明

GDD 里 D1 那条卖点写的是"气味触觉"——进入气味区时 Input.vibrate_handheld,时长随浓度映射。代码在 player_cat.gd:437,一行,PC 上永远不会报错,因为桌面端这个调用就是空转。
在安卓上,它是这样刷日志的(每 0.44 秒一条,进局一分多钟就攒了上百条):
W GodotNativeBridge: SecurityException: VIBRATE permission not found.
   Make sure it is declared in the manifest or enabled in the export preset.
我去查包里的清单:
$ aapt dump permissions build/ScentCity.apk
package: com.scentcity.game
(没有任何 uses-permission)
这个包一条权限都没声明。 而我那个自动复验脚本 ⑥ 项写的是"零联网红线:不得有 INTERNET 权限",它把"权限清单:(无)"当成好消息打了个勾。
所以真实情况是:触觉这个卖点在安卓上从来就没生效过,而且它一直在往系统日志里扔异常——这种东西对稳定性检测(TapPlay)只有坏处。
修起来是一行(非 gradle 导出走 custom_permissions 这个逃生口):
ini
permissions/custom_permissions=PackedStringArray("android.permission.VIBRATE")
重出包之后,同一台模拟器、同一个存档、进局 45 秒:
$ dumpsys package com.scentcity.game | grep VIBRATE
      android.permission.VIBRATE
      android.permission.VIBRATE: granted=true
$ logcat -d | grep -c "VIBRATE permission not found"
0
然后我给自己原来那个检查脚本补了一条会红的断言:扫 scripts/*.gd,只要有人调 vibrate_handheld,包里就必须声明 VIBRATE。先在修之前那个包上跑一遍确认它是红的:
  [FAIL] 代码调用 vibrate_handheld 的文件:player_cat.gd → 必须声明 VIBRATE  ->  未声明
再在修完之后重出包跑一遍,才转绿。一条永远不会红的检查,等于没有检查——这条我在日志④里写过一次,这次是我自己又栽了一遍才真正读懂它。

3.3 稳不稳定、吃多少资源

能测的部分:
  • 进程从 20:08 起到 20:15,连续运行约 7 分钟无崩溃、无 ANR,logcat 里没有 FATAL / SIGSEGV; 后台/前台切换那条(上面 3.1 末)也过了。
  • top 读数:CPU 82.7%、RES 770MB、SHR 385MB。
  • dumpsys meminfo:TOTAL PSS 590,227 KB ≈ 577 MB,其中 Native Heap 129,511 KB ≈ 126 MB,Dalvik 堆只有 5.3 MB(游戏逻辑几乎不在 Java 侧,符合预期)。
但这三个数都不能外推到手机:x86_64 虚拟机 + 宿主 GPU(-gpu host,GL 映射全算进 PSS),CPU 是拿宿主核心在跑,内存也偏大。它们能说明的只有一件事:没有明显的资源失控,Java 堆干净。 真正的功耗和发热,只能等实体机。

四、最让我难受的一个坑

不是 CDN 那 3KB/s,那个只是慢。
最难受的是:我拖了四天没测安卓,理由是"我没有手机",而模拟器其实早就装好了。
AVD、镜像、adb、导出模板——全在 D:\toolchain\ 下躺着。我甚至用它装过一次包。但我一直把"真机测试"当成一个整体任务,觉得"反正不是真机,测了也不算",于是它就一直排不上队。结果这几天里,触控层、震动权限、结局链在手机上到底通不通,我全是靠"应该没问题"在撑。
而真正该做的事其实很简单:模拟器回答不了帧率,但它能回答"它动得起来吗"。 后者才是这篇日志、也是这个包最要命的问题。我用一个我回答不了的问题,把一个我能回答的问题给堵住了。
现在回头看:如果那天我没去开模拟器,VIBRATE 这件事会一路跟我到评审手里——评审拿到的第一个安卓包,触觉是死的,日志里每 0.44 秒扔一条异常,而我的检查脚本会告诉我"权限清单:(无)✅"。

五、如果重来一次

三件事,能省下大概两天:
  1. 先写检查脚本,再写宣传语。 我在商店页和日志里写"5 首 BGM""气味触觉"的时候,两个都还没有对应的包内检查。BGM 那条后来靠解包救回来了,触觉这条如果没开模拟器就救不回来。
  2. 每改一次代码就重新出一次包,并当场解包看清单。 别拿 10-04 的 Windows 包说今晚的事——我自己刚才就差点这么干。
  3. 相机缩放别猜。 桌面 1.50 / 移动 1.75 的分流已经写进代码(main.default_camera_zoom() 按 OS.has_feature("mobile") 走),1.75 这个数在模拟器上看起来够用(2400×1080 下近十只猫同屏、名字和气泡都读得清),但它仍然是推出来的,不是量出来的。如果重来,我会在第一天就把"能不能一眼看清几只猫在干什么"变成一张可以打勾的截图对比,而不是留到最后一晚。

六、结尾

五天里我最没底的部分,最后是用一块模拟器收的尾。它没有回答我最初害怕的那个问题("在别人手机上到底卡不卡"),但它回答了我一直回避的那个问题("它到底能不能玩")。
有些"还没条件做"其实只是"还没拆开做"。 这句话我打算留着,下一个 21 天再验证一次。
如果你已经玩到了这里,我想问你一句实话:双端投稿的评审,你们会拿什么设备打开这个包? 我这边缺的就是那台设备。

七、留给评论区的问题

在评论区告诉我:你手机上一共装了多少个游戏?其中有多少是你自己或者朋友做的?
我想问这个,是因为过去这些天我发现一个挺魔幻的事:做这个游戏最难的部分不是规则、不是美术,是**"让这个东西出现在别人手机上"**。你也这样觉得吗?
如果你也在做游戏——不管是独立开发还是公司项目——评论区聊聊你被工具链卡住过的经历,我逐条看。
#聚光灯gamejam开发者日志 #聚光灯gamejam #涌现 #猫咪游戏 #独立开发 #游戏开发
【童谣镇】聚光灯第二次开发日志截图
【童谣镇】聚光灯第二次开发日志
开发进度: 美术 1、主角人物立绘已细化完成 2、所有NPC的QQ人形象与呼吸动画已设计完成 3、大部分UI界面已设计完成 4、面包房建模与树屋建模以及基础房屋、路灯、树木模型已完成。 5、制作过场动效,制作通用动效材质ing 6、广场资产替换、永续桥和植被的资产替换、房屋资产替换,河流制作 7、学校模型的材质完成 8、石墩子、小道具模型制作ing 9、NPC正比胸像绘制ing 策划 1、任务系统
16 赞
10 回复
目前个人认为目前聚光灯值得一玩的游戏截图
目前个人认为目前聚光灯值得一玩的游戏
T0是美术风格优秀,并且以玩法为主。 T1是玩法或者美术稍微弱一点,但也很推荐一玩。 排名不分先后: 1️⃣寂静园:复古像素风格的横版解密游戏,关卡设计精妙,很好的运用了"金币"这一关键机制,初解密会感到有些困难,不过当熟练机制之后,便会茅塞顿开 2️⃣spectreX:运用光影折射的横版解密,通关方式多样,不同的光影运用会有意想不到的效果。 3️⃣光与影:同样也是光影解密,和spectreX不同
11 赞
5 回复
00:07
雨天決行 开发者日志02-人工智能的自我修养截图
雨天決行 开发者日志02-人工智能的自我修养
又和大家见面啦!第二篇日志,说实话一开始不知道该怎么编排,但团队里惊喜的成果越来越多,我们已经迫不及待把更新的内容端上来给大家啦!那么事不宜迟,快来看看都有什么新情报吧ദ്ദി˶ー̀֊ー́ )✧ 一.美术(重磅升级) 以主美小为的生命力作为燃料(bushi)本次美术组取得了大进程!首先是各个ui界面的优化和细化,上次大家看到时还只是初具雏形的草稿,现在大多都完整起来了哦! 同时,随着配色的补全,手
43 赞
39 回复
00:30
《失心》游戏开发者日志01|游戏UI迭代及实机演示截图
《失心》游戏开发者日志01|游戏UI迭代及实机演示
进入《失心》之前,玩家首先看到的是我们工作室 UNLOOK 的标识。我们将原来的标识转成 SVG,并让其中的红色瞳点转动、观察,再逐步显露完整字形,希望这个短暂的开场能带出一点好奇和不安。 这次《失心》的开局 UI,我们围绕小灵通(因为游戏的主要交互道具就是小灵通)做了几轮调整,希望玩家从打开游戏开始,就能感受到故事里的年代和气氛(故事年代背景为2000s)。 早期版本先确定了一个方向:把菜单放进
15 赞
10 回复
00:34
《荒原复苏指南》开发日志④:关卡演示堂堂袭来!!截图
《荒原复苏指南》开发日志④:关卡演示堂堂袭来!!
- 人类曾因掌握元素合成技术而一度辉煌,又因滥用元素能量而逐渐从内里衰败。 - 30世纪80年代。社会文化充斥着激进乐观主义与庞大机械美学,在这里,污染和能源共生,幸福与痛苦并存。官方广播和宣传画里依旧在宣扬“科学将战胜一切”、“元素能量将再造新农田”的口号,而世界主城却已经因为污染过度而濒临崩溃、空间挤压严重。为了寻找新的生存空间与无污染能源,官方启动了“重构拓荒计划”。 - 玩家将作为前线拓展
18 赞
6 回复
开发日志01截图
开发日志01
“涌现” 1.读作 ‌yǒng xiàn‌,意思是(人或事物)在同一时期大量出现,或者突然出现。‌‌ 2.科学含义‌:在复杂性科学里,涌现指大量简单个体相互作用后,整体产生了单个个体不具备的新特性,也就是“整体大于部分之和”,比如蚁群表现出的智慧、人工智能大模型的推理能力。 刚看见这个题目的时候,有一点点懵。看了词语解释之后,才有了一点想法。 考虑到时间还有个人开发的能力限制,目前决定做一个纯粹的
2 赞
【涌现符】开发日志#1截图
【涌现符】开发日志#1
大家好,我们是电子织机队,核心成员都来自同一个学校社团。 经过了五天的设计大烧烤终于把玩法大概定了下来。虽然题目一出大家立刻都想到了涌现式玩法,但是在这么短的时间内设计出优秀好玩的涌现式玩法对于没有太多经验的学生还是难度颇高,涌现式叙事对于没有专门编剧的我们队也难以达到理想的效果。 皮尔斯提出的"Symbols grow"是一个很有趣的概念,也即一个符号在使用中产生解释,解释引导预期和行动,经验又
4 赞
2 回复
《源墨名出》开发者日志 01|情绪会变成颜色,也会淤成一团墨截图
《源墨名出》开发者日志 01|情绪会变成颜色,也会淤成一团墨
大家好,这里是脑洞俱乐部,很高兴能够站在这里与大家一同参加本次聚光灯大赛。 10 月 1 号题目公布 ——「涌现」。我们盯着这两个字沉默了三分钟,然后有人说:要不,我们聊聊情绪吧。 于是就有了《源墨名出》 我们是怎么理解 "涌现" 的? 我们觉得,情绪这东西本来是看不见的。但当它被你看见、被你说出口、被人接住的时候,它就 "涌现" 成了具体的样子 —— 我们让它涌现成了颜色。 红是愤怒,橙是喜悦,
19 赞
14 回复
开发者日志03截图
开发者日志03
大家好,第三篇开发日志来了。先公布一件事:我们的游戏正式定名为《尸涌》!这是一款以丧尸战斗和村庄探索为核心的第一人称射击游戏。这次也把最近几轮的战斗、成长、界面和探索进展一起整理出来。 故事从一位旅行者的失踪开始。主角作为她的好友,沿着她的旅行轨迹来到这个村庄,寻找她留下的线索,却逐渐发现村民与城里的制药公司之间,藏着秘密人体实验。村庄里的丧尸灾变究竟是怎么发生的?失踪的好友又去了哪里?这是我们刚
1 赞
开发者日志02 ---------- 玩法确定好了?那就直接冲!!截图
开发者日志02 ---------- 玩法确定好了?那就直接冲!!
书接上回,我们已经定了游戏的基础玩法,接下来就是正式搭建框架和往里面填内容了。来自程序的话:我认为做游戏就两步:第一步,先创造这个世界,指定它的规则,创作它的样貌。第二部,往里面增添内容,创造生命,创造天气,地貌河流。(像是个创世神) 接下来隆重介绍一下玩法: 左侧是玩家的飞船背包,所有的道具和捡的垃圾都会装在这里,右侧则是飞船的模块系统,玩家可以往里面填充飞船的模块,一次来规划自己的飞船。 例如
5 赞