读一读

prefab.GetComponentsInChildren<Image>();//不能获取到Active为false的物体的组件
prefab.GetComponentsInChildren<Image>(true);//这个才能获取所有的,包括自己和子物体

Handheld.Vibrate();

set dir=Game_copy

if not exist %dir% ( md %dir%)

mklink/J Game_copy\Assets unity\Assets
mklink/J Game_copy\ProjectSettings unity\ProjectSettings
mklink/J Game_copy\Packages unity\Packages
mklink/J Game_copy\PackageSources unity\PackageSources

pause


写成bat可运行文件,放在项目所在目录下,双击运行

一般来是,除开Library和Temp目录,其它的目录加链接就好了,然后就可以打开这个"新的"项目了


通过调用Animation自带的方法CrossFade()方法就可以实现动画的淡入浅出了

CrossFade(name,0.1)


但是值得注意的是,调用下一个动画的时候需要保证前一个动画是在运行中的,问题就来了。在一些战斗角色中,普通攻击是几段攻击的,都是需要判定在攻击动画完成后才能回到站立或则奔跑状态的,所以就需要限制攻击动画保持未完成状态使其一直播放最后一帧动画,可以直接设置动画的Wrap Mode模式为Clamp Forever

屏幕截图 2020-10-14 182905.png


using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Animations;
using System.Linq;
#endif

[RequireComponent(typeof(Animator))]
public class Script_11 : MonoBehaviour {

}

#if UNITY_EDITOR
[CustomEditor(typeof(Script_11))]
public class ScriptEditor_11 : Editor
{
    private AnimationClip[] m_Clips = null;
    private Script_11 m_Script = null;
    private void OnEnable()
    {
        m_Script = (target as Script_11);
        Animator animator = m_Script.gameObject.GetComponent<Animator>();
        AnimatorController controller = (AnimatorController)animator.runtimeAnimatorController;
        m_Clips = controller.animationClips;
    }

    private int m_SelectIndex = 0;
    private float m_SliderValue = 0;
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        EditorGUI.BeginChangeCheck();
        m_SelectIndex = EditorGUILayout.Popup("动画", m_SelectIndex, m_Clips.Select(pkg => pkg.name).ToArray());
        m_SliderValue = EditorGUILayout.Slider("进度", m_SliderValue, 0f, 1f);
        if (EditorGUI.EndChangeCheck())
        {
            AnimationClip clip = m_Clips[m_SelectIndex];
            float time = clip.length * m_SliderValue;
            clip.SampleAnimation(m_Script.gameObject, time);
        }
    }
}
#endif



GIF.gif


动画融合就是用层,使得两个动画在同一套骨骼上同时播放。例如下半身的跑步,上半身的招收。为了让上下部分的骨骼相互不影响,可以设置他们的AvatarMask。点击Layers面板的+号新增加一层,让Base Layer来处理整体逻辑,而让New Layer专门用来做动画融合,Weight设置融合的权重,Mask就是遮罩文件了,Blending设置的Override表示直接覆盖掉其它层的动画。

图片.png


动画混合是使用Blend Tree来制作的。动画混合是指在两个动画切换的时候,为了避免太过生硬而混合在一起的过程。例如,控制角色向前跑、向左跑和向右跑,左右切换跑的时候就要用到它。在Layer中单机鼠标右键,从弹出的快捷菜单中选择Create State->From New Blend Tree命令创建它。双击打开,右键Add Motion,添加动画文件,在Inspector取消勾选Automate Thresholds,就可以自己设置Threshold的值。

GIF.gif


using Unity.Collections;
using UnityEngine;
using UnityEngine.Jobs;

public struct mJob : IJobParallelForTransform {

    [ReadOnly]
    public NativeArray<Vector3> position;

    public void Execute(int index, TransformAccess transform)
    {
        transform.position = position[index];
    }
}


using UnityEngine;
using Unity.Collections;
using UnityEngine.Jobs;
using Unity.Jobs;

public class Script2 : MonoBehaviour {

    public Transform[] cubes;

    void Update () {
        if (Input.GetMouseButtonDown(0))
        {
            //随机设置坐标
            NativeArray<Vector3> position = new NativeArray<Vector3>(cubes.Length,Allocator.Persistent);
            for (int i = 0; i < position.Length; i++)
            {
                position[i] = Vector3.one * Random.Range(i, i + 10);
            }
            //设置Transform
            TransformAccessArray transformArray = new TransformAccessArray(cubes);
            mJob job = new mJob { position = position };
            JobHandle jobHandle = job.Schedule(transformArray);
            jobHandle.Complete();//等待线程结束
            Debug.LogError("结束同步");
            transformArray.Dispose();
            position.Dispose();
        }
    }
}


只要继承IJobParallelForTransform接口,并且实现Execute()方法,就可以在工作线程中处理耗时操作了,同步坐标等。


using UnityEngine;
using UnityEngine.Events;

public class CustomWait : CustomYieldInstruction
{
    private UnityAction m_IntervalCallback;
    private float m_StartTime;
    private float m_LastTime;
    private float m_Interval;
    private float m_Time;
    
    public CustomWait(float time, float interval, UnityAction callback)
    {
        m_StartTime = Time.time;
        m_LastTime = Time.time;
        m_Interval = interval;
        m_Time = time;
        m_IntervalCallback = callback;
    }

    //判断协成是否继续等待 false为协成结束
    public override bool keepWaiting
    {
        get
        {
            if (Time.time - m_StartTime >= m_Time)
            {
                return false;
            }
            else if (Time.time - m_LastTime >= m_Interval)
            {
                m_LastTime = Time.time;
                m_IntervalCallback();
            }
            return true;
        }
    }
}

public class TestCustomWait : MonoBehaviour {
    
    IEnumerator Start () {
        yield return new CustomWait(10f, 1f, delegate ()
        {
            Debug.LogError("自定义的协成等待");
        });
    }
}


继承CustomYieldInstruction,实现keepWaiting接口,根据具体情况返回状态。

图片.png


脚本挂得越多,执行效率就越低。Unity会需要遍历每一个脚本,然后通过反射调用每个脚本的方法。不可避免的,场景中不止一个脚本,有时候就会遇到执行先后的问题。通过Edit/Project Settings/Script Execution Order,配置具体脚本的执行索引,越小越先执行。

图片.png


cube t:prefab  搜索名字为cube,类型为prefab的物体

20 t:sprite  搜索名字为20,类型为sprite的物体

l:paths 搜索标签为paths的物体