纳金网

标题: 实现攻击扣血的流程(转载) [打印本页]

作者: 王者再临    时间: 2014-10-31 19:33
标题: 实现攻击扣血的流程(转载)

这个流程主要实现以下功能:界面上显示玩家当前的总血量,当被其他玩家发射的子弹打中后,会减1格血,血量为0时判定为死亡,会重置玩家的位置到出生点,并且重设血量为最大血量。


实现这个逻辑,分了以下几个步骤。


1.维护玩家血量相关信息。

首先玩家血量要用图形化在界面上显示,首先需要在场景中建立一个GUITexture,这里起名为GUI_heart,来表示当前血量图片。为了控制血量的显示,为GUI_heartf附加了一个控制脚本,名为HeartControl.cs。这个脚本的内容如下:

01.using UnityEngine;

02.using System.Collections;

03.

04.public class HeartControl : MonoBehaviour {

05.    public Texture2D[] heartImageArray;

06.    private const int maxLives = 5;

07.    private static int lives = maxLives;

08.

09.    public static void DecreaseLive()

10.    {

11.        lives--;

12.        if(lives==0)

13.        {

14.            lives=maxLives;

15.            PlayerManager.selfPlayer.position = GameObject.Find("SpwanPlayer").transform.position;

16.        }

17.    }

18.    // Use this for initialization

19.    void Start () {

20.

21.    }

22.

23.    // Update is called once per frame

24.    void Update () {

25.        if(PlayerManager.selfPlayer!=null)

26.        {

27.            guiTexture.enabled = true;

28.            guiTexture.texture = heartImageArray[lives-1];

29.        }

30.        else

31.        {

32.            guiTexture.enabled = false;

33.        }

34.

35.

36.    }

37.}

这里heartImageArray表示不同血量所对应的血量图片,血量用心型图标来显示,5格血就是5颗心。把这个数组声明为public,可以在编辑器中,设置这个数组的尺寸,以及每个入口点所对应的图片,十分方便。

maxLives就是最大血量有5格血,lives是当前人物的血量。

在每帧更新函数Update()中,首先检查当前玩家的变量是否为空,为空可能是因为是Server端,这种情况下就不需要显示血量,因此将图片设为false:guiTexture.enabled = false;

如果不为空,那么将根据当前血量的值,把对应数组中的图片赋值给这个guiTexture当前的texture,这样就实现图片随血量值的变化而变化。

这里PlayerManager.selfPlayer中的PlayerManager我自己建立的一个全局的静态类,维护了唯一的静态变量private static Transform _selfplayer,代表客户端所对应的玩家自己。这个类可以被所有脚本所访问,访问起来十分方便,实现如下:

01.using UnityEngine;

02.using System.Collections;

03.using System;

04.

05.public static class PlayerManager  {

06.

07.    private static Transform _selfplayer = null;

08.    public static Transform selfPlayer

09.    {

10.        get

11.        {

12.            return _selfplayer;

13.        }

14.        set

15.        {

16.            _selfplayer = value;

17.

18.        }

19.    }

20.

21.}

后期随着逻辑的复杂,可以为这个脚本的玩家增加更多的数据来维护。

      然后是DecreaseLive函数,这个函数可以被外部所调用,给玩家减血,调用后,自动扣除一滴血,为0时,正如规定的一样,重设玩家血量为最大血量,并且找到重生点的位置,将玩家位置重置。

2.控制子弹打中玩家的逻辑

实现大体流程是先给玩家的人物身上附加一个释放子弹的脚本,当客户端自己的玩家按键触发技能时,就调用一个网络上的RPC,告诉所有客户端和服务器在本地创建一个飞行的子弹。并且在这个人物脚本里添加一个响应人物碰撞的事件函数,然后检查是不是碰撞的对象是子弹,而且不是这个人物所发射的,如果检测成功,就调用HeartControl脚本的减血函数。

这个脚本名为Shoot.cs,实现如下:

001.using UnityEngine;

002.using System.Collections;

003.

004.public class Shoot : MonoBehaviour

005.{

006.    public Texture skillTex1;

007.    public Texture skillTex2;

008.    public Transform bulletPrefab;

009.    public Transform explosionEffect;

010.    public AnimationClip attackAnim;

011.

012.    // Use this for initialization

013.    void Start ()

014.    {

015.

016.    }

017.

018.    // Update is called once per frame

019.    void Update ()

020.    {

021.        if (networkView.isMine && Input.GetKeyUp ("2")) {

022.            ShootBullet ();

023.

024.        }

025.            if (networkView.isMine && Input.GetKeyUp ("3")) {

026.            ExplosiveEffect();

027.

028.        }

029.

030.    }

031.

032.    void OnGUI ()

033.    {

034.        if (networkView.isMine)

035.        {

036.            if(GUI.Button (new Rect ((float)(0.5*Screen.width-60), (float)(Screen.height-60), 60, 60), skillTex1))

037.                {

038.            ShootBullet();}

039.

040.            if(GUI.Button(new Rect((float)0.5*Screen.width,(float)Screen.height-60,60,60),skillTex2))

041.            {

042.                ExplosiveEffect();

043.            }

044.        }

045.

046.    }

047.

048.    void OnCollisionEnter(Collision collisionInfo)

049.    {

050.

051.

052.        if(collisionInfo.gameObject.tag=="bullet" )

053.        {

054.            BulletScript bs = (BulletScript)collisionInfo.gameObject.GetComponent("BulletScript");

055.            if(bs.Owner != gameObject)

056.            {

057.                print("OnCollisionEnter"+collisionInfo.gameObject.name);

058.                Destroy(collisionInfo.gameObject);

059.

060.

061.                if(!networkView.isMine)

062.                    return;

063.                HeartControl.DecreaseLive();

064.            }

065.

066.

067.

068.        }

069.    }

070.

071.

072.

073.    void ExplosiveEffect()

074.    {

075.

076.        networkView.RPC("SpwanExplosion",RPCMode.All);

077.        SendMessage("PlayAnimation_Attack");

078.    }

079.

080.    void ShootBullet()

081.    {

082.        networkView.RPC("SpawnBullet",RPCMode.All);

083.    }

084.

085.    [RPC]

086.    void SpawnBullet ()

087.    {

088.

089.

090.        Vector3 forward = transform.TransformDirection (Vector3.forward);

091.        Transform effectPoint = transform.Find ("effectPoint");

092.        PrefabDepends preScript = (PrefabDepends)GameObject.Find("GameObject_GlobalController").GetComponent("PrefabDepends");

093.        if (effectPoint) {

094.

095.            Transform bullet = (Transform)Instantiate (preScript.bulletPrefab, effectPoint.position, Quaternion.identity);

096.            bullet.rigidbody.AddForce (forward * 2000);

097.            BulletScript bs = (BulletScript)bullet.GetComponent("BulletScript");

098.            bs.Owner = gameObject;

099.        }

100.

101.    }

102.

103.    [RPC]

104.    void SpwanExplosion()

105.    {

106.        Vector3 forward = transform.TransformDirection (Vector3.forward);

107.        Transform effectPoint = transform.Find ("effectPoint2");

108.        if (effectPoint) {

109.            //Object temp = Network.Instantiate (bulletPrefab, effectPoint.position, Quaternion.identity, 0);

110.

111.            Transform explosion = (Transform)Instantiate (explosionEffect, effectPoint.position, Quaternion.identity);

112.            //Network.Instantiate(bulletPrefab,transform.Find("effectPoint").position,Quaternion.identity,0);

113.        }

114.    }

115.

116.}


SpawnBullet就是调用的RPC call,在这里除了用子弹的prefab创建出子弹附加初始速度,还给子弹的脚本BulletScript的一个变量Owner赋值为脚本所附加到的玩家,这是为了判断这个子弹是哪个玩家发出用的。

碰撞检测的函数是OnCollisionEnter,要想触发这个函数,人物身上需要有一个Collider控件,而CharacterController是没有用的。所有的子弹都设为了名为"bullet"的tag,所以在这里检测,如果碰撞的对象是bullet,并且子弹上的脚本的变量Owner不是这个玩家自己,说明被别人的子弹击中,就先销毁本地创建出来的子弹,然后判断如果这个玩家是这个客户端所对应的,就进行减血。这个判断是必要的,因为这里的血量是全局静态的,只有一份代表自己,其他玩家被子弹攻击到了,不需要更新自己的血量。



作者: cgjch8    时间: 2014-11-1 16:48
不错不错
作者: moonljj    时间: 2014-11-2 11:08
学习了,不错
作者: HIDEOKOJIMA    时间: 2014-11-2 17:12
Thanks for sharing this one !




欢迎光临 纳金网 (http://old.narkii.com/club/) Powered by Discuz! X2.5