Unity2d 遮蔽系统增强--画家算法实现
背景
为什么要使用遮蔽系统,主要的目的是在场景中很好的还原人类视觉认知的真实场景,当然2d游戏中不存在远小近大的,光线几何透视效果,但是近处物体遮挡远处物体的基本物理特性还是要实现的。这可能让人联想起3d场景的画家算法。
2d物体的遮挡顺序一样可以使用画家算法,该算法原理简单描述就是近物遮挡远物,幸运的是在Unity2d中,我们也可以很方便的只要动态更新(一个对象的Z属性)=(它的Y属性)即可以巧妙的实现此效果,是不是有点邪恶?嘿嘿。所以要将遮盖物的Z置得足够大以防止任何一个物体它的Y属性大过遮盖物的Z属性。
说实话当时自己学习这块的时候,也有些看似懂了,过了段时间还是蒙的感觉,后来自己动手用Unity显示了一遍,才彻底明白。我们先看下遮蔽的效果,
是不是还是很逼真的。
我们再通过两张图片来揭秘实现的核心,“动态更新(一个对象的Z属性)=(它的Y属性)即可以巧妙的实现此效果”,确实挺巧妙地,通俗的解释就是越靠近屏幕底部的就离我们越近,越靠前,离屏幕的顶部越近越远。我觉得这可能是一种视觉的习惯问题,就和我们看到正方形,感觉高总比宽长一点似的,当然这个结论是我臆想的。不用纠结是什么原理,还有待继续研究。
这里我们将遮蔽物,置为红色便于查看,当角色精灵的Y值小于遮蔽物时,它的Z值也小于遮蔽物,再将遮蔽物透明化看的更清楚
当精灵的Y值大于遮蔽物的Y值时,值精灵Z值等于Y值,这样精灵自然不会被遮蔽物遮挡,而是位于遮蔽物的前方。
实现
当明白了具体原理以后实现就变的轻松加Easy了。
在来看一遍原理,“动态更新(一个对象的Z属性)=(它的Y属性)即可以巧妙的实现此效果”,既然有动态那一定就有静态了,那我们来分一份。什么是静态的什么是动态的。我想聪明的读者,一定会想到,不动的自然是静态的,会动的当然是动态的(傻子都知道)。
言归正传,静态的是指遮蔽物比如截图中看到树,雕像,大型建筑,围墙什么的在真实世界中是有高度的东西,在2d世界中就会转换成了遮蔽物,角色行走在周围就会产生遮蔽效果。而行走的精灵角色自然就是动态的,它与遮蔽物和别的精灵一起也会产生遮蔽效果。
静态遮蔽物的实现很简单,就是初始化的时候置Postion的Z值为Y值代码即可
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ///
/// 初始化地图遮罩层 /// private void InitMapMask(IEnumerable { int masknum = arglist.Count(); //获取遮罩物数量 var mapMask = new SingleSpriteSetting[masknum]; for ( int i = 0; i < masknum; i++) { XElement args = arglist.ElementAt(i); mapMask[i] = new SingleSpriteSetting(); mapMask[i].Source = string .Format(@"{0}", args.Attribute("Src").Value); mapMask[i].Width_ = Convert.ToSingle(args.Attribute("Width").Value); mapMask[i].Height_ = Convert.ToSingle(args.Attribute("Height").Value); mapMask[i].X = Convert.ToSingle(args.Attribute("X").Value); mapMask[i].Y = Convert.ToSingle(args.Attribute("Y").Value); mapMask[i].CenterY = Convert.ToSingle(args.Attribute("CenterY").Value); mapMask[i].Opacity = Convert.ToSingle(args.Attribute("Opacity").Value); GameObject goMapMask = new GameObject("MapMask" + i); SpriteRenderer addSpriteRenderer = goMapMask.AddComponent addSpriteRenderer.sprite = SpriteFrameImageInfoFactory.CreatLeftBottomSingleSprite(mapMask[i].Source); addSpriteRenderer.color = new Color(1, 1, 1, mapMask[i].Opacity); goMapMask.transform.position = new Vector3(mapMask[i].X, mapMask[i].Y, mapMask[i].PainterZ); goMapMask.transform.parent = this .transform; } } |
动态物体的画家算法实现就要难一些了,因为角色是在不断移动的,它的Y值是随着物体动态变化,所以这里我的做法是把sprite的postion属性做了一层属性的包装,在移动算法的时候实时更新的是封装属性,保证z值随y值实时变化。具体代码如下:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ///
/// 使用线程版 /// public Vector3 Sprite2DPosition { get { return new Vector3(_Sprite2DPosition.x, _Sprite2DPosition.y, 0); } set { _Sprite2DPosition = value; //是否使用2d画家算法进行遮蔽 if (_isUsePainterMask) { transform.position = new Vector3(value.x, value.y, value.y); } else { transform.position = new Vector3(value.x, value.y, 0); } Debug.Log("change position:" + transform.position); } } |
总结
本章通过Unity中的3d技术,通过一个看似在2d中无用的z轴属性,完成了帅气的2d遮罩效果,希望对于各位读者有用。