Unity3D UNET 模仿局域网游戏(二)

紧接着上一篇博客,上一篇博客中,我们已经能够分别移动角色,并且控制他射击了,而且还稍微区分了一下不同的角色。这篇博客中我们继续讲解后面的内容。 
既然角色都已经可以射击了,那肯定还得需要一个血量对吧,所以现在我们就添加血量。给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
    }
}

这时候就可以同步了。在下一篇博客中我们将对游戏增加一点小内容。 
本博客用作新手学习讨论,如有不好或错误的地方也请指出来,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值