本节要实现的目标:
1、玩家拾取血包增加血量
2、玩家可用激光对NPC造成伤害
一、导入资源文件
文件下载:地址
1、导入Package
2、运行_Scenes里面的BattleStar_GameScene场景,观察
二、NavMesh寻路系统
1、添加自动寻路脚本
我们发现,在Hierarchy里面有GameOverPosition,它代表着我们到达该地,将取得游戏胜利。我们添加自动寻路脚本,观察在迷宫中如何到达目的地。我们先将FPSController设置为NavMesh Agent,自动寻路到该位置看看实际效果。
给FPSController添加endPosition脚本、NavMeshAgent组件,并取消激活FPSController的First Person Controller脚本,避免功能冲突
代码语言:javascript复制using UnityEngine;
using UnityEngine.AI;
public class endPosition : MonoBehaviour {
NavMeshAgent agent;
private void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.destination = GameObject.Find("GameOverPosition").transform.position;
}
}
2、重设NavMesh寻路区域
我们发现,FPSController找到了目的地,但它在某地区是穿墙而过。这是不合逻辑的。我们重新设置下NavMesh寻路区域:
Navigation-Object-Mesh Renderer将Door设置成Walkable;Floor勾选Navigation Static-Walkable;Floor_Plane取消勾选Navigation Static;mazemodel-Not Walkable;outside-Not Walkable;Roof-Not Walkable;Wall_1、3-Walkable;Wall_2、4-Not Walkable。Bake
运行游戏,我们发现FPSController正确寻路到目标点,现在我们完成了系统的NavMesh寻路系统设置,接下来我们增加人物捡到血包加血功能
三、实现血包加血功能
观察游戏项目,我们发现控制人物血量的属性PlayerHealth在FPSController—Player脚本里面
1、除了场景中的血包外,我们再在FPSController附近另增加两个如下图所示血瓶,model位于Assets-Plugins-HealthMedicalSet-Models-bottle 02
2、添加Mesh Collider,更改Shader使其看起来更好看些
3、添加如下代码,让瓶子运行时自转
代码语言:javascript复制using UnityEngine;
public class RotateSelf : MonoBehaviour {
int RotateSpeed = 90;
void Update () {
transform.Rotate(Vector3.up * RotateSpeed * Time.deltaTime, Space.World);
}
}
4、激活FPSController的First Person Controller脚本,停止运行End Position,可看到如下效果。后续这类操作不再赘述
5、给血瓶增添触发代码
a、修改FPSController-Player代码,public int static playerHealth=5改为public int playerHealth=5,这样我们便能在面板看到初始血量,当然,我们赋值的应该是下方的PlayerHealth属性
b、我们给血瓶赋予脚本blood,该脚本用于给玩家增加血量
本操作用到了Collider的OnTriggerEnter方法。当带有Collider组件的物体接触到外物时,会触发它的OnColliderEnter方法,但当该物体开启Is Trigger时,两个物体就变为可穿透状态了。当穿透时,系统会自动触发OnTriggerEnter方法
代码语言:javascript复制using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class blood : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
if (other.name == "FPSController")
{
if (other.GetComponent<Player>().PlayerHealth < 5)
{
other.GetComponent<Player>().PlayerHealth = 1;
//计算方法: 把左边的变量和第一个符号移到右边, 变量1 = 变量1 表达式运算结果)
//如:i = 1 则是: i = i 1
//i = 1 2 * 3 则是: i = i (1 2 * 3)
}
}
}
}
6、我们只完成了给人物增加血量,但人物一开始血量是满的,我们再增加一个减血瓶,效果是接触后减3滴血,观看效果
代码语言:javascript复制using UnityEngine;
public class blood_down : MonoBehaviour {
void OnTriggerEnter(Collider other)
{
if (other.name == "FPSController")
{
other.GetComponent<Player>().PlayerHealth -= 3;
}
}
}
减血、加血过多是因为碰撞后未立即销毁对象,出现多次减血加血现象,这对我们观察无影响。读者可自行尝试在代码里添加Destroy(gameObject)销毁目标
四、玩家用激光对NPC造成伤害
本节用到的关键代码是Physics.Raycast,可回顾上篇文章——Physics.Raycast()知识点讲解,和我们之前做过的动画项目——Unity动画射线Physics.Raycast()
本节设计思路:准星位于屏幕中央,即从屏幕中央处开火。运用Physics.Raycast()方法,当按下鼠标左键时发射射线,返回射线检测到的物体。如果是机器人,则更改机器人的血量值,使其减少展现出造成伤害的效果
当然,这要求我们不断检测是否按下鼠标左键,若写在Update函数中,会很消耗计算资源。我们运用协程方法StartCorotine()方法,来不断执行该命令,减少资源消耗
1、本项目是有准星来瞄准的,但我们发现捡到枪后准星并没有出现,我们将HUDCanvas—GamePanel—ReticleImage的Scalex、y、z设置成2,放大准星
2、本项目玩家发射子弹是采用了开火动画 射线检测方式,代码位于Gun中,Gun作为组件放在FPSController—FirstPersonCharacter—GunWithHand上。当射线碰撞检测到Robot,会调用Robot代码中的RobotHealth,使RobotHealth--使其受伤。下面展示的Robot中的代码,保证当Robot生命值为0时,调用RobotDie()方法
代码语言:javascript复制 private float robotHealth;
public float RobotHealth
{
get
{
return robotHealth;
}
set
{
robotHealth = value;
healthImage.localScale = new Vector3(value / 5, 1, 1);
if (robotHealth == 0)
{
RobotDie();
}
}
}
当然,我们发现Robot代码中也包含如下代码,我们也可在Gun中直接调用这段代码,造成机器人生命值减一的效果
代码语言:javascript复制 public void RobotGetHurt()
{
RobotHealth -= 1;
}
3、当Robot生命值下降后,在Robot代码的RobotHealth属性set中,本项目写了healthImage.localScale = new Vector3(value / 5, 1, 1)代码,用来缩放Robot头上血条,呈现出减血的效果
Transform.localScale 自身缩放
代码语言:javascript复制//扩大物体的x轴向0.1个单位
transform.localScale = Vector3(0.1,0,0);
本项目的Gun、GunModelTrigger、HealthPackage、Robot代码包含本节内容,读者可重点观察,加深本节印象。
最后新开“第九章U3D代码注解”一文记录本章重点代码,用于速查定义节省时间