这个流程主要实现以下功能:界面上显示玩家当前的总血量,当被其他玩家发射的子弹打中后,会减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不是这个玩家自己,说明被别人的子弹击中,就先销毁本地创建出来的子弹,然后判断如果这个玩家是这个客户端所对应的,就进行减血。这个判断是必要的,因为这里的血量是全局静态的,只有一份代表自己,其他玩家被子弹攻击到了,不需要更新自己的血量。
|