创建 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
加载中...
13票,平均分:1.00/113
667
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

松山健翔

他长期在一家游戏开发公司从事编程和项目管理工作。
2019年,他加入Beyond Inc.,在横滨办公室工作。
他主要负责服务器端开发项目的项目管理(偶尔也参与编程)。
他的爱好是骑自行车(公路赛)和观看赛马。