最近越来越觉得Unity3D的UI很好玩,所以我尝试去制作可折叠的公告牌。先上个成品图:
首先新建Canvas,在Canvas里面新建两个Panel,一个Panel用于放置背景,一个Panel用于公告牌。在公告牌的Panel里面新建3个Button和3个Image和3个Text。具体设置如图
然后新建一个空物体命名为BoardManager,挂上脚本BoardManager.cs,用于控制公告的显示,折叠式公告牌原理是点击按钮,使Image(公告)为active,通过2D刚体碰撞,让其他按钮向下移。
public class BoardManager : MonoBehaviour {
public void ControlBoard(GameObject obj)
{
bool open = obj.GetComponent<Board>().Open;
open = !open;
obj.GetComponent<Board>().Open = open;
obj.SetActive(open);//选择激活或者灭活
}
}
然后在3个Image上都挂载Board.cs,记录公告状态显示
public class Board : MonoBehaviour {
public bool Open = false;//初始状态都为关
}
因为要利用在Button属性面板如图设置
因为需要利用到2D物体的碰撞,需要加入2D刚体,和2D的碰撞体,这是一个巨大无比的坑。
首先给3个Button都添加刚体和碰撞体,然后给3个图片都添加碰撞体
2D碰撞体贼坑,本来用OnCollisionEnter2D检测碰撞,但是却死活检测不到,刚体也加了,碰撞体也加了就是没卵用,百度谷歌大法都用了,也没啥用,后来幸好我点击编辑碰撞体,才发现,2D碰撞体最初是给一个点而不是一个形状,所以即使看起来碰撞了,其实只要碰撞框没重合就没有碰撞信息
然后给第二个Button加上Button2_Move.cs
public class Button2_Move : MonoBehaviour {
public GameObject Panel;//公告牌面板
float x = 0;//第二个Button初始位置x
float y = 25;//第二个Button初始位置y
float cur_x;//第二个Button当前位置
float cur_y;//第二个Button当前位置
void Start()
{
cur_x = x;//
cur_y = y;//初始化当前位置x,y
}
// Update is called once per frame
void Update() {
if (Panel.transform.FindChild("Image1").gameObject.activeSelf == false)
{
Return0();//如果第一个公告不显示就退回起始点
}
Panel.transform.FindChild("Image2").gameObject.GetComponent<RectTransform>().localPosition = new Vector3(cur_x, cur_y - 155, 0);//实时更新Image2的位置保证它是跟在按钮2下方
}
void Return0()
{
GetComponent<RectTransform>().localPosition = new Vector3(x, y, 0);//返回
cur_y = y;//记录当前位置
}
void OnCollisionEnter2D(Collision2D coll)
{
RectTransform coll_Tranform = coll.gameObject.GetComponent<RectTransform>();
GetComponent<RectTransform>().localPosition = new Vector3(x, y - coll_Tranform.sizeDelta.y, 0);//位置改为x不变,y加上碰撞Image的height
cur_y = y - coll_Tranform.sizeDelta.y;//记录当前位置
}
}
然后为第三个Button加上Button3_Move.cs。本来按道理将button的行为应该一样,可是考虑到Button3比Button2多了一个可能位置,然后我也暂时没想到优化的办法,先将就着吧。
public class Button3_Move : MonoBehaviour {
public GameObject Panel;
float cur_x;
float cur_y;//当前位置的x,y
float x = 0;
float y = -95;//初始位置的x,y
float x1 = 0;
float y1 = -299;//中间位置的x,y
void Start()
{
cur_x = x;
cur_y = y;
}
// Update is called once per frame
void Update()
{
Panel.transform.FindChild("Image3").gameObject.GetComponent<RectTransform>().localPosition = new Vector3(cur_x, cur_y - 165, 0);//实时更新Image3,保证Image3在Button3下方
if (Panel.transform.FindChild("Image1").gameObject.activeSelf == true)
{
if(Panel.transform.FindChild("Image2").gameObject.activeSelf == false)
{
Return2();//当第一个公告牌打开,第二个隐藏时
}
}
else
{
if (Panel.transform.FindChild("Image2").gameObject.activeSelf == false)
{
Return1();//当两个公告牌都隐藏时
}
}
}
void Return1()
{
GetComponent<RectTransform>().localPosition = new Vector3(x, y, 0);
cur_y = y;//记录当前位置
}
void Return2()
{
GetComponent<RectTransform>().localPosition = new Vector3(x1, y1, 0);
cur_y = y1;//记录当前位置
}
void OnCollisionEnter2D(Collision2D coll)
{
RectTransform coll_Tranform = coll.gameObject.GetComponent<RectTransform>();
Debug.Log(coll.gameObject.name);
GetComponent<RectTransform>().localPosition = new Vector3(cur_x, cur_y - coll_Tranform.sizeDelta.y, 0);//位置下移
cur_y = cur_y - coll_Tranform.sizeDelta.y;//记录当前位置
}
}
至于第二个公告牌的滚动字幕则是用了Mask和动画录制后的效果,其他额外效果都是动画录制播放