紧接着上一篇博客,上一篇博客中,我们已经能够分别移动角色,并且控制他射击了,而且还稍微区分了一下不同的角色。这篇博客中我们继续讲解后面的内容。
既然角色都已经可以射击了,那肯定还得需要一个血量对吧,所以现在我们就添加血量。给Player添加Health脚本并编辑:
using UnityEngine;
using System.Collections;
public class Health : MonoBehaviour {
public const int maxHealth = 100; //最大血量
public int currentHealth = maxHealth; //当前血量
//当玩家和子弹碰撞时调用的方法
public void TakeDamage(int damage)
{
currentHealth -= damage;
if (currentHealth <= 0) //如果当前血量小于等于0
{
currentHealth = maxHealth; //就让他回复满血状态,方便后面我们让他重生时需要
}
}
}
然后需要给Player添加一个Tag 名字为”Player”,给子弹也就是Bullet 添加一个脚本Bullet,并编辑:
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour {
//当子弹与物体碰撞时
void OnCollisionEnter(Collision other)
{
//如果碰撞的物体的Tag 是Player
if (other.collider.tag == "Player")
{
//调用碰撞物体的TakeDamage,传递一个参数是10
other.collider.SendMessage("TakeDamage", 10);
Destroy(gameObject); //销毁子弹
}
}
}
既然有了血量,我们是不是就应该给他添加一个血条,现在我们就添加血条。新建UI–>Slider,然后把slider下的Handle Slide Area删掉,把Fill 移动到Background的子物体,再把Fill Area删掉。
把 Fill 选择填充父背景,也就是Background,保证他们两个一样大。修改颜色成绿色,Bbackgroud修改颜色成红色。Fill 选择这个
然后这是效果图
最后,我们要把这个血条添加到角色身上去。选中Canvas,Render Mode改为World Space,让摄像机渲染这个UI。把Canvas拖到Player的子物体。做如下改变:
拖动Slider到角色头顶,然后效果图
血条就添加好了,现在我们让他能够随着生命值改变。修改Health类
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Health : MonoBehaviour {
public const int maxHealth = 100; //最大血量
public int currentHealth = maxHealth; //当前血量
public Slider healthSlider;
//当玩家和子弹碰撞时调用的方法
public void TakeDamage(int damage)
{
currentHealth -= damage;
if (currentHealth <= 0) //如果当前血量小于等于0
{
currentHealth = maxHealth; //就让他回复满血状态,方便后面我们让他重生时需要
}
healthSlider.value = (float)currentHealth / maxHealth; //修改Slider的比例
}
}
这时我们发现当角色旋转时,血条也会旋转,看起来不美观,我们让他只”看着摄像机”。
给Canvas添加一个脚本LookAtCamera并编辑
using UnityEngine;
using System.Collections;
public class LookAtCamera : MonoBehaviour {
// Update is called once per frame
void Update () {
transform.LookAt(Camera.main.transform);
}
}
这样血条就会一直对着摄像机了。现在运行游戏,是可以使用的,
但是!!细心的你会发现,他们的血条有可能不同步。这是因为,血量的判断在客户端和服务端都进行了判断,相当于各自计算各自的,但是!!当服务端的子弹碰撞到Player时,会计算生命值,然后销毁子弹,而当服务端的子弹销毁时,客户端的子弹也会跟着一起消失,而服务端已经计算了,而客户端没有计算(就像网络游戏有延迟一样),就会导致不同步。现在我们来让子弹同步。要解决这个问题,我们就要让血量的检测在服务端进行,然后同步到客户端就行了。修改Health类继承NetworkBehaviour,
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Networking;
public class Health : NetworkBehaviour {
public const int maxHealth = 100; //最大血量
//检测一个属性,当服务端改变值时,会同步到客户端
//当值改变时,会调用一个方法 如:OnChangeHealth
[SyncVar(hook = "OnChangeHealth")]
public int currentHealth = maxHealth; //当前血量
public Slider healthSlider;
//当玩家和子弹碰撞时调用的方法
public void TakeDamage(int damage)
{
if (!isServer) //如果不是服务端
{
return;
}
currentHealth -= damage;
if (currentHealth <= 0) //如果当前血量小于等于0
{
currentHealth = maxHealth; //就让他回复满血状态,方便后面我们让他重生时需要
}
}
//当服务端检测的属性值改变时调用的方法
//health:改变后的值
void OnChangeHealth (int health)
{
healthSlider.value = (float)health / maxHealth; //修改Slider的比例
}
}
这时候就同步了。。接下来我们设置当角色生命值为0时重生。修改Health类,这里修改的地方比较少,我就直接放修改的图片,大家对应着修改就行了。
这时候运行,你会发现,只有当客户端攻击时角色死亡位置才会重置,服务端攻击不会。这是因为一开始我们设置了,
这代表只有客户端才有权限,而服务端的攻击然后重置位置,这是没有权限的,所以现在我们要让它能够在服务端也重置位置,修改Health类
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Networking;
public class Health : NetworkBehaviour {
public const int maxHealth = 100; //最大血量
//检测一个属性,当服务端改变值时,会同步到客户端
//当值改变时,会调用一个方法 如:OnChangeHealth
[SyncVar(hook = "OnChangeHealth")]
public int currentHealth = maxHealth; //当前血量
public Slider healthSlider;
//当玩家和子弹碰撞时调用的方法
public void TakeDamage(int damage)
{
if (!isServer) //如果不是服务端
{
return;
}
currentHealth -= damage;
if (currentHealth <= 0) //如果当前血量小于等于0
{
currentHealth = maxHealth; //就让他回复满血状态,方便后面我们让他重生时需要
RpcRespawn(); //调用一个方法,设置重生的位置
}
}
//当服务端检测的属性值改变时调用的方法
//health:改变后的值
void OnChangeHealth (int health)
{
healthSlider.value = (float)health / maxHealth; //修改Slider的比例
}
//远程调用,表示调用这个方法时就会在客户端调用,方法名必须以Rpc开头
[ClientRpc]
void RpcRespawn()
{
if (!isLocalPlayer)
{
return;
}
transform.position = Vector3.zero; //把位置设置到0,0,0
}
}
这时候就可以同步了。在下一篇博客中我们将对游戏增加一点小内容。
本博客用作新手学习讨论,如有不好或错误的地方也请指出来,谢谢。