【Unity小游戏】游戏开发案例,轻松打造一款塔防游戏!(下)

您所在的位置:网站首页 unity制作游戏教程 【Unity小游戏】游戏开发案例,轻松打造一款塔防游戏!(下)

【Unity小游戏】游戏开发案例,轻松打造一款塔防游戏!(下)

2023-05-11 14:02| 来源: 网络整理| 查看: 265

欢迎来到如何在 Unity 中创建塔防游戏的第二部分。你正在Unity中制作一个塔防游戏,在第一部分结束时,你可以放置和升级怪物。你还有一个敌人攻击饼干。

然而,敌人不知道该面对哪条路!此外,这是攻击的一个严重的失误。在这一部分中,你将添加敌人的生成波次,武装你的怪物,这样他们就可以保护你珍贵的饼干。

开始

在 Unity 中,打开本教程系列第一部分中已完成的项目,或者如果您现在刚刚加入,请下载入门项目并打开 TowerDefense-Part2-Starter。

 使敌人转起来

在上一个教程结束时,敌人沿着道路前进,但似乎不知道该面对哪条路。

在 IDE 中打开 MoveEnemy.cs,然后添加以下方法来解决此问题。

private void RotateIntoMoveDirection() { Vector3 newStartPosition = waypoints [currentWaypoint].transform.position; Vector3 newEndPosition = waypoints [currentWaypoint + 1].transform.position; Vector3 newDirection = (newEndPosition - newStartPosition); float x = newDirection.x; float y = newDirection.y; float rotationAngle = Mathf.Atan2 (y, x) * 180 / Mathf.PI; GameObject sprite = gameObject.transform.Find("Sprite").gameObject; sprite.transform.rotation = Quaternion.AngleAxis(rotationAngle, Vector3.forward); } 复制代码

RotateIntoMoveDirection rotates the enemy so that it always looks forward, like so: RotateIntoMoveDirection 旋转敌人,使其始终向前看,如下所示:

它通过从下一个航点的位置中减去当前航点的位置来计算 虫子 的当前移动方向。 它使用 `Mathf.Atan2` 来确定 `newDirection` 指向的角度(以弧度为单位),假设零点向右。将结果乘以 `180 / Mathf.PI` 会将角度转换为度数。 最后,它检索名为 Sprite 的子项,并沿 z 轴将其旋转 `rotationAngle` 度。请注意,您旋转的是子项而不是父项,因此生命条(您很快就会添加它)保持水平状态。 复制代码

在 Update() 中,将注释 // TODO: Rotate into move direction 替换为对 RotateIntoMoveDirection 的以下调用:

RotateIntoMoveDirection(); 复制代码

保存文件并切换到 Unity。运行场景;现在你的怪物知道他要去哪里了。

BugFollowsRoad.gif

现在错误表现在哪里?

一个敌人?几乎不令人印象深刻。让成群结队的人来。就像每个塔防游戏一样,成群结队的人会一波又一波地来!

通知玩家

在你让部落开始行动之前,你需要让玩家知道即将到来的猛攻。另外,为什么不在屏幕顶部显示当前波次的数字?

多个游戏对象需要生成波次信息,因此您需要将其添加到 GameManager 上的 GameManagerBehavior 组件中。

在 IDE 中.cs打开 GameManagerBehavior,然后添加以下两个变量:

public Text waveLabel; public GameObject[] nextWaveLabels; 复制代码

waveLabel 在屏幕右上角存储对波读数的引用。 nextWaveLabels 存储两个游戏对象,当它们组合在一起时,将创建一个动画,您将在新波开始时显示,如下所示:

nextWaveAnimation

保存文件并切换到 Unity。在层次结构中选择游戏管理器。单击“生成波次标签”右侧的小圆圈,然后在“选择文本”对话框中,选择“场景”选项卡中的“生成波次标签”。

现在将下一波标签的大小设置为 2。然后将元素 0 分配给 NextWaveBottomLabel,将元素 1 分配给 NextWaveTopLabel,方法与设置 Wave Label 的方式相同。

这就是您的游戏管理器行为应该的样子

如果玩家输掉了游戏,他应该不会看到下一波消息。要解决此问题,请在 IDE 中切换回 GameManagerBehavior.cs并添加另一个变量:

public bool gameOver = false; 复制代码

在 gameOver 中,您将存储玩家是否输掉了游戏。

同样,您将使用属性来保持游戏元素与当前波同步。将以下代码添加到 GameManagerBehavior :

private int wave; public int Wave { get { return wave; } set { wave = value; if (!gameOver) { for (int i = 0; i < nextWaveLabels.Length; i++) { nextWaveLabels[i].GetComponent().SetTrigger("nextWave"); } } waveLabel.text = "WAVE: " + (wave + 1); } } 复制代码

创建私有变量、属性和 getter 现在应该是第二天性。但同样,setter有点棘手。

使用新的 value 更新 wave 。

然后你检查游戏是否没有结束。如果是这样,则遍历 nextWaveLabels 中的所有标签 — 这些标签具有 Animator 组件。要在动画器上触发动画,请设置触发器 nextWave。

最后,您将 waveLabel 的 text 设置为 wave + 1 的值。为什么是 +1 ?– 正常人不会从零开始计数。奇怪,我知道:]

在 Start() 中,设置此属性的值:

Wave = 0; 复制代码

您从 Wave 数字 0 开始计数。

保存文件,然后在 Unity 中运行场景。波读数从 1 正确开始。

Internally you start counting with 0, but for the player everything starts with wave 1.

对于玩家来说,一切都从第 1 波开始。

生成敌人波次

这听起来很明显,但你需要能够创造更多的敌人来释放成群结队的敌人——现在你不能这样做。此外,一旦当前生成波次被抹去,你就不应该产生下一波——至少目前是这样。

因此,游戏必须能够识别场景中是否有敌人,而标签是识别游戏对象的好方法。

设置敌人标签

在项目浏览器中选择敌人预制件。在检查器的顶部,单击“标记”下拉列表,然后选择“添加标记”。

Create Tag

创建一个命名为enemy_的标签。 create a new tag

选择敌人预制件。在检查器中,将其标签设置为敌人。

 定义敌人波次信息

现在你需要定义一波敌人。在 IDE 中打开 SpawnEnemy.cs,并在 SpawnEnemy 之前添加以下类实现:

[System.Serializable] public class Wave { public GameObject enemyPrefab; public float spawnInterval = 2; public int maxEnemies = 20; } 复制代码

Wave 包含一个 enemyPrefab ,这是实例化该波中所有敌人的基础, spawnInterval 是波中敌人之间的时间(以秒为单位)和 maxEnemies ,即在该波中生成的敌人数量。

此类是可序列化的,这意味着您可以在检查器中更改值。

将以下变量添加到 SpawnEnemy 类:

public Wave[] waves; public int timeBetweenWaves = 5; private GameManagerBehavior gameManager; private float lastSpawnTime; private int enemiesSpawned = 0; 复制代码

这将设置一些用于生成的变量,这些变量与您沿航点移动敌人的方式非常相似。 您将在 waves 中定义游戏的各种波次,并分别在 enemiesSpawned 和 lastSpawnTime 中跟踪生成的敌人数量和生成时间。

玩家在杀戮后需要休息,因此将 timeBetweenWaves 设置为5秒

将 Start() 的内容替换为以下代码。

lastSpawnTime = Time.time; gameManager = GameObject.Find("GameManager").GetComponent(); 复制代码

在这里,您将 lastSpawnTime 设置为当前时间,这将是脚本在场景加载后立即启动的时间。然后以熟悉的方式检索 GameManagerBehavior 。

将此添加到 Update() :

int currentWave = gameManager.Wave; if (currentWave < waves.Length) { float timeInterval = Time.time - lastSpawnTime; float spawnInterval = waves[currentWave].spawnInterval; if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) || timeInterval > spawnInterval) && enemiesSpawned < waves[currentWave].maxEnemies) { lastSpawnTime = Time.time; GameObject newEnemy = (GameObject) Instantiate(waves[currentWave].enemyPrefab); newEnemy.GetComponent().waypoints = waypoints; enemiesSpawned++; } if (enemiesSpawned == waves[currentWave].maxEnemies && GameObject.FindGameObjectWithTag("Enemy") == null) { gameManager.Wave++; gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f); enemiesSpawned = 0; lastSpawnTime = Time.time; } } else { gameManager.gameOver = true; GameObject gameOverText = GameObject.FindGameObjectWithTag ("GameWon"); gameOverText.GetComponent().SetBool("gameOver", true); } 复制代码

逐步完成此代码:

获取当前波次的索引,并检查它是否是最后一个波次。 如果是这样,请计算自上次敌人生成以来经过了多少时间,以及是否是时候生成敌人了。在这里,您考虑两种情况。如果是波中的第一个敌人,请检查 timeInterval 是否大于 timeBetweenWaves 。否则,请检查 timeInterval 是否大于此波次的 spawnInterval 。无论哪种情况,你都要确保你没有为这一波生成所有的敌人。 如有必要,通过实例化 enemyPrefab 的副本来生成敌人。您还可以增加 enemiesSpawned 计数。 你检查屏幕上的敌人数量。如果没有,它是波次中的最后一个敌人,你就会生成下一波。你还会给玩家在波次结束时剩余的所有金币的10%。 在击败最后一波运行后,游戏赢得了动画。  设置生成间隔

保存文件并切换到 Unity。在层次结构中选择道路。在检查器中,将波次的大小设置为 4。

现在,将所有四个元素的“敌人预制件”设置为“敌人”。设置生成间隔和最大敌人数字段,如下所示:

Element 0: Spawn Interval: 2.5, Max Enemies: 5 Element 1: Spawn Interval: 2, Max Enemies: 10 Element 2: Spawn Interval: 2, Max Enemies: 15 Element 3: Spawn Interval: 1, Max Enemies: 5

最终设置应如下面的屏幕截图所示。

Waves 当然,你可以使用这些设置来增加或减少攻击伤害。 运行游戏。啊哈!虫子正在向你的饼干进军!

bugs.gif

可选:添加不同类型的敌人

没有一个塔防游戏只有一种类型的敌人是完整的。幸运的是,预制件文件夹包含另一个选项,Enemy2。

在检查器中选择预制件\Enemy2,然后将MoveEnemy脚本添加到其中。将其速度设置为 3,将其标签设置为 敌人。您现在可以使用这个快速错误来让玩家保持警惕!

更新玩家生命值

即使成群结队的虫子冲向饼干,玩家也不会受到任何伤害。但仅此而已。当玩家让敌人入侵时,他应该受到打击。

在 IDE 中.cs打开“游戏管理器行为”,然后添加以下两个变量:

public Text healthLabel; public GameObject[] healthIndicator; 复制代码

您将使用 healthLabel 访问玩家的生命值读数,并使用 healthIndicator 访问五个绿色饼干嘎吱嘎吱的小怪物——它们只是以比标准健康标签更有趣的方式代表玩家健康。

管理生命值

接下来,添加一个属性以在 GameManagerBehavior 中维护玩家的生命值:

private int health; public int Health { get { return health; } set { if (value < health) { Camera.main.GetComponent().Shake(); } health = value; healthLabel.text = "HEALTH: " + health; if (health


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3