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

举报
CoderZ1010 发表于 2022/09/25 04:17:35 2022/09/25
【摘要】 本文介绍如何实现一个物体的开关控制系统,例如门的开关控制、灯的开关控制等,一切包含打开、关闭这两种状态的物体,均可以通过继承下面的抽象类进行重写实现。 状态枚举: 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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。