Unity【SwitchableObject】- 实现一个物体开关控制系统
【摘要】
本文介绍如何实现一个物体的开关控制系统,例如门的开关控制、灯的开关控制等,一切包含打开、关闭这两种状态的物体,均可以通过继承下面的抽象类进行重写实现。
状态枚举:
namespace SK.Framework{ /// <summary> /// 状态 /// </summary> p...
本文介绍如何实现一个物体的开关控制系统,例如门的开关控制、灯的开关控制等,一切包含打开、关闭这两种状态的物体,均可以通过继承下面的抽象类进行重写实现。
状态枚举:
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 状态
-
/// </summary>
-
public enum SwitchState
-
{
-
/// <summary>
-
/// 开着的
-
/// </summary>
-
Open,
-
/// <summary>
-
/// 关着的
-
/// </summary>
-
Close,
-
}
-
}
接口:
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 可开关物体接口
-
/// </summary>
-
public interface ISwitchableObject
-
{
-
SwitchState State { get; }
-
-
void Switch();
-
-
void Open();
-
-
void Close();
-
}
-
}
抽象类:
-
using UnityEngine;
-
-
namespace SK.Framework
-
{
-
public abstract class SwitchableObject : MonoBehaviour, ISwitchableObject
-
{
-
//默认设为关闭状态
-
[SerializeField] protected SwitchState state = SwitchState.Close;
-
-
/// <summary>
-
/// 当前状态
-
/// </summary>
-
public SwitchState State { get { return state; } }
-
-
/// <summary>
-
/// 切换 若为打开状态则关闭 若为关闭状态则打开
-
/// </summary>
-
public void Switch()
-
{
-
switch (State)
-
{
-
case SwitchState.Open: Close(); break;
-
case SwitchState.Close: Open(); break;
-
}
-
}
-
-
/// <summary>
-
/// 开门
-
/// </summary>
-
public abstract void Open();
-
/// <summary>
-
/// 关门
-
/// </summary>
-
public abstract void Close();
-
}
-
}
开关处理器,例如我们想要通过一个开关控制多个灯时,或者通过一个开关控制一对门时,均可以通过开关处理器,同时处理多个可开关物体:
-
using UnityEngine;
-
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 开关处理器(把手)
-
/// </summary>
-
public class SwitchableObjectHandler : SwitchableObject
-
{
-
[SerializeField] private SwitchableObject[] handleArray;
-
-
public override void Open()
-
{
-
if (state == SwitchState.Open) return;
-
state = SwitchState.Open;
-
for (int i = 0; i < handleArray.Length; i++)
-
{
-
handleArray[i].Open();
-
}
-
}
-
public override void Close()
-
{
-
if (state == SwitchState.Close) return;
-
state = SwitchState.Close;
-
for (int i = 0; i < handleArray.Length; i++)
-
{
-
handleArray[i].Close();
-
}
-
}
-
}
-
}
这里以门的开关控制为例,我们将门的类型分为移动门和旋转门,首先创建一个门的基类:
-
using UnityEngine;
-
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 可开关门
-
/// </summary>
-
public abstract class SwitchableDoor : SwitchableObject
-
{
-
//开/关所用的时长
-
[SerializeField] protected float duration = 0.5f;
-
//打开状态的值
-
protected Vector3 openValue;
-
//关闭状态的值
-
protected Vector3 closeValue;
-
}
-
}
1.移动门:
参数说明:
1.State: 门的默认状态(在场景中门是开着还是关着的);
2.Duration:开关门动作的时长;
3.Direction:门从默认状态到另一个状态的移动方向;
4.Magnitude:门从默认状态到另一状态移动的长度。
-
using UnityEngine;
-
using System.Collections;
-
-
#if UNITY_EDITOR
-
using UnityEditor;
-
#endif
-
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 移动门
-
/// </summary>
-
public class MoveDoor : SwitchableDoor
-
{
-
[SerializeField] private Vector3 direction; //移动方向
-
[SerializeField] private float magnitude = 1f; //移动的长度
-
private Coroutine switchCoroutine;
-
-
private void Start()
-
{
-
switch (state)
-
{
-
case SwitchState.Open:
-
openValue = transform.position;
-
closeValue = transform.position + direction.normalized * magnitude;
-
break;
-
case SwitchState.Close:
-
openValue = transform.position + direction.normalized * magnitude;
-
closeValue = transform.position;
-
break;
-
}
-
}
-
public override void Open()
-
{
-
if (state == SwitchState.Open) return;
-
state = SwitchState.Open;
-
if (switchCoroutine != null) StopCoroutine(switchCoroutine);
-
switchCoroutine = StartCoroutine(OpenCoroutine());
-
}
-
public override void Close()
-
{
-
if (state == SwitchState.Close) return;
-
state = SwitchState.Close;
-
if (switchCoroutine != null) StopCoroutine(switchCoroutine);
-
switchCoroutine = StartCoroutine(CloseCoroutine());
-
}
-
-
private IEnumerator OpenCoroutine()
-
{
-
float beginTime = Time.time;
-
Vector3 beginPos = transform.position;
-
for (;(Time.time - beginTime) < duration;)
-
{
-
float t = (Time.time - beginTime) / duration;
-
transform.position = Vector3.Lerp(beginPos, openValue, t);
-
yield return null;
-
}
-
transform.position = openValue;
-
switchCoroutine = null;
-
}
-
private IEnumerator CloseCoroutine()
-
{
-
float beginTime = Time.time;
-
Vector3 beginPos = transform.position;
-
for (; (Time.time - beginTime) < duration;)
-
{
-
float t = (Time.time - beginTime) / duration;
-
transform.position = Vector3.Lerp(beginPos, closeValue, t);
-
yield return null;
-
}
-
transform.position = closeValue;
-
switchCoroutine = null;
-
}
-
#if UNITY_EDITOR
-
private void OnDrawGizmosSelected()
-
{
-
if (!Application.isPlaying)
-
{
-
switch (state)
-
{
-
case SwitchState.Open:
-
openValue = transform.position;
-
closeValue = transform.position + direction.normalized * magnitude;
-
break;
-
case SwitchState.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
-
}
-
}
2.旋转门:
参数说明:
1.State: 门的默认状态(在场景中门是开着还是关着的);
2.Duration:开关门动作的时长;
3.Angle:门从默认状态到另一个状态的旋转角度。
-
using UnityEngine;
-
using System.Collections;
-
-
#if UNITY_EDITOR
-
using UnityEditor;
-
#endif
-
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 旋转门
-
/// </summary>
-
public class RotateDoor : SwitchableDoor
-
{
-
[SerializeField] private float angle = 90f; //旋转角度
-
private Coroutine switchCoroutine;
-
-
private void Start()
-
{
-
switch (state)
-
{
-
case SwitchState.Open:
-
openValue = transform.forward + transform.position;
-
closeValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
-
break;
-
case SwitchState.Close:
-
openValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
-
closeValue = transform.forward + transform.position;
-
break;
-
}
-
}
-
public override void Open()
-
{
-
if (state == SwitchState.Open) return;
-
state = SwitchState.Open;
-
if (switchCoroutine != null) StopCoroutine(switchCoroutine);
-
switchCoroutine = StartCoroutine(OpenCoroutine());
-
}
-
public override void Close()
-
{
-
if (state == SwitchState.Close) return;
-
state = SwitchState.Close;
-
if (switchCoroutine != null) StopCoroutine(switchCoroutine);
-
switchCoroutine = StartCoroutine(CloseCoroutine());
-
}
-
-
private IEnumerator OpenCoroutine()
-
{
-
float beginTime = Time.time;
-
Quaternion beginRot = transform.rotation;
-
Quaternion targetRot = Quaternion.LookRotation(openValue - transform.position, transform.up);
-
for (; (Time.time - beginTime) < duration;)
-
{
-
float t = (Time.time - beginTime) / duration;
-
transform.rotation = Quaternion.Lerp(beginRot, targetRot, t);
-
yield return null;
-
}
-
transform.rotation = targetRot;
-
switchCoroutine = null;
-
}
-
private IEnumerator CloseCoroutine()
-
{
-
float beginTime = Time.time;
-
Quaternion beginRot = transform.rotation;
-
Quaternion targetRot = Quaternion.LookRotation(closeValue - transform.position, transform.up);
-
for (; (Time.time - beginTime) < duration;)
-
{
-
float t = (Time.time - beginTime) / duration;
-
transform.rotation = Quaternion.Lerp(beginRot, targetRot, t);
-
yield return null;
-
}
-
transform.rotation = targetRot;
-
switchCoroutine = null;
-
}
-
#if UNITY_EDITOR
-
private void OnDrawGizmosSelected()
-
{
-
if (!Application.isPlaying)
-
{
-
switch (state)
-
{
-
case SwitchState.Open:
-
openValue = transform.forward + transform.position;
-
closeValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
-
break;
-
case SwitchState.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
-
}
-
}
测试代码:
-
using UnityEngine;
-
using SK.Framework;
-
-
public class Example : MonoBehaviour
-
{
-
[SerializeField] private SwitchableObject door;
-
-
private void OnGUI()
-
{
-
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();
-
}
-
}
文章来源: coderz.blog.csdn.net,作者:CoderZ1010,版权归原作者所有,如需转载,请联系作者。
原文链接:coderz.blog.csdn.net/article/details/123548918
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)