静默之城:替一座失语的港口,把英语说完

静默之城标题画面

有些话没说出口,就一直悬在雾里。我做了一款用碎片时间学英语的网页游戏,名叫静默之城。你不是坐在题库前面背单词。你是一名聆听者,走进一座失语的港口,替它把话说完。

静默之城标题画面,雨夜的雾港车站,中间是继续游戏按钮
雾港的灯还亮着。你从这里进站。

传统的语言游戏问你:这句翻译对不对。静默之城问的是另一件事:这句话该怎么说。同一个意思,可以说得温暖,也可以说得平淡,或者疏离。你选的语气会改变对方的信任,故事也会走向不同的结局。词典查不到的那些东西——语感、分寸、得体——才是这城里真正要练的。


雾把词吞掉了

雾港得了静默症。对话里有些词消失了,只剩语境还亮着。你要靠前后文把那个词听出来。猜错了不会跳出一个红叉,对方只是换一种方式再跟你说一次,像真人没听清时那样。

雨夜里的雾港,中央弹出一句英文和中文,旁边是朗读按钮
你听见了别人没听见的。点一下,可以朗读。

同一句话,三种温度

轮到你开口时,不会让你从零打出一句完美英语。你会看到两三种说法,意思相近,温度不同。选一句,就是你对这个人的态度。米拉在雾港站值夜班,清醒,嘴硬,心软。你怎么接她的话,她就怎么看你。

与雾港站值班员 Mira 的双语对话,英文在上,中文在下
米拉从售票窗后面看着你。这句话,你可以有不同的说法。

听来的词,还会再遇见

对话里收下的词会进词灵阁。回声室用原来的语境让你再填一次、再听一次。之后回到剧情里,这些词会在新的场面里醒过来。收集,隔一段时间再认,然后在下一场戏里用上。一章大约十到十五分钟,适合课间、通勤和睡前。

雾港地图,序章雾港站可以进入,第一章深夜咖啡馆尚未解锁
完成一章,雾会退开一点,下一处才让你进去。

这一版是可以玩的开端:序章和两章剧情,十一枚词灵。适合已经能读简单英语、又想把话说得更像那么回事的人,大致是欧标 A2 到 B2。用浏览器打开就能玩,进度留在这台设备上,对话也可以听朗读。

城还在雾里练习怎么开口。从这里进入雾港。

栖景 Quiet:我独立做的免费开源壁纸应用

栖景 Quiet 今日灵感

我想要的桌面很简单:打开电脑,先看到一张喜欢的风景。没有推荐流,没有弹窗,也不该为了一张壁纸看广告。所以我自己做了栖景 Quiet。

它免费,源码公开,没有广告。Windows 和 Mac 都能用。风景来自 Unsplash,也可以用自己的照片。

省流版:

  • 免费,开源,没有广告。
  • 我一个人独立开发,慢慢打磨。
  • 精选推荐、山野、海岸、极简,都能直接设成桌面。
  • 可以收藏,也可以 30 分钟、1 小时、4 小时或 1 天自动换一张。

打开就是一张风景

进应用先看到今日灵感。喜欢的话,点一下就能设为桌面壁纸。

栖景 Quiet 的今日灵感,一张海岸岩壁风景,下面有设为桌面壁纸的按钮
打开应用,先是一张今日灵感。

想看哪一类,就停在哪一类

发现壁纸里有精选推荐、山野、海岸和极简。图片来自 Unsplash,作者名字可以点开。自动切换会沿着你当前看的这一组往下换,不用每次自己翻。

栖景 Quiet 的发现壁纸页面,九张风景并排,上方是精选推荐、山野、海岸、极简
四组风景,直接铺开。

看中了,就留下

点开一张图,可以收藏、下载,或者设为壁纸。自己的 JPG、PNG、WebP 也能导入,这些照片留在你的电脑上。

栖景 Quiet 的壁纸预览,山间云雾,旁边有收藏、下载和设为壁纸
预览之后,收藏、下载,或设成桌面。

免费,也公开

栖景不收费,里面没有广告位。源码按 MIT 协议公开,可以自己看它是怎么做的。

现在可以在 Windows 和 Mac 上使用。手机版还在后面。

给开源 Windows 安装包做免费代码签名

Windows 上把安装包直接发给别人时,系统经常会把它当成未知发布者,SmartScreen 会拦住。这篇只谈代码签名本身:哪些办法其实签了也没用,免费的 SignPath Foundation 适合什么项目,以及它和 GitHub Actions 怎么配合。不涉及任何一个具体应用的地址、账号或配置。

省流版:

  • 自己生成的证书只在你这台电脑上可信,别人下载照样报警。
  • 苹果开发者会员只能签 Mac,不能签 Windows 安装包。
  • 公开、使用 OSI 开源协议、并由托管 CI 构建的项目,可以申请 SignPath Foundation。用户看到的发布者名字是 SignPath Foundation,不是作者本人。
  • 审核没有固定天数。公开经验里常见的是一两周,也有人等到一个月以上。结果发到申请邮箱。
  • 私钥不会发给你。签名在对方的服务里完成。

一、Mac 和 Windows 是两套签名

Mac 上给公开下载的应用签名,用的是 Developer ID Application,签完还要做公证。企业账号是给组织内部发应用的,拿去公开下载,证书有被吊销的风险。这套会员资格不能用来签 Windows 的 .exe。

Windows 要减少 SmartScreen 的拦截,需要系统信任的 Authenticode 证书。本机用工具做出来的自签名证书,换一台电脑就不被信任。

付费证书里,普通的 OV 往往也要积累一段时间的信誉,报警才会变少。EV 可以更快去掉提示,但通常要求公司主体,费用也更高。微软的 Artifact Signing,个人申请目前主要面向美国和加拿大,组织核验也不覆盖所有地区,提交前要先看自己是否符合地区要求。

二、SignPath 实际在签什么

SignPath Foundation 面向符合条件的开源项目,免费签发 Windows 安装包。常见条件是:仓库公开、协议属于 OSI 认可的开源协议、安装包由 GitHub 托管的构建机器从公开仓库打出来,而不是在个人电脑上手工打包再上传。

它不会把证书文件交给你。构建完成后,CI 把未签名的安装包交出去,签名完成后再拿回来。用户属性里的发布者是 SignPath Foundation。

申请时他们还会看这些公开材料,而不是看你的私钥:

  • 仓库必须是公开的。私有仓库不能走这套免费签名。
  • 要有一个用户能打开的下载页,并且页面上写明该项目使用 SignPath Foundation 做代码签名。
  • 如果软件会把数据发到开发者自己的服务器,需要有公开的隐私政策,并让用户知道这件事。具体收集哪些字段,不要写进签名教程。
  • 通过之后,GitHub 和 SignPath 账号都要打开两步验证。

三、申请表只记字段,不记答案

表单在 signpath.org/apply.html。它会要项目名、仓库地址、主页、下载页、隐私政策、一句话介绍、项目说明和维护者类型。这些内容填进表单即可。

不要把填好的表、组织编号、项目标识、令牌写进博客、仓库说明或聊天记录。令牌等同于签名权限。仓库地址和下载页本身是公开的,但没有必要在一篇教程里再抄一遍。

介绍和说明用英文写清软件做什么、安装包从哪来。没有媒体报道就照实写,不要编下载量。邮箱用一个真能收信的地址,不要用 GitHub 的 noreply 邮箱。

维护者是个人就选 Individual,构建系统是 GitHub Actions 就选 GitHub Actions。公司名称可以留空。没有维基百科页面也留空。

四、审核要多久,怎么通知

SignPath 没有公布固定工作日。别人公开记下来的等待多半是 1 到 2 周,也有 4 周甚至更久。新仓库、材料不齐,都会更慢。对方先回邮件让你补下载页或隐私政策,这是补材料,不是拒绝。

通过、补材料、拒绝,都发到申请表里的那个邮箱。账号也用这个邮箱开通。提交后看收件箱,也看垃圾邮件。网站上没有另外的进度查询页。

五、通过之后怎么接到构建流程

等邮件里的开通说明到了再接。下面只保留机制,不写任何一项真实配置的值。

  1. 登录 SignPath,打开两步验证。
  2. 安装他们的 GitHub App,只授权需要签名的那个仓库。可信构建系统选择 GitHub.com,这样签名请求必须来自托管的 GitHub Actions,而不是任意一台机器。
  3. 在 SignPath 里建立项目和签名策略。策略用来规定谁可以批准一次签名。
  4. 如果 CI 上传文件时会先打成 zip,产物配置就要按「压缩包里的可执行文件」来描述,而不是按一个裸的 exe。文件名只放在 SignPath 的配置里,不要写进文章。
  5. API 令牌放进仓库的 Actions secret。组织编号和项目标识放进 Actions 变量。这些值只留在 GitHub 的设置页。

比较稳妥的接法是:令牌还没填时,发布流程照常交出未签名的安装包,避免审核没通过就让整个发布失败。令牌填上之后,构建完成、发布之前,把未签名文件提交给 SignPath 的官方 Action,等签名结束,再用签好的文件替换原文件,然后才挂到 Release。

Action 的名字以 SignPath 文档里的当前版本为准。不要把工作流文件、安装包文件名和密钥名称整段贴出来。

六、签完之前仍然是未签名

申请提交之后、第一次签名成功之前,用户下载到的仍然是未签名安装包,SmartScreen 仍可能出现。邮件通过并且新的构建跑完,发布者才会变成 SignPath Foundation。

Mac 不走这套。Mac 仍然用开发者自己的 Developer ID 和公证。两套签名可以同时存在,不能互相代替。

Flutter 启动图(Splash Screen)完整指南Android

从 dp / px 原理到 1024px 导出,一篇讲清楚

在 Flutter 项目中配置启动图(Splash Screen),是很多新手甚至老手都会踩坑的地方:

  • dp 和 px 到底有什么区别?
  • 为什么说 Logo 要放在 160dp 的安全区?
  • Figma 里我到底该画多大?
  • 为什么教程又说要导出 1024px?
  • flutter_native_splash 能不能用 SVG?

这篇文章我会 从原理讲到实操,一步步带你把 Flutter 启动图这件事彻底搞清楚。

省流版:

  • 品牌图片:尺寸必须为 200×80 dp。
  • 带有图标背景的应用图标:尺寸必须为 240×240 dp,并且位于直径 160 dp 的圆圈内。
  • 无图标背景的应用图标:尺寸必须为 288×288 dp,并且位于直径 192 dp 的圆圈内。

一、Flutter / Android 启动图的核心思想

先说一个最重要的结论:

启动图不是“全屏海报”,而是“居中的 Logo + 背景色”

Android(以及 Flutter 使用的 Android SplashScreen API)在不同设备上,会对启动图进行 裁剪和缩放,真正安全可见的区域,是一个 圆形安全区。(这个应该是基于Android12之后的。Android 11 及以下 是直接放一张满屏的启动图。)


二、dp 和 px 的区别(人话版)

1️⃣ px 是什么?

  • px = 像素
  • 是屏幕上最小的物理点

问题是:

不同手机,像素密度完全不同
同样 160px,在不同手机上看起来大小不一样


2️⃣ dp 是什么?

  • dp = density-independent pixel(与密度无关的像素)
  • 是 Android / Flutter 用来保证 “看起来一样大” 的单位

简单理解:

dp 决定“看起来多大”,px 决定“清不清楚”


3️⃣ 关键结论(一定要记住)

在 Figma 里:1px ≈ 1dp(逻辑等价)

也就是说:

  • 你在 Figma 里画 160px
  • 在 Flutter / Android 里就是 160dp 的视觉尺寸

三、为什么是 160dp?启动图安全区解释

Android 官方对启动图图标有明确规则:

  • 启动图会被放进一个 圆形 Mask
  • 只有圆内的内容是 100% 安全的
  • 圆外内容在某些设备上一定会被裁掉

推荐安全区

  • 安全圆直径:160dp
  • 超出这个范围:有被裁风险

四、Figma 中正确的启动图画法

Step 1:创建画布

  • 新建 Frame
  • 尺寸:288 × 288
  • 单位:px(默认即可)

288dp 是 Android 启动图推荐的最大逻辑画布


Step 2:画安全圆

  • 在画布中画一个 160 × 160 的圆
  • 水平 + 垂直居中
  • 作为辅助参考(可以加描边)

所有 Logo 内容 必须完全放在圆内


Step 3:设计 Logo

  • Logo、文字、图形全部放在安全圆内
  • 圆外只作为留白或背景

五、那为什么又要“导出 1024px”?(重点)

这里是最多人迷糊的地方。

1️⃣ 160dp 是什么?

  • 是 设计规则
  • 决定 Logo 看起来多大
  • 决定会不会被裁

2️⃣ 1024px 是什么?

  • 是 导出清晰度
  • 决定图片在高分屏上会不会糊

3️⃣ 二者不冲突

可以这样理解:

我按 160dp 的规则来画 再用 1024px 的分辨率来导出

就像:

  • 同一张证件照
  • 用 500 万像素拍 or 5000 万像素拍
  • 脸的比例一样,只是清晰度不同

六、Figma 导出 1024px PNG 的正确方式

⚠️ 不需要重新画 1024 的画布

正确步骤:

  1. 选中 288 × 288 的最外层 Frame
  2. 右侧找到 Export
  3. 格式选择:PNG
  4. 把 1x 改成:1024 ÷ 288 ≈ 3.56x (不正规)

导出后就是:

1024 × 1024 px 的启动图 PNG


推荐的省心方案(更简单)

直接用:

  • 4x
  • 导出尺寸:1152 × 1152 px

这个尺寸:

  • 更清晰
  • 无副作用
  • flutter_native_splash 完全支持

七、为什么 flutter_native_splash 不能用 SVG?

因为不支持,我导入之后 flutter pub run flutter_native_splash:create 后直接报 Your image must be in one of the following formats: [png, apng, jpg, jpeg, jpe, jfif, tga, tpic, gif, ico, bmp, dib]

最后建议大家看官方文档https://developer.android.com/develop/ui/views/launch/splash-screen?hl=zh-cn

🎨 Aseprite for Mac 快捷键使用指南|像素绘图效率秘籍

Aseprite 是一款专为像素艺术设计的专业软件,支持帧动画、图层操作、调色板等多种功能。而在 macOS 上,掌握快捷键能够极大提升你的绘图效率!

本篇文章将整理 Aseprite 在 Mac 系统下最常用的快捷键,帮助你从新手快速进阶高效创作者。

✏️ 基础绘图工具快捷键(macOS)

快捷键功能说明图标/备注
B画笔工具(Brush)🖌️ 最常用绘图工具
E橡皮擦工具(Eraser)🧽
G填充工具(Fill)🪣 一键填色
I吸管工具(Eyedropper)🎯 取色
L直线工具(Line)📏
U图形工具(矩形/椭圆)◼️ ⚪
Shift + B铅笔工具(Pencil)✏️ 像素级绘制
H拖动画布(Hand)✋ 拖动查看画布
Z缩放工具(Zoom)🔍 双击恢复100%缩放

🎞️ 动画帧操作快捷键

快捷键功能图标/说明
Return(回车)播放/暂停动画▶️ 动画预览
⌥ + N下一帧→
⌥ + B上一帧←
⌘ + N新建帧➕ 添加关键帧
⌘ + ⇧ + N新建图层📑
⌘ + ⇧ + D复制当前帧📄
F2重命名图层或帧✏️

⌨️ 选择、移动与编辑

快捷键功能说明图标/备注
M矩形选区工具(Marquee)⬛
⌘ + D取消选择❌
⌘ + T移动选区↔️
V移动图层工具🧱 移动画布中的对象

🎨 色彩与画笔控制

快捷键功能说明图标/备注
X交换前景/背景色🔄
D重置为默认黑白色⚫⚪
[ / ]调整画笔大小🔍
⌘ + E合并图层(Merge Layer Down)🧷
数字键 1-9设置图层不透明度(10%-90%)💡 快速透明控制

🖼️ 文件与画布快捷键(macOS)

快捷键功能说明图标/备注
⌘ + N新建文件📄
⌘ + S保存文件💾
⌘ + ⇧ + S另存为📁
⌘ + Z撤销↩️
⌘ + ⇧ + Z重做↪️
⌘ + C / ⌘ + V复制 / 粘贴📋
⌘ + ⌥ + C修改画布大小(Canvas Size)🖼️
Tab隐藏/显示面板界面👀 获得纯净绘图空间

🧅 Onion Skin 快捷键

快捷键功能说明图标/备注
⌥ + O开启/关闭 Onion Skin(洋葱皮)🧅 参考前后帧内容
⌥ + 1/2/3设置 Onion Skin 显示前几帧/后几帧🔍 控制范围

📌 提高效率的小建议

  • 推荐新手设置常用快捷键为左手覆盖区域(如 B/E/G/X/⌘Z 等),操作更顺手。
  • 使用 Onion Skin 查看动画流畅性,按 Alt + O 开关即可。
  • 多用图层和帧组织动画结构,再配合 ⌘ + ⇧ + D 快速复制帧。

📎 附加资源


💬 结语

使用 Mac 版 Aseprite 时,合理利用快捷键将极大提高创作效率,让你的像素画更加流畅、直观、有节奏感。希望这份指南对你有帮助!

🔖 如果你喜欢这篇文章,欢迎收藏、点赞或分享给其他像素爱好者!
📮 更多 Aseprite 教程与开发分享,欢迎访问我的博客:www.ilovedsy.com

OnDrawGizmos()、OnDrawGizmosSelected()不调用、不执行方法

这个是真的坑,搜了半天,还看了官方技术文档,我还天真的想是不是方法被弃用了,原来是这个SceneView 关闭了Gizmos。再点击一下这个图标即可。如下图。

You can see at code lines 81,I have worte the Debug.Log,but when I use the

Unity ,the Console hasn’t print anything.

code

So, actually you must to click this button.

unity_scene

When I clicked this button ,look, It’s work.And you can see the red line and Debug.log print the string.

unity_sceneClicked
happy

挑战100天做一款游戏🎮物理碰撞学习

game_dev_screenshot
game_dev_codes

这一节主要内容

1.给场景里的箱子、树木、还有Tilemap道具加上Box Collider 2D 组件

2.通过给Ruby添加Rigidbody 2D 组件,解决Ruby在道具周边移动时会旋转的问题

3.通过C#代码层,在FixedUpdate()函数中,合理的重新绘制Ruby的position在碰撞之前停止移动,而不必在 Ruby 已经进入箱子之后再移动 Ruby。之前一直是写在Update函数中的,这次新学的FixedUpdate()和其还是有区别的。(关于区别我放在末尾)

4.通过更改道具和Ruby Collider的大小使阻挡更合理

5.给瓦片地图添加Tilemap Collider 2D组件,通过调整Collider Type属性来完成合理的阻挡

6.通过给Tilemap添加Composite Collider 2D 自动添加 Rigidbody 2D ,优化地图碰撞

Update 和 FixedUpdate 区别

update跟当前平台的帧数有关,而FixedUpdate是真实时间,所以处理物理逻辑的时候要把代码放在FixedUpdate而不是Update.

Update是在每次渲染新的一帧的时候才会调用,也就是说,这个函数的更新频率和设备的性能有关以及被渲染的物体(可以认为是三角形的数量)。在性能好的机器上可能fps 30,差的可能小些。这会导致同一个游戏在不同的机器上效果不一致,有的快有的慢。因为Update的执行间隔不一样了。

Update需要时要进行单位转换(乘以Time.deltaTime):单位/帧*帧/秒=单位/秒。以保证按照单位时间被调用(这样从帧转换到了时间,但数值变小了,为了变回原值还要乘以Time.deltaTime的倒数的数值【注意是数值】)

FixedUpdate要乘以fixDeltaTime

Unity2D 装饰世界

接上一期,我们已经有了瓦片地图,现在我们添加更多的元素来充实我们的游戏世界。

关于瓦片的快捷键和官方的瓦片教程,可以看这里

1601b3b6-6ea0-4cae-b1b6-d8beebe01be4_3.5.png.400x0x1

这一节我们通过改变游戏对象的y坐标来绘制游戏对象。

1.选择 Edit > Project Settings。

2. 在左侧类别菜单中,单击 Graphics。

3.在 Camera Settings 中,找到 Transparency Sort Mode 字段。此字段决定了精灵的绘制顺序。使用下拉菜单将此设置从 Default 更改为 Custom Axis。7892a369-ac56-4457-93a7-ee30f0f67c1c_TranspSortMode.png.2000x0x1

4.在 Transparency Sort Axis 中添加以下坐标:

  • x = 0
  • y = 1
  • z = 0

此设置告诉 Unity 在 y 轴上基于精灵的位置来绘制精灵。

5.关闭 Project Settings 窗口并保存你的更改。

6. 按 Play 以进入运行模式并测试你的更改。现在,你的角色比箱子高时,角色应该会绘制在箱子的后面;而角色比箱子低时,绘制在箱子的前面。 这只是一个开始,但并不完美,因为在箱子后面(而不是前面)绘制 Ruby 的时机似乎过早。为此解决此问题,你需要调整 Sprite Renderer 组件。