necrobody anims/play: любая загруженная анимация на теле (танцы зомби и т.п.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
31ebbb9bc8
commit
5fc04fd668
+107
-1
@@ -3,6 +3,8 @@ using System.Globalization;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace NecromancerTome
|
||||
@@ -31,6 +33,84 @@ namespace NecromancerTome
|
||||
static readonly List<Quaternion> _frozenRot = new List<Quaternion>();
|
||||
static int _playerId = -1;
|
||||
|
||||
/// <summary>Любая загруженная анимация на теле (16.10: «Может и танцевать сможешь заставить?.. сильно бы помогло в
|
||||
/// создании контента»): клип играется поверх контроллера через Playables, по кругу. Танцы есть у зомби (twitch_dance) -
|
||||
/// их клипы в памяти, пока в мире есть зомби с таким аниматором.</summary>
|
||||
static PlayableGraph _graph;
|
||||
static AnimationClipPlayable _clip;
|
||||
public static string Playing;
|
||||
|
||||
public static List<AnimationClip> FindClips(string _filter)
|
||||
{
|
||||
var list = new List<AnimationClip>();
|
||||
var seen = new HashSet<string>();
|
||||
foreach (AnimationClip c in Resources.FindObjectsOfTypeAll<AnimationClip>())
|
||||
{
|
||||
if (c != null && (_filter.Length == 0 || c.name.IndexOf(_filter, System.StringComparison.OrdinalIgnoreCase) >= 0) && seen.Add(c.name))
|
||||
{
|
||||
list.Add(c);
|
||||
}
|
||||
}
|
||||
list.Sort((x, y) => string.CompareOrdinal(x.name, y.name));
|
||||
return list;
|
||||
}
|
||||
|
||||
public static string Play(string _name, float _speed)
|
||||
{
|
||||
Animator a = Anim();
|
||||
if (a == null)
|
||||
{
|
||||
return "нет аниматора тела";
|
||||
}
|
||||
AnimationClip clip = null;
|
||||
foreach (AnimationClip c in FindClips(_name))
|
||||
{
|
||||
if (c.name == _name)
|
||||
{
|
||||
clip = c;
|
||||
break;
|
||||
}
|
||||
clip = clip ?? c;
|
||||
}
|
||||
if (clip == null)
|
||||
{
|
||||
return "нет загруженной анимации «" + _name + "» (necrobody anims слово)";
|
||||
}
|
||||
StopPlay();
|
||||
_graph = PlayableGraph.Create("NecroBodyPlay");
|
||||
_graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
|
||||
var output = AnimationPlayableOutput.Create(_graph, "body", a);
|
||||
_clip = AnimationClipPlayable.Create(_graph, clip);
|
||||
_clip.SetSpeed(_speed);
|
||||
output.SetSourcePlayable(_clip);
|
||||
_graph.Play();
|
||||
Playing = clip.name;
|
||||
return "играет " + clip.name + " (" + NecroBody.F(clip.length) + " с" + (clip.isLooping ? ", петля" : "") + (clip.humanMotion ? ", гуманоид" : ", не гуманоид - может лечь криво") + "), скорость " + NecroBody.F(_speed);
|
||||
}
|
||||
|
||||
public static void StopPlay()
|
||||
{
|
||||
if (_graph.IsValid())
|
||||
{
|
||||
_graph.Destroy();
|
||||
}
|
||||
Playing = null;
|
||||
}
|
||||
|
||||
/// <summary>Петля для клипов без своей петли.</summary>
|
||||
static void LoopPlay()
|
||||
{
|
||||
if (!_graph.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
AnimationClip c = _clip.GetAnimationClip();
|
||||
if (c != null && !c.isLooping && _clip.GetTime() >= c.length)
|
||||
{
|
||||
_clip.SetTime(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static EntityPlayerLocal Player() => GameManager.Instance?.World?.GetPrimaryPlayer();
|
||||
|
||||
public static BodyAnimator Body()
|
||||
@@ -67,6 +147,7 @@ namespace NecromancerTome
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
StopPlay();
|
||||
Params.Clear();
|
||||
Pose.Clear();
|
||||
Freeze = false;
|
||||
@@ -144,6 +225,7 @@ namespace NecromancerTome
|
||||
_bones.Clear();
|
||||
return;
|
||||
}
|
||||
LoopPlay();
|
||||
if (!Active || Bone("") == null && _anim == null)
|
||||
{
|
||||
return;
|
||||
@@ -235,7 +317,7 @@ namespace NecromancerTome
|
||||
public class ConsoleCmdNecroBody : ConsoleCmdAbstract
|
||||
{
|
||||
public override string[] getCommands() => new[] { "necrobody" };
|
||||
public override string getDescription() => "NecromancerTome: аниматор тела - params [ф]|clips|set п v|unset п|trigger п|speed k|freeze [off]|bones [ф]|show к|pose к x y z|add к dx dy dz|unpose к|item pos|rot|off|show|holdoffset [N]|save|off";
|
||||
public override string getDescription() => "NecromancerTome: аниматор тела - params [ф]|clips|set п v|unset п|trigger п|speed k|freeze [off]|bones [ф]|show к|pose к x y z|add к dx dy dz|unpose к|item pos|rot|off|show|holdoffset [N]|anims [слово]|play имя [скорость]|play off|save|off";
|
||||
|
||||
static bool Num(List<string> _p, int _i, out float _v)
|
||||
{
|
||||
@@ -425,6 +507,30 @@ namespace NecromancerTome
|
||||
Out(sb.ToString());
|
||||
return;
|
||||
}
|
||||
case "anims":
|
||||
{
|
||||
List<AnimationClip> l = NecroBody.FindClips(arg);
|
||||
var sb = new StringBuilder("анимаций в памяти" + (arg.Length > 0 ? " со словом " + arg : "") + ": " + l.Count);
|
||||
int shown = 0;
|
||||
foreach (AnimationClip c in l)
|
||||
{
|
||||
if (shown++ >= 200)
|
||||
{
|
||||
sb.Append("\n ... (уточните слово)");
|
||||
break;
|
||||
}
|
||||
sb.Append("\n ").Append(c.name).Append(" ").Append(NecroBody.F(c.length)).Append(" с").Append(c.humanMotion ? "" : " [не гуманоид]");
|
||||
}
|
||||
Out(sb.ToString());
|
||||
return;
|
||||
}
|
||||
case "play" when arg == "off":
|
||||
NecroBody.StopPlay();
|
||||
Out("анимация снята");
|
||||
return;
|
||||
case "play" when arg.Length > 0:
|
||||
Out(NecroBody.Play(arg, Num(_params, 2, out float ps) ? ps : 1f));
|
||||
return;
|
||||
case "off":
|
||||
NecroBody.Reset();
|
||||
Out("тело - как у игры");
|
||||
|
||||
Reference in New Issue
Block a user