unity实战:狂暴机器人游戏教程(下篇)

Posted 肖尘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity实战:狂暴机器人游戏教程(下篇)相关的知识,希望对你有一定的参考价值。

文章目录


前言

不了解或者看不懂的可以去看
unity实战:狂暴机器人游戏教程(上篇)


提示:以下是本篇文章正文内容,下面案例可供参考

三、敌人

3.1创建机器人

步骤1 创建脚本

单击“Resources”文件夹,然后将RedRobot、YellowRobot和BlueRobot拖到玩家面前的某个位置(位于地面之上)
如下图所示。

同时选中RedRobot、YellowRobot和BlueRobot游戏对象,在检视视图中单击Add Component按钮,然后选择New Script命令。命名脚本为Robot。这将在Assets文件夹中创建一个新脚本。将Robot脚本从Assets文件夹移动到Scripts文件夹。在代码编辑器中打开Robot脚本。添加以下变量。

[SerializeField]private string robotType; 
public int health; 
public int range; 
public float fireRate; 
public Transform missileFireSpot; 
UnityEngine.AI.NavMeshAgent agent; 
private Transform player; 
private float timeLastFired; 
private bool isDead;

robotType表示机器人的类型:RedRobot、BlueRobot或YellowRobot。
health是机器人生命值,
range是它能射击的距离,
fireRate 是它能射击的速度。
agent是对NavMeshAgent组件的引用,
player是机器人跟踪的对象,
isDead表示机器人是否死亡。

保存脚本并切换回Unity。单击RedRobot游戏对象,然后在 robotType字段中输入 RedRobot。将Health设置为 14,Range值为 150,Fire Rate为2。单击Apply按钮,将这些更改应用到预置。如下图所示。

对YellowBot执行相同的操作:Robot Type设为YellowRobot,Health设为20,Range设为300,Fire Rate设为3。
单击Apply按钮。
对BlueRobot执行相同的操作:Robot Type设为BlueRobot,Health设为10,Range设为200,Fire Rate设为1。
单击Apply按钮。
Missile Fire Spot参数是机器人发射导弹的位置。

单击RedRobot游戏对象旁边的箭头以显示其子对象。拖动其子游戏对象 MissileFireSpot 到Missile Fire Spot属性栏。
对YellowBot和BlueRobot执行同样的操作。如下图所示。

步骤2 定义生命周期

现在在代码编辑器中打开Robot脚本,修改代码。

void Start() // 1
isDead = false;
agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
player = GameObject.FindGameObjectWithTag("Player").transform; // Update is called once per frame 
void Update() // 2
if (isDead)  return;
// 3    transform.LookAt(player); 
// 4    agent.SetDestination(player.position); 
// 5    if (Vector3.Distance(transform.position,player.position) < range && Time.time - timeLastFired > fireRate) 
// 6    timeLastFired = Time.time; fire(); 
private void fire()  
        Debug.Log("Fire");

下面是对应编号代码中操作的解释:
①默认情况下,所有的机器人都是活的。然后将代理和player值分别设置为 NavMesh 代理和player组件。
②检查机器人是否已死。
③让机器人面对玩家。
④告诉机器人使用 NavMesh 找到玩家。
⑤检查玩家是否在射击范围内,并且是否攻击冷却完毕。
⑥更新timeLastFired到当前时间,并调用Fire方法,它只是暂时将消息记录到控制台。
接下来需要为玩家游戏对象分配一个合适的标签,以便于让机器人找到它。
保存脚本,回到Unity。点击Player游戏物体,点击标签下拉菜单,并选择Player标签。
运行游戏,将看到机器人向玩家移动,并且“Fire”日志不断出现在控制台中,如下图所示。

现在机器人在向玩家静态地移动。如果他们脚下的轮子滚起来的话,看起来会好得多。而且,机器人在向玩家开火时也应该有射击动作。
步骤1 添加足部动画
在随便哪个机器人上单击一个 RobotRampage_BotBall_v1 的游戏对象(展开其子对象上的箭头找到它),
然后转到Window\\Animation以打开Animation窗口。
单击Create按钮: 在名称处输入Ball,保存到Animations文件夹下,然后单击保存按钮。
单击AddProperty按钮,单击Transform旁边的箭头,然后单击Rotation旁边的+号,如图下所示。

一对关键帧(灰色菱形)将出现在时间轴上的1秒的位置。

单击最后一个关键帧,并注意到游戏对象的Rotation字段已在检视视图的转换组件中变为红色。将Rotation X值设置为-360。这将导致球旋转360度。
同时选择其他两个机器人的RobotRampage_BotBall_v1子游戏对象。选中所有RobotRampage_BotBall_v1游戏后,将RobotRampage_BotBall_v1拖到检视视图中。如下图所示。

运行游戏,会看到机器人脚下的球在旋转

步骤3添加射击动画

全选三个RobotRampage_Bot游戏对象,并通过单击Controller字段旁边的圆圈选择Robot,如下图所示。

逐个选择每个RobotRampage_Bot,单击Prefab栏的Apply按钮,应用对预制体的修改,如下图所示。

现在打开Robot脚本。添加变量,然后修改Fire ()方法:

public Animator robot;
private void fire()  robot.Play("Fire");

保存脚本,回到Unity。选择YellowRobot并将子物体RobotRampage_Bot拖入Robot属性。应用对预制体的修改。
如下图所示。

在RedRobot和BlueRobot上执行同样的操作。确保在完成操作后应用对预制体的更改。
运行游戏,看到机器人开火了

3.2发射机器人导弹

步骤1 创建导弹运动逻辑

新建一个C#脚本,命名为“Missile”。
将RobotMissileBlue、RobotMissileRed和RobotMissileYellow的预制体从项目视图的Resources文件夹拖到层级视图上。
保持选中层级视图中的RobotMissileBlue、RobotMissileRed和RobotMissileYellow游戏对象,然后将Missile脚本拖到检视面板。
在代码编辑器中打开Missile脚本并添加以下变量:

public float speed = 30f; 
public int damage = 10;

speed是导弹飞行的快慢。
damage是导弹命中玩家时造成的伤害。

现在,在damage变量下面添加以下方法:

//1
void Start()  
StartCoroutine("deathTimer"); 
// 2
void Update() 
transform.Translate(Vector3.forward * speed * Time.deltaTime);
 
// 3
IEnumerator deathTimer() 
yield return new WaitForSeconds(10); Destroy(gameObject);

在计算机术语中,会经常听到“线程”这个词。这是一种让计算机同时做多种事情的方法。在Unity中,可以使用coroutines(协程)来模拟线程。

协同方法返回IEnumerator。这些决定了协同的持续时间。下面是代码对应的注释:
①当实例化一个导弹,将开始一个名为“deathTimer”的协同方法。
②每帧向正前方移动相应的距离。
③该方法立即返回一个 WaitForSeconds,设置为10。意为该方法将在yield语句等待十秒后恢复。如果导弹没有击中球员,它将会自毁。
保存脚本,回到Unity。依次单击RobotMissileBlue、RobotMissileRed和RobotMissileYellow游戏对象上的Prefab栏的Apply按钮,应用对预制体的更改。

步骤2 添加导弹发射方法

打开Robot脚本。在该文件的顶部,在类的“”下面添加以下内容:

[SerializeField] GameObject missileprefab;

missilePrefab 是导弹的预制体。修改Fire方法,代码如下。

private void fire() 
GameObject missile = Instantiate(missileprefab); missile.transform.position=missileFireSpot.transform.position; missile.transform.rotation=missileFireSpot.transform.rotation; robot.Play("Fire");

这将实例化一个新的 missilePrefab,并设置其位置和旋转到机器人的射击点。保存脚本回到Unity。

从层级视图中删除RobotMissileBlue、RobotMissileRed和RobotMissileYellow游戏对象。
单击RedRobot游戏对象,将RobotMissileRed预置体从Resources文件夹拖到Robot组件的Missile prefab栏中,然后单击Apply按钮。如图3-3-1所示。

在YellowRobot和BlueRobot游戏对象上执行同样的操作,确保最后单击了Apply按钮。
运行游戏,看到机器人发射导弹

3.3增加伤害

步骤1 添加玩家受击方法

导弹会伤害到玩家,玩家也会损坏机器人。新建一个新的C#脚本,命名它Player并添加以下变量:

public int health; 
public int armor; 
public GameUI gameUI;
private GunEquipper gunEquipper; 
private Ammo ammo;

health是玩家的剩余生命值。当生命值为零,游戏结束。
armor是一个玩家的装甲,减少50%的伤害。
一旦装甲变成0,玩家将受到100%伤害。
gameUI和gunEquipper是对脚本的引用。
ammo是提前建立的弹药类。将以下内容添加到Start方法:

void Start () 
ammo = GetComponent<Ammo>();
gunEquipper = GetComponent<GunEquipper>();

这只是初始化对Ammo和GunEquipper组件的引用。添加以下方法:

public void TakeDamage(int amount)  
int healthDamage = amount;
if (armor > 0) 
int effectiveArmor = armor * 2; effectiveArmor -= healthDamage;
if (effectiveArmor > 0)  
armor = effectiveArmor / 2; 
return;
armor = 0;
health -= healthDamage; 
Debug.Log("Health is " + health); 
if (health <= 0)  Debug.Log("GameOver");

TakeDamage ()根据玩家剩余的装甲量来计算伤害减免。
如果玩家没有盔甲,那么将会受到完整伤害。
如果生命值达到0,游戏将会结束;
现在,只需要将其记录到控制台。
保存脚本,回到Unity。
将Player脚本添加到Player游戏对象。
设置Health为100,Armor为 20,
并拖动GameUI游戏对象到GameUI字段。

步骤2 导弹检测碰撞

当导弹与玩家的碰撞器相撞,它将通过OnCollisionEnter()处理伤害玩家的计算。在代码编辑器中打开Missile脚本并添加以下方法:

void OnCollisionEnter(Collision collider) 
if(collider.gameObject.GetComponent<Player>()!=null&&collider.gameObject.tag == "Player") 
collider.gameObject.GetComponent<Player>().TakeDamage(damage);

Destroy(gameObject);

导弹通过检查与它碰撞的游戏对象Tag是否为Player来判断是否击中玩家。
它还要检查是否Player脚本处于激活状态,因为Player组件将在游戏结束后被禁用。
如果两个条件都满足,它将通过调用Player脚本上的TakeDamage方法来计算伤害。
导弹还会同时销毁自身。
保存脚本,回到Unity。

运行游戏。让炮弹击中自己,查看控制台播放的玩家受击信息

步骤3 添加机器人受击方法

当玩家的生命值到0时,记录游戏结束。稍后,将会实现更好的处理方法。
目前机器人仍然是无敌的。因为它们还没有添加受击方法。打开Robot脚本并添加以下方法:

// 1
public void TakeDamage(int amount)  
if (isDead) return;
health -= amount; 
if (health <= 0) 
isDead = true; 
robot.Play("Die"); 
StartCoroutine("DestroyRobot"); 
// 2
IEnumerator DestroyRobot() 
yield return new WaitForSeconds(1.5f); 
Destroy(gameObject);

①这与玩家TakeDamage()方法的逻辑大致相同。唯一不同的地方是,机器人将在生命值为0的时候先播放死亡动画再调用DestroyRobot ()销毁自身。
②这在摧毁机器人之前增加了一个1.5秒的延迟,为Die动画播放完成提供了足够的时间。
保存脚本。

步骤4 实现聚焦

不同的枪支应该有不同的攻击范围、破坏力以及通过鼠标右键可以实现不同程度的聚焦。
打开Gun脚本,并添加以下变量:

public float zoomFactor; 
public int range;
public int damage;
private float zoomFOV; 
private float zoomSpeed = 6;

当玩家点击鼠标右键时,zoomFactor控制缩放级别。
zoomFOV是最终缩放视角。
range是枪的射程。猎枪的射程最短,而手枪最长。
damage是枪造成的伤害。
保存脚本回到Unity。
单击1Pistol游戏对象,并将其ZoomFactor设置为1.3,Range为60,Damage为3。
单击2AssaultRifle游戏对象,并将其ZoomFactor设置为1.4,Range为30,Damage为1。
单击3Shotgun游戏对象,并将其ZoomFactor设置为1.1,Range为10,Damage为10。

打开Gun脚本并更新Start ()方法到以下内容

void Start() 
zoomFOV = Constants.CameraDefaultZoom / zoomFactor; 
lastFireTime = Time.time - 10;

这只是初始化了缩放因子。修改Update()方法,代码如下。

protected virtual void Update() 
// Right Click (Zoom)
if (Input.GetMouseButton(1)) 
Camera.main.fieldOfView=Mathf.Lerp(Camera.main.fieldOfView,zoomFOV,zoomSpeed * Time.deltaTime);
 else 
Camera.main.fieldOfView = Constants.CameraDefaultZoom;

如果玩家点击鼠标右键,这将通过 Mathf Lerp平滑地播放缩放效果。

步骤5 添加射线

为了确定机器人是否被击中,将使用光线。光线是一个隐形的射线,但是可以检测到碰撞。首先,必须定义命中的方法。添加以下内容:

private void processHit(GameObject hitObject) 
if (hitObject.GetComponent<Player>() != null) hitObject.GetComponent<Player>().TakeDamage(damage);
if(hitObject.GetComponent<Robot>()!=null) hitObject.GetComponent<Robot>().TakeDamage(damage);

这个方法将伤害值传递给正确的游戏对象。为了实现光线,将以下内容添加到Fire方法的底部。

Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f0.5f0)); 
RaycastHit hit;
if (Physics.Raycast(ray,out hit,range))  processHit(hit.collider.gameObject);

这将创建一个射线,并检查射线的命中。道理很简单,如果射线在枪的射程内与一个游戏对象碰撞就会触发processHit方法。
processHit判断命中的是否是机器人,如果是,机器人将会受到伤害。
保存脚本,回到Unity。运行游戏,按住鼠标右键缩放,然后攻击那些机器人,直到他们死掉。

3.4创建补给

步骤1 添加拾取补给的方法

玩家需要一种方法来恢复生命值、护甲和弹药。案例将在场景的随机位置添加一些漂浮的补给物让玩家拾取。在代码编辑器中打开Player脚本,并添加以下内容:

// 1
private void pickupHealth()  
health += 50;
if (health > 200) health = 200; 
private void pickupArmor()  armor += 15; 
// 2
private void pickupAssaultRifleAmmo()  ammo.AddAmmo(Constants.AssaultRifle,50); 
private void pickupPisolAmmo()  ammo.AddAmmo(Constants.Pistol,20); private void pickupShotgunAmmo()  ammo.AddAmmo(Constants.Shotgun,10);

这些方法实现了玩家捡到补给物时获得的增益效果。
现在添加以下内容:

public void PickUpItem(int pickupType)  
switch (pickupType) 
case Constants.PickUpArmor: 
pickupArmor();break;
case Constants.PickUpHealth: 
pickupHealth();break;
case Constants.PickUpAssaultRifleAmmo: pickupAssaultRifleAmmo();break;
case Constants.PickUpPistolAmmo: 
pickupPisolAmmo();break;
case Constants.PickUpShotgunAmmo: 
pickupShotgunAmmo();break; default:
Debug.LogError("Bad pickup type passed" + pickupType); break;

PickUpItem方法通过传入int参数,获取正在拾取的补给物的类型。

步骤2 创建补给逻辑

Constants文件引用所有补给物类型的ID。这些ID对应了五种类型的补给物。这些ID将作为参数传递到PickUpItem 方法中。
保存脚本,回到Unity。新建一个C#脚本,命名为“Pickup”,并添加字段,代码如下。

public int type;

这表示补给物的类型。现在添加以下内容

void OnTriggerEnter(Collider collider) 
if(collider.gameObject.GetComponent<Player>()!=null&&collider.gameObject.tag == "Player") 
collider.gameObject.GetComponent<Player>().PickUpItem(type);Destroy(gameObject);

这会让补给物监听与玩家的碰撞,从而调用玩家身上Player脚本上的PickUpItem方法,并传入自身的补给类型,然后销毁自身。
保存脚本,回到Unity。

在Resources文件夹中,选择PickupAmmoAssaultRifle、PickupAmmoPistol、PickupAmmoShotgun、PickupHealth和PickupArmor预设。选中所有这些选项后,单击脚本类别中的Add Component按钮,选择Pickup脚本。
接下来,添加Rigidbody。勾选Is Kinematic。
最后,添加BoxCollider。勾选Is Trigger,并设置Size为(1.5、1.5、1.5)。如下图所示

现在来配置每个补给物的类型。
选择Resources文件夹中的PickupAmmoPistol,
并将其Type设置为1,
将PickupAmmoAssaultRifle设置为2,
PickupAmmoShotgun为3,
PickupHealth为4,
PickupArmor为5。

步骤3 添加补给的漂浮动画

现在要做的事情是再补给物上添加旋转和浮动的动画。动画已经预先创建好了,现在只是需要创建Animator。在项目视图的Animations文件夹中创建一个Animator Controller,命名为“Pickup”。
双击Pickup动画控制器打开Animator视图。在空网格处右击唤出快捷菜单,然后选择Create State\\Empty命令。在检视视图中,更名为“Spin”并将Motion设置为cubeSpin,如下图所示。

接下来,返回到项目视图并选择Resources文件夹。
展开PickupAmmoAssaultRifle、PickupAmmoPistol、PickupAmmoShotgun、PickupHealth和PickupArmor预设,
选中它们的子物体。
将项目视图中Animations文件夹里的Pickup拖到检视视图。

现在,将这五个补给物(不是子物体)复制到场景上,位置略高于地面,如下图所示。

运行游戏。控制玩家移动到每个补给上。
当主角接触到补给的时候,会获得增益,并且补给物会消失。
如图所示。下一章将会添加一个UI来查看这些增益效果。

3.5补给刷新点生成

步骤1 创建补给点

在层级视图中删除所有的Pickup和Robot游戏对象。
创建一个新的C#脚本,将其命名为“PickupSpawn”,并添加字段。

private GameObject[] pickups;

pickups将保存所有补给类型。现在添加以下方法:

// 1void spawnPickup() // Instantiate a random pickup
GameObject pickup = Instantiate(pickups[Random.Range(0,pickups.Length)]);
pickup.transform.position = transform.position; pickup.transform.parent = transform; 
// 2IEnumerator respawnPickup() 
yield return new WaitForSeconds(20); spawnPickup(); 
// 3void Start()  spawnPickup();
// 4public void PickupWasPickedUp()  StartCoroutine("respawnPickup");

下面是每个方法的工作:
①实例化一个随机类型的补给,并设置它的位置。
②在调用spawnPickup方法之前等待20秒。
③在自身实例化时生成一个补给。
④当玩家捡起补给时,重置协同方法。
保存脚本。打开Pickup脚本,然后在Destroy(gameObject)上添加以下行:

GetComponentInParent<PickupSpawn>().PickupWasPickedUp();

当补给与主角相撞时,将在PickupSpawn脚本上启动生成计时器。
保存脚本回到Unity。

创建一个空的游戏对象,命名为“PickupSpawn”,并添加PickupSpawn脚本。


选中PickupSpawn的游戏对象,设置其Pickups属性的Size为5。
Lock检视视图。将Resources文件夹中的PickupAmmoAssaultRifle、PickupAmmoPistol、PickupAmmoShotgun、PickupHealth和 PickupArmor预设分别拖入到Pickups元素中。
最后,UnLock检视视图。

步骤2 设置所有补给点

现在,将PickupSpawn游戏对象拖到Resources文件夹中,创建一个预制体。
创建一个空的游戏对象,命名为“PickupSpawns”。将其Position设置为 (0、0、0)。将PickupSpawn拖入到PickupSpawns,使其成为PickupSpawns的子物体。然后再复制出六个。
为了保持整洁,将每个子对象名称都更改为“PickupSpawn”。
如下图所示。

从最顶部PickupSpawn的游戏对象开始设置位置:
运行游戏,会看到七个补给生成在场景中。走过去,把它们捡起来。

步骤3 创建传送点

现在,补给已经可以自动生成了,下面来实现机器人的自动生成。
将Teleporter预置从Resources文件夹拖到场景的根目录下。
创建一个C#脚本,将其命名为“RobotSpawn”。
在代码编辑器中打开它,并在类的“”之后添加以下变量:

[SerializeField] GameObject[] robots;
private int timesSpawned; 
private int healthBonus = 0;

Robots保存了将要用来实例化的所有类型的机器人预制体。
healthBonus 是每个机器人每波获得多少生命值,当玩家活得越久,游戏将变得越难。
timesSpawned 是机器人的生成周期。

接下来添加以下方法:

public void SpawnRobot()  
timesSpawned++;
healthBonus += 1 * timesSpawned;
GameObject robot = Instantiate(robots[Random.Range(0,robots.Length)]);
robot.transform.position=transform.position;
robot.GetComponent<Robot>().health += healthBonus;

SpawnRobot ()方法用来实例化一个机器人,并设置它的生命值和位置。
保存脚本回到Unity。

将RobotSpawn脚本拖到Teleporter游戏对象上。在层级视图中选择Teleporter游戏对象,然后将RedRobot、YellowRobot和BlueRobot预制体从Resource文件夹中拖到检视视图的Robots字段中。

步骤4 设置所有传送点

在层级视图中,创建一个空的游戏对象,将其命名

以上是关于unity实战:狂暴机器人游戏教程(下篇)的主要内容,如果未能解决你的问题,请参考以下文章

unity实战:狂暴机器人游戏教程(下篇)

unity实战:狂暴机器人游戏教程(上篇)

unity实战:狂暴机器人游戏教程(上篇)

unity实战:狂暴机器人游戏教程(上篇)

unity实战:狂暴机器人游戏教程(上篇)

Unity5新特性----实战2D游戏