创建 Da○saba○bar(第一期)
![]()
“每周 Da○saba○ber Creation”现已上线!
我们决定以 Di○gos○ini 的风格突然启动。
好久不见。
我是系统开发部的松山。
我平时在手机上浏览Facebook或者看漫画的时候,
经常会看到“Da○saba○bar”的广告。我
不讨厌这种混乱的游戏,所以
就决定试玩一下,看看能不能营造出什么氛围。
顺便一提,我只玩过试玩版,所以
可能和正式版有很大不同,请大家多多包涵。
大致要求
和往常一样,我们先来明确一下要求。①
游戏采用二维网格状场景。②
玩家可以通过触摸屏幕上下左右移动角色
。③ 游戏包含多种武器和关卡
。④ 敌人会自然生成并向玩家移动
。⑤ 游戏对玩家、敌人和武器进行碰撞检测
。⑥ 击败敌人后会显示经验值,收集经验值可以获取新武器或提升武器等级。
暂时就这些了。
我会边做边考虑细节。
像时间测量和音效之类的小制作环节,我会留到以后再做(同时给人一种它们可能还没完成的感觉)。
项目创建
我好久没用 Unity 了,所以我会安装最新版本。2022.3.18f1
似乎是最新的 LTS 版本,所以我就安装这个。Unity
Hub 很方便。
我会把项目命名为“BeBeSurvivor”,并创建一个 2D 应用。
资源
我在资源商店里搜索制作所需的素材(精灵图)。
浏览免费的2D素材时,我找到了我需要的所有东西。
◾️ 亡灵生存素材包
这个素材包包含了所有必要的材料,例如玩家、敌人和武器。
它甚至可以正常运行,所以我本来可以用它完成所有工作,但
我很高兴能够只使用这些素材。

◾️低多边形纹理包:
是一个用于覆盖场景的图像包。
它也包含在亡灵幸存者资源包中,但我们不妨也试试使用这个单独的纹理包。

使用包管理器导入这两个文件。
铺设场地
低多边形材质包里有很多材质,所以我只挑选我觉得会用到的。
它们有点大,所以我调整一下比例。
效果如下。

可以将其制作成预制件,然后使用脚本将其铺展到合适的区域
。

脚本内容如下:
// 生成一个范围从 (-50, -50, 0.5) 到 (50, 50, 0.5) 的场(5 x 5 网格) Vector2 pos = new Vector2(-50, 50); float size = 5f; int cnt = 20; for(int x = 0; x <= cnt; x++) { for(int y = 0; y <= cnt; y++) { // 如果 x 和 y 均为 0 且 cnt 为 0,则生成 field[1],否则生成 field[0] int idx = (x == 0 || x == cnt || y == 0 || y == cnt) ? 1 : 0; // 为中心网格生成 field[2] if(x == cnt / 2 && y == cnt / 2) { idx = 2; } // 生成游戏对象 obj = Instantiate(field[idx], new Vector3(pos.x + (x * size), pos.y - (y * size), 0.5f), Quaternion.identity); obj.transform.parent = parent.transform; } }
我会尝试只在外围和中心放置不同的图片。
这次我只用有限大小的屏幕,但我认为无限滚动效果会更好。
(不过,我觉得这段代码写得挺粗糙的……)
玩家
幸存者素材包里有一些不错的素材,所以我打算用它们。

还有动画模式,所以创建等待、移动和死亡的动画,并将
它们设置为动画师。

这是它移动时的样子(待机状态)

运动(输入系统)
移动玩家角色。
屏幕中心是原点,角色会朝你点击的方向移动。
在我离开 Unity 的这段时间里,发布了
“输入系统”也需要从包管理器导入它。
我简单试了一下,但没能从输入操作中正确获取信息。
暂时先跳过这个操作,继续使用传统的脚本控件实现方式。
(有时间我会再尝试调整输入操作。)
var mouse = Mouse.current; if(mouse.press.ReadValue() == 1) // 按下状态 { if(holdTime > 0.0f) // 等待 { holdTime -= Time.deltaTime; if(holdTime < 0.0f) holdTime = 0.0f; } else // 移动 { Vector2 pos = mouse.position.ReadValue(); } } else // 释放状态 { holdTime = HoldTime; }
可以通过 `mouse.current` 获取操作信息。
可以通过 `mouse.press.ReadValue()` 获取点击状态,触摸开启时返回 1,触摸关闭时返回 0。
经过一段时间后,通过 `mouse.position.ReadValue()` 获取触摸坐标,并
计算移动方向(向量)。大致如下所示。

由于两点的坐标已知,我们可以直接通过相减来计算向量。
由于长度无关紧要,我们用归一化矩阵对其进行归一化。
Vector2 vec = (pos - center).normalized;
如果将此值设置为玩家的坐标(localPosition),角色就会移动。
就像这样。(等待↔移动)

趁此机会,只提取移动方向的 X 分量,并改变角色的方向(绕 y 轴旋转 180°)。
摄像机跟踪
在这种情况下,角色会超出摄像机的视野范围,所以我们需要让摄像机跟随角色移动,以确保角色始终位于屏幕中心。你只需要将
主摄像机的变换的 localPosition 与角色的坐标匹配即可。

代码如下所示。请注意,z 坐标固定为相机坐标。
// 跟随摄像机 Vector3 pos = playerController.GetPosition(); pos.z = -1.0f; mainCamera.gameObject.transform.localPosition = pos;
实现后效果如下:

敌人
目前,我先放一些稻草人作为敌人。
我会使用幸存者素材包,里面有一些不错的素材。(谢谢)

还有动画模式,所以可以创建移动和死亡动画,并将
其设置为动画师。

目前,我就先这样吧。

碰撞检测
使用 Unity 标准提供的 Collider2D进行碰撞检测
首先,进行一些准备工作。
给玩家和敌人各添加一个 2D 圆形碰撞器。
勾选 IsTrigger 属性。

另外,给玩家添加一个 2D 刚体(敌人不需要)。
由于这次不需要进行物理计算,请将刚体类型设置为 Kinematic。

在脚本中获取命中检测。
将以下函数添加到玩家和敌人的代码中。(触发器类型)
private void OnTriggerEnter2D(Collider2D collision) { // 碰撞器撞击时调用 // 如果撞击到敌人,则造成伤害 if (collision.tag == "Enemy") { Debug.Log("玩家被击中:" + collision.name); } } private void OnTriggerStay2D(Collider2D collision) { // 碰撞器保持接触时持续调用 } private void OnTriggerExit2D(Collider2D collision) { // 碰撞器离开时调用 }
我们将使用标签来确定击中的对象。
玩家标签默认已注册,因此请添加敌人和武器标签。
为每个对象设置标签。

如果让它在接触到目标时输出日志,日志内容将如下所示。

本月内容就到这里。
暂时就这些。
我觉得我已经实现了基本机制。Unity
的功能非常丰富,所以实现起来相对容易。
在下一期中
我想加入武器(3 种类型 x 3 个等级)
我计划稍后将 Unity 项目上传到 GitHub。
请稍等片刻。
上传完成后,我会更新这篇文章。
我已将 Unity 项目上传到 GitHub。
希望这能对你有所帮助。
BeBe幸存者
好了,今天就到这里。
*虽然开头写的是“每周”,但下一期计划在三月份发布。
13