首先来看看这个游戏的简介吧! ↓ ↓ ↓ ↓ ↓

这是一个关于退伍老兵Bell的故事,Bell是一名穷困潦倒的退伍老兵,为摆脱贫困,他签下了一份神秘真人秀的参赛合约。
可这场“游戏”,比预想中提前降临。他被保镖打晕在地,醒来时发现自己被遗弃在了一座荒芜孤岛之上↓↓。

他手中仅有一台信号追踪器和一本生存指南,必须追寻信号源头,找到逃离的出路。
获胜奖励是一笔巨额财富;而赌注,是他的性命。而你,或许,将亲手决定他最终的命运。

游戏目标是在不同的地形上走动,在收集资源的过程中可以前往山坡收集信号,找到逃离的方向最终逃离。

这是官方链接:幸运信号 |Ludum Dare 游戏创作马拉松 — Fortune Signal,里面有Windows版本的下载链接。

开始

做完 FruitMatches 水果三消后,我想试试团队合作的项目,正好了解到 Lumdum Dare 59 ,于是我组队参加了这个比赛。

这是一个72小时的短期比赛,算上我配置是一策划两美术三程序。

开发

其实在比赛开始之前,我们打算用一个塔防类的合作项目练练手,不过中途因为各种事情导致项目没有完成,不过好在大家在合作过程中发现了一些问题并讨论解决。其中让我觉得值得记录的是,我们没有使用GitHub作为合并项目的工具,而是采用了团结云来合作,我了解到团结云是Unity 中国专为中国开发者推出的云端协作平台,省去了本地打包的步骤,策划可以直接在Unity中体验游戏,确认无误后再通知程序打包。

团结云合作

准备工作

  1. 想用团结云合作,需要下载国区特供Unity Hub:

国区特供UnityHub实例图片

  1. 然后还需要下载这两个软件:

TuanjieDevops

PlasticSCM

  1. 确认Unity版本一致后,需要加入同一个云开发组织,详细教程可以参见TuanjieDevops中的引导教程。 (只能用团结云客户端,网页端拉不了)

加入组织

操作说明

1. 将UnityHub中的项目连接到团结云,具体操作如下:

关联项目1

关联项目2

选择对应的云开发组织后点击连接即可。

2. 在Unity中提交更改

在Unity中提交更改

3. 在Plastic SCM中查看变更集和切换分支

查看变更集和切换分支

4. 在Unity中拉取队友的更新:有冲突的情况可以先备份自己的工作内容,再将队友的拉下来,解决冲突后粘上去

正式比赛

后来,正式开始了比赛。比赛开始时公开了这次比赛的主题 "Signal" ,经过了一番讨论,我们决定做一个2D Tilemap 探索游戏项目,主玩法是“有限体力/理智/生命管理 + 地形探索 + 随机事件 + 战斗/拾取 + 寻找信号站通关”。

游戏截图

这是我们的游戏截图。我们从项目核心向外讲:

bootstrap 启动器场景

这个项目接近尾声时,阿然老师新创建了一个启动器场景GameEntry,我们需要从这个场景进入游戏。后来通过搜索资料,我了解到这个场景叫做启动器场景,也就是bootstrap

我们可以在这个启动器场景中创建GameLoader对象,挂载GameLoader脚本,并且在Awake()中写入DontDestroyOnLoad(gameObject),统一管理游戏场景的加载和淡入淡出。

GameLoader 场景加载管理器

  1. 单例模式与持久化
1
2
3
4
5
6
7
public static GameLoader instance { get; private set; }
private void Awake()
{
DontDestoryOnLoad(gameObject);
instance = this;
// ...
}
  1. 核心加载流程

游戏中的加载

1
2
3
4
5
6
private async UniTask LoadScene(string sceneName)
{
await FadeIn(); // 屏幕变黑
await SceneManager.LoadSceneAsync(sceneName).ToUniTask(); // 异步加载新场景
await FadeOut(); // 屏幕恢复透明
}
1
2
3
4
5
6
7
private async UniTask FadeIn()
{
if (m_blackScreen == null) return;
   
m_blackScreen.gameObject.SetActive(true);
    await m_blackScreen.DOFade(1f, m_fadeDuration).SetEase(Ease.Linear).ToUniTask();
}

下面我们来理解这段代码的重点:

  • private async UniTask FadeIn()async表明这是一个异步方法,返回UniTask
  • m_blackScreen.DOFade(1f, m_fadeDuration)DOFade 会改变 Image 的透明度。
    • 1f:目标透明度是 1,也就是完全不透明
    • m_fadeDuration:渐变持续时间,比如 0.5 秒
  • .SetEase(Ease.Linear):设置动画速度曲线为线性。也就是透明度匀速变化,不会先快后慢或先慢后快。
  • .ToUniTask():DOTween 默认返回的是 Tween,不是 UniTask。这里把 Tween 转成 UniTask,这样就可以用 await 等它播放完。

GameManager 游戏管理器