Unity 新手引导
根据Shader动态生成遮罩

圆形遮罩镂空处理脚本:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; /// <summary>
/// 圆形遮罩镂空
/// </summary>
public class CircleGuidance : MonoBehaviour
{
public static CircleGuidance instance;
/// <summary>
/// 高亮显示目标
/// </summary>
public Image target;
/// <summary>
/// 区域范围缓存
/// </summary>
private Vector3[] corners = new Vector3[];
/// <summary>
/// 镂空区域中心
/// </summary>
private Vector4 center;
/// <summary>
/// 镂空区域半径
/// </summary>
private float radius;
/// <summary>
/// 遮罩材质
/// </summary>
private Material material;
/// <summary>
/// 当前高亮区域半径
/// </summary>
private float currentRadius;
/// <summary>
/// 高亮区域缩放的动画时间
/// </summary>
private float shrinkTime = 0.5f;
/// <summary>
/// 事件渗透组件
/// </summary>
private GuidanceEventPenetrate eventPenetrate;
private void Awake()
{
instance = this;
}
public void Init(Image target)
{
this.target = target;
eventPenetrate = GetComponent<GuidanceEventPenetrate>();
if (eventPenetrate != null)
{
eventPenetrate.SetTargetImage(target);
}
Canvas canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
//获取高亮区域的四个顶点的世界坐标
target.rectTransform.GetWorldCorners(corners);
//计算最终高亮显示区域的半径
radius = Vector2.Distance(WorldToCanvasPos(canvas, corners[]), WorldToCanvasPos(canvas, corners[])) / ;
//计算高亮显示区域的中心
float x = corners[].x + ((corners[].x - corners[].x) / );
float y = corners[].y + ((corners[].y - corners[].y) / );
Vector3 centerWorld = new Vector3(x, y, );
Vector2 center = WorldToCanvasPos(canvas, centerWorld);
//设置遮罩材质中的中心变量
Vector4 centerMat = new Vector4(center.x, center.y, , );
material = GetComponent<Image>().material;
material.SetVector("_Center", centerMat);
//计算当前高亮显示区域的半径
RectTransform canRectTransform = canvas.transform as RectTransform;
if (canRectTransform != null)
{
//获取画布区域的四个顶点
canRectTransform.GetWorldCorners(corners);
//将画布顶点距离高亮区域中心最近的距离昨晚当前高亮区域半径的初始值
foreach (var corner in corners)
{
currentRadius = Mathf.Max(Vector3.Distance(WorldToCanvasPos(canvas, corner), corner), currentRadius);
}
}
material.SetFloat("_Slider", currentRadius);
}
/// <summary>
/// 收缩速度
/// </summary>
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);
}
} /// <summary>
/// 世界坐标转换为画布坐标
/// </summary>
/// <param name="canvas">画布</param>
/// <param name="world">世界坐标</param>
/// <returns></returns>
private Vector2 WorldToCanvasPos(Canvas canvas, Vector3 world)
{
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, world, canvas.GetComponent<Camera>(), out position);
return position;
}
}
矩形遮罩镂空处理脚本:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; /// <summary>
/// 矩形遮罩镂空
/// </summary>
public class RectGuidance : MonoBehaviour
{
public static RectGuidance instance;
/// <summary>
/// 高亮显示目标
/// </summary>
public Image target;
/// <summary>
/// 区域范围缓存
/// </summary>
private Vector3[] corners = new Vector3[];
/// <summary>
/// 镂空区域中心
/// </summary>
private Vector4 center;
/// <summary>
/// 最终的偏移x
/// </summary>
private float targetOffsetX = ;
/// <summary>
/// 最终的偏移y
/// </summary>
private float targetOffsetY = ;
/// <summary>
/// 遮罩材质
/// </summary>
private Material material;
/// <summary>
/// 当前的偏移x
/// </summary>
private float currentOffsetX = 0f;
/// <summary>
/// 当前的偏移y
/// </summary>
private float currentOffsetY = 0f;
/// <summary>
/// 高亮区域缩放的动画时间
/// </summary>
private float shrinkTime = 0.5f;
/// <summary>
/// 事件渗透组件
/// </summary>
private GuidanceEventPenetrate eventPenetrate; private void Awake()
{
instance = this;
}
public void Init(Image target)
{
this.target = target;
eventPenetrate = GetComponent<GuidanceEventPenetrate>();
if (eventPenetrate != null)
{
eventPenetrate.SetTargetImage(target);
}
Canvas canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
//获取高亮区域的四个顶点的世界坐标
target.rectTransform.GetWorldCorners(corners);
//计算高亮显示区域在画布中的范围
targetOffsetX = Vector2.Distance(WorldToCanvasPos(canvas, corners[]), WorldToCanvasPos(canvas, corners[])) / 2f;
targetOffsetY = Vector2.Distance(WorldToCanvasPos(canvas, corners[]), WorldToCanvasPos(canvas, corners[])) / 2f;
//计算高亮显示区域的中心
float x = corners[].x + ((corners[].x - corners[].x) / );
float y = corners[].y + ((corners[].y - corners[].y) / );
Vector3 centerWorld = new Vector3(x, y, );
Vector2 center = WorldToCanvasPos(canvas, centerWorld);
//设置遮罩材质中的中心变量
Vector4 centerMat = new Vector4(center.x, center.y, , );
material = GetComponent<Image>().material;
material.SetVector("_Center", centerMat);
//计算当前高亮显示区域的半径
RectTransform canRectTransform = canvas.transform as RectTransform;
if (canRectTransform != null)
{
//获取画布区域的四个顶点
canRectTransform.GetWorldCorners(corners);
//计算偏移初始值
for (int i = ; i < corners.Length; i++)
{
if (i % == )
{
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);
}
/// <summary>
/// 收缩速度
/// </summary>
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);
}
} /// <summary>
/// 世界坐标转换为画布坐标
/// </summary>
/// <param name="canvas">画布</param>
/// <param name="world">世界坐标</param>
/// <returns></returns>
private Vector2 WorldToCanvasPos(Canvas canvas, Vector3 world)
{
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, world, canvas.GetComponent<Camera>(), out position);
return position;
}
}
新手引导管理脚本,通过此脚本管理遮罩跟引导步骤,动态添加按钮点击事件等:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; /// <summary>
/// 新手引导管理
/// </summary>
public class GuideManagers : MonoBehaviour
{
/// <summary>
/// 引导步骤数组(如:第一步-》第二步。。。。)
/// </summary>
public List<GuideUIList> guideList = new List<GuideUIList>();
/// <summary>
/// 当前数组索引
/// </summary>
private int currentIndex = ;
/// <summary>
/// 是否完成所有的新手引导
/// </summary>
private bool isFinish = false;
/// <summary>
/// 遮罩对象
/// </summary>
private GameObject maskPrefabs;
/// <summary>
///
/// </summary>
public void Next()
{
if (isFinish || currentIndex > guideList.Count)
{
return;
}
//注销上一步按钮点击事件
if (currentIndex != && guideList[currentIndex - ].go.GetComponent<EventTriggerListener>() != null)
{
EventTriggerListener.GetListener(guideList[currentIndex - ].go).onClick -= null;
} if (maskPrefabs == null)
{
maskPrefabs = Instantiate(Resources.Load<GameObject>("RectGuidance_Panel"), this.transform);
}
//初始化遮罩
maskPrefabs.GetComponent<RectGuidance>().Init(guideList[currentIndex].go.GetComponent<Image>()); ; currentIndex++;
//给当前按钮添加点击事件
if (currentIndex < guideList.Count)
{
EventTriggerListener.GetListener(guideList[currentIndex - ].go).onClick += (go) =>
{
Next();
};
}
//最后一个按钮点击事件处理
else if (currentIndex == guideList.Count)
{
EventTriggerListener.GetListener(guideList[currentIndex - ].go).onClick += (go) =>
{
maskPrefabs.gameObject.SetActive(false);
//注销最后一个按钮的点击事件
EventTriggerListener.GetListener(guideList[currentIndex - ].go).onClick -= null;
};
isFinish = true;
}
}
}
/// <summary>
/// 引导ui数组
/// </summary>
[Serializable]
public class GuideUIList
{
/// <summary>
/// 引导步骤对象
/// </summary>
public GameObject go; public GuideUIList(GameObject go)
{
this.go = go;
}
}
Unity 新手引导的更多相关文章
- Unity3D新手引导开发手记
最近开始接手新手引导的开发,记录下这块相关的心得 首先客户端是Unity,在接手前,前面的同学已经初步完成了新手引导框架的搭建,这套框架比较简单,有优点也有缺点,稍后一一点评 我们的新手引导是由一个个 ...
- NGUI的新手引导的实现
先声明一下,UNITY新手,如果说的有不对的地方,欢迎各位大神指正. 最近在项目需要实现新手引导,最基础的需求就是需要一个带黑色遮罩的引导UI,类似下图这种: 对,就是这么敷衍的UI,因为是我随手做的 ...
- 关于Unity中NGUI的Tab商城、Scrollview和打字机效果的实现
Tab商城实例 UIToggle 和 UIToggledObjects+ Box Collider(实现商城功能必备) 1.创建两个个UI Sprite,Sprite1和Sprite2 2.给Spri ...
- (转)Unity3D新手引导开发手记
转自:http://www.cnblogs.com/ybgame/p/3844315.html 最近开始接手新手引导的开发,记录下这块相关的心得 首先客户端是Unity,在接手前,前面的同学已经初步完 ...
- Unity 游戏框架:UI 管理神器 UI Kit
UI Kit 快速入门 首先我们来进行 UI Kit 的快速入门 制作一个界面的,步骤如下: 准备 生成代码 逻辑编写 运行 1. 准备 先创建一个场景 TestUIHomePanel. 删除 Hie ...
- Unity3d入门 - 关于unity工具的熟悉
上周由于工作内容较多,花在unity上学习的时间不多,但总归还是学习了一些东西,内容如下: .1 根据相关的教程在mac上安装了unity. .2 学习了unity的主要的工具分布和对应工具的相关的功 ...
- 聊聊Unity项目管理的那些事:Git-flow和Unity
0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了.敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理.项目从最初使用svn到之后的Git One Track策略再到现在的GitFlo ...
- Unity游戏内版本更新
最近研究了一下游戏内apk包更新的方法. ios对于应用的管理比较严格,除非热更新脚本,不太可能做到端内大版本包的更新.然而安卓端则没有此限制.因此可以做到不跳到网页或应用商店,就覆盖更新apk包. ...
- Unity 序列化
Script Serialization http://docs.unity3d.com/Manual/script-Serialization.html 自定义序列化及例子: http://docs ...
随机推荐
- python函数 | 列表生成式
在编写程序或者查看别人的程序时,经常会遇到列表生成式,这个使用起来并不复杂,但是非常有用,使我们的代码更加简洁灵活.很多python使用者并不太会使用它.今天,就给大家详细讲解列表生成式和生成器表达式 ...
- sqlg rdbms 上实现的Apache TinkerPop
sqlg 可以让关系型数据库支持Apache TinkerPop,当前支持的数据库有postgresql,hsqldb,h2,mariadb,mysql,mssqlserver 以下是一个简单的使用 ...
- Cloud-init原理
Ubuntu修改主机名后,重启自动恢复原来的主机名? 这是因为Ubuntu18.10上,默认安装并启动了cloud-init, 需要停止它的四个服务进程,才可以使用传统的方式修改主机名. cloud- ...
- PTES渗透测试执行标准
渗透测试注意事项: 1:测试一定要获得授权方才能进行,切勿进行恶意攻击 2:不要做傻事 3:在没有获得书面授权时,切勿攻击任何目标 4:考虑你的行为将会带来的后果 5:天网恢恢疏而不漏 渗透测试执行标 ...
- 【Beta】Scrum meeting 9
目录 写在前面 进度情况 任务进度表 Beta-1阶段燃尽图 遇到的困难 照片 commit记录截图 文档集合仓库 后端代码仓库 技术博客 写在前面 例会时间:5.13 22:30-22:45 例会地 ...
- BERT模型
BERT模型是什么 BERT的全称是Bidirectional Encoder Representation from Transformers,即双向Transformer的Encoder,因为de ...
- Learning to Track Any Object
Learning to Track Any Object 2019-10-28 12:14:49 Paper: https://arxiv.org/abs/1910.11844 1.
- 【maven】maven下载依赖jar的源码
mvn dependency:sourcesmvn dependency:resolve -Dclassifier=javadoc 命令使用方法:首先进入到相应的pom.xml目录中,然后执行以上命令 ...
- 【Linux】Linux环境变量的设置和查看
Linux的变量种类 按变量的生存周期来划分,Linux变量可分为两类: 1 永久的:需要修改配置文件,变量永久生效. 2 临时的:使用export命令声明即可,变量在关闭shell时失效. 设置变量 ...
- tensorflow keras analysis
目录 Q: where is Sequential defined? Q: where is compile()? tensorflow keras analysis code from keras. ...