理解(利用遮罩层来实现 不亮的区域全部被遮罩且无法点击 亮的区域仅可被点击)
红色的的是红点(红点下期再讲)
如图:仅仅只能点击亮的区域 将凉的区域拖拽到装备区域才可进行下一步点击 否则就会继续上一次的新手引导 直到点击争取才可
这个是拖拽中 装备跟随鼠标移动
拖拽到左侧区域才可进行下一步引导 否则继续上一步引导
新手引导完毕需要记录,以免下一次打开还会打开新手引导界面
新手引导其实就是一个界面 所以需要的时候直接打开这个UI即可
具体的是在C#中实现的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NewGuide : MonoBehaviour,ICanvasRaycastFilter
{
Canvas canvas;
Material material;
Vector3[] corners = new Vector3[4];
float current;
float radius;
float maskType = 0;
Vector4 center;
//List<float> config = new List<float>()
//{
// 0,0,1,350f,200f
//};
public void StartGuide(List<float> config)
{
canvas = GameObject.Find("TopLayer").GetComponent<Canvas>();
maskType = config[0];
if (maskType==0)
{
SetCirclGuideMask(config);
}
else
{
SetRectangleGuideMask(config);
}
}
void SetCirclGuideMask(List<float> config)
{
Vector3 position = new Vector3(config[1], config[2], config[3]);
float w = config[4];
float h = config[5];
//半径
radius = Mathf.Sqrt(w * w + h * h) / 2;
Vector3 uiPos = WorldToCanvasPos(canvas, position);
center = new Vector4(uiPos.x, uiPos.y, 0f, 0f);
material = GetComponent<Image>().material;
material.SetVector("_Center", center);
//material.SetFloat("_Radius", radius);
material.SetFloat("_MaskType", config[0]);
(canvas.transform as RectTransform).GetWorldCorners(corners);
for (int i = 0; i < corners.Length; i++)
{
current = Mathf.Max(Vector3.Distance(WorldToCanvasPos(canvas, corners[i]), center), current);
}
material.SetFloat("_Radius", current);
}
Vector3 bottomLeft, topRight, bottomLeftMax, topRightMax;
private void SetRectangleGuideMask(List<float> config)
{
Vector3 position = new Vector3(config[1], config[2], config[3]);
Vector3 uiPos = WorldToCanvasPos(canvas, position);
bottomLeft = new Vector2(uiPos.x - config[4] / 2, uiPos.y - config[5] / 2);
topRight = new Vector2(uiPos.x + config[4] / 2, uiPos.y + config[5] / 2);
if (material==null)
{
material = GetComponent<Image>().material;
if (material==null)
{
Debug.LogError("null");
return;
}
}
(canvas.transform as RectTransform).GetWorldCorners(corners);
bottomLeftMax = WorldToCanvasPos(canvas, corners[0]);
topRightMax = WorldToCanvasPos(canvas, corners[2]);
material.SetVector("_Rectangle", new Vector4(bottomLeftMax.x, bottomLeftMax.y, topRightMax.x, topRightMax.y));
material.SetFloat("_MaskType", config[0]);
}
float yVelocity = 0f;
Vector2 yVelocityLeft;
Vector2 yVelocityRight;
void Update()
{
if (maskType==0)
{
float value = Mathf.SmoothDamp(current, radius, ref yVelocity, 0.3f);
if (!Mathf.Approximately(value, current))
{
current = value;
material.SetFloat("_Radius", current);
}
}
else
{
Vector2 value = Vector2.SmoothDamp(bottomLeftMax, bottomLeft, ref yVelocityLeft, 0.3f);
Vector2 value1 = Vector2.SmoothDamp(topRightMax, topRight, ref yVelocityRight, 0.3f);
bottomLeftMax = value;
topRightMax = value1;
material.SetVector("_Rectangle", new Vector4(bottomLeftMax.x-10, bottomLeftMax.y-10, topRightMax.x+10, topRightMax.y+10));
}
}
//坐标转换
Vector2 WorldToCanvasPos(Canvas canvas, Vector3 world)
{
Vector2 position = Vector2.zero;
Vector3 screenPoint = canvas.worldCamera.WorldToScreenPoint(world);
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, new Vector2(screenPoint.x, screenPoint.y),
canvas.worldCamera, out position);
return position;
}
public bool IsRaycastLocationValid(Vector2 sp,Camera eventCamera)
{
if (canvas==null)
{
return true;
}
Vector2 uipos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform
, sp, canvas.worldCamera, out uipos);
if (this.maskType==0)
{
if ((uipos.x-center.x)*(uipos.x- center.y) +(uipos.y- center.x) *(uipos.y- center.y) <=radius*radius)
{
return false;
}
}
else
{
if ((bottomLeft.x<=uipos.x && uipos.x<=topRight.x) && (bottomLeft.y<=uipos.y && uipos.y<=topRight.y))
{
return false;
}
}
return true;
}
}
此外还学借助shader
//以下是shader代码
Shader "UI/GuideMask"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
//-------------------add----------------------
_Center("Center", vector) = (0, 0, 0, 0)
_Silder ("_Silder", Range (0,1000)) = 1000 // sliders
//-------------------add----------------------
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
//-------------------add----------------------
float _Silder;
float2 _Center;
//-------------------add----------------------
v2f vert(appdata_t IN)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = IN.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
return OUT;
}
sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
//-------------------add----------------------
color.a*=(distance(IN.worldPosition.xy,_Center.xy) > _Silder);
color.rgb*= color.a;
//-------------------add----------------------
return color;
}
ENDCG
}
}
}
简单拖拽穿脱装备(是拖拽还是滑动的问题)
local Item=BaseClass("Item",UIWrapComponent)
local base=UIWrapComponent
--时间变量
local t=0
local function IsEquip(self)
if self.itemData==nil then
return false
else
if self.itemData.goodsType==1 then
return true
else
return false
end
end
end
local function OnCreate(self)
base.OnCreate(self)
self.icon=self:AddComponent(UIImage,"Icon",AtlasConfig.Goods)
self.numText=self:AddComponent(UIText,"Icon/Num")
self.nameText=self:AddComponent(UIText,"Icon/Name")
self.drag=self:AddComponent(UIPointerDrag,"Icon")
self.downUp=self:AddComponent(UIPointerDownUp,"Icon")
self.redImg=self:AddComponent(UIImage,"Red")
self.downUp:SetOnDown(function ()
self.isDown=true
self.mousePositionY=Input.mousePosition.y
self.isDrag=false
t=0
DataManager:GetInstance():Broadcast("TriggerGuide",101,1)
end)
--开始拖拽
self.drag:SetOnBeginDrag(function (eventData)
self.sv:OnBeginDrag(eventData)
if not IsEquip(self) then
return
end
self.icon:SetRayCastTarget(false)
self.pos=self.icon.transform.localPosition
self.startParent=self.icon.transform.parent
self.curparent=GameObject.Find("GameLuach/UIRoot/TopLayer").transform
self.icon.transform.parent=self.curparent
end)
--拖拽中
self.drag:SetOnDrag(function (eventData)
if self.isDrag then
if not IsEquip(self) then
return
end
local flag,uipos=RectTransformUtility.ScreenPointToLocalPointInRectangle(self.icon.transform.parent:GetComponent(typeof(RectTransform)),
Vector2(Input.mousePosition.x,Input.mousePosition.y),
self.icon.transform.parent:GetComponent(typeof(Canvas)).worldCamera)
if flag then
self.icon.transform.localPosition=Vector3(uipos.x,uipos.y,0)
end
else
--归位
self.icon.transform:SetParent(self.transform)
self.icon.transform.localPosition=Vector3.zero
self.icon:SetRayCastTarget(true)
self.sv:OnDrag(eventData)
end
end)
--[[1=系统广播
equipType:int#装备类型
1=头盔(head)
2=铠甲(upbody)
3=鞋子(downbody)
4=项链(neck)
5=护腕(hand)
6=戒指(finger)
7=主武器(weapon01)
8=法宝]]
self.drag:SetOnEndDrag(function (eventData)
self.sv:OnEndDrag(eventData)
if not IsEquip(self) then
DataManager:GetInstance():Broadcast("TriggerGuide",101,-1)
return
end
--归位
self.icon.transform:SetParent(self.transform)
self.icon.transform.localPosition=Vector3.zero
self.icon.transform.localEulerAngles=Vector3.zone
self.icon.transform.localScale=Vector3.one
self.icon:SetRayCastTarget(true)
if eventData.pointerCurrentRaycast.gameObject==nil then
DataManager:GetInstance():Broadcast("TriggerGuide",101,-1)
return
end
local str=eventData.pointerCurrentRaycast.gameObject.name
local tag=eventData.pointerCurrentRaycast.gameObject.tag
local equipType=tonumber(str)
if tag=="EquipItem" then
--职业
local needJob=LangUtil.GetEquipById(self.itemData.equipmentId).needJob
if needJob==GameMain.career then
if equipType==self.equipData.equipType then
local msgId=MsgIDDefine.EQUIPMENT_C_PUTONEQUIPMENT
local msg={}
msg.playerEquipmentId=self.equipData.playerEquipmentId
HallConnector:GetInstance():SendMessage(msgId,msg)
DataManager:GetInstance():Broadcast("TriggerGuide",101,1)
else
DataManager:GetInstance():Broadcast("unwearableSendBagModel","装备类型不匹配")
DataManager:GetInstance():Broadcast("TriggerGuide",101,-1)
end
else
DataManager:GetInstance():Broadcast("unwearableSendBagModel","装备职业类型不符合")
DataManager:GetInstance():Broadcast("TriggerGuide",101,-1)
end
else
DataManager:GetInstance():Broadcast("TriggerGuide",101,-1)
end
end)
end
local function Refresh(self,data,equipData,sv)
self.itemData=data
self.equipData=equipData
self.sv=sv
if data==nil then
self.icon:SetSpriteName("Bag格子.png")
self.numText:SetText("")
self.nameText:SetText("")
self.redImg:SetActive(false)
else
local itemData=nil
if self.itemData.goodsType==1 then
itemData=LangUtil.GetEquipById(self.itemData.equipmentId)
else
itemData=LangUtil.GetItemById(self.itemData.itemId)
end
if itemData~=nil then
self.icon:SetSpriteName(itemData.icon..".png")
self.nameText:SetText(itemData.name)
self.numText:SetText("数量:"..data.num)
self.numText:SetColor(Color.red)
print(self.itemData.isRed)
if self.itemData.isRed==true then
self.redImg:SetActive(true)
else
self.redImg:SetActive(false)
end
else
print(self.itemData.equipmentId.."装备".."格子"..self.transform.gameObject.name)
print(self.itemData.itemId.."Item")
self.icon:SetSpriteName("Bag格子.png")
self.numText:SetText("")
self.nameText:SetText("")
self.redImg:SetActive(false)
end
end
end
local function Update(self)
if not self.isDown then
return
end
t=t+Time.deltaTime
if t<=0.3 then
if Mathf.Abs(Input.mousePosition.y-self.mousePositionY)>=10 then
self.isDrag=false
self.isDown=false
end
else
if self.itemData==nil then
self.isDrag=false
else
if self.itemData.goodsType==1 then
self.isDrag=true
else
self.isDrag=false
end
end
self.isDown=false
end
end
Item.OnCreate=OnCreate
Item.Refresh=Refresh
Item.Update=Update
return Item