开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

蛮牛译馆

关注:497

当前位置:游戏蛮牛 技术专区 蛮牛译馆

查看: 3819|回复: 28

[外文翻译] 如何在unity中制作塔防游戏(Part II-1)

[复制链接]  [移动端链接]
排名
980
昨日变化
11

25

主题

116

帖子

2215

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
8677
好友
7
蛮牛币
319
威望
0
注册时间
2013-11-22
在线时间
626 小时
最后登录
2017-3-1

蛮牛译员

发表于 2016-3-12 22:00:44 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 caedmom 于 2016-3-19 17:25 编辑

目录:
如何在unity中制作塔防游戏(Part II-1)


01.png

欢迎来到如何在unity中制作塔防游戏的第二部分。现在正在unity中创建一个塔防游戏,而且在第一部分可以放置并升级怪兽了。还有一个敌人来袭击曲奇。
然而,敌人不知道该面向哪个方向!还有,这是进行攻击的一个可怜的理由。在这部分,将添加一波波敌人并武装怪兽以便他们可以保护珍贵的曲奇。
Getting Started
开始吧
在unity中,打开第一篇教程完成的项目,或者如果你是刚刚加入的,下载起始项目(回复可见)并打开TowerDefense-Part2-Starter。

旋转敌人
在上一篇教程的最后,敌人追踪了路径,但是不知道该面向哪边。
在MonoDevelop中打开MoveEnemy.cs ,添加下边的方法来修复这个问题

[C#] 纯文本查看 复制代码
privatevoid RotateIntoMoveDirection(){
//1
  Vector3 newStartPosition = waypoints [currentWaypoint].transform.position;
  Vector3 newEndPosition = waypoints [currentWaypoint +1].transform.position;
  Vector3 newDirection =(newEndPosition - newStartPosition);
//2
float x = newDirection.x;
float y = newDirection.y;
float rotationAngle = Mathf.Atan2(y, x)*180/ Mathf.PI;
//3
  GameObject sprite =(GameObject)
      gameObject.transform.FindChild("Sprite").gameObject;
  sprite.transform.rotation=
      Quaternion.AngleAxis(rotationAngle, Vector3.forward);
}


RotateIntoMoveDirection 旋转了敌人以便它可以一直看向前方,像这样:
1.通过从下一个路径点减掉当前路径点的位置来计算虫子当前的移动方向。
2.用Mathf.Atan2来决定newDirection 点所朝方向的角度,在角度内,假设零点朝向右边。用结果乘以180 / Mathf.PI 将角度转换为度。
3.最后,检索命名为Sprite 的子集并沿Z轴方向旋转rotationAngle 。注意旋转的是子对象而不是父类,这样生命条——一会儿将要添加——保持水平。



02.png

Update()中,用下边的RotateIntoMoveDirection声明替换注释 // TODO:Rotate into move direction

[C#] 纯文本查看 复制代码
RotateIntoMoveDirection();
保存文件并切换到unity。运行场景;现在怪兽知道他们的走向了。

03.gif

现在虫子看向它移动的方向

只有一个敌人?太让人印象深刻了。让成群的敌人出现吧。就想每一个塔防游戏一样,成群的敌人会一波一波的来!

通知玩家
在设置成群的运动之前,需要让玩家知道即将到来的袭击。还有,为什么不在屏幕顶部显示当前这波敌人的数量?
几个GameObjects都需要这波敌人的信息,所以要将它添加到GameManager的GameManagerBehavior 组件。
在MonoDevelop中打开GameManagerBehavior.cs 并添加这两个变量:

[C#] 纯文本查看 复制代码
public Text waveLabel;
public GameObject[] nextWaveLabels;


waveLabel 存储了从屏幕右上角读取的一波敌人数量的引用。nextWaveLabels 存储了两个GameObjects,当两个游戏对象结合到一起时,会创建一个动画来显示新一波进攻的开始,像下图所显示:

04.gif

保存文件并切换到unity。在Hierarchy中选择GameManager 。点击Wave Label右边的小圆圈,在Select Text 对话框中,选择 Scene 标签中的WaveLabel 。
现在将Next Wave Labels 的Size 设置为2。然后和设置Wave Label的方法一样给 Element 0 分配NextWaveBottomLabel 并且Element 1 分配NextWaveTopLabel 。

05.png

这就是Game Manager Behavior的样子

如果玩家在游戏中输掉了,将不会再看到下一波敌人的消息。为了控制这个,在MonoDevelop切换到GameManagerBehavior.cs 并添加另一个变量:

[C#] 纯文本查看 复制代码
publicbool gameOver =false;


在gameOver 存储玩家是否输掉了游戏。
再次,会用这个属性来保持游戏元素与当前这波敌人同步。在GameManagerBehavior中添加以下代码:

[C#] 纯文本查看 复制代码
privateint wave;
publicint Wave {
  get {return wave;}
  set {
    wave = value;
if(!gameOver){
for(int i =0; i < nextWaveLabels.Length; i++){
        nextWaveLabels.GetComponent<Animator>().SetTrigger("nextWave");
}
}
    waveLabel.text="WAVE: "+(wave +1);
}
}



创建私有变量,属性和getter方法应该已经习惯了,不过setter方法有些棘手。
用新的value来更新wave
然后检查游戏还没有结束。如果是这样,就要迭代nextWaveLabels 里所有的标签——这些有Animator 组件的标签。为了触发Animator 的动画需要设置一个nextWave触发器。
最后,将waveLabeltext 设置为wave + 1。为什么是+1?——正常人不会从零开始计数。奇怪哈,我也知道:]
Start()中,设置成这个属性值:

[C#] 纯文本查看 复制代码
Wave =0;



Wave0开始计数。
保存文件,然后运行unity场景。Wave正是从1开始读取。



06.png

对于玩家来说所有都要从wave等于1开始

Waves: Spawn, Spawn, Spawn一波波敌人:一大批,一大批,一大批
这点显而易见,不过需要能够创建更多的敌人来成群结队释放——现在还不能做这个。比外,当前这波敌人没有被彻底消灭时不可以产生下一波敌人——至少现在是这样。
因此,游戏必须能够识别出场景中是否还有敌人, Tags 是一个分辨游戏对象的好方法。

创建敌人标签
Select the Enemy prefab inthe Project Browser. At the top of the Inspector, click on the Tag dropdownand selectAdd Tag.
在工程浏览视口选择Enemy 预制件。在Inspector顶部,点击Tag 下拉菜单并选择Add Tag

07.png

创建一个名为EnemyTag

08.png


选择Enemy 预制件,在Inspector中设置它的TagEnemy

定义敌人的波数

现在需要定义一个敌人的波数。在MonoDevelop中打开SpawnEnemy.cs ,在SpawnEnemy之前添加以下类实现:

[C#] 纯文本查看 复制代码
[System.Serializable]
publicclass Wave {
public GameObject enemyPrefab;
publicfloat spawnInterval =2;
publicint maxEnemies =20;
}



Wave 控制一个enemyPrefab,列举这一波敌人的基础,一个spawnInterval,几秒钟内每一波敌人之间的时间间隔,还有 maxEnemies,即这一波敌人的数量。这个类是Serializable,这就意味着可以在监视面板改变这些值。
SpawnEnemy 类中添加以下变量:

[C#] 纯文本查看 复制代码
public Wave[] waves;
publicint timeBetweenWaves =5;
private GameManagerBehavior gameManager;
privatefloat lastSpawnTime;
privateint enemiesSpawned =0;



这个为大量产生设置了一些类似于如何让敌人沿着路径点移动的变量。
可以在waves中定义游戏中一波波不同的敌人并追踪生成敌人的数量,当在enemiesSpawnedlastSpawnTime中大量生成时,请分开做。玩家在把他们全部杀掉后需要休息一下,因此将 timeBetweenWaves 设置为5秒。
用下边代码替换Start() 中的内容。

[C#] 纯文本查看 复制代码
lastSpawnTime = Time.time;
gameManager =
    GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();



lastSpawnTime 设置为当前时间,当场景加载完就会开始执行脚本。然后用同样的方法检索GameManagerBehavior
将这个添加到Update()

[C#] 纯文本查看 复制代码
// 1
int currentWave = gameManager.Wave;
if(currentWave < waves.Length){
// 2
float timeInterval = Time.time- lastSpawnTime;
float spawnInterval = waves[currentWave].spawnInterval;
if(((enemiesSpawned ==0&& timeInterval > timeBetweenWaves)||
       timeInterval > spawnInterval)&&
      enemiesSpawned < waves[currentWave].maxEnemies){
// 3  
    lastSpawnTime = Time.time;
    GameObject newEnemy =(GameObject)
        Instantiate(waves[currentWave].enemyPrefab);
    newEnemy.GetComponent<MoveEnemy>().waypoints= waypoints;
    enemiesSpawned++;
}
// 4 
if(enemiesSpawned == waves[currentWave].maxEnemies&&
      GameObject.FindGameObjectWithTag("Enemy")==null){
    gameManager.Wave++;
    gameManager.Gold= Mathf.RoundToInt(gameManager.Gold* 1.1f);
    enemiesSpawned =0;
    lastSpawnTime = Time.time;
}
// 5 
}else{
  gameManager.gameOver=true;
  GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
  gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}


一步一步看一下这个代码:
1.获取当前这波敌人的索引,判断是不是最后一个。
2.如果是,计算最后一个敌人生成需要的时间并且计算是否到了生成敌人的时间。这里需要考虑两点。如果它是这波敌人中的第一个,检查timeInterval 是否大于timeBetweenWaves。否则,检查timeInterval 是否大于这一波敌人的spawnInterval。无论哪种情况,确认没有在这一波中生成所有的敌人。
3.如果有必要,通过实例化一个enemyPrefab来生成敌人。这样也增加了enemiesSpawned计数。
4.在屏幕中检查敌人的数量。如果没有并且它是这波敌人中的最后一个,那么就生成下一波敌人。在这波敌人的最后要给玩家所有剩余金币的百分之十。
5.打败最后一波敌人运行游戏胜利动画。


设置生成间隔

保存文件并切换到unity。在Hierarchy中选择Road 。在Inspector中,设置WavesSize4
现在,为Enemy 所有四个元素设置Enemy Prefab 。如下设置Spawn IntervalMax Enemies 区域:
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
最终设置应该是下边截图的样子。

09.png

当然,可以自己尝试这些设置来增加或减少杀害。
运行游戏。哈哈!虫子们向着曲奇进军啦。



10.gif


可选:添加不同类型的敌人
没有哪一个塔防游戏里只有一种类型的敌人。幸运的是,Prefabs 文件夹包含了另一个选择,Enemy2.
Inspector 中选择Prefabs\Enemy2 并将MoveEnemy 脚本添加给它。
将它的Speed 设置为3TagEnemy。现在可以用这个快速的虫子来让玩家保持警觉了!


更新玩家生命值——温柔地杀掉我吧
即使虫子们成群结队的向着曲奇奔来,玩家确没有受到伤害。不过不再会是这样了。当敌人蚕食了曲奇玩家应该受到影响。

11.png
在MonoDevelop中打开GameManagerBehavior.cs 。添加下边两个变量:

[C#] 纯文本查看 复制代码
public Text healthLabel;
public GameObject[] healthIndicator;



healthLabel 来访问玩家的生命值读取数据,用healthIndicator 来访问五个绿色的吃曲奇的小怪兽——它们只是用一个比标准生命条更有趣的方式代表玩家的生命值。

管理生命值

接下来,在GameManagerBehavior中添加属性来维护玩家的生命值。

[C#] 纯文本查看 复制代码
privateint health;
publicint Health {
  get {return health;}
  set {
// 1
if(value < health){
      Camera.main.GetComponent<CameraShake>().Shake();
}
// 2
    health = value;
    healthLabel.text="HEALTH: "+ health;
// 3
if(health <=0&&!gameOver){
      gameOver =true;
      GameObject gameOverText = GameObject.FindGameObjectWithTag("GameOver");
      gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}
// 4 
for(int i =0; i < healthIndicator.Length; i++){
if(i < Health){
        healthIndicator.SetActive(true);
}else{
        healthIndicator.SetActive(false);
}
}
}
}



这个用来管理玩家的生命值。再一次,大部分的代码在setter方法中:
1.如果正在减少玩家的生命值,用CameraShake 组件来创建一个漂亮的抖动效果。这个脚本已经在项目中了,这里不再介绍。
2.更新私有变量和屏幕左上角的生命条。
3.如果生命值降到0并且游戏还没有结束,将gameOver 设置为true 并触发GameOver 动画。
4.从曲奇上边移走一个怪兽。如果仅仅是禁用了它们,这样写起来会更简单些,不过当生命值增加的时候还可以重用它们。
Start()中初始化Health

[C#] 纯文本查看 复制代码
Health =5;



当屏幕开始播放时将Health 设置为5.
有了这个属性,现在无论什么时候虫子到达了曲奇都可以更新玩家的生命值。保存这个文件,还是在MonoDevelop中切换到MoveEnemy.cs

更新生命值

为了更新玩家的生命值,在Update() 中找到为// TODO: deduct health 的注释并用下边的代码替换它:

[C#] 纯文本查看 复制代码
GameManagerBehavior gameManager =
    GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
gameManager.Health-=1;



这个获取到GameManagerBehavior 并且从生命值减1。
保存文件并切换到unity。
Hierarchy 中选择GameManager 并将其 Health Label 设置为HealthLabel
Hierarchy 中扩大Cookie ,将它的五个小怪兽拖拽到GameManagerHealth Indicator 数组中——健康指示是这五个绿色小怪兽在开心地吃他们的曲奇呢。
播放场景并等待虫子到达曲奇。直到失败什么都不要做。

12.gif

怪兽之战:怪兽的复仇

怪兽在位置上吗?检查一下。敌人在前进吗?检查一下——他们看起来真卑鄙!现在是时候攻击它们啦!
这步需要一下这些:
一个生命条,由此玩家可以知道哪些敌人强哪些敌人弱。
在怪兽的范围内检测敌人。
决策点——射击哪个敌人。
大量的子弹。

敌人的生命条
用两个图片来实现生命条,一个用作黑色背景,另一个浅绿色的条来伸缩匹配敌人的生命值。
Prefabs\EnemyProject Browser拖入到场景中。
然后将Images\Objects\HealthBarBackground 拖拽到HierarchyEnemy 上作为子集。
Inspector中,将HealthBarBackgroundPosition 设置为(0, 1, -4)。接下来在Project Browser 中选择Images\Objects\HealthBar 并确保它的Pivot 设置为了Left。然后,在 Hierarchy 中将它作为Enemy 的子集添加并将它的Position 设置为(-0.63, 1, -5)。将它的X Scale 设置为125
HealthBar 游戏对象添加一个命名为HealthBarC# 脚本。之后,会编辑它来调整生命条的长度。
随着在Hierarchy选择了Enemy ,确保它的位置是(20, 0, 0)。点击Inspector 顶部的Apply 来将刚才的改变保存为预制件的一部分。最后,从Hierarchy.中删除Enemy

13.png


现在重复这些步骤来为Prefabs\Enemy2添加生命条。

调整生命条的长度

在MonoDevelop中打开HealthBar.cs ,添加以下变量:

[C#] 纯文本查看 复制代码
publicfloat maxHealth =100;
publicfloat currentHealth =100;
privatefloat originalScale;



maxHealth 存储敌人的最大生命点,currentHealth 追踪生命值的剩余量。最后,originalScale 记录记录生命条的原始长度。
Start()中存储对象的originalScale

[C#] 纯文本查看 复制代码
originalScale = gameObject.transform.localScale.x;



保存localScalex值。
通过将下边代码添加到Update()中来设置生命条的缩放:

[C#] 纯文本查看 复制代码
Vector3 tmpScale = gameObject.transform.localScale;
tmpScale.x= currentHealth / maxHealth * originalScale;
gameObject.transform.localScale= tmpScale;



localScale 复制出一个临时变量,因为不可能只适应它的x 值。然后,基于虫子当前的生命值计算一个新的x缩放值,并将临时变量设置回localScale
保存文件并在unity中运行游戏。就会在敌人的上方看到生命条啦。

14.png



游客,如果您要查看本帖隐藏内容请回复

原文作者:Barbara Reichart

扫描下方二维码关注游戏蛮牛官方微信~每日都有精选干货与你分享呦~
蛮牛微信.jpg
本文由蛮牛译馆倾情奉献,翻译:xiaojiejie,审校:caedmom,如有问题请及时联系,除 合作社区 及 合作媒体 外,禁止转载。



unity 两点 角度;unity 两点之间的角度

回复

使用道具 举报

3偶尔光临
298/300
排名
5371
昨日变化
8

1

主题

45

帖子

298

积分

Rank: 3Rank: 3Rank: 3

UID
77454
好友
0
蛮牛币
424
威望
0
注册时间
2015-3-6
在线时间
92 小时
最后登录
2016-9-24
QQ
发表于 2016-3-13 04:49:53 | 显示全部楼层
0.0                                 0.0
[发帖际遇]: fanjianan 在论坛发帖时没有注意,被小偷偷去了 2 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

排名
43753
昨日变化
101

0

主题

20

帖子

32

积分

Rank: 1

UID
134979
好友
0
蛮牛币
27
威望
0
注册时间
2016-1-18
在线时间
10 小时
最后登录
2017-3-1
发表于 2016-3-13 11:41:02 | 显示全部楼层
哇.又更新了....太棒了

回复 支持 反对

使用道具 举报

排名
43753
昨日变化
101

0

主题

20

帖子

32

积分

Rank: 1

UID
134979
好友
0
蛮牛币
27
威望
0
注册时间
2016-1-18
在线时间
10 小时
最后登录
2017-3-1
发表于 2016-3-13 12:46:59 | 显示全部楼层
LZ....有些地方在数组 for 循环的时候,你忘记加 [i]   下标取值了......编译会报错.....
[发帖际遇]: 致命之喵 发帖时在路边捡到 2 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

2初来乍到
102/150
排名
18641
昨日变化
19

1

主题

33

帖子

102

积分

Rank: 2Rank: 2

UID
138818
好友
0
蛮牛币
98
威望
0
注册时间
2016-3-8
在线时间
54 小时
最后登录
2016-12-10
发表于 2016-3-13 23:36:22 | 显示全部楼层
还会继续更新么?

回复

使用道具 举报

排名
11627
昨日变化
14

0

主题

14

帖子

75

积分

Rank: 2Rank: 2

UID
136636
好友
0
蛮牛币
75
威望
0
注册时间
2016-2-15
在线时间
19 小时
最后登录
2016-6-4
发表于 2016-3-14 14:05:26 | 显示全部楼层
大神啊。。。公众号上就看到了!感谢

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1274/1500
排名
1067
昨日变化
4

1

主题

175

帖子

1274

积分

Rank: 6Rank: 6Rank: 6

UID
10274
好友
1
蛮牛币
1560
威望
0
注册时间
2013-12-14
在线时间
374 小时
最后登录
2016-6-2
发表于 2016-3-14 16:02:03 | 显示全部楼层
不错,看看

回复

使用道具 举报

6蛮牛粉丝
1403/1500
排名
838
昨日变化
4

6

主题

214

帖子

1403

积分

Rank: 6Rank: 6Rank: 6

UID
59634
好友
23
蛮牛币
3064
威望
0
注册时间
2014-12-5
在线时间
341 小时
最后登录
2017-3-1
QQ
发表于 2016-3-15 08:47:29 | 显示全部楼层
感谢译馆人员不辞辛劳的翻译,收藏啦

回复 支持 反对

使用道具 举报

7日久生情
2150/5000
排名
1051
昨日变化
3

72

主题

446

帖子

2150

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
71862
好友
23
蛮牛币
4206
威望
0
注册时间
2015-1-29
在线时间
685 小时
最后登录
2017-3-1

专栏作家蛮牛译员

QQ
发表于 2016-3-15 11:55:14 | 显示全部楼层
caiguangduo 发表于 2016-3-15 08:47
感谢译馆人员不辞辛劳的翻译,收藏啦

你也要抓紧时间贡献自己的成果哈

回复 支持 反对

使用道具 举报

0

主题

4

帖子

24

积分

Rank: 1

UID
140610
好友
0
蛮牛币
44
威望
0
注册时间
2016-3-15
在线时间
21 小时
最后登录
2016-5-10
发表于 2016-3-15 14:20:02 | 显示全部楼层
推個~推個~推個~推個~推個~推個~推個~推個~推個~推個~

回复 支持 反对

使用道具 举报

2初来乍到
134/150
排名
13151
昨日变化
22

0

主题

15

帖子

134

积分

Rank: 2Rank: 2

UID
101366
好友
0
蛮牛币
44
威望
0
注册时间
2015-5-18
在线时间
87 小时
最后登录
2016-6-6
发表于 2016-3-15 17:25:14 | 显示全部楼层
学习学习

回复

使用道具 举报

排名
18641
昨日变化
19

0

主题

22

帖子

59

积分

Rank: 2Rank: 2

UID
21719
好友
0
蛮牛币
127
威望
0
注册时间
2014-4-16
在线时间
23 小时
最后登录
2016-11-23
发表于 2016-3-17 21:47:52 | 显示全部楼层
good,thank you

回复

使用道具 举报

0

主题

2

帖子

5

积分

Rank: 1

UID
141792
好友
1
蛮牛币
16
威望
0
注册时间
2016-3-18
在线时间
3 小时
最后登录
2016-7-22
发表于 2016-3-18 00:32:22 | 显示全部楼层
有没有资源下载啊

回复 支持 反对

使用道具 举报

7日久生情
2146/5000
排名
273
昨日变化
2

1

主题

292

帖子

2146

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
7133
好友
0
蛮牛币
1397
威望
0
注册时间
2013-11-4
在线时间
551 小时
最后登录
2017-2-13
发表于 2016-3-18 13:13:10 | 显示全部楼层
如何在unity中制作塔防游戏(Part II-1)
[发帖际遇]: 一个袋子砸在了 styu 头上,styu 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1498/1500
排名
1038
昨日变化
2

0

主题

138

帖子

1498

积分

Rank: 6Rank: 6Rank: 6

UID
65630
好友
0
蛮牛币
2245
威望
0
注册时间
2015-1-4
在线时间
621 小时
最后登录
2016-12-15
发表于 2016-3-24 11:40:18 | 显示全部楼层
塔防游戏的有趣想法

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表