/// <summary> /// copies component values into the default state's preset. /// if needed, creates & adds default state to the state list. /// to be called on app startup and statemanager recombine /// </summary> #if UNITY_EDITOR public void RefreshInitialState() { m_InitialState = null; m_InitialState = new vp_AIState(GetType().Name, "Internal_Initial", null); m_InitialState.Preset = new vp_AIComponentPreset(); m_InitialState.Preset.InitFromComponent(this); }
/// <summary> /// adds a state to the list of states that blocks this one /// </summary> public void AddBlocker(vp_AIState blocker) { if (!CurrentlyBlockedBy.Contains(blocker)) { CurrentlyBlockedBy.Add(blocker); } }
/// <summary> /// restores the int block list onto all states by name, by /// fetching block lists in string-list format from the /// backup dictionary and converting them back to int-lists /// to be set on the components /// </summary> static void RestoreBlockLists(vp_AIComponent component) { foreach (string s in m_BlockListBackups.Keys) { vp_AIState blocker = GetState(component, s); if (blocker == null) { continue; } List <string> stringBlockList; if (!m_BlockListBackups.TryGetValue(s, out stringBlockList)) { continue; } List <int> intBlockList = new List <int>(); foreach (string b in stringBlockList) { int blockee = GetStateId(component, b); if (blockee != -1) { intBlockList.Add(GetStateId(component, b)); } } blocker.StatesToBlock = intBlockList; } }
/// <summary> /// removes a state from the list of states that blocks this one /// </summary> public void RemoveBlocker(vp_AIState blocker) { if (CurrentlyBlockedBy.Contains(blocker)) { CurrentlyBlockedBy.Remove(blocker); } }
/// <summary> /// gets a random audio clip for the specified state /// </summary> protected virtual AudioClip OnMessage_GetAudioClipForState(object obj) { if (obj == null) { return(null); } if (obj.GetType() != typeof(vp_AIState)) { return(null); } vp_AIState state = (vp_AIState)obj; if (state == null) { return(null); } if (state.AudioClips == null) { return(null); } if (state.AudioClips.Count == 0) { return(null); } reroll: AudioClip clip = state.AudioClips[Random.Range(0, state.AudioClips.Count)]; if (clip == null) { return(null); } if (clip == null) { return(null); } // if the animation was the last one played, reroll for another animation if (clip == state.LastAudioClip && state.AudioClips.Count > 1) { goto reroll; } if (state.AudioProbability > 0) { if ((float)Random.Range(0f, 1f) > state.AudioProbability) { return(null); } } return(clip); }
/// <summary> /// Refreshes a state from the States and Presets section /// </summary> public virtual vp_AIState RefreshState(vp_AIState state) { if (state.Name == null) { return(null); } return(States.Find(s => s.Name == state.Name)); }
/// <summary> /// draws a button showing if a state is on or off, allowing /// the user to toggle states at runtime. will also show /// a text saying if the state is currently disallowed /// </summary> public static void RunTimeStateField(vp_AIComponent component, vp_AIState state, List <vp_AIState> stateList) { EditorGUILayout.BeginHorizontal(); GUI.color = m_ColorTransparentWhite; if (!state.Enabled) { GUILayout.Space(20); GUI.enabled = true; GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); GUILayout.BeginHorizontal(); if (GUILayout.Button(state.Name, vp_EditorGUIUtility.CenteredBoxStyle, GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { vp_AIComponent[] compos = component.gameObject.GetComponentsInChildren <vp_AIComponent>(); foreach (vp_AIComponent c in compos) { c.StateManager.SetState(state.Name, true); c.Refresh(); } } GUILayout.EndHorizontal(); GUI.color = m_ColorTransparentWhite; } else { GUILayout.Space(20); GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); if (GUILayout.Button(state.Name, ((!state.Blocked) ? vp_EditorGUIUtility.CenteredBoxStyleBold : vp_EditorGUIUtility.CenteredStyleBold) , GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { vp_AIComponent[] compos = component.gameObject.GetComponentsInChildren <vp_AIComponent>(); foreach (vp_AIComponent c in compos) { c.StateManager.SetState(state.Name, false); c.Refresh(); } } } if (state.Name != "Default") { if (state.Blocked) { GUILayout.TextField("(Blocked on " + component.GetType().ToString() + "(" + state.BlockCount + "))", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); } if ((state.TextAsset == null) && (!state.Blocked)) { GUILayout.TextField("(No preset)", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); } } EditorGUILayout.EndHorizontal(); }
/// <summary> /// Returns a popup list with enabled audio states /// </summary> public static vp_AIState GetAudioState(string title, vp_AIState state, string tooltip = "") { List <vp_AIState> states = m_AI.States.Where(s => s.Name != "Default" && s.IsAudioState).ToList(); states.Insert(0, null); state = states.FirstOrDefault(s => s != null && s.Name == state.Name); int selected = state == null ? 0 : states.IndexOf(state); GUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent(title, title + "\n\n" + tooltip), GUILayout.MinWidth(100), GUILayout.MaxWidth(200)); selected = EditorGUILayout.Popup(selected, AudioStateNames); GUILayout.EndHorizontal(); return(selected == -1 ? null : states[selected]); }
/// <summary> /// sees if the component has a default state. if so, makes /// sure it's in index zero of the list, if not, creates it. /// </summary> public void RefreshDefaultState() { vp_AIState defaultState = null; if (States.Count == 0) { // there are no states, so create default state defaultState = new vp_AIState(GetType().Name, "Default", null); States.Add(defaultState); } else { for (int v = States.Count - 1; v > -1; v--) { if (States[v].Name == "Default") { // found default state, make sure it's in the back defaultState = States[v]; States.Remove(defaultState); States.Add(defaultState); } } if (defaultState == null) { // there are states, but no default state so create it defaultState = new vp_AIState(GetType().Name, "Default", null); States.Add(defaultState); } } if (defaultState.Preset == null || defaultState.Preset.ComponentType == null) { defaultState.Preset = new vp_AIComponentPreset(); } if (defaultState.TextAsset == null) { defaultState.Preset.InitFromComponent(this); } defaultState.Enabled = true; // default state is always enabled m_DefaultState = defaultState; }
/// <summary> /// draws a slot to which the user can drag a preset TextAsset /// </summary> private static void PresetField(vp_AIState state) { TextAsset orig = state.TextAsset; state.TextAsset = (TextAsset)EditorGUILayout.ObjectField(state.TextAsset, typeof(TextAsset), false); if (state.TextAsset != orig) { if (state.TextAsset != null) { if ((vp_AIComponentPreset.GetFileTypeFromAsset(state.TextAsset) == null || vp_AIComponentPreset.GetFileTypeFromAsset(state.TextAsset).Name != state.TypeName)) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "Error: The file '" + state.TextAsset.name + " ' does not contain a preset of type '" + state.TypeName + "'."); state.TextAsset = orig; return; } } } }
/// <summary> /// draws a disabled preset field for the built-in default /// state, making the user aware of the state /// </summary> public static void DefaultStateField(vp_AIState state) { EditorGUILayout.BeginHorizontal(); GUI.enabled = false; GUILayout.Label("Default", "Textfield", GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); PresetField(state); GUILayout.TextField("(editor)", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); EditorGUILayout.Space(); GUI.color = Color.clear; GUILayout.Button("...", GUILayout.MinWidth(24), GUILayout.MaxWidth(24)); GUILayout.Button("X", GUILayout.MinWidth(24), GUILayout.MaxWidth(24)); GUI.color = Color.white; GUI.enabled = true; EditorGUILayout.EndHorizontal(); }
/// <summary> /// removes this state from the 'CurrentlyBlockedBy' list of /// all states in this state's 'StatesToBlock' list /// </summary> public void RelaxBlockingList(vp_AIState blocker) { if (blocker == null) { return; } if (blocker.StatesToBlock == null) { return; } if (m_States == null) { return; } foreach (int blockee in blocker.StatesToBlock) { m_States[blockee].RemoveBlocker(blocker); } }
/// <summary> /// draws a row displaying a preset state name, a path and /// buttons for browsing the path + deleting the state /// </summary> public static void StateField(vp_AIState state, List <vp_AIState> stateList, vp_AIComponent component) { GUI.enabled = !Application.isPlaying; // only allow preset field interaction in 'stopped' mode EditorGUILayout.BeginHorizontal(); string orig = state.Name; if (state.Name == "Default") { GUI.enabled = false; EditorGUILayout.TextField(state.Name, GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); GUI.enabled = true; } else { if (m_ShowBlockListFor != null) { if (!component.States.Contains(m_ShowBlockListFor)) { m_ShowBlockListFor = null; } else if (m_ShowBlockListFor.StatesToBlock.Contains(component.States.IndexOf(state))) { GUI.color = m_ColorGrayYellow; } } state.Name = EditorGUILayout.TextField(state.Name, GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); GUI.color = Color.white; } if (orig != state.Name) { int collisions = -1; foreach (vp_AIState s in stateList) { if (s.Name == state.Name) { collisions++; } } if (state.Name == "Default") { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "'Default' is a reserved state name."); state.Name = orig; } else if (state.Name.Length == 0) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "State name can't be empty."); state.Name = orig; } else if (collisions > 0) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "There is already a state named '" + state.Name + "'.\nTIP: If you need a similar state name, begin by adding numbers at the end."); state.Name = orig; } else { EditorUtility.SetDirty(component); } } PresetField(state); if (state.Name == "Default") { if (state.TextAsset == null) { GUI.enabled = false; GUILayout.TextField("(Inspector)", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(60)); } else { GUI.enabled = true; if (GUILayout.Button("Unlock", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(30), GUILayout.MinHeight(15))) { state.TextAsset = null; EditorUtility.SetDirty(component); } } } else { if (stateList.IndexOf(state) == 0) { GUI.enabled = false; } GUI.SetNextControlName("state"); if (GUILayout.Button("^", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(16))) { BackupBlockLists(component); int i = stateList.IndexOf(state); if (i != 0) { stateList.Remove(state); stateList.Insert(i - 1, state); } RestoreBlockLists(component); // focus this button to get rid of possible textfield focus, // or the textfields won't update properly when moving state GUI.FocusControl("state"); EditorUtility.SetDirty(component); } GUI.enabled = true; if (GUILayout.Button(new GUIContent(state.IsAnimationState ? m_AnimationTexture : m_AnimationOffTexture, "Enable/Disable Animation State for " + state.Name), SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(11))) { state.IsAnimationState = !state.IsAnimationState; } GUI.color = state.IsAudioState ? m_ColorYellow : Color.white; if (UnityEditorInternal.InternalEditorUtility.HasPro()) { GUI.color = state.IsAudioState ? m_ColorYellowPro : Color.white; } if (GUILayout.Button(new GUIContent(m_SoundTexture, "Enable/Disable Audio State for " + state.Name), SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(11))) { state.IsAudioState = !state.IsAudioState; } GUI.color = Color.white; if (state.StatesToBlock != null) { if ((state.StatesToBlock.Count > 0) && ((m_ShowBlockListFor == null) || (!component.States.Contains(m_ShowBlockListFor)) || m_ShowBlockListFor == state)) { GUI.color = m_ColorGrayYellow; } } GUI.enabled = (component.States.Count > 2); if (GUILayout.Button("B", SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(16))) { if (m_ShowBlockListFor == state) { m_ShowBlockListFor = null; } else { m_ShowBlockListFor = state; } EditorUtility.SetDirty(component); } GUI.enabled = true; GUI.color = Color.white; if (GUILayout.Button("X", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(16))) { vp_MessageBox.Create(vp_MessageBox.Mode.YesNo, "Confirm", "Are you sure you want to delete the state '" + state.Name + "'?", delegate(vp_MessageBox.Answer answer) { if (answer == vp_MessageBox.Answer.Yes) { BackupBlockLists(component); stateList.Remove(state); RestoreBlockLists(component); EditorUtility.SetDirty(component); } }); EditorUtility.SetDirty(component); } } GUI.enabled = true; EditorGUILayout.EndHorizontal(); }
/// <summary> /// chooses a random sound to play from the list of sounds /// provided for this state /// </summary> protected virtual bool OnMessage_PlaySound(object obj) { if (m_Audio.isPlaying) { return(false); } if (obj == null) { return(false); } if (obj.GetType() != typeof(vp_AIState)) { return(false); } vp_AIState state = (vp_AIState)obj; if (state == null) { return(false); } if (state.AudioClips == null) { return(false); } if (state.AudioClips.Count == 0) { return(false); } if (Time.time < state.LastTimeAudioPlayed) { return(false); } state.LastTimeAudioPlayed = Time.time + state.AudioPlayInterval; reroll: AudioClip clip = state.AudioClips[Random.Range(0, state.AudioClips.Count)]; if (clip == null) { return(false); } if (clip == null) { return(false); } // if the animation was the last one played, reroll for another animation if (clip == state.LastAudioClip && state.AudioClips.Count > 1) { goto reroll; } if (state.AudioProbability < 1) { if ((float)Random.Range(0f, 1f) > state.AudioProbability) { return(false); } } m_Audio.pitch = Random.Range(state.AudioPitch.x, state.AudioPitch.y) * Time.timeScale; m_Audio.clip = clip; m_Audio.Play(); state.LastAudioClip = clip; return(true); }
public static void AudioStates() { List <vp_AIState> states = m_AI.States.Where(s => s.Name != "Default" && s.IsAudioState).ToList(); if (states.Count == 0) { GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.Space(20); if (m_AI.States.Count == 1) { EditorGUILayout.HelpBox("No states have been added. Please add some states in the States and Presets section below.", MessageType.Info); } else { EditorGUILayout.HelpBox("No states have been marked for audio. Please click the Audio button next to a state to add it here.", MessageType.Info); } GUILayout.Space(20); GUILayout.EndHorizontal(); } for (int i = 0; i < states.Count; ++i) { vp_AIState state = states[i]; state.AudioClipsFoldout = EditorGUILayout.Foldout(state.AudioClipsFoldout, state.Name, state.AudioClipsFoldout ? SubFoldoutStyle : new GUIStyle("Foldout")); if (state.AudioClipsFoldout) { EditorGUI.indentLevel++; for (int n = 0; n < state.AudioClips.Count; n++) { GUILayout.BeginHorizontal(); state.AudioClips[n] = (AudioClip)EditorGUILayout.ObjectField(state.AudioClips[n], typeof(AudioClip), false); if (state.AudioClips.Count > 1) { if (GUILayout.Button("Remove", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(50), GUILayout.MaxWidth(50), GUILayout.MinHeight(15))) { state.AudioClips.RemoveAt(n); --n; return; } } GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(new GUIContent("Add Audio Clip", "Add a new audio clip for this state"), GUILayout.MinWidth(150), GUILayout.MaxWidth(150))) { state.AudioClips.Add(null); } GUILayout.EndHorizontal(); EditorGUILayout.LabelField(new GUIContent("Pitch (Min:Max)", "random pitch range the sound will play at")); GUILayout.Space(-20); state.AudioPitch = EditorGUILayout.Vector2Field("", state.AudioPitch); state.AudioProbability = EditorGUILayout.Slider(new GUIContent("Probability " + (state.AudioProbability == 1 ? "(always)" : ""), "probability at which the sound will play. 1 will always play the sound."), state.AudioProbability, 0, 1); state.AudioPlayInterval = EditorGUILayout.Slider(new GUIContent("Play Interval", "Interval in seconds at which this state plays sounds"), state.AudioPlayInterval, 0, 10); GUILayout.Space(5); GUI.backgroundColor = Color.white; EditorGUI.indentLevel--; } states[i] = state; } }
public static void Animation() { Animation oldAnimation = m_AI.Animation.Animation; if (m_AI.Animation.Animation == null) { foreach (Animation anim in m_AI.gameObject.GetComponentsInChildren <Animation>(true)) { m_AI.Animation.Animation = (Animation)EditorGUILayout.ObjectField(new GUIContent("Animation Object", "The object with an Animation component that has animations for this AI"), anim, typeof(Animation), true); } } else { m_AI.Animation.Animation = (Animation)EditorGUILayout.ObjectField(new GUIContent("Animation Object", "The object with an Animation component that has animations for this AI"), m_AI.Animation.Animation, typeof(Animation), true); } if (m_AI.Animation.Animation != oldAnimation) { Reset(); } if (m_AI.Animation.Animation == null) { GUILayout.Space(10); m_AI.Animation.Animation = (Animation)EditorGUILayout.ObjectField(new GUIContent("Animation Object", "The object with an Animation component that has animations for this AI"), m_AI.Animation.Animation, typeof(Animation), true); GUILayout.BeginHorizontal(); GUILayout.Space(20); EditorGUILayout.HelpBox("An Animation component could not be found. Please add an animation component above.", MessageType.Info); GUILayout.Space(20); GUILayout.EndHorizontal(); } else { List <vp_AIState> states = m_AI.States.Where(s => s.Name != "Default" && s.IsAnimationState).ToList(); if (states.Count == 0) { GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.Space(20); if (m_AI.States.Count == 1) { EditorGUILayout.HelpBox("No states have been added. Please add some states in the States and Presets section below.", MessageType.Info); } else { EditorGUILayout.HelpBox("No states have been marked for animation. Please click the Animation button next to a state to add it here.", MessageType.Info); } GUILayout.Space(20); GUILayout.EndHorizontal(); } for (int i = 0; i < states.Count; ++i) { vp_AIState state = states[i]; state.AnimationFoldout = EditorGUILayout.Foldout(state.AnimationFoldout, state.Name, state.AnimationFoldout ? SubFoldoutStyle : new GUIStyle("Foldout")); if (state.AnimationFoldout) { EditorGUI.indentLevel++; state.AutoPlayAnimations = EditorGUILayout.Toggle(new GUIContent("Auto Play Animations", "Whether or not animations should play automatically while this state is active. If disabled, animations can be played with code."), state.AutoPlayAnimations); if (state.AnimationClips.Count == 0) { state.AnimationClips.Add(new vp_AIState.vp_AnimationState()); } for (int n = 0; n < state.AnimationClips.Count; n++) { GUILayout.BeginHorizontal(); if (n > state.AnimationClips.Count - 1) { state.AnimationClips.RemoveAt(n); return; } state.AnimationClips[n].Foldout = EditorGUILayout.Foldout(state.AnimationClips[n].Foldout, state.AnimationClips[n].Clip == null ? state.Name + " Animation Clip " + (n + 1).ToString() : state.AnimationClips[n].Clip.name); if (state.AnimationClips.Count > 1) { if (GUILayout.Button("Remove", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(50), GUILayout.MaxWidth(50), GUILayout.MinHeight(15))) { state.AnimationClips.RemoveAt(n); --n; return; } } GUILayout.EndHorizontal(); if (state.AnimationClips[n].Foldout) { EditorGUI.indentLevel++; GUILayout.BeginHorizontal(); List <AnimationClip> animationClips = new List <AnimationClip>(); animationClips.Add(null); foreach (AnimationState s in m_AI.Animation.Animation) { animationClips.Add(s.clip); } if (!animationClips.Contains(state.AnimationClips[n].Clip)) { state.AnimationClips[n].Clip = null; } int index = 0; if (state.AnimationClips[n].Clip != null) { index = animationClips.IndexOf(state.AnimationClips[n].Clip); } string[] animationNames = new string[animationClips.Count]; for (int z = 0; z < animationNames.Length; z++) { animationNames[z] = z == 0 ? "None" : animationClips[z].name; } index = EditorGUILayout.Popup(index, animationNames); state.AnimationClips[n].Clip = animationClips[index]; GUI.enabled = false; state.AnimationClips[n].Clip = (AnimationClip)EditorGUILayout.ObjectField(state.AnimationClips[n].Clip, typeof(AnimationClip), false); GUI.enabled = true; GUILayout.Space(5); GUILayout.EndHorizontal(); state.AnimationClips[n].WrapMode = (WrapMode)EditorGUILayout.EnumPopup(new GUIContent("Wrap Mode", "WrapMode for this animation"), state.AnimationClips[n].WrapMode); state.AnimationClips[n].AnimationSpeed = EditorGUILayout.Slider(new GUIContent("Animation Speed", "Speed at which to play this animation. 1 is normal speed."), state.AnimationClips[n].AnimationSpeed, 0, 10); state.AnimationClips[n].CrossfadeLength = EditorGUILayout.Slider(new GUIContent("Crossfade Length", "Speed at which to crossfade to this animation. 0.3 is default."), state.AnimationClips[n].CrossfadeLength, 0, 3); state.AnimationClips[n].Layer = EditorGUILayout.IntSlider(new GUIContent("Layer", "Layer for this animation. 0 is default."), state.AnimationClips[n].Layer, -100, 100); state.AnimationClips[n].PlayMode = (PlayMode)EditorGUILayout.EnumPopup(new GUIContent("Play Mode", "Play Mode for this animation. Stop Same Layer is default."), state.AnimationClips[n].PlayMode); EditorGUI.indentLevel--; } } GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(new GUIContent("Add Animation", "Add a new animation for this state"), GUILayout.MinWidth(100), GUILayout.MaxWidth(100))) { state.AnimationClips.Add(new vp_AIState.vp_AnimationState()); } GUILayout.EndHorizontal(); GUILayout.Space(5); GUI.backgroundColor = Color.white; EditorGUI.indentLevel--; } states[i] = state; } } }
/// <summary> /// performs an animation for the AI and returns /// whether or not the animation was successfully executed /// </summary> protected virtual bool OnMessage_Animate(object obj) { if (obj == null) { return(false); } if (obj.GetType() != typeof(vp_AIState)) { return(false); } vp_AIState state = (vp_AIState)obj; if (state == null) { return(false); } if (state.AnimationClips == null) { return(false); } if (state.AnimationClips.Count == 0) { return(false); } reroll: vp_AIState.vp_AnimationState clip = state.AnimationClips[Random.Range(0, state.AnimationClips.Count)]; if (clip == null) { return(false); } if (clip.Clip == null) { return(false); } if (Animation.GetClip(clip.Clip.name) == null) { return(false); } // if the animation was the last one played, reroll for another animation if (clip == state.LastAnimationClip && state.AnimationClips.Count > 1) { goto reroll; } Animation[clip.Clip.name].layer = clip.Layer; Animation[clip.Clip.name].speed = clip.AnimationSpeed; Animation[clip.Clip.name].wrapMode = clip.WrapMode; state.LastAnimationClip = clip; state.LastAnimationClipLength = Animation[clip.Clip.name].length / Animation[clip.Clip.name].speed; Animation.CrossFade(clip.Clip.name, clip.CrossfadeLength, clip.PlayMode); return(true); }
/// <summary> /// draws a field allowing the user to create, reorganize, /// name, assign presets to and delete states on a component /// </summary> public static bool StateFoldout(bool foldout, vp_AIComponent component, List <vp_AIState> stateList, vp_AIComponentPersister persister = null) { bool before = foldout; foldout = EditorGUILayout.Foldout(foldout, (foldout && !Application.isPlaying) ? "State Preset" : "States" ); if (foldout != before) { m_ShowBlockListFor = null; component.RefreshDefaultState(); } if (foldout) { if (m_ShowBlockListFor != null) { if (!stateList.Contains(m_ShowBlockListFor)) { foldout = false; } } } if (foldout) { for (int v = 0; v < stateList.Count; v++) { vp_AIState s = stateList[v]; if (!Application.isPlaying) { vp_AIPresetEditorGUIUtility.StateField(s, stateList, component); if ((m_ShowBlockListFor != null) && m_ShowBlockListFor == s) { StateBlockList(component, s); } } else { vp_AIPresetEditorGUIUtility.RunTimeStateField(component, s, stateList); } } GUILayout.BeginHorizontal(); if (!Application.isPlaying) { if (GUILayout.Button("Add State", GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { m_ShowBlockListFor = null; string newStateName = "Untitled"; int n = 1; while (GetStateId(component, newStateName) != -1) { n++; newStateName = newStateName.Substring(0, 8) + (n < 10?"0":"") + n.ToString(); } stateList.Add(new vp_AIState(component.GetType().Name, newStateName, "")); component.RefreshDefaultState(); EditorUtility.SetDirty(component); } } else { GUI.color = Color.clear; GUILayout.Button("", GUILayout.MinWidth(36), GUILayout.MaxWidth(36)); GUI.color = Color.white; } if (!Application.isPlaying) { GUILayout.EndHorizontal(); } if (persister != null) { vp_AIPresetEditorGUIUtility.PersistToggle(persister); } if (Application.isPlaying) { GUILayout.EndHorizontal(); } vp_EditorGUIUtility.Separator(); } return(foldout); }
/// <summary> /// /// </summary> static void StateBlockList(vp_AIComponent component, vp_AIState blocker) { GUILayout.BeginHorizontal(); GUILayout.Space(20); GUILayout.BeginVertical(); string componentName = component.GetType().ToString(); if (componentName.Contains("vp_")) { componentName = componentName.Substring(3); } EditorGUILayout.HelpBox("'" + blocker.Name + "' blocks " + ((blocker.StatesToBlock.Count > 0) ? blocker.StatesToBlock.Count.ToString() : "no") + " state" + ((blocker.StatesToBlock.Count == 1) ? "" : "s") + " on this " + componentName + ".", MessageType.None); GUILayout.BeginVertical(); int e = 0; foreach (vp_AIState blockee in component.States) { if (blockee == blocker) { continue; } if (blockee.Name == "Default") { continue; } int i = component.States.IndexOf(blockee); if (component.States[i].StatesToBlock.Contains(component.States.IndexOf(blocker))) { GUI.enabled = false; } if (e % 2 == 0) { GUILayout.BeginHorizontal(); } GUILayout.Space(20); bool before = blocker.StatesToBlock.Contains(i); bool after = before; after = GUILayout.Toggle(after, blockee.Name); if (before != after) { if (!before) { blocker.StatesToBlock.Add(i); } else { blocker.StatesToBlock.Remove(i); } EditorUtility.SetDirty(component); } if (e % 2 == 1) { GUILayout.Space(10); GUILayout.EndHorizontal(); } e++; GUI.enabled = true; } if (e % 2 == 1) { GUILayout.EndHorizontal(); } GUILayout.EndVertical(); GUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("Select states to be disallowed on this " + componentName + " while the '" + blocker.Name + "' state is enabled. A state can not block itself, a state that blocks it or the Default state.", MessageType.Info); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.MinWidth(100), GUILayout.MaxWidth(50))) { m_ShowBlockListFor = null; EditorUtility.SetDirty(component); } GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.EndHorizontal(); GUILayout.Space(10); }