【游戏】UI层粒子特效存在的问题及解决方案
一,UI层粒子特效存在的问题
1.粒子特效的裁剪问题。某种滑动出滚动列表后被裁剪
2.粒子特效与UI元素之间的层级问题。能够被某些UI元素遮盖,或夹在某些UI元素之间
3.粒子特效的适应问题。在不同分辨率下粒子特效不能像UI一样自动适应
这些问题所有人都遇到过,解决方案也是多种多样,本博客提出一个统一的解决方案,能够同时解决以上3个问题。
二,解决方案
自己实现一套UI层的粒子系统,即粒子系统发射的每个粒子都是一个UI元素,这样就可以不用做任何事情,以上问题就可以迎刃而解。
废话不多说,直接上代码:
使用UnityEngine;
使用UnityEngine.UI;
/// <summary>
///由ggr在2018/07/30添加
//// UI层的粒子特效,能解决的问题:
/// 1,粒子特效在滚动列表区外裁剪
//// 2,粒子特效层级调整,即可以在夹在任意两个UI元素之间
/// 3,不同分辨率的适应
/// /使用:
///主要是特效的美术人员使用。///
1,在粒子系统的物体上挂上这个脚本
/// 2,此时会替换和清空粒子系统的渲染器模块
/// 3,把材质球拖到脚本上的材质顶部上
/// </ summary>
[ExecuteInEditMode ]
[RequireComponent(typeof(CanvasRenderer),typeof(ParticleSystem))]公共类UIParticleSystem:MaskableGraphic {[Tooltip(“勾上这个,会把粒子系统放在LateUpdate里运行”)] public bool fixedTime = true; [Range(1,60)] public int maxParticleCount = 15;
private Transform _transform;
专用ParticleSystem pSystem;
私有ParticleSystem.Particle []粒子;
私有UIVertex [] _quad =新的UIVertex [4];
私有Vector4 imageUV = Vector4.zero;
私有ParticleSystem.TextureSheetAnimationModule textureSheetAnimation;
私人诠释textureSheetAnimationFrames;
私有Vector2 textureSheetAnimationFrameSize;
专用的ParticleSystemRenderer pRenderer;
私人物质当前材料;
private Texture currentTexture;
私有ParticleSystem.MainModule mainModule;
公共重写Texture mainTexture {
get {
return currentTexture;
}
}
受保护的布尔Initialize(){
如果(_transform == null){_
transform =变换;
}
if(pSystem == null){
pSystem = GetComponent <ParticleSystem>();
if(pSystem == null){
返回false;
}
mainModule = pSystem.main;
如果(pSystem.main.maxParticles> maxParticleCount){
mainModule.maxParticles = maxParticleCount;
}
pRenderer = pSystem.GetComponent <ParticleSystemRenderer>();
如果(pRenderer!= null){
pRenderer.material = null;
pRenderer.enabled = false;
}
currentMaterial =材料;
如果(currentMaterial && currentMaterial.HasProperty(“ _ MainTex”)){
currentTexture = currentMaterial.mainTexture;
如果(currentTexture == null)currentTexture = Texture2D.whiteTexture;
}
material = currentMaterial;
mainModule.scalingMode = ParticleSystemScalingMode.Hierarchy;
粒子= null;
}
如果(粒子==空)粒子=新的ParticleSystem.Particle [pSystem.main.maxParticles];
imageUV =新的Vector4(0,0,1,1);
textureSheetAnimation = pSystem.textureSheetAnimation;
textureSheetAnimationFrames = 0;
textureSheetAnimationFrameSize = Vector2.zero;
如果(textureSheetAnimation.enabled){
textureSheetAnimationFrames = textureSheetAnimation.numTilesX * textureSheetAnimation.numTilesY;
textureSheetAnimationFrameSize = new Vector2(1f / textureSheetAnimation.numTilesX,1f / textureSheetAnimation.numTilesY);
}
返回true;
}
受保护的重写void Awake(){
base.Awake();
如果(!Initialize())enabled = false;
raycastTarget = false;
}
受保护的重写void OnPopulateMesh(VertexHelper vh){#
如果为UNITY_EDITOR,
如果(!Application.isPlaying){
如果(!Initialize()){
返回;
}
} #ENDIF
vh.Clear();
如果(!gameObject.activeInHierarchy){
返回;
}
Vector2 temp = Vector2.zero;
Vector2 corner1 = Vector2.zero;
Vector2 corner2 = Vector2.zero;
int count = pSystem.GetParticles(particles);
for(int i = 0; i <count; i){
粒子系统。粒子粒子=粒子[i];
Vector2位置=(mainModule.simulationSpace == ParticleSystemSimulationSpace.Local?Particle.position:_transform.InverseTransformPoint(particle.position));
浮点旋转= -particle.rotation * Mathf.Deg2Rad;
浮点旋转90 =旋转Mathf.PI / 2;
Color32 color =粒子.GetCurrentColor(pSystem);
浮点尺寸=粒子.GetCurrentSize(pSystem)* 0.5f;
如果(mainModule.scalingMode == ParticleSystemScalingMode.Shape)position / = canvas.scaleFactor;
Vector4粒子UV =图像UV;
如果(textureSheetAnimation.enabled){
float frameProgress = 1-(particle.remainingLifetime / particle.startLifetime);
如果(textureSheetAnimation.frameOverTime.curveMin!= null){
frameProgress = textureSheetAnimation.frameOverTime.curveMin.Evaluate(1-(particle.remainingLifetime / particle.startLifetime));
}否则if(textureSheetAnimation.frameOverTime.curve!= null){
frameProgress = textureSheetAnimation.frameOverTime.curve.Evaluate(1-(particle.remainingLifetime / particle.startLifetime));;
}否则if(textureSheetAnimation.frameOverTime.constant> 0){
frameProgress = textureSheetAnimation.frameOverTime.constant-(particle.remainingLifetime / particle.startLifetime);
}
frameProgress = Mathf.Repeat(frameProgress * textureSheetAnimation.cycleCount,1);
int帧= 0;
开关(textureSheetAnimation.animation){
案例ParticleSystemAnimationType.WholeSheet:
frame = Mathf.FloorToInt(frameProgress * textureSheetAnimationFrames);
休息;
案例ParticleSystemAnimationType.SingleRow:
frame = Mathf.FloorToInt(frameProgress * textureSheetAnimation.numTilesX);
int row = textureSheetAnimation.rowIndex;
框架=行* textureSheetAnimation.numTilesX;
休息;
}
框架%= textureSheetAnimationFrames;
particleUV.x =(帧%textureSheetAnimation.numTilesX)* textureSheetAnimationFrameSize.x;
particleUV.y = Mathf.FloorToInt(frame / textureSheetAnimation.numTilesX)* textureSheetAnimationFrameSize.y;
particleUV.z =粒子UV.x textureSheetAnimationFrameSize.x;
particleUV.w =粒子UV.y textureSheetAnimationFrameSize.y;
}
temp.x =粒子UV.x;
temp.y =粒子UV.y;
_quad [0] = UIVertex.simpleVert;
_quad [0] .color =颜色;
_quad [0] .uv0 = temp;
temp.x =粒子UV.x;
temp.y =粒子UV.w;
_quad [1] = UIVertex.simpleVert;
_quad [1] .color =颜色;
_quad [1] .uv0 = temp;
temp.x =粒子UV.z;
temp.y =粒子UV.w;
_quad [2] = UIVertex.simpleVert;
_quad [2] .color =颜色;
_quad [2] .uv0 = temp;
temp.x =粒子UV.z;
temp.y =粒子UV.y;
_quad [3] = UIVertex.simpleVert;
_quad [3] .color =颜色;
_quad [3] .uv0 = temp;
if(rotation == 0){
corner1.x = position.x-大小;
corner1.y = position.y-大小;
corner2.x = position.x大小;
corner2.y = position.y大小;
temp.x = corner1.x;
temp.y = corner1.y;
_quad [0] .position = temp;
temp.x = corner1.x;
temp.y = corner2.y;
_quad [1] .position = temp;
temp.x = corner2.x;
temp.y = corner2.y;
_quad [2] .position = temp;
temp.x = corner2.x;
temp.y = corner1.y;
_quad [3] .position = temp;
} 别的 {
右边的Vector2 =新的Vector2(Mathf.Cos(旋转),Mathf.Sin(旋转))*大小;
Vector2 up =新Vector2(Mathf.Cos(rotation90),Mathf.Sin(rotation90))*大小;
_quad [0] .position =位置-右-上;
_quad [1] .position =位置-右上;
_quad [2] .position =右上角的位置;
_quad [3] .position =位置右-向上;
}
vh.AddUIVertexQuad(_quad);
}
}
void Update(){
if(!fixedTime && Application.isPlaying){
pSystem.Simulate(Time.unscaledDeltaTime,false,false,true);
SetAllDirty();
if(((currentMaterial!= null && currentTexture!= currentMaterial.mainTexture)||(material!= null && currentMaterial!= null && material.shader!= currentMaterial.shader)){
pSystem = null;
初始化();
}
}
}
void LateUpdate(){
如果(!Application.isPlaying){
SetAllDirty();
} else {
if(fixedTime){
pSystem.Simulate(Time.unscaledDeltaTime,false,false,true);
SetAllDirty();
if(((currentMaterial!= null && currentTexture!= currentMaterial.mainTexture)||(material!= null && currentMaterial!= null && material.shader!= currentMaterial.shader)){
pSystem = null;
初始化();
}
}
}
如果(材料== currentMaterial)回报;
pSystem = null;
初始化();
}
}
还需要一个shader,这里我就直接拿的UI Default的shader,只是混合公式我改变成Blend SrcAlpha one,即粒子的重叠模式
代码:
着色器“ 17zuoye / UI粒子添加剂” {
属性{
_MainTex(“ Sprite Texture”,2D)=“ white” {}
_Color(“ Tint”,Color)=(0.5,0.5,0.5,0.5)
_StencilComp(“模板比较”,浮点数)= 8 _Stencil(“模板ID”,浮点数)= 0 _StencilOp(“模板操作”,浮点数)= 0 _StencilWriteMask(“模板写屏蔽”,浮点数)= 255 _StencilReadMask(“ S掩码”,浮点数)= 255
_ColorMask(“ Color Mask”,Float)= 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip(“使用Alpha剪辑”,浮动)= 0
}
SubShader {
标签{
“ Queue” =“ Transparent”“ IgnoreProjector” =“ True”“ RenderType” =“ Transparent”“ PreviewType” =“平面”“ CanUseSpriteAtlas” =“ True”
}
模具{
Ref [_Stencil] Comp [_StencilComp] Pass [_StencilOp] ReadMask [_StencilReadMask] WriteMask [_StencilWriteMask]
}
取消照明关闭ZWrite Off ZTest [unity_GUIZTestMode]混合SrcAlpha一种ColorMask [_ColorMask]
传递{
名称“默认” CGPROGRAM#pragma顶点vert#pragma片段frag#pragma目标2.0
#include“ UnityCG.cginc” #include“ UnityUI.cginc” // 2D Mask剪裁。
#pragma multi_compile __ UNITY_UI_CLIP_RECT#pragma multi_compile __ UNITY_UI_ALPHACLIP
struct appdata_t {
float4顶点:POSITION float4颜色:COLOR float2 texcoord:TEXCOORD0 UNITY_VERTEX_INPUT_INSTANCE_ID
}
struct v2f {
float4顶点:SV_POSITION fixed4颜色:COLOR float2 texcoord:TEXCOORD0 float4 worldPosition:TEXCOORD1 UNITY_VERTEX_OUTPUT_STEREO
}
fixed4 _Color fixed4 _TextureSampleAdd float4 _ClipRect
v2f vert(appdata_t v){
v2f OUT UNITY_SETUP_INSTANCE_ID(v)UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT)OUT.worldPosition = v.vertex OUT.vertex = UnityObjectToClipPos(OUT.worldPosition)
OUT.texcoord = v.texcoord
OUT.color = v.color
return OUT
}
sampler2D _MainTex
fixed4 frag(v2f IN):SV_Target {
fixed4 albedo = tex2D(_MainTex,IN.texcoord)
fixed4 color = 2.0f * IN.color * _Color * albedo#ifdef UNITY_UI_CLIP_RECT color.a * = UnityGet2DClipping(IN.worldPosition.xy,_ClipRect)#endif
#ifdef UNITY_UI_ALPHACLIP剪辑(color.a-0.001)#endif
返回颜色
}
ENDCG
}
}
}
三,验证
1,裁剪
2,层级
3,适应
四,使用
转载声明:本文涉及网络,不作任何商业用途。
全部评论
暂无留言,赶紧抢占沙发