Unity3D自定义按钮—OnGUI

在塔防游戏中,防守单位都是动态创建的,通常游戏中将提供若干个按钮,当选中其中一个按钮后,这个按钮将保持激活状态,这时在场景中选择位置按下鼠标,即可创建一个防守单位,同时也会扣除一些用于创建防守单位的资金或点数。

接下来我们将创建一个自定义的按钮,虽然使用OnGUI创建按钮更容易,但OnGUI的效率较低,也不利于制作布局复杂或有特殊需求的UI,更难为它制作动画。

1)创建角本GUIButton.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using UnityEngine; 
using System.Collections; 
   
public class GUIButton : MonoBehaviour  
{
    
// 按钮状态 
    
protected enum StateID 
    
{
        
NORMAL=0,  
// 正常 
        
FOCUS,      
//  高亮 
        
ACTIV,      
//  选中 
    
}
    
protected StateID m_state = StateID. NORMAL; 
    
// 按钮的贴图 
    
public Texture[] m_ButtonSkin; 
   
    
// 按钮的ID 
    
public int m_ID = 0; 
   
    
// 按钮是否处于激活状态 
    
protected bool m_isOnActiv =
false
   
    
// 按钮的缩放 
    
public float m_scale = 1.0f; 
   
    
// 按钮的屏幕位置 
    
Vector2 m_screenPosition; 
     
   
// 按钮的当前贴图 
    
public GUITexture m_texture; 
   
   
// 初始化按钮 
    
void Awake()
    
{
        
//  获得贴图 
        
m_texture =
this
.guiTexture; 
   
        
// 获得位置 
        
m_screenPosition =
new
Vector3(m_texture.pixelInset.x, m_texture.pixelInset.y, 0); 
   
        
// 设置默认状态 
        
SetState(StateID.NORMAL); 
    
}
   
    
//更新按钮状态,选中按钮,返回它的ID 
    
public int UpdateState(bool mouse,Vector3 mousepos)
    
{
        
int result = -1; 
   
        
if
(m_texture.HitTest(mousepos))
        
{
            
if
(mouse)
            
{
                
SetState(StateID.ACTIV); 
   
                
return
m_ID; 
            
}
            
else
                
SetState(StateID.FOCUS); 
   
        
}
        
else
        
{
            
if
(m_isOnActiv)
                
SetState(StateID.ACTIV); 
            
else
                
SetState(StateID.NORMAL); 
        
}
   
        
return
result; 
    
}
   
    
// 设置按钮状态 
    
protected virtual void SetState(StateID state)
    
{
        
if
(m_state == state)
            
return
   
        
m_state = state; 
   
        
m_texture.texture = m_ButtonSkin[(int)m_state]; 
   
        
float w = m_ButtonSkin[(int)m_state].width * m_scale; 
        
float h = m_ButtonSkin[(int)m_state].height * m_scale; 
   
        
m_texture.pixelInset =
new
Rect(
this
.m_screenPosition.x, m_screenPosition.y, w, h); 
    
}
   
    
// 设置按钮缩放 
    
public virtual void SetScale(float scale)
    
{
        
m_scale = scale; 
   
        
float w = m_ButtonSkin[0].width * scale; 
        
float h = m_ButtonSkin[0].height * scale; 
   
        
m_screenPosition.x *= scale; 
        
m_screenPosition.y *= scale; 
   
        
m_texture.pixelInset =
new
Rect(m_screenPosition.x, m_screenPosition.y, w, h); 
    
}
        
// 设置激活状态 
    
public virtual void SetOnActiv(bool isactiv)
    
{
        
if
(isactiv)
            
SetState(StateID.ACTIV); 
        
else
if
(m_isOnActiv)
            
SetState(StateID.NORMAL); 
   
        
m_isOnActiv = isactiv; 
    
}
}

在这个脚本中,Awake函数初始化了按钮的状态,按钮一共有三种状态,包括正常、高亮和激活。

在UpdateState函数中,判断是否选中按钮,如果选中,则返回按钮的ID。

SetState函数用来设置按钮的状态,实际上是在更新按钮的贴图。

SetScale函数用来设置按钮的缩放,在手机平台,因为机器设备的分辨率不统一,所以在不同平台对按钮进行相应缩放是必要的。

SetOnActiv函数会将按钮设为激活状态,当按钮处于这种状态,即使鼠标从按钮上移开,按钮的状态也不会改变。

2)在Project窗口的GUI文件夹中找到ui_turret_n.png,确定它处于选择状态,在菜单栏选择【GameObject】→【Create Other】→【GUI Texture】创建一个显示有UI贴图的游戏体,然后为它指定角本GUIButton.cs,在Button Skin中设置对应按钮三种状态的贴图,将按钮的ID设为1,如图4-27所示。

3)我们将不使用3d坐标改变按钮的位置,将按钮的Position设为0,然后将Pixel Inset的X和Y设为5,如图4-27所示,按钮将出现在屏幕坐标(5,5)的位置,如图4-28所示。

4)将按钮命名为button_0,并设为GameManager的子物体,如图4-29所示。

5)打开GameManager.cs,加入按钮等相关属性如下,然后将前面创建的防守单位与m_guardPrefab关联。新建一个名为ground的Layer,将m_groundlayer与其关联。

(此处省略××××××字,包括源代码)

8)将地面的Layer设为ground,使射线可以与地面碰撞。

运行游戏,按一下屏幕上的按钮,然后在地面上点一下,即可创建一个防守单位。

这个塔防游戏到这里就结束了,它还非常简陋,但具备了塔防游戏的基本要素,如果添加更多的细节和更好的画面,相信它可以变成一款不错的游戏。

来自:51cto