您当前的位置: 首页 >  unity

幻世界

暂无认证

  • 0浏览

    0关注

    237博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Unity开发小技巧】玩家引导遮罩,聚焦效果

幻世界 发布时间:2019-06-03 10:21:55 ,浏览量:0

欢迎加入Unity业内qq交流群:956187480

 

GUidance.unitypackage_unity新手引导-Unity3D代码类资源-CSDN下载

就新手引导来讲表现方式目前有很多种,有用特殊标识(手指,指向标等)醒目的东西引导新手的注意力,并进行下去。但在实际制作中,我们要定位到确切的ui控件需要玩家按照指示操作,此时常规的做法就是用遮罩面板遮挡全部ui层,然后复制目标ui设置显示层级。这个方案虽然很简单方便,但是在UI的界面逻辑上造成了很多遗留问题。另外一个方案就是目前市面上比较流行的方案,用动态的遮罩shader直接覆盖效果如上图。参考Siki学院。

实现:

需要的三个控制脚本:

圆形UI:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// 
/// 圆形遮罩镂空引导
/// 
public class CircleGuidanceController : MonoBehaviour
{
	/// 
	/// 要高亮显示的目标
	/// 
	public Image Target;
	
	/// 
	/// 区域范围缓存
	/// 
	private Vector3[] _corners = new Vector3[4];

	/// 
	/// 镂空区域圆心
	/// 
	private Vector4 _center;

	/// 
	/// 镂空区域半径
	/// 
	private float _radius;

	/// 
	/// 遮罩材质
	/// 
	private Material _material;

	/// 
	/// 当前高亮区域的半径
	/// 
	private float _currentRadius;

	/// 
	/// 高亮区域缩放的动画时间
	/// 
	private float _shrinkTime = 0.5f;

	/// 
	/// 世界坐标向画布坐标转换
	/// 
	/// 画布
	/// 世界坐标
	/// 返回画布上的二维坐标
	private Vector2 WorldToCanvasPos(Canvas canvas, Vector3 world)
	{
		Vector2 position;

		RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform,
			world, canvas.GetComponent(), out position);
		return position;
	}

	private void Awake()
	{
		//获取画布
		Canvas canvas = GameObject.Find("Canvas").GetComponent();
		//获取高亮区域的四个顶点的世界坐标
		Target.rectTransform.GetWorldCorners(_corners);
		//计算最终高亮显示区域的半径
		_radius = Vector2.Distance(WorldToCanvasPos(canvas, _corners[0]), WorldToCanvasPos(canvas, _corners[2])) / 2f;
		//计算高亮显示区域的圆心
		float x = _corners[0].x + ((_corners[3].x - _corners[0].x) / 2f);
		float y = _corners[0].y + ((_corners[1].y - _corners[0].y) / 2f);
		Vector3 centerWorld = new Vector3(x,y,0);
		Vector2 center = WorldToCanvasPos(canvas, centerWorld);
		//设置遮罩材料中的圆心变量
		Vector4 centerMat = new Vector4(center.x,center.y,0,0);
		_material = GetComponent().material;
		_material.SetVector("_Center",centerMat);
		//计算当前高亮显示区域的半径
		RectTransform canRectTransform = canvas.transform as RectTransform;
		if (canRectTransform != null)
		{
			//获取画布区域的四个顶点
			canRectTransform.GetWorldCorners(_corners);
			//将画布顶点距离高亮区域中心最远的距离作为当前高亮区域半径的初始值
			foreach (Vector3 corner in _corners)
			{
				_currentRadius = Mathf.Max(Vector3.Distance(WorldToCanvasPos(canvas, corner), center), _currentRadius);
			}
		}
		_material.SetFloat("_Slider", _currentRadius);
	}

	/// 
	/// 收缩速度
	/// 
	private float _shrinkVelocity = 0f;

	private void Update()
	{
		//从当前半径到目标半径差值显示收缩动画
		float value = Mathf.SmoothDamp(_currentRadius, _radius, ref _shrinkVelocity, _shrinkTime);
		if (!Mathf.Approximately(value, _currentRadius))
		{
			_currentRadius = value;
			_material.SetFloat("_Slider", _currentRadius);
		}
	}
}

方形ui:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// 
/// 矩形引导组件
/// 
public class RectGuidanceController : MonoBehaviour
{

	/// 
	/// 高亮显示的目标
	/// 
	public Image Target;
	
	/// 
	/// 区域范围缓存
	/// 
	private Vector3[] _corners = new Vector3[4];

	/// 
	/// 镂空区域中心
	/// 
	private Vector4 _center;

	/// 
	/// 最终的偏移值X
	/// 
	private float _targetOffsetX = 0f;

	/// 
	/// 最终的偏移值Y
	/// 
	private float _targetOffsetY = 0f;

	/// 
	/// 遮罩材质
	/// 
	private Material _material;
	
	/// 
	/// 当前的偏移值X
	/// 
	private float _currentOffsetX = 0f;

	/// 
	/// 当前的偏移值Y
	/// 
	private float _currentOffsetY = 0f;

	/// 
	/// 动画收缩时间
	/// 
	private float _shrinkTime = 0.5f;

	/// 
	/// 时间渗透组件
	/// 
	private GuidanceEventPenetrate _eventPenetrate;

	/// 
	/// 世界坐标到画布坐标的转换
	/// 
	/// 画布
	/// 世界坐标
	/// 转换后在画布的坐标
	private Vector2 WorldToCanvasPos(Canvas canvas, Vector3 world)
	{
		Vector2 position;
		RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, world,
			canvas.GetComponent(), out position);
		return position;
	}

	private void Awake()
	{
		_eventPenetrate = GetComponent();
		if(_eventPenetrate != null)
			_eventPenetrate.SetTargetImage(Target);
		//获取画布
		Canvas canvas = GameObject.Find("Canvas").GetComponent();
		//获取高亮区域四个顶点的世界坐标
		Target.rectTransform.GetWorldCorners(_corners);
		//计算高亮显示区域咋画布中的范围
		_targetOffsetX = Vector2.Distance(WorldToCanvasPos(canvas, _corners[0]), WorldToCanvasPos(canvas, _corners[3])) / 2f;
		_targetOffsetY = Vector2.Distance(WorldToCanvasPos(canvas, _corners[0]), WorldToCanvasPos(canvas, _corners[1])) / 2f;
		//计算高亮显示区域的中心
		float x = _corners[0].x + ((_corners[3].x - _corners[0].x) / 2f);
		float y = _corners[0].y + ((_corners[1].y - _corners[0].y) / 2f);
		Vector3 centerWorld = new Vector3(x,y,0);
		Vector2 center = WorldToCanvasPos(canvas, centerWorld);
		//设置遮罩材料中中心变量
		Vector4 centerMat = new Vector4(center.x,center.y,0,0);
		_material = GetComponent().material;
		_material.SetVector("_Center",centerMat);
		//计算当前偏移的初始值
		RectTransform canvasRectTransform = (canvas.transform as RectTransform);
		if (canvasRectTransform != null)
		{
			//获取画布区域的四个顶点
			canvasRectTransform.GetWorldCorners(_corners);
			//求偏移初始值
			for (int i = 0; i < _corners.Length; i++)
			{
				if (i % 2 == 0)
					_currentOffsetX = Mathf.Max(Vector3.Distance(WorldToCanvasPos(canvas, _corners[i]), center), _currentOffsetX);
				else
					_currentOffsetY = Mathf.Max(Vector3.Distance(WorldToCanvasPos(canvas, _corners[i]), center), _currentOffsetY);
			}
		}
		//设置遮罩材质中当前偏移的变量
		_material.SetFloat("_SliderX",_currentOffsetX);
		_material.SetFloat("_SliderY",_currentOffsetY);
	}

	private float _shrinkVelocityX = 0f;
	private float _shrinkVelocityY = 0f;

	private void Update()
	{
		//从当前偏移值到目标偏移值差值显示收缩动画
		float valueX = Mathf.SmoothDamp(_currentOffsetX, _targetOffsetX, ref _shrinkVelocityX, _shrinkTime);
		float valueY = Mathf.SmoothDamp(_currentOffsetY, _targetOffsetY, ref _shrinkVelocityY, _shrinkTime);
		if (!Mathf.Approximately(valueX, _currentOffsetX))
		{
			_currentOffsetX = valueX;
			_material.SetFloat("_SliderX",_currentOffsetX);
		}

		if (!Mathf.Approximately(valueY, _currentOffsetY))
		{
			_currentOffsetY = valueY;
			_material.SetFloat("_SliderY",_currentOffsetY);
		}
	}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GuidanceEventPenetrate : MonoBehaviour, ICanvasRaycastFilter
{
	private Image _targetImage;

	public void SetTargetImage(Image target)
	{
		_targetImage = target;
	}
	public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
	{
		if (_targetImage == null)
			return true;

		return !RectTransformUtility.RectangleContainsScreenPoint(_targetImage.rectTransform, sp, eventCamera);
	}
}

还有另外两个shader在资源包里面 :GUidance.unitypackage_unity新手引导-Unity3D代码类资源-CSDN下载

欢迎加入Unity业内qq交流群:956187480

qq扫描二维码加群

关注
打赏
1660704426
查看更多评论
立即登录/注册

微信扫码登录

0.0419s