[Unity3D]Unity3D游戏开发之2D贴图实现血条组件

      各位朋友,你们好,欢迎你们关注个人博客,我是秦元培,个人博客地址是blog.csdn.net/qinyuanpeiide

   在上一篇文章中,咱们以经典的打砖块游戏为例,讲解了一个Unity3D游戏的完整实现过程。今天呢,咱们来作一个在游戏中十分重要的组成元素:血条。血条是什么呢?血条是生命值的一种体现,就像《仙剑奇侠传三》电视剧中,当景天说他想让那些被邪剑仙害死的人活过来的时候,天帝说须要等量的生命值来换,因此电视剧中的结局就变成了景天留在世上的时间并很少了,雪见依偎着他坐在新安当门口的时候,天上突然下起了雪。聊完了游戏,咱们继续回到Unity3D中来,咱们今天要实现的是基于2D贴图的血条组件的开发。在正式开始以前,咱们先来了解下原理:血条由先后两张大小相等贴图组成,前面的贴图就是咱们能够看到的血量贴图,然后面的贴图就是咱们的背景贴图,经过改变血量贴图的宽度,咱们就能够实现血条的效果。好,讲完了原理咱们就来一块儿学习今天的内容吧!学习

    首先,咱们准备两张不一样颜色的贴图,如图:测试


    接下来,咱们打开Unity3D建立一个新的项目,咱们首先在场景中建立两个GUITexture对象,咱们将这两个GUITexture对象分别命名为HPBackwardHPForward。在GUITexture中有一个很重要的属性PixelInset,它是一个Rect类型的值,用以描述GUITexture对象的左上角位置、宽度、高度。这里咱们使用默认的坐标值,将宽度改成64,将高度改成5。两张贴图的设置要保持一致。如图所示:ui


    在这里须要讲一下PixelInset,因为GUITexture是采用的二维屏幕坐标来定位的,即左下角为(0,0),右上角为(1,1),因此咱们不能直接使用三维坐标来改变GUITexture对象的位置。在Unity中有一个WorldToScreenPoint()方法能够将三维坐标转化为二为左边,因此咱们的思路是获取目标物体的位置,将其转化为二维坐标,再赋值给GUITexture对象。好,基于这样的思路,咱们能够编写下面的脚本:spa

  using UnityEngine;
  using System.Collections;
  
  public class Texture2DHP : MonoBehaviour 
  {
  	//前景贴图
  	public Texture ForwardTexture;
  	//背景贴图
  	public Texture BackwardTexture;
      //目标对象
  	public Transform Target;
  	//水平偏移量
  	public float OffSetX=0.05F;
  	//垂直偏移量
  	public float OffSetY=0.05F;
  	
  	//最大血量
  	public int MaxHP=100;
  	//当前血量
  	public int HP=100;
  	//血条宽度
  	public int mWidth=64;
  	//血条高度
  	public int mHeight=5;
  	
  	//前景
  	private Transform Forward;
  	//背景
  	private Transform Backward;
  	
  	void Start () 
  	{
  	   //得到前景和背景
  	   Forward=transform.Find("HPForward");
  	   Backward=transform.Find("HPBackward");
  	   //设置前景、背景贴图
  	   Forward.guiTexture.texture=ForwardTexture;
  	   Backward.guiTexture.texture=BackwardTexture;
  	   //根据目标对象初始化血条位置
  	   UpdateLocation(Target,OffSetX,OffSetY);
  	}
  	
  	
  	void Update () 
  	{
  	   UpdateLocation(Target,OffSetX,OffSetY);
  	   UpdateHP(HP);
  	}
  	
  	//更新位置
  	private void UpdateLocation(Transform mTransform,float mOffSetX,float mOffSetY)
  	{
  	    //获取目标对象高度
  	    float mHight=Target.collider.bounds.size.y;
  	    float mScale=Target.transform.localScale.y;
  	    mHight=mHight * mScale;
  		//将三维坐标转化为二维坐标
  		Vector3 mPos3d=new Vector3(mTransform.position.x,mTransform.position.y+mHight,mTransform.position.z);
  		Vector2 mPos2d=Camera.main.WorldToScreenPoint(mPos3d);
  	    //更新贴图的位置
  		Forward.position=new Vector3(mPos2d.x/Screen.width+mOffSetX,mPos2d.y/Screen.height+mOffSetY,0);
  		Backward.position=new Vector3(mPos2d.x/Screen.width+mOffSetX,mPos2d.y/Screen.height+mOffSetY,0);
  	}
  	
  	//更新血量
  	public void UpdateHP(int mValue)
  	{
  		
  		if(mValue<0 || mValue>MaxHP)
  		 return;
  		 SetGUITextureWidth(Forward.guiTexture,
  			(int)(mWidth * (mValue/(double)MaxHP)));	
  	}
  		
  	//设置贴图宽度
      private void SetGUITextureWidth(GUITexture mTexture,int mValue)
      {
  	    mTexture.pixelInset=new Rect(mTexture.pixelInset.x,mTexture.pixelInset.y,
  			mValue,mTexture.pixelInset.height);
      }
  }

   在上面的代码中,咱们须要把握如下几点:.net

   一、目标物体的高度是根据Collider来获取的,因此要使用血条组件的物体必须带有碰撞器。3d

   二、经过WorldToScreenPoint()方法获取二维坐标后,要分别用xy坐标去除以屏幕宽度、屏幕高度,目的是使坐标值介于0,1之间,由于GUITexture使用这样的坐标系。code

   三、当改变脚本中的血量和目标物体的位置时,血条位置和血条量会自动更新。换言之,咱们只要要改变HP的值就能够实现血条数值的更新。orm

   好了,如今咱们在场景中建立一个空的GameObject,命名为Texture2DHP。咱们将前面建立的两个GUITexture对象拖放到该对象下,使其成为子对象。咱们把脚本拖放到Texture2DHP对象上,此时,咱们应该能够看到下面的内容:对象


    咱们将开始项目前准备好的两张贴图导入项目并将它们赋给脚本,其中红色的为血量贴图,黄色的背景贴图。好了,到目前为止,一个血条组件已经基本成型了,为了让它能够在项目中复用,咱们将其制做成预设。下面来说解预设的制做方法:

    预设,在Unity3D中称为Prefab,是一种能够复用的游戏体。咱们首先在Project窗口中建立一个Prefab文件夹,而后在该文件下建立一个名为Texture2DHPPrefab。咱们将Hierarchy窗口中的Texture2DHP拖放到Prefab中,Prefab将变成亮蓝色,此时代表预设已经建立成功。保存项目,将Hierarchy窗口中的Texture2DHP对象删除,在接下来的游戏开发中,咱们将会一直用到这个预设文件。好,咱们如今来测试一下今天的成果,咱们首先在场景中建立一个Cube和一个胶囊体,而后咱们将Texture2DHP预设直接拖放到游戏场景中,设置其目标物体为Cube,血量HP35,将其更名为CubeHP。相似地,咱们为胶囊体建立一个血条组件,设置其血量HP85,将其更名为CapsuleHP。好了,如今咱们来运行游戏:


   那么,咱们如何在脚本中动态的改变血条的血量呢?咱们只须要获取指定名称的Texture2DHP组件,而后获取Texture2DHP脚本并修改其中的HP的值就能够了。怎么样,效果还不错吧?不过基于这种方式实现的血条有一个问题,就是全部对象的血条都是在一个平面上的,这样血条的大小是不会随着距离摄像机距离的变化而表现出一种渐变的效果的,这是原理性的问题,咱们目前还没法避免。博主测试模型的时候,常常出现没法获取模型高度的问题,暂时尚未想到较好的解决办法,若是你们有更好的想法,欢迎你们给我留言。那么,有没有更好的方法呢?有,那就是NGUI!好了,关于NGUI的问题,博主稍后会与你们分享。但愿你们继续关注个人博客哦。今天的内容就是这个样子啦,博主期待和你们一块儿成长,加油!


   每日箴言:对于单纯善良的人来讲,这个世界其实不复杂



    喜欢个人博客请记住个人名字:秦元培,个人博客地址是blog.csdn.net/qinyuanpei

    转载请注明出处,本文做者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/24796009