Unity 制作旋转门 推拉门 柜门 抽屉 点击自动开门效果 开关门自动播放音效 (附带编辑器扩展代码)

简易的门制作

对于一个新手来说,这个工具是最好的选择
请添加图片描述

上一篇关于开关门的文章相对于复杂,感兴趣的可以查看上篇开关门制作

优点
  • 挂载就能使用
  • 控制面板一看就懂(全是中文)
  • 简单的调试就能获得自己想要的效果
  • 易懂且易修改的代码
面板

请添加图片描述

参数
  • 锁:勾选后不能对门进行操作
  • 声音:激活时自动播放
  • 激活:测试开关门
  • 查看结果位置:按住查看结果,松开返回
    请添加图片描述
    旋转门的使用不做介绍
推拉门(推拉抽屉):
  • 起始位置:门的初始位置
  • 结束位置:门要移动的位置
  • 得到位置按钮:当你在场景中调整门的位置后,把当前门的位置赋值到左侧
代码

挂载之后会自动添加Audio Source组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(AudioSource))]
public class Door_Interaction : MonoBehaviour
{
    public enum doorType { RotatingDoor = 0, SlidingDoor = 1 }
    public doorType doorMovementType;
    public bool open;
    public bool locked;
    public float rotateAngle = 90;
    public float speed = 1;
    public enum axis { X = 0, Y = 1, Z = 2 }
    public axis rotateAxis = axis.Y;
    public Vector3 startingPosition;
    public Vector3 endingPosition;
    public AudioClip startClip;
    public AudioClip endClip;
    private AudioSource sound;
    public Quaternion originRotation;
    public Quaternion openRotation;
    private float r;
    private bool opening;

    [Tooltip("激活测试")]
    public bool activate = false;
    void Start()
    {
        InitRotation();
        sound = GetComponent<AudioSource>();
        r = 0;
    }
    public void InitRotation()
    {
        originRotation = transform.rotation;
        openRotation = originRotation;
        if (rotateAxis == axis.Y)
        {
            openRotation = Quaternion.Euler(new Vector3(originRotation.eulerAngles.x, originRotation.eulerAngles.y + rotateAngle, originRotation.eulerAngles.z));
        }
        else if (rotateAxis == axis.X)
        {
            openRotation = Quaternion.Euler(new Vector3(originRotation.eulerAngles.x + rotateAngle, originRotation.eulerAngles.y, originRotation.eulerAngles.z));
        }
        else if (rotateAxis == axis.Z)
        {
            openRotation = Quaternion.Euler(new Vector3(originRotation.eulerAngles.x, originRotation.eulerAngles.y, originRotation.eulerAngles.z + rotateAngle));
        }
    }

    void Update()
    {
        if (activate)
        {
            activate = false;
            if (opening == false && locked == false)
            {
                open = !open;
                r = 0;
                opening = true;
            }
        }
        if (opening)
        {
            ChangeState(open);
        }
    }
    void ChangeState(bool State)
    {
        Quaternion quaternion;
        Vector3 vector3;
        if (State)
        {
            quaternion = openRotation;
            vector3 = endingPosition;
            if (startClip!=null&& r==0)
            {
                sound.clip = startClip;
                sound.Play();
            }
            
        }
        else
        {
            quaternion = originRotation;
            vector3 = startingPosition;
            if (endClip != null && r == 0)
            {
                sound.clip = endClip;
                sound.Play(); 
            }
        }
        r += Time.deltaTime * speed;
        if (doorMovementType == doorType.RotatingDoor)
        {
            if (Quaternion.Angle(quaternion, transform.rotation) > 0.1F)
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, quaternion, r);
            }
            else
            {
                transform.rotation = quaternion;
                r = 0;
                opening = false;
            }
        }
        else if (doorMovementType == doorType.SlidingDoor)
        {
            if (Vector3.Distance(transform.localPosition, vector3) > 0.005F)
            {
                transform.localPosition = Vector3.Lerp(transform.localPosition, vector3, r);
            }
            else
            {
                transform.localPosition = vector3;
                r = 0;
                opening = false;
            }
        }
    }
}
编辑器扩展代码

需要注意!这个代码必须放在Editor文件下才能正常使用,Unity会自己处理Editor文件夹,就像Resources文件夹一样
我之前写的通用相机控制器也是一样的使用方法
感兴趣的可以查看通用相机控制器
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(Door_Interaction)), CanEditMultipleObjects]
public class Door_Interaction_Editor : Editor
{
    private SerializedProperty open;
    private SerializedProperty locked;
    private SerializedProperty rotateAngle;
    private SerializedProperty speed;
    private SerializedProperty rotateAxis;
    private SerializedProperty startingPosition;
    private SerializedProperty endingPosition;
    private SerializedProperty activate;
    private SerializedProperty startClip;
    private SerializedProperty endClip;
    private GUIStyle defaultStyle = new GUIStyle();

    public void OnEnable()
    {
        open = serializedObject.FindProperty("open");
        locked = serializedObject.FindProperty("locked");
        rotateAngle = serializedObject.FindProperty("rotateAngle");
        speed = serializedObject.FindProperty("speed");
        rotateAxis = serializedObject.FindProperty("rotateAxis");
        startingPosition = serializedObject.FindProperty("startingPosition");
        endingPosition = serializedObject.FindProperty("endingPosition");
        activate = serializedObject.FindProperty("activate");
        startClip = serializedObject.FindProperty("startClip");
        endClip = serializedObject.FindProperty("endClip");
    }
    bool IsButtonDown = false;
    Vector3 CurrentPosition= Vector3.zero;
    Quaternion CurrentRotation = Quaternion.identity;
    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        var myScript = target as Door_Interaction;
        var doorGUIContent = new GUIContent("门类型", "选择不同门的类型参数也有所改变");
        GUIContent[] doorOptions;
        doorOptions = new[] { new GUIContent("旋转门"), new GUIContent("推拉门") };

        myScript.doorMovementType = (Door_Interaction.doorType)EditorGUILayout.Popup(doorGUIContent, (int)myScript.doorMovementType, doorOptions);
        EditorGUILayout.PropertyField(open,new GUIContent("当前状态"));
        EditorGUILayout.PropertyField(locked, new GUIContent("锁"));
        EditorGUILayout.PropertyField(speed, new GUIContent("执行速度"));

        EditorGUILayout.PropertyField(startClip, new GUIContent("打开时的声音"));
        EditorGUILayout.PropertyField(endClip, new GUIContent("关闭时的声音"));
        EditorGUILayout.PropertyField(activate, new GUIContent("激活"));

        GUILayout.Space(20);//间隔
        if (myScript.doorMovementType == Door_Interaction.doorType.RotatingDoor) {

            EditorGUILayout.PropertyField(rotateAngle, new GUIContent("旋转角度"));
            EditorGUILayout.PropertyField(rotateAxis, new GUIContent("轴", "门的旋转轴。 默认是Y "));
            GUILayout.Space(20);//间隔
            if (GUILayout.RepeatButton(new GUIContent("查看结束位置", "在视图中查看结束位置")))
            {
                if (IsButtonDown == false)
                {
                    IsButtonDown = true;
                    myScript.InitRotation();
                    CurrentRotation = myScript.transform.localRotation;
                }
                myScript.transform.rotation = myScript.openRotation;
            }
            else
            {
                if (IsButtonDown)
                {
                    IsButtonDown = false;
                    myScript.transform.localRotation = CurrentRotation;
                }
            }
        } else if (myScript.doorMovementType == Door_Interaction.doorType.SlidingDoor) {

            defaultStyle.alignment = TextAnchor.UpperCenter; //字体对齐方式: 水平靠左,垂直居中
            defaultStyle.normal.textColor = Color.yellow; //字体颜色:黄色
            defaultStyle.fontSize = 15; //字体大小: 20

            GUILayout.Label("起始位置", defaultStyle);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(startingPosition, new GUIContent(""));
            if (GUILayout.Button(new GUIContent("得到位置", "将当前的局部坐标赋值给开始位置")))
            {
                myScript.startingPosition = myScript.transform.localPosition;
            }
            EditorGUILayout.EndHorizontal();

            GUILayout.Label("结束位置", defaultStyle);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(endingPosition, new GUIContent(""));
            if (GUILayout.Button(new GUIContent("得到位置", "将当前的局部坐标赋值给结束位置")))
            {
                myScript.endingPosition = myScript.transform.localPosition;
            }
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(20);//间隔
            if (GUILayout.RepeatButton(new GUIContent("查看结束位置", "在视图中查看结束位置")))
            {
                if (IsButtonDown==false)
                {
                    IsButtonDown = true;
                    CurrentPosition = myScript.transform.localPosition;
                }
                myScript.transform.localPosition = myScript.endingPosition;
            }
            else
            {
                if (IsButtonDown)
                {
                    IsButtonDown = false;
                    myScript.transform.localPosition = CurrentPosition;
                }
            } 
        }
        serializedObject.ApplyModifiedProperties();//顾名思义 应用修改的属性
        if (GUI.changed == true) {
            EditorUtility.SetDirty(target);//这个函数告诉引擎,相关对象所属于的Prefab已经发生了更改。
        }
    }
}

别要Demo了,按照流程赋值粘贴代码就能用 !

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐沢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值