Unity2d 遮蔽系统增强--画家算法实现

发表于2017-05-01
评论0 1.2k浏览

背景

为什么要使用遮蔽系统,主要的目的是在场景中很好的还原人类视觉认知的真实场景,当然2d游戏中不存在远小近大的,光线几何透视效果,但是近处物体遮挡远处物体的基本物理特性还是要实现的。这可能让人联想起3d场景的画家算法。

2d物体的遮挡顺序一样可以使用画家算法,该算法原理简单描述就是近物遮挡远物,幸运的是在Unity2d中,我们也可以很方便的只要动态更新(一个对象的Z属性)=(它的Y属性)即可以巧妙的实现此效果,是不是有点邪恶?嘿嘿。所以要将遮盖物的Z置得足够大以防止任何一个物体它的Y属性大过遮盖物的Z属性。

说实话当时自己学习这块的时候,也有些看似懂了,过了段时间还是蒙的感觉,后来自己动手用Unity显示了一遍,才彻底明白。我们先看下遮蔽的效果,

45

是不是还是很逼真的。

我们再通过两张图片来揭秘实现的核心,“动态更新(一个对象的Z属性)=(它的Y属性)即可以巧妙的实现此效果”,确实挺巧妙地,通俗的解释就是越靠近屏幕底部的就离我们越近,越靠前,离屏幕的顶部越近越远。我觉得这可能是一种视觉的习惯问题,就和我们看到正方形,感觉高总比宽长一点似的,当然这个结论是我臆想的。不用纠结是什么原理,还有待继续研究。

这里我们将遮蔽物,置为红色便于查看,当角色精灵的Y值小于遮蔽物时,它的Z值也小于遮蔽物,再将遮蔽物透明化看的更清楚

mainx1

当精灵的Y值大于遮蔽物的Y值时,值精灵Z值等于Y值,这样精灵自然不会被遮蔽物遮挡,而是位于遮蔽物的前方。

mainx2

实现

当明白了具体原理以后实现就变的轻松加Easy了。

在来看一遍原理,“动态更新(一个对象的Z属性)=(它的Y属性)即可以巧妙的实现此效果”,既然有动态那一定就有静态了,那我们来分一份。什么是静态的什么是动态的。我想聪明的读者,一定会想到,不动的自然是静态的,会动的当然是动态的(傻子都知道)。

言归正传,静态的是指遮蔽物比如截图中看到树,雕像,大型建筑,围墙什么的在真实世界中是有高度的东西,在2d世界中就会转换成了遮蔽物,角色行走在周围就会产生遮蔽效果。而行走的精灵角色自然就是动态的,它与遮蔽物和别的精灵一起也会产生遮蔽效果。

静态遮蔽物的实现很简单,就是初始化的时候置Postion的Z值为Y值代码即可

[C#] 纯文本查看 复制代码
 
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 arglist)
{
    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值实时变化。具体代码如下:

[C#] 纯文本查看 复制代码
 
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遮罩效果,希望对于各位读者有用。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论