本文同時(shí)發(fā)布至我的個(gè)人博客,點(diǎn)擊進(jìn)入我的個(gè)人博客閱讀。本博客供技術(shù)交流與經(jīng)驗(yàn)分享,可自由轉(zhuǎn)載。轉(zhuǎn)載請?jiān)谠u論區(qū)或私信簡單通知,感謝!
游戲需求
- 實(shí)現(xiàn)點(diǎn)擊效果。
- 用
Plane或其他物體做地面, tag 為Finish。 - 點(diǎn)擊地面后,出現(xiàn)一個(gè)圓形攻擊標(biāo)記,兩秒后自動(dòng)消失。注意:該攻擊標(biāo)記不能擋住點(diǎn)擊。(Primitive Objects / Cylinder)
- 請使用一個(gè)簡單工廠創(chuàng)建、管理這些的標(biāo)記,并自動(dòng)收回這些標(biāo)記(注意,這些對象創(chuàng)建后,放在列表內(nèi),不必釋放)。
效果展示:

實(shí)現(xiàn)過程
(一)Camera 和 Plane 的基本配置
? 設(shè)置好Camera的位置與角度,并設(shè)置視圖為正交,如下圖:
? 為方便顯示,創(chuàng)建Plane后再添加一個(gè)Material,使其變?yōu)樗{(lán)色,如下圖:
(二)定義并實(shí)現(xiàn)EsayFactory類
? 首先創(chuàng)建一個(gè)繼承MonoBehaviour的Basecode類,自定義一個(gè)namespace并引用,在該namespace定義并實(shí)現(xiàn)EsayFactory類。
? EsayFactory類為工廠類,它負(fù)責(zé)管理Cylinder的創(chuàng)建、停用和重復(fù)使用。重復(fù)使用的實(shí)現(xiàn)主要通過講使用完畢的Cylinder加入一個(gè)List中,在需要時(shí)重新拿出使用的方法來實(shí)現(xiàn)。這樣做的好處是,避免了重復(fù)地創(chuàng)建和銷毀游戲?qū)ο螅軠p少游戲的內(nèi)存消耗。
? 需要注意的是:嚴(yán)格控制單實(shí)例,避免用戶創(chuàng)建多個(gè)EsayFactory對象。
public class EsayFactory : System.Object
{
public List<GameObject> markList = new List<GameObject>();
private static EsayFactory _factory;
private Camera _camera;
//控制單實(shí)例
public static EsayFactory GetInstance()
{
if (_factory == null)
{
_factory = new EsayFactory();
_factory._camera = Camera.main;
}
return _factory;
}
public void placeAttackMark(Vector3 target)
{
Ray _ray = _camera.ScreenPointToRay(target);
RaycastHit _hit;
if (Physics.Raycast(_ray, out _hit))
{
if (_hit.collider.gameObject.tag.Contains("Finish"))
{
GameObject attackMark;
//List中若無可用對象則創(chuàng)建新對象
if (markList.Count == 0)
{
attackMark = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
//避免Cylinder擋住點(diǎn)擊
attackMark.GetComponent<Collider>().enabled = false;
}
//若有可用對象則拿出重用
else
{
attackMark = markList[0];
markList.RemoveAt(0);
}
attackMark.transform.SetParent(_hit.collider.gameObject.transform);
attackMark.transform.position = _hit.point;
//添加一個(gè)自定義的實(shí)現(xiàn)了延時(shí)2s刪除功能的組件
DelayToDelete _delay = attackMark.AddComponent<DelayToDelete>();
_delay.delete(markList, attackMark, 2.0f);
}
}
}
(三)實(shí)現(xiàn)延時(shí)刪除
? DelayToDelete繼承MonoBehaviour類,實(shí)現(xiàn)了兩個(gè)方法:私有方法delayTo()實(shí)現(xiàn)了具體延時(shí)功能的實(shí)現(xiàn),公有方法delete()實(shí)現(xiàn)了具體的2秒后刪除的功能需求。這里采用了Action類來代替Invoke()方法,其好處是拓展性更強(qiáng),可讀性也更高。StartCoroutine是MonoBehaviour中的一個(gè)調(diào)用協(xié)同程序的方法,通過使用 yield return new WaitForSeconds(delaySeconds);可以實(shí)現(xiàn)延時(shí)一定實(shí)現(xiàn)后執(zhí)行。
public class DelayToDelete : MonoBehaviour
{
public void delete(List<GameObject> markList, GameObject attackMark, float delaySeconds)
{
StartCoroutine(delayTo(() =>
{
//移出游戲范圍并加入List中等待重用
attackMark.transform.position = new Vector3(0f, -99f, 0f);
markList.Add(attackMark);
}
, 2.0f));
}
private IEnumerator delayTo(Action action, float delaySeconds)
{
//延時(shí)執(zhí)行action();
yield return new WaitForSeconds(delaySeconds);
action();
}
}
(四)完成Basecode
? Basecode類主要負(fù)責(zé)每幀檢查用戶是否做了點(diǎn)擊事件,若點(diǎn)擊則調(diào)用placeAttackMark方法:
public class Basecode : MonoBehaviour {
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
Vector3 point = Input.mousePosition;
EsayFactory.GetInstance().placeAttackMark(point);
}
}
}