Unity2D小地图与伤害数字UI

Unity2D小地图

在游戏中,按下小地图键打开小地图,显示所有房间信息以及玩家所在位置。

这里使用到的方法原理,即采用小地图专用摄像机,通过设置其Target Texture和Culling Mask属性,将拍摄到的画面渲染在一张Texture图片上,然后将该Texture图片做成UI显示出来。

Hierarchy面板中的结构:

MiniMap游戏物体下,有小地图摄像机与画布对象,以及画布下的Raw Image对象(用于显示Texture)。

设置被拍摄物体的Layer

首先,我们将要显示在小地图上的对象的Layer设置在一个单独的Layer上。如这里我要显示房间的墙壁,我就将房间墙壁的Layer设置为MiniMap:

由于MiniMap图层只用作小地图显示,因此一般会在游戏对象下新添加一张被拍摄图片作为MiniMap图层的替代品,比如要在小地图显示玩家的位置,可以在玩家游戏物体下添加一张sprite图片,将该图片的Layer设置为MiniMap。这样当玩家移动时,图片也会跟着移动,由其渲染在小地图上代替玩家本身。

设置摄像机

  • 新建摄像机,设置为正交拍摄(调整摄像机坐标(Z轴)和背景不透明度),取消Audio Listener组件

  • 设置摄像机Culling Mask属性为MiniMap(小地图图层),这样相机只会渲染MiniMap图层的对象

  • 在Project面板中新建一张Render Texture图片(这里命名为MiniMapBG),作为摄像机的输出目标,设置好图片的大小,并将摄像机Target Texture属性设置为它

设置画布

  • 在画布下新建UI:Raw Image,将其Texture属性也设置为刚刚创建的Render Texture

至此,小地图创建工作以及大致完成,剩下的功能可根据需要自行修改。

 

伤害数字UI

当敌人受到伤害,则在其位置显示伤害数字,并且在显示期间数字会向上移动一段距离

原理:世界坐标画布。

  • 在敌人对象下新建Canvas画布,设置为世界坐标,Reset一下其Transform数据,然后将Canvas组件下的Event Camera设置为主相机Main Camera(注意如果要把Canvas做成预制体,那么也要将主相机做成预制体,这样才能在Canvas预制体中设置Event Camera属性)

  • 在画布Canvas下新建Text对象,用于显示伤害数字。由于其Transform中的长宽太大,导致摄像机拍不到,这里我直接将Scale属性设置为0.01,总之要调整好它的大小,同时设置好其他属性,字体,字体大小,是否居中等

代码思路:

  • Text设置为非active,当敌人受到伤害后,在敌人脚本中将其设置为active

  • 新建脚本,挂在Canvas下,当检测到Text为avtive,则启动计时器,当计时器时间小于规定的显示时间,则增加其Y坐标向上移动;当计时器超过规定时间,则重置坐标与计时器,将Text设置为非active

  • 这里伤害的数值用的是C#事件来实现,Canvas脚本监听敌人脚本的事件触发,触发后更改Text对象的text属性即可

    //敌人脚本中,受伤后调用的方法
	protected void OnHurt(int damageAmount)
    {
        if(!isHurt)
        {
            isHurt = true;

            //被击shader
            sp.material.SetFloat("_FlashAmount", 1);
            hurtTimeCounter = hurtTimeLength;

            //被击后退
            enemyRig.AddForce(new Vector2(hurtMovmentVector.x, hurtMovmentVector.y));

            //切换受伤动画
            enemyAnim.SetTrigger("hurt");

            //敌人受伤数值随机
            damageAmount = Random.Range(damageAmount - hurtInterval, damageAmount + hurtInterval + 1);
            //敌人受伤UI
            damageText.gameObject.SetActive(true);
            EventEnemyHurt?.Invoke(damageAmount);//等价于if(EventEnemyHurt!=null) { EventEnemyHurt(damageAmount); }
        }
    }
public class HitBarCanvas : MonoBehaviour
{
    public Text damageText;
    public float textSpeed;
    public float timer;//规定显示的事件
    public float nowTime;//计时器


    private void Awake()
    {
        //FindObjectOfType<Enemy>().EventEnemyHurt += ShowDamageText;
        //不能直接找,要从父对象上找脚本,不然都去找第一个Enemy脚本了
        GetComponentInParent<Enemy>().EventEnemyHurt += ShowDamageText;//注册事件
    }


    void Update()
    {
        VisibelController();
    }

    public void VisibelController()
    {
        if (damageText.gameObject.activeInHierarchy)
        {
            nowTime += Time.deltaTime;
            if (nowTime < timer)
            {
                //设置lacalPosition本地坐标,而不是transform.position世界坐标
                damageText.transform.localPosition += new Vector3(0, textSpeed * Time.deltaTime, 0);
            }
            else
            {
                damageText.transform.localPosition = new Vector3(0, 0, 0);//设置localPosition本地坐标才对
                nowTime = 0;
                damageText.gameObject.SetActive(false);
            }
        }
    }
	//事件触发后执行的方法
    public void ShowDamageText(int damageAmount)
    {
        damageText.text = damageAmount.ToString();
    }
}

注意:

  • 如果敌人向左右移动时的图片翻转用的是设置Sclae的方法,那么这里伤害数字也会跟着翻转,可以通过设置SpriteRenderer组件中的 flipX 属性来实现翻转,就能避免此问题

  • 在敌人对象销毁时,记得解绑事件

if (movementVector.x != 0)//反转人物图片
        {
            if (movementVector.x < 0)
            {
                sp.flipX = true; //用sprite renderer来翻转图片,用localScale的话,其子物体伤害信息也会跟着翻转
            }
            else
            {
                sp.flipX = false;
            }
        }
private void OnDisable()
    {
        //解绑事件
        if(EventEnemyHurt!=null)
        {
            foreach (var item in EventEnemyHurt.GetInvocationList())
            {
                EventEnemyHurt -= item as DelEnemyHurt;
                //EventEnemyHurt为事件,DelEnemyHurt为委托
            }
        }
    }

上一篇
下一篇