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

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

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

状态枚举:


  
  1. namespace SK.Framework
  2. {
  3. /// <summary>
  4. /// 状态
  5. /// </summary>
  6. public enum SwitchState
  7. {
  8. /// <summary>
  9. /// 开着的
  10. /// </summary>
  11. Open,
  12. /// <summary>
  13. /// 关着的
  14. /// </summary>
  15. Close,
  16. }
  17. }

接口: 


  
  1. namespace SK.Framework
  2. {
  3. /// <summary>
  4. /// 可开关物体接口
  5. /// </summary>
  6. public interface ISwitchableObject
  7. {
  8. SwitchState State { get; }
  9. void Switch();
  10. void Open();
  11. void Close();
  12. }
  13. }

 抽象类:


  
  1. using UnityEngine;
  2. namespace SK.Framework
  3. {
  4. public abstract class SwitchableObject : MonoBehaviour, ISwitchableObject
  5. {
  6. //默认设为关闭状态
  7. [SerializeField] protected SwitchState state = SwitchState.Close;
  8. /// <summary>
  9. /// 当前状态
  10. /// </summary>
  11. public SwitchState State { get { return state; } }
  12. /// <summary>
  13. /// 切换 若为打开状态则关闭 若为关闭状态则打开
  14. /// </summary>
  15. public void Switch()
  16. {
  17. switch (State)
  18. {
  19. case SwitchState.Open: Close(); break;
  20. case SwitchState.Close: Open(); break;
  21. }
  22. }
  23. /// <summary>
  24. /// 开门
  25. /// </summary>
  26. public abstract void Open();
  27. /// <summary>
  28. /// 关门
  29. /// </summary>
  30. public abstract void Close();
  31. }
  32. }

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


  
  1. using UnityEngine;
  2. namespace SK.Framework
  3. {
  4. /// <summary>
  5. /// 开关处理器(把手)
  6. /// </summary>
  7. public class SwitchableObjectHandler : SwitchableObject
  8. {
  9. [SerializeField] private SwitchableObject[] handleArray;
  10. public override void Open()
  11. {
  12. if (state == SwitchState.Open) return;
  13. state = SwitchState.Open;
  14. for (int i = 0; i < handleArray.Length; i++)
  15. {
  16. handleArray[i].Open();
  17. }
  18. }
  19. public override void Close()
  20. {
  21. if (state == SwitchState.Close) return;
  22. state = SwitchState.Close;
  23. for (int i = 0; i < handleArray.Length; i++)
  24. {
  25. handleArray[i].Close();
  26. }
  27. }
  28. }
  29. }

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


  
  1. using UnityEngine;
  2. namespace SK.Framework
  3. {
  4. /// <summary>
  5. /// 可开关门
  6. /// </summary>
  7. public abstract class SwitchableDoor : SwitchableObject
  8. {
  9. //开/关所用的时长
  10. [SerializeField] protected float duration = 0.5f;
  11. //打开状态的值
  12. protected Vector3 openValue;
  13. //关闭状态的值
  14. protected Vector3 closeValue;
  15. }
  16. }

1.移动门:

参数说明:

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

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

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

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


  
  1. using UnityEngine;
  2. using System.Collections;
  3. #if UNITY_EDITOR
  4. using UnityEditor;
  5. #endif
  6. namespace SK.Framework
  7. {
  8. /// <summary>
  9. /// 移动门
  10. /// </summary>
  11. public class MoveDoor : SwitchableDoor
  12. {
  13. [SerializeField] private Vector3 direction; //移动方向
  14. [SerializeField] private float magnitude = 1f; //移动的长度
  15. private Coroutine switchCoroutine;
  16. private void Start()
  17. {
  18. switch (state)
  19. {
  20. case SwitchState.Open:
  21. openValue = transform.position;
  22. closeValue = transform.position + direction.normalized * magnitude;
  23. break;
  24. case SwitchState.Close:
  25. openValue = transform.position + direction.normalized * magnitude;
  26. closeValue = transform.position;
  27. break;
  28. }
  29. }
  30. public override void Open()
  31. {
  32. if (state == SwitchState.Open) return;
  33. state = SwitchState.Open;
  34. if (switchCoroutine != null) StopCoroutine(switchCoroutine);
  35. switchCoroutine = StartCoroutine(OpenCoroutine());
  36. }
  37. public override void Close()
  38. {
  39. if (state == SwitchState.Close) return;
  40. state = SwitchState.Close;
  41. if (switchCoroutine != null) StopCoroutine(switchCoroutine);
  42. switchCoroutine = StartCoroutine(CloseCoroutine());
  43. }
  44. private IEnumerator OpenCoroutine()
  45. {
  46. float beginTime = Time.time;
  47. Vector3 beginPos = transform.position;
  48. for (;(Time.time - beginTime) < duration;)
  49. {
  50. float t = (Time.time - beginTime) / duration;
  51. transform.position = Vector3.Lerp(beginPos, openValue, t);
  52. yield return null;
  53. }
  54. transform.position = openValue;
  55. switchCoroutine = null;
  56. }
  57. private IEnumerator CloseCoroutine()
  58. {
  59. float beginTime = Time.time;
  60. Vector3 beginPos = transform.position;
  61. for (; (Time.time - beginTime) < duration;)
  62. {
  63. float t = (Time.time - beginTime) / duration;
  64. transform.position = Vector3.Lerp(beginPos, closeValue, t);
  65. yield return null;
  66. }
  67. transform.position = closeValue;
  68. switchCoroutine = null;
  69. }
  70. #if UNITY_EDITOR
  71. private void OnDrawGizmosSelected()
  72. {
  73. if (!Application.isPlaying)
  74. {
  75. switch (state)
  76. {
  77. case SwitchState.Open:
  78. openValue = transform.position;
  79. closeValue = transform.position + direction.normalized * magnitude;
  80. break;
  81. case SwitchState.Close:
  82. openValue = transform.position + direction.normalized * magnitude;
  83. closeValue = transform.position;
  84. break;
  85. }
  86. }
  87. Handles.color = Color.cyan;
  88. Handles.DrawWireCube(openValue, Vector3.one * .1f);
  89. Handles.DrawWireCube(closeValue, Vector3.one * .1f);
  90. Handles.DrawLine(openValue, closeValue);
  91. Handles.Label(openValue, "Open");
  92. Handles.Label(closeValue, "Close");
  93. }
  94. #endif
  95. }
  96. }

 

2.旋转门:

 参数说明:

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

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

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


  
  1. using UnityEngine;
  2. using System.Collections;
  3. #if UNITY_EDITOR
  4. using UnityEditor;
  5. #endif
  6. namespace SK.Framework
  7. {
  8. /// <summary>
  9. /// 旋转门
  10. /// </summary>
  11. public class RotateDoor : SwitchableDoor
  12. {
  13. [SerializeField] private float angle = 90f; //旋转角度
  14. private Coroutine switchCoroutine;
  15. private void Start()
  16. {
  17. switch (state)
  18. {
  19. case SwitchState.Open:
  20. openValue = transform.forward + transform.position;
  21. closeValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
  22. break;
  23. case SwitchState.Close:
  24. openValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
  25. closeValue = transform.forward + transform.position;
  26. break;
  27. }
  28. }
  29. public override void Open()
  30. {
  31. if (state == SwitchState.Open) return;
  32. state = SwitchState.Open;
  33. if (switchCoroutine != null) StopCoroutine(switchCoroutine);
  34. switchCoroutine = StartCoroutine(OpenCoroutine());
  35. }
  36. public override void Close()
  37. {
  38. if (state == SwitchState.Close) return;
  39. state = SwitchState.Close;
  40. if (switchCoroutine != null) StopCoroutine(switchCoroutine);
  41. switchCoroutine = StartCoroutine(CloseCoroutine());
  42. }
  43. private IEnumerator OpenCoroutine()
  44. {
  45. float beginTime = Time.time;
  46. Quaternion beginRot = transform.rotation;
  47. Quaternion targetRot = Quaternion.LookRotation(openValue - transform.position, transform.up);
  48. for (; (Time.time - beginTime) < duration;)
  49. {
  50. float t = (Time.time - beginTime) / duration;
  51. transform.rotation = Quaternion.Lerp(beginRot, targetRot, t);
  52. yield return null;
  53. }
  54. transform.rotation = targetRot;
  55. switchCoroutine = null;
  56. }
  57. private IEnumerator CloseCoroutine()
  58. {
  59. float beginTime = Time.time;
  60. Quaternion beginRot = transform.rotation;
  61. Quaternion targetRot = Quaternion.LookRotation(closeValue - transform.position, transform.up);
  62. for (; (Time.time - beginTime) < duration;)
  63. {
  64. float t = (Time.time - beginTime) / duration;
  65. transform.rotation = Quaternion.Lerp(beginRot, targetRot, t);
  66. yield return null;
  67. }
  68. transform.rotation = targetRot;
  69. switchCoroutine = null;
  70. }
  71. #if UNITY_EDITOR
  72. private void OnDrawGizmosSelected()
  73. {
  74. if (!Application.isPlaying)
  75. {
  76. switch (state)
  77. {
  78. case SwitchState.Open:
  79. openValue = transform.forward + transform.position;
  80. closeValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
  81. break;
  82. case SwitchState.Close:
  83. openValue = Quaternion.AngleAxis(angle, transform.up) * transform.forward + transform.position;
  84. closeValue = transform.forward + transform.position;
  85. break;
  86. }
  87. }
  88. Handles.color = Color.cyan;
  89. Handles.DrawWireCube(openValue, Vector3.one * .1f);
  90. Handles.DrawWireCube(closeValue, Vector3.one * .1f);
  91. Handles.DrawLine(transform.position, openValue);
  92. Handles.DrawLine(transform.position, closeValue);
  93. Handles.Label(openValue, "Open");
  94. Handles.Label(closeValue, "Close");
  95. }
  96. #endif
  97. }
  98. }

测试代码:


  
  1. using UnityEngine;
  2. using SK.Framework;
  3. public class Example : MonoBehaviour
  4. {
  5. [SerializeField] private SwitchableObject door;
  6. private void OnGUI()
  7. {
  8. if (GUILayout.Button("Open", GUILayout.Width(200f), GUILayout.Height(50f))) door.Open();
  9. if (GUILayout.Button("Close", GUILayout.Width(200f), GUILayout.Height(50f))) door.Close();
  10. if (GUILayout.Button("Switch", GUILayout.Width(200f), GUILayout.Height(50f))) door.Switch();
  11. }
  12. }

文章来源: coderz.blog.csdn.net,作者:CoderZ1010,版权归原作者所有,如需转载,请联系作者。

原文链接:coderz.blog.csdn.net/article/details/123548918

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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