第九章 技能系統
與物品系統類似,技能系統也是一個較爲複雜的系統,其中UI設計部分涉及到一些新知識,進行重點學習。
9.1 物品信息管理系統
技能管理系統的大致操作與揹包系統類似。
9.1.1 技能信息的設計
技能信息的保存格式如下
我們在Atlas中新創建一個記事本存儲技能信息,與物品信息類似,命名爲SkillInfoInList,內容如下(部分信息進行了修改)
5001,魔法彈,skill-09,傷害 350%,SingleTarget,Attack,350,0,20,10,Magician,1,Enemy,5
5002,治療,skill-13,治癒30HP,Passive,HP,30,0,10,20,Magician,2,Self,0
5003,冥想,skill-10,魔法恢復20,Passive,MP,20,0,0,30,Magician,5,Self,0
5004,法力涌動,skill-05,攻擊力爲200%持續15秒,Buff,Attack,200,15,30,30,Magician,7,Self,0
5005,戰鬥熱誠,skill-12,攻擊力速度爲200%持續30,Buff,AttackSpeed,200,30,30,30,Magician,8,Self,0
5006,究極風暴,skill-11,攻擊力400% 所有敵人,MultiTarget,Attack,400,0,50,40,Magician,9,Position,10
爲了便於管理物品信息和技能信息,我們新建一個TextInfo來存儲這兩個txt文檔
9.1.2 實現技能信息的讀取
與ObjectsInfo類似,我們在GameSetting中添加一個SkillsInfo以訪問讀取技能信息,在腳本中設定各種屬性
public enum ApplyRole{ //適用角色
Swordman,
Magician
}
public enum ApplyType{ //適用類型
Passive,
SingleTarget,
MultiTarget
}
public enum ApplyProperty{ //適用屬性
Attack,
Aefense,
AttackSpeed,
HP,
MP
}
public enum ReleaseType{ //釋放類型,對自身,敵人(需要鼠標指定)和某個位置(鼠標指定)
Self,
Enemy,
Position
}
public class SkillInfo{ //技能信息表中對應的各條屬性
public int id;
public string name;
public string icon_name;
public string des;
public ApplyType applyType;
public ApplyProperty applyProperty;
public int applyValue;
public int applyTime;
public int mpCost;
public int coldTime;
public ApplyRole applyRole;
public int level;
public ReleaseType releaseType;
public float releaseDistance;
}
在SkillsInfo中,將技能信息存入字典的操作如下
public static SkillsInfo _instance;
public TextAsset skillInfoListText;
private Dictionary<int,SkillInfo> skillInfoDict = new Dictionary<int,SkillInfo>();
void Awake()
{
_instance = this;
ReadInfo ();
}
其中ReadInfo ()的實現可參考物品信息(見揹包系統),再提供一個外部的訪問接口,通過這個接口即可訪問id對應的技能信息
public void GetSkillInfoListText(int id)
{
SkillInfo skillInfo = null;
skillInfoDict.TryGetValue (id, out skillInfo);
return skillInfo;
}
9.2 UI界面的設計
9.2.1 基礎技能界面的創建
在界面中新建一個Scroll View存儲所有的技能,以及一組Invisible Widget用來顯示單個技能,如下圖所示。在Invisible Widget下再創建兩個Sprite,一個用來顯示技能圖標,另一個作爲技能描述的背景。
在技能描述中,再新建4個Label,顯示其餘信息,完成後如下圖所示。完成之後,將其保存爲Prefab,之後根據不同職業動態添加技能欄信息。
爲了實現技能拖拽到快捷欄的效果,在SkillItem中加上Box Collider與Drag Scroll View。
在運行時即可實現上下拖動的效果,這麼拖動顯然不方便,我們在技能欄的右邊加入一個滾動條(可以搜索control),設置一下Depth即可
之後指定一下SkillGrid中ScrollView中的Scroll Bar即可
我們將預先設置好的Grid大小設置爲單個技能的大小
可以通過Grid可以直接對技能進行排序,將SkillItem拖放到Prefabs之下
爲了管理SkillItem的內容,我們爲其添加一個SkillItem的腳本,代碼如下
void InitProperty()
{
iconName = transform.Find ("IconName").GetComponent<UISprite> (); //找到每個Sprite/Label的對應控件
name_label = transform.Find ("Property/Name").GetComponent<UILabel> ();
skillType_label = transform.Find ("Property/SkillType").GetComponent<UILabel> ();
skillDes_label = transform.Find ("Property/SkillDes").GetComponent<UILabel> ();
cost_label = transform.Find ("Property/Cost").GetComponent<UILabel> ();
}
void SetId(int id) //初始化並在外部調用,進行創建,更新顯示
{
InitProperty ();
this.id = id;
info = SkillsInfo._instance.GetSkillInfoFromDict (id);
iconName.spriteName = info.icon_name;
name_label.text = info.name;
switch (info.applyType)
{
case SkillsInfo.ApplyType.Passive:
skillType_label.text = "增益";
break;
case SkillsInfo.ApplyType.Buff:
skillType_label.text = "增強";
break;
case SkillsInfo.ApplyType.SingleTarget:
skillType_label.text = "單體";
break;
case SkillsInfo.ApplyType.MultiTarget:
skillType_label.text = "羣體";
break;
}
skillDes_label.text = info.des;
cost_label.text = info.mpCost.ToString();
}
通過判斷當前角色是魔法師或者劍士,我們選擇不同的技能列表,在Skill腳本中
public int[] MagicianSkillList;
public int[] SwordmanSkillList;
private PlayerStatus ps;
void Start()
{
ps = GameObject.FindGameObjectWithTag (Tags.player).GetComponent<PlayerStatus> ();
int[] idList = null;
switch (ps.role)
{
case playerRole.Magician:
idList = MagicianSkillList;
break;
case playerRole.Swordman:
idList = SwordmanSkillList;
break;
}
}
其中MagicianSkillList和SwordmanSkillList的設置根據SkillInfoInList得到
在確定當前角色後,我們調用SetId方法創建技能面板,在Skill腳本中,添加
public UIGrid grid; //控制所有技能創建的網格,控制所有skillItemPrefab
public GameObject skillItemPrefab; //單個技能面板
void Start()
{
foreach (int id in idList) //遍歷idList之中的id信息
{
GameObject itemGO = NGUITools.AddChild(grid.gameObject,skillItemPrefab); //對於每一個id,在grid之中添加技能信息的Prefab
grid.AddChild(itemGO.transform);
itemGO.GetComponent<SkillItem>().SetId(id); //調用SetId方法,更改技能的顯示
}
}
即可創建出技能欄的內容,如下所示。
9.2.2 技能的拖拽功能
爲SkillItem下的IconName添加腳本SkillItemIcon,控制拖動效果,勾選Clone On Drag。將SkillItemIcon腳本繼承自UIDragDropItem,以實現拖拽功能。(需刪除Start()方法和Update()方法,否則會出錯),如下所示,但此時無法拖拽出技能欄。
因此我們需要讓克隆的圖標按鈕能夠移出ScrollView,在SkillItemIcon中添加
public class SkillItemIcon : UIDragDropItem{
protected override void OnDragDropStart ()
{
base.OnDragDropStart ();
transform.parent = transform.root; //把父類放到UI root下
this.GetComponent<UISprite> ().depth = 40;
}
}
對6個快捷欄添加box collider,並將它們的標籤設置爲ShortCut,在SkillItemIcon中,通過如下代碼得到id
public int skillId;
skillId = transform.parent.GetComponent<SkillItem> ().id;
之後通過OnDragDropRelease函數實現隨意拖拽效果
protected override void OnDragDropRelease (GameObject surface)
{
base.OnDragDropRelease (surface);
if (surface != null && surface.tag == Tags.shortcutItem)
{
surface.GetComponent<Shortcut>().SetSkill(skillId); //實現設置技能的效果,下節實現
}
}
9.3 技能的快捷方式
我們創建一個Invisible Widget用以存儲技能欄的快捷方式,通過快捷方式我們可以方便地使用技能。在Invisible Widget中新建6個Sprite,命名爲Shortcut1~6,用以存儲這6個技能,爲1~6的快捷方式建立Shortcut腳本,在每個Sprite下創建Child Label作爲數字提示(做成Prefab可能更好),如下所示
在拖拽的時候,我們需要創建技能圖標,因此在Shortcut1~6中創建Child Sprite作爲技能顯示圖標,並且由於技能快捷欄開始是不顯示的, 設置它的active爲false。並且我們增加id和info用以讀取字典中技能的信息,在SkillItemIcon中通過調用Shortcut中的SetSkill完成,其中SetSkill函數如下
public enum ShortType{
Skill,
Null
}
private ShortType type = ShortType.Null; //默認爲Null,即默認情況下按下快捷鍵不顯示
private int id;
private SkillsInfo.SkillInfo info;
public void SetSkill(int id) //外界進行調用
{
type = ShortType.Skill;
this.id = id;
this.info = SkillsInfo._instance.GetSkillInfoFromDict (id);
icon.spriteName = info.icon_name;
}
即可將技能拖入快捷方式之中。
9.4 人物等級對技能的限制
接下來考慮任務等級對技能的影響,當人物等級小於技能要求等級時,無法使用拖動技能按鈕,因此對SkillItem的Prefab添加Child Sprite,裏面儲存禁用技能的圖標。在SkillItem腳本中添加並在初始化中設置爲隱藏。
private GameObject iconMask;
iconMask.SetActive (false);
void InitProperty()
{
iconMask = transform.Find ("IconMask").gameObject;
}
之後設置一個實時根據等級信息改變技能顯示與否的功能函數,當每次點擊功能面板的技能圖標時調用
public void UpdateItem(int level) //level從別的函數調用,判斷當前等級
{
if (level < info.level) //info.level對應技能等級,當前等級小於技能等級時,顯示iconMask並禁用拖拽功能
{
iconMask.SetActive (true);
iconName.GetComponent<SkillItemIcon> ().enabled = false;
} else
{
iconMask.SetActive (false);
iconName.GetComponent<SkillItemIcon> ().enabled = true;
}
}
調用位置在Skill腳本中,添加調用UpdateItem(int level)的函數,如下
public void UpdateShow()
{
SkillItem[] items = this.GetComponentsInChildren<SkillItem> ();
foreach (SkillItem item in items)
{
item.UpdateItem(ps.level);
}
}
之後在void Show()中調用,即
void Show()
{
isShow = true;
this.gameObject.SetActive (true);
UpdateShow (); //調用 UpdateShow ();
tween.PlayForward ();
}
即可實現該功能