Unity3D学习(13)之UI界面与背包系统

       之前傻傻地认为Unity3D的UI只是在OnGUI的时候画画Button,Image用的,根本没想过UI的效果竟然可以这么棒。废话不多说先上个效果图。

                                    

是不是看起来特别帅,感觉一个好的UI界面是一个游戏成功的一半啊。

首先建立一个Canvas,并且在Canvas里面建立五个Panel分别命名为Window(主界面),HeadBag(次级界面1),HandBag(次级界面2),FootBag(次级界面3),Equip(装备界面)。并且将层次设置为UI界面,用UIcamera来渲染。

然后在Window界面建立一个Panel命名为Title,和三个Button分别命名为Head,Hand,Foot指向三个次级界面。为了让button,panel更好看我们可以加个图片控制UI显示的形状,比如Title用了SFtitle这张贴图。


为了让panel有动画,我录制了进来(window)和退出(Exit)的动画。设置Bool参数Open控制状态变换

接着制作HeadBag,HandBag,FootBag次级菜单,添加Grid Layout Group组件,用于布局。然后在菜单里面添加10个按钮,1个退出菜单,9个装备菜单。利用Button的text写下背包名称,在image组件添加图片,即为所储存的装备。

同理复制粘贴搞定另外两个,同时录制好进出的动画。然后考虑菜单随鼠标摆动。编写TiltWindow.cs

public class TiltWindow : MonoBehaviour
{
    public Vector2 range = new Vector2(5f, 3f);//旋转范围

    Transform mTrans;
    Quaternion mStart;
    Vector2 mRot = Vector2.zero;

    void Start()
    {
        mTrans = transform;
        mStart = mTrans.localRotation;
    }

    void Update()
    {
        Vector3 pos = Input.mousePosition;//获取鼠标位置

        float halfWidth = Screen.width * 0.5f;
        float halfHeight = Screen.height * 0.5f;
        float x = Mathf.Clamp((pos.x - halfWidth) / halfWidth, -1f, 1f);//求相对x比例,并且限制上下界
        float y = Mathf.Clamp((pos.y - halfHeight) / halfHeight, -1f, 1f);//求相对y比例,并且限制上下界
        mRot = Vector2.Lerp(mRot, new Vector2(x, y), Time.deltaTime * 5f);//求插值

        mTrans.localRotation = mStart * Quaternion.Euler(-mRot.y * range.y, mRot.x * range.x, 0f);//进行旋转
    }
}

这时第一个Bug出现了,动画机的问题,当物体处在动画状态时,会阻塞在动画那里,使得脚本失去效果,所以我们需要让动画播放完毕之后使animator失效。顺便写一写菜单切换,可以在场景建立空对象命名为MenuManger,拥有脚本MeneManger.cs控制菜单的切换。切换菜单有两个动作,一个是关闭旧的菜单,一个是开启新的菜单,关闭首先要激活旧菜单的animator,播放退出动画,然后灭活菜单,这里我使用协程,一秒钟之后灭活,开启也要激活animator,播放进入动画,然后使动画机失效,TiltWindow脚本才能有效。

然后为了让图片跟随鼠标移动,设置UIImage,有图片时改为不透明色,没有图片时改为透明色,编写UIimage.cs,UIimage属性具体设置如下:

public class UIimage : MonoBehaviour {

    private Image mouse_Image;//鼠标点击的图片
    public Color visable;//可见色
    public Color unvisable;//不可见色
	// Use this for initialization
	void Start () {
        mouse_Image = GetComponent<Image>();
	}
	
	// Update is called once per frame
	void Update () {
		if(MenuManger.texture != null)//判断如果鼠标点击图片非空,则将UIimage设置为可见,并且将鼠标图片赋值给UIimage,同时随时更新UIimage位置
        {
            mouse_Image.color = visable;
            mouse_Image.sprite = MenuManger.texture;
            this.transform.position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
        }
        else //否则不可见
        {
            mouse_Image.color = unvisable;
        }
	}
}

然后还需要考虑图片类型,比如头部装备不能放在手部装备处。编写Bag.cs记录类型编号
public class Bag : MonoBehaviour {
    public int type;
}
HeadBag类型为0,HandBag为1,FootBag为2。同时Equip板也用Grid组件建立三个按钮,挂上Bag.cs也分别设置为0,1,2。
然后考虑鼠标图片与HeadBag,HandBag,FootBag的Button贴图切换。用GetTexture传入本身对象,与鼠标的图片交换即可,需要判断条件只有类型相同才可以交换,或者鼠标没有图片时。还有鼠标图片与Equip的Button贴图,条件是类型相同或者Button有图片但是鼠标没有图片。
编写MenuManager的脚本,控制MenuManager切换,鼠标

public class MenuManger : MonoBehaviour {
    private GameObject Current;//当前菜单
    private GameObject Previous;//旧菜单
    public GameObject Window;//在属性面板拖入相应菜单
    public GameObject HeadBag;//
    public GameObject HandBag;//
    public GameObject FootBag;//
    public static Sprite texture;//鼠标获取的图片
    public static int type = -1;//鼠标获得图片类型,-1表示无图片
	// Use this for initialization
	void Start () {
        texture = null;
        Current = Window;
        Previous = Window;
        StartCoroutine(OpenDelay());//关闭动画
    }

    public void getTexture(GameObject obj)
    {
        if(type == -1 || type == obj.GetComponent<Bag>().type)
        {
            Sprite previous = texture;//保存鼠标先前的图片
            texture = obj.GetComponent<Image>().sprite;//
            obj.GetComponent<Image>().sprite = previous;//交换图片
            type = obj.GetComponent<Bag>().type;//保存类型
        }
        if(texture == null)
        {
            type = -1;//如果为空置-1
        }
    }
    public void putTexture(GameObject obj)
    {
        if ((type == -1 && obj.GetComponent<Image>().sprite != null)  ||type == obj.GetComponent<Bag>().type)
        {
            Sprite previous = texture;//保存鼠标先前图片
            texture = obj.GetComponent<Image>().sprite;//
            obj.GetComponent<Image>().sprite = previous;//交换图片
            type = obj.GetComponent<Bag>().type;//保存类型
        }
        if (texture == null)
        {
            type = -1;
        }
    }
    public IEnumerator OpenDelay()
    {
        int CoolTimes = 1;//延迟1秒
        while (CoolTimes > 0)
        {
            print("还剩" + CoolTimes);
            yield return new WaitForSeconds(1);//等待1秒
            CoolTimes--;
        }
        Current.GetComponent<Animator>().enabled = false;//灭活动画
    }
    public IEnumerator CloseDelay()
    {
        int CoolTimes = 1;//延迟1秒
        Previous.GetComponent<Animator>().enabled = true;//激活动画
        Previous.GetComponent<Animator>().SetBool("Open", false);//播放关闭动画
        while (CoolTimes > 0)
        {
            print("还剩" + CoolTimes);
            yield return new WaitForSeconds(1);//等待1秒
            CoolTimes--;
        }
        Previous.SetActive(false);//灭活旧菜单
        OpenPanel();//打开新菜单
    }
    void OpenPanel()
    {
        Current.SetActive(true);//激活菜单
        Previous.GetComponent<Animator>().enabled = true;//激活动画
        Current.GetComponent<Animator>().SetBool("Open", true);//播放开启动画
        StartCoroutine(OpenDelay());//开启延迟
    }

    public void OpenPanel(GameObject panel)//打开菜单
    {
        Previous = Current;//保存旧菜单对象
        Current = panel;//保存新菜单对象
        StartCoroutine(CloseDelay());//协程关闭菜单
    }
}

在BUutton的Onclick函数调用相应函数,具体设置如下


然后用UIcamera负责渲染UI层,main camera渲染背景,用canvas加panel贴背景图,再放个粒子系统。设置如下


这就大功告成了,其实真正做应该是花了一天时间但是看博客,学课堂案例的代码学了挺久,一直以为很难,但其实只有真正动手才能知道难在哪里。再次吐槽我的电脑,明明下了Unity Web Player但是就是看不了demo,什么方法都试过了,我也无话可说,同样的操作同学的电脑却可以成功,而我只能凭着想象力把游戏做出来。微笑微笑微笑

有兴趣看我的工程可以去我的Gihub上看Demo.


  • 6
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值