Unity【SwitchableObject】- 实现一个物体开关控制系统

简介: Unity【SwitchableObject】- 实现一个物体开关控制系统

 

本文介绍如何实现一个物体的开关控制系统,例如门的开关控制、灯的开关控制等,一切包含打开、关闭这两种状态的物体,均可以通过继承下面的抽象类进行重写实现。

状态枚举:

namespaceSK.Framework{
/// <summary>/// 状态/// </summary>publicenumSwitchState    {
/// <summary>/// 开着的/// </summary>Open,
/// <summary>/// 关着的/// </summary>Close,
    }
}

image.gif

接口:

namespaceSK.Framework{
/// <summary>/// 可开关物体接口/// </summary>publicinterfaceISwitchableObject    {
SwitchStateState { get; }
voidSwitch();
voidOpen();
voidClose();
    }
}

image.gif

抽象类:

usingUnityEngine;
namespaceSK.Framework{
publicabstractclassSwitchableObject : MonoBehaviour, ISwitchableObject    {
//默认设为关闭状态        [SerializeField] protectedSwitchStatestate=SwitchState.Close;
/// <summary>/// 当前状态/// </summary>publicSwitchStateState { get { returnstate; } }
/// <summary>/// 切换 若为打开状态则关闭 若为关闭状态则打开/// </summary>publicvoidSwitch()
        {
switch (State)
            {
caseSwitchState.Open: Close(); break;
caseSwitchState.Close: Open(); break;
            }
        }
/// <summary>/// 开门/// </summary>publicabstractvoidOpen();
/// <summary>/// 关门/// </summary>publicabstractvoidClose();
    }
}

image.gif

开关处理器,例如我们想要通过一个开关控制多个灯时,或者通过一个开关控制一对门时,均可以通过开关处理器,同时处理多个可开关物体:

usingUnityEngine;
namespaceSK.Framework{
/// <summary>/// 开关处理器(把手)/// </summary>publicclassSwitchableObjectHandler : SwitchableObject    {
        [SerializeField] privateSwitchableObject[] handleArray;
publicoverridevoidOpen()
        {
if (state==SwitchState.Open) return;
state=SwitchState.Open;
for (inti=0; i<handleArray.Length; i++)
            {
handleArray[i].Open();
            }
        }
publicoverridevoidClose()
        {
if (state==SwitchState.Close) return;
state=SwitchState.Close;
for (inti=0; i<handleArray.Length; i++)
            {
handleArray[i].Close();
            }
        }
    }
}

image.gif

这里以门的开关控制为例,我们将门的类型分为移动门和旋转门,首先创建一个门的基类:

usingUnityEngine;
namespaceSK.Framework{
/// <summary>/// 可开关门/// </summary>publicabstractclassSwitchableDoor : SwitchableObject    {
//开/关所用的时长        [SerializeField] protectedfloatduration=0.5f;
//打开状态的值protectedVector3openValue;
//关闭状态的值protectedVector3closeValue;
    }
}

image.gif

1.移动门:

image.gif

参数说明:

1.State: 门的默认状态(在场景中门是开着还是关着的);

2.Duration:开关门动作的时长;

3.Direction:门从默认状态到另一个状态的移动方向;

4.Magnitude:门从默认状态到另一状态移动的长度。

image.gif

usingUnityEngine;
usingSystem.Collections;
#ifUNITY_EDITORusingUnityEditor;
#endifnamespaceSK.Framework{
/// <summary>/// 移动门/// </summary>publicclassMoveDoor : SwitchableDoor    {
        [SerializeField] privateVector3direction; //移动方向        [SerializeField] privatefloatmagnitude=1f; //移动的长度privateCoroutineswitchCoroutine;
privatevoidStart()
        {
switch (state)
            {
caseSwitchState.Open:
openValue=transform.position;
closeValue=transform.position+direction.normalized*magnitude;
break;
caseSwitchState.Close:
openValue=transform.position+direction.normalized*magnitude;
closeValue=transform.position;
break;
            }
        }
publicoverridevoidOpen()
        {
if (state==SwitchState.Open) return;
state=SwitchState.Open;
if (switchCoroutine!=null) StopCoroutine(switchCoroutine);
switchCoroutine=StartCoroutine(OpenCoroutine());
        }
publicoverridevoidClose()
        {
if (state==SwitchState.Close) return;
state=SwitchState.Close;
if (switchCoroutine!=null) StopCoroutine(switchCoroutine);
switchCoroutine=StartCoroutine(CloseCoroutine());
        }
privateIEnumeratorOpenCoroutine()
        {
floatbeginTime=Time.time;
Vector3beginPos=transform.position;
for (;(Time.time-beginTime) <duration;)
            {
floatt= (Time.time-beginTime) /duration;
transform.position=Vector3.Lerp(beginPos, openValue, t);
yieldreturnnull;
            }
transform.position=openValue;
switchCoroutine=null;
        }
privateIEnumeratorCloseCoroutine()
        {
floatbeginTime=Time.time;
Vector3beginPos=transform.position;
for (; (Time.time-beginTime) <duration;)
            {
floatt= (Time.time-beginTime) /duration;
transform.position=Vector3.Lerp(beginPos, closeValue, t);
yieldreturnnull;
            }
transform.position=closeValue;
switchCoroutine=null;
        }
#ifUNITY_EDITORprivatevoidOnDrawGizmosSelected()
        {
if (!Application.isPlaying)
            {
switch (state)
                {
caseSwitchState.Open:
openValue=transform.position;
closeValue=transform.position+direction.normalized*magnitude;
break;
caseSwitchState.Close:
openValue=transform.position+direction.normalized*magnitude;
closeValue=transform.position;
break;
                }
            }
Handles.color=Color.cyan;
Handles.DrawWireCube(openValue, Vector3.one* .1f);
Handles.DrawWireCube(closeValue, Vector3.one* .1f);
Handles.DrawLine(openValue, closeValue);
Handles.Label(openValue, "Open");
Handles.Label(closeValue, "Close");
        }
#endif    }
}

image.gif

image.gif

2.旋转门:

image.gif

参数说明:

1.State: 门的默认状态(在场景中门是开着还是关着的);

2.Duration:开关门动作的时长;

3.Angle:门从默认状态到另一个状态的旋转角度。

image.gif

usingUnityEngine;
usingSystem.Collections;
#ifUNITY_EDITORusingUnityEditor;
#endifnamespaceSK.Framework{
/// <summary>/// 旋转门/// </summary>publicclassRotateDoor : SwitchableDoor    {
        [SerializeField] privatefloatangle=90f; //旋转角度privateCoroutineswitchCoroutine;
privatevoidStart()
        {
switch (state)
            {
caseSwitchState.Open:
openValue=transform.forward+transform.position;
closeValue=Quaternion.AngleAxis(angle, transform.up) *transform.forward+transform.position;
break;
caseSwitchState.Close:
openValue=Quaternion.AngleAxis(angle, transform.up) *transform.forward+transform.position;
closeValue=transform.forward+transform.position;
break;
            }
        }
publicoverridevoidOpen()
        {
if (state==SwitchState.Open) return;
state=SwitchState.Open;
if (switchCoroutine!=null) StopCoroutine(switchCoroutine);
switchCoroutine=StartCoroutine(OpenCoroutine());
        }
publicoverridevoidClose()
        {
if (state==SwitchState.Close) return;
state=SwitchState.Close;
if (switchCoroutine!=null) StopCoroutine(switchCoroutine);
switchCoroutine=StartCoroutine(CloseCoroutine());
        }
privateIEnumeratorOpenCoroutine()
        {
floatbeginTime=Time.time;
QuaternionbeginRot=transform.rotation;
QuaterniontargetRot=Quaternion.LookRotation(openValue-transform.position, transform.up);
for (; (Time.time-beginTime) <duration;)
            {
floatt= (Time.time-beginTime) /duration;
transform.rotation=Quaternion.Lerp(beginRot, targetRot, t);
yieldreturnnull;
            }
transform.rotation=targetRot;
switchCoroutine=null;
        }
privateIEnumeratorCloseCoroutine()
        {
floatbeginTime=Time.time;
QuaternionbeginRot=transform.rotation;
QuaterniontargetRot=Quaternion.LookRotation(closeValue-transform.position, transform.up);
for (; (Time.time-beginTime) <duration;)
            {
floatt= (Time.time-beginTime) /duration;
transform.rotation=Quaternion.Lerp(beginRot, targetRot, t);
yieldreturnnull;
            }
transform.rotation=targetRot;
switchCoroutine=null;
        }
#ifUNITY_EDITORprivatevoidOnDrawGizmosSelected()
        {
if (!Application.isPlaying)
            {
switch (state)
                {
caseSwitchState.Open:
openValue=transform.forward+transform.position;
closeValue=Quaternion.AngleAxis(angle, transform.up) *transform.forward+transform.position;
break;
caseSwitchState.Close:
openValue=Quaternion.AngleAxis(angle, transform.up) *transform.forward+transform.position;
closeValue=transform.forward+transform.position;
break;
                }
            }
Handles.color=Color.cyan;
Handles.DrawWireCube(openValue, Vector3.one* .1f);
Handles.DrawWireCube(closeValue, Vector3.one* .1f);
Handles.DrawLine(transform.position, openValue);
Handles.DrawLine(transform.position, closeValue);
Handles.Label(openValue, "Open");
Handles.Label(closeValue, "Close");
        }
#endif    }
}

image.gif

image.gif

测试代码:

usingUnityEngine;
usingSK.Framework;
publicclassExample : MonoBehaviour{
    [SerializeField] privateSwitchableObjectdoor;
privatevoidOnGUI()
    {
if (GUILayout.Button("Open", GUILayout.Width(200f), GUILayout.Height(50f))) door.Open();
if (GUILayout.Button("Close", GUILayout.Width(200f), GUILayout.Height(50f))) door.Close();
if (GUILayout.Button("Switch", GUILayout.Width(200f), GUILayout.Height(50f))) door.Switch();
    }
}

image.gif

目录
相关文章
|
图形学
Unity遍历子物体以及孙物体
遍历子物体以及孙物体
|
1月前
|
图形学
小功能⭐️Unity获取场景中所有物体
小功能⭐️Unity获取场景中所有物体
小功能⭐️Unity获取场景中所有物体
|
1月前
|
前端开发 图形学
Unity精华☀️UI和物体可见性的判断方法
Unity精华☀️UI和物体可见性的判断方法
|
1月前
|
图形学
小功能⭐️获取Unity游戏物体上,所挂载组件的名称
小功能⭐️获取Unity游戏物体上,所挂载组件的名称
|
1月前
|
图形学
小功能⭐️解决Unity无法对一个物体上的所有材质球进行更改
小功能⭐️解决Unity无法对一个物体上的所有材质球进行更改
|
1月前
|
数据可视化 图形学
小功能⭐️Unity2018 Shader Graph——全息影像、物体消融
小功能⭐️Unity2018 Shader Graph——全息影像、物体消融
|
1月前
|
图形学
小功能⭐️Unity中利用材质自发光实现物体闪烁效果
小功能⭐️Unity中利用材质自发光实现物体闪烁效果
|
1月前
|
图形学
小功能⭐️Unity 如何判断物体是否在摄像机视野内或外
小功能⭐️Unity 如何判断物体是否在摄像机视野内或外
|
1月前
|
图形学
小功能⭐️Unity解决物体移动速度过快不能检测到碰撞
小功能⭐️Unity解决物体移动速度过快不能检测到碰撞
|
1月前
|
图形学
小功能⭐️不用传参,Unity获得鼠标悬浮处的物体、UI!
小功能⭐️不用传参,Unity获得鼠标悬浮处的物体、UI!