Unity开启篇(二十) —— 如何使用Unity制作像Bomberman一样的游戏(一)

版本记录

版本号 时间
V1.0 2019.01.31 星期四

前言

Unity是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。Unity类似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的图型化开发环境为首要方式的软件。其编辑器运行在Windows 和Mac OS X下,可发布游戏至WindowsMacWiiiPhoneWebGL(需要HTML5)、Windows phone 8和Android平台。也可以利用Unity web player插件发布网页游戏,支持Mac和Windows的网页浏览。它的网页播放器也被Mac 所支持。网页游戏 坦克英雄和手机游戏王者荣耀都是基于它的开发。
下面我们就一起开启Unity之旅。感兴趣的看下面几篇文章。
1. Unity开启篇(一) —— Unity界面及创建第一个简单的游戏 (一)
2. Unity开启篇(二) —— Unity界面及创建第一个简单的游戏 (二)
3. Unity开启篇(三) —— 一款简单射击游戏示例 (一)
4. Unity开启篇(四) —— 一款简单射击游戏示例 (二)
5. Unity开启篇(五) —— 一款简单射击游戏示例 (三)
6. Unity开启篇(六) —— Unity动画简介 (一)
7. Unity开启篇(七) —— Unity动画简介 (二)
8. Unity开启篇(八) —— Unity声音简介(一)
9. Unity开启篇(九) —— Unity声音简介(二)
10. Unity开启篇(十) —— Unity粒子系统简介(一)
11. Unity开启篇(十一) —— Unity粒子系统简介(二)
12. Unity开启篇(十二) —— Unity脚本简介(一)
13. Unity开启篇(十三) —— Unity脚本简介(二)
14. Unity开启篇(十四) —— Unity UI简介(一)
15. Unity开启篇(十五) —— Unity UI简介(二)
16. Unity开启篇(十六) —— Unity UI简介(三)
17. Unity开启篇(十七) —— Unity UI简介(四)
18. Unity开启篇(十八) —— Unity UI简介(五)
19. Unity开启篇(十九) —— Unity UI简介(六)

Getting Started with this Bomberman tutorial

首先看下写作环境

C# 6, Unity 2017.x, Unity

在本教程中,您将学习以下内容:

  • 丢炸弹并将它们扔到tile位置。
  • 通过使用光线投射检查free tiles产生爆炸。
  • 处理与玩家碰撞的爆炸。
  • 处理与炸弹相撞的爆炸。
  • 处理玩家死亡以确定胜利/平局。

打开已经下载好的项目,在Unity中打开Starter Project并启动此Bomberman教程。资源在几个文件夹中排序:

  • Animation Controllers:保持玩家动画控制器,包括在玩家四处走动时动画玩家肢体的逻辑。
  • Materials:包含关卡的block材质
  • Models:包含玩家,关卡和炸弹模型以及他们的材料
  • Music:包含音轨
  • Physics Materials:保存玩家的物理材料 - 这些是为表面添加物理属性的特殊材料。 在本教程中,它用于让玩家毫不费力地在水平上移动。
  • Prefabs:包含炸弹和爆炸预制件
  • Scenes:保持游戏场景
  • Scripts:包含启动脚本, 一定要打开它们并仔细阅读它们,因为它们被大量注释以使它们更容易理解
  • Sound Effects:保持炸弹和爆炸的声音效果
  • Textures:包含两个玩家的纹理

Dropping A Bomb

如果它尚未打开,请打开游戏场景并运行它。

两个玩家都可以使用WASD键和方向键在地图上走动。

通常情况下,当玩家1(红色的)按下Space时,他应该将炸弹放在他的脚下,玩家2应该可以按Enter / Return来做同样的事情。

但是,这还不行。 您需要首先实现放置炸弹的代码,因此请在您喜欢的代码编辑器中打开Player.cs脚本。

此脚本处理所有玩家移动和动画逻辑。 它还包括一个名为DropBomb的方法,它只检查是否附加了bombPrefab GameObject

private void DropBomb() 
{
  if (bombPrefab) 
  { //Check if bomb prefab is assigned first

  }
} 

要在player下方制作炸弹,请在if语句中添加以下行:

Instantiate(bombPrefab, myTransform.position, bombPrefab.transform.rotation);  

这将使炸弹在玩家的脚上产生。 将更改保存到脚本中,然后运行场景以尝试它:

它工作得很棒!

炸弹掉落的方式有一个小问题,你可以把它放在任何你想要的地方,当你需要计算爆炸产生的位置时,这会产生一些问题。

在本教程介绍如何进行爆炸时,您将了解为什么这一点非常重要。

1. Snapping

接下来的任务是确保炸弹在掉落到位,这样它们就能很好地与地板上的栅格对齐。 此网格(tile)上的每个图块都是1×1,因此进行此更改非常容易。

Player.cs中,编辑你刚刚添加到DropBomb()Instantiate(),如下所示:

Instantiate(bombPrefab, new Vector3(Mathf.RoundToInt(myTransform.position.x), 
  bombPrefab.transform.position.y, Mathf.RoundToInt(myTransform.position.z)),
  bombPrefab.transform.rotation);  

Mathf.RoundToInt调用玩家位置的xz值,将任何浮点数舍入为int值,然后将炸弹捕捉到tile位置:

保存您的更改,播放场景并在丢弃一些炸弹时四处奔跑。 炸弹现在将出现在响应位置:

虽然在地图上投下炸弹非常有趣,但你知道它真的是关于爆炸! 是时候为这件事添加一些火力了。


Creating Explosions

首先,您需要一个新脚本:

  • 在“项目”视图中选择Scripts文件夹。
  • Create按钮。
  • 选择C# Script
  • 将新创建的脚本命名为Bomb

现在将Bomb脚本附加到Bomb预制件:

  • Prefabs文件夹中,选择Bomb GameObject
  • Inspector窗口中,单击Add Component按钮。
  • 在搜索框中键入bomb
  • 选择刚刚制作的Bomb脚本。

最后,在代码编辑器中打开Bomb脚本。 在Start()内部,添加以下代码行:

Invoke("Explode", 3f);

Invoke()接受2个参数,首先是要调用的方法的名称,其次是调用之前的延迟。 在这种情况下,你想让炸弹在三秒内爆炸,所以你调用Explode() - 接下来你会添加它。

Update()下添加以下内容:

void Explode() 
{

}  

在生成任何Explosion GameObjects之前,您需要一个GameObject类型的公共变量,以便您可以在编辑器中指定Explosion prefab。 在Start()上面添加以下内容:

public GameObject explosionPrefab;

保存文件并返回编辑器。 在Prefabs文件夹中选择Bomb预制件,然后将Explosion预制件拖到Explosion Prefab插槽中:

完成后,返回代码编辑器。 你终于可以编写爆炸的代码!

Explode()内,添加以下行:

Instantiate(explosionPrefab, transform.position, Quaternion.identity); //1

GetComponent<MeshRenderer>().enabled = false; //2
transform.Find("Collider").gameObject.SetActive(false); //3
Destroy(gameObject, .3f); //4

这段代码执行以下操作:

  • 1) 在炸弹的位置发生爆炸。
  • 2) 禁用网格渲染器,使炸弹不可见。
  • 3) 禁用对撞机,允许玩家穿过并进入爆炸。
  • 4) 0.3秒后摧毁炸弹,这可确保在GameObject被销毁之前所有爆炸都会产生。

保存您的Bomb脚本并返回编辑器,运行下游戏, 它们开始爆炸!

Cool guys don’t look at explosions!

1. Add a LayerMask

幸运的是,游戏中的墙壁是防弹的。 炸弹不是防弹的,玩家绝对不是防弹的。 您需要一种方法来判断对象是否是墙。 一种方法是使用LayerMask

LayerMask选择性地过滤掉某些层,并且通常与光线投射一起使用。 在这种情况下,您只需要过滤掉块,这样光线就不会碰到其他任何东西。

Unity编辑器中,单击右上角的Layers按钮,然后选择Edit Layers…

如有必要,请单击Layers一词前面的展开三角形,以展开图层列表(如果不可见)。

单击User Layer 8旁边的text field,然后键入Blocks。 这定义了您可以使用的新图层。

在层次结构视图中,选择Map容器对象内的Blocks GameObject

将图层更改为新创建的Blocks图层:

Change Layer对话框出现时,单击Yes, change children按钮,以应用于分散在地图上的所有黄色块。

最后添加一个对LayerMask的公共引用,这样Bomb脚本就可以通过在explosionPrefab的引用下方添加以下行来访问该图层。

public LayerMask levelMask;

不要忘记保存您的代码。

2. Bigger! The Explosions Must be Bigger!

下一步是增加爆炸时候的爆炸感。 要做到这一点,你需要创建一个协同程序(coroutine)

注意:coroutine本质上是一个允许您暂停执行并将控制权返回给Unity的函数。 稍后,该函数的执行将从最后一次停止的位置恢复。

人们经常将coroutine与多线程混淆。 它们不一样:Coroutines在同一个线程中运行,并且它们在中间点恢复。

要了解有关协同程序以及如何定义它们的更多信息,请查看 Unity documentation

返回代码编辑器并编辑Bomb脚本。 在Explode()下,添加一个名为CreateExplosions的新IEnumerator

private IEnumerator CreateExplosions(Vector3 direction) 
{
  return null; // placeholder for now
}  

3. Create the Coroutines

Instantiate调用和在Explode()中禁用MeshRenderer之间添加以下四行代码:

StartCoroutine(CreateExplosions(Vector3.forward));
StartCoroutine(CreateExplosions(Vector3.right));
StartCoroutine(CreateExplosions(Vector3.back));
StartCoroutine(CreateExplosions(Vector3.left));  

StartCoroutine调用将为每个方向启动CreateExplosions IEnumerator一次。

现在是有趣的部分。 在CreateExplosions()内部,替换使用这段代码替换掉return null; // placeholder for now

//1
for (int i = 1; i < 3; i++) 
  { 
  //2
  RaycastHit hit; 
  //3
  Physics.Raycast(transform.position + new Vector3(0,.5f,0), direction, out hit, 
    i, levelMask); 

  //4
  if (!hit.collider) 
  { 
    Instantiate(explosionPrefab, transform.position + (i * direction),
    //5 
      explosionPrefab.transform.rotation); 
    //6
  } 
  else 
  { //7
    break; 
  }

  //8
  yield return new WaitForSeconds(.05f); 
}

这看起来像一个非常复杂的代码片段,但它实际上相当简单。这是一个逐节解释:

  • 1) 迭代你希望爆炸覆盖的每个距离单位的for循环。在这种情况下,爆炸将达到两米。
  • 2) RaycastHit对象包含有关Raycast命中或未命中位置的所有信息。
  • 3) 这条重要的代码行从炸弹中心向你通过StartCoroutine调用的方向发出一个光线投射。然后它将结果输出到RaycastHit对象。 i参数决定了光线应该行进的距离。最后,它使用名为levelMaskLayerMask来确保光线仅检查关卡中的块并忽略播放器和其他对撞。
  • 4) 如果光线投射没有击中任何东西,那么它就是一个free tile
  • 5) 在raycast检查的位置产生爆炸。
  • 6) raycast击中一个block
  • 7) 一旦光线投射击中一个块,它就会跳出for循环。这可以确保爆炸不会跳过墙壁。
  • 8) 在执行for循环的下一次迭代之前等待0.05秒。这使得它看起来像向外扩展,使爆炸更具说服力。

以下是它的实际效果:

红线是raycast。 它会检查炸弹周围的tiles是否有空闲空间,如果找到,则会产生爆炸。 当它碰到一个块时,它不会产生任何东西,它会停止向那个方向检查。

现在你可以看到炸弹需要卡在瓷砖中心的原因了。 如果炸弹可以到达任何地方,那么在某些边缘情况下,raycast将击中一个block而不会产生任何爆炸,因为它没有与水平线正确对齐:

最后,在项目视图的Prefabs文件夹中选择Bomb预制件,并将Level Mask更改为Blocks

再次运行场景并放下一些炸弹。 观察你的爆炸很好地散布在block周围:

恭喜,您刚刚完成本教程中最难的部分!

接下来就是要处理爆炸后的反应!

后记

本篇主要讲述了如何使用Unity制作像Bomberman一样的游戏,感兴趣的给个赞或者关注~~~

推荐阅读更多精彩内容