diff --git a/Spine/SpineObject.cs b/Spine/SpineObject.cs index 5854cc2..35d7761 100644 --- a/Spine/SpineObject.cs +++ b/Spine/SpineObject.cs @@ -167,6 +167,7 @@ namespace Spine // 拷贝渲染设置 UsePma = other.UsePma; Physics = other.Physics; + _animationState.TimeScale = other._animationState.TimeScale; // 拷贝皮肤加载情况 _skinLoadStatus = other._skinLoadStatus.ToDictionary(); diff --git a/SpineViewer/Models/SpineObjectConfigModel.cs b/SpineViewer/Models/SpineObjectConfigModel.cs index 8b92b71..58dc5fd 100644 --- a/SpineViewer/Models/SpineObjectConfigModel.cs +++ b/SpineViewer/Models/SpineObjectConfigModel.cs @@ -17,6 +17,8 @@ namespace SpineViewer.Models public string Physics { get; set; } = ISkeleton.Physics.Update.ToString(); + public float TimeScale { get; set; } = 1f; + public float Scale { get; set; } = 1f; public bool FlipX { get; set; } @@ -54,5 +56,15 @@ namespace SpineViewer.Models public bool DebugPoints { get; set; } public bool DebugClippings { get; set; } + + } + + public class AnimationConfigModel + { + string Name { get; set; } = ""; + + float TimeScale { get; set; } = 1f; + + float Alpha { get; set; } = 1f; } } diff --git a/SpineViewer/Models/SpineObjectModel.cs b/SpineViewer/Models/SpineObjectModel.cs index 71237f9..19e8d0b 100644 --- a/SpineViewer/Models/SpineObjectModel.cs +++ b/SpineViewer/Models/SpineObjectModel.cs @@ -129,6 +129,12 @@ namespace SpineViewer.Models set { lock (_lock) SetProperty(_spineObject.Physics, value, v => _spineObject.Physics = v); } } + public float TimeScale + { + get { lock (_lock) return _spineObject.AnimationState.TimeScale; } + set { lock (_lock) SetProperty(_spineObject.AnimationState.TimeScale, Math.Clamp(value, -100f, 100f), v => _spineObject.AnimationState.TimeScale = v); } + } + /// /// 缩放倍数, 绝对值大小, 两个方向大小不一致时返回 -1, 设置时不会影响正负号 /// @@ -388,6 +394,7 @@ namespace SpineViewer.Models UsePma = _spineObject.UsePma, Physics = _spineObject.Physics.ToString(), + TimeScale = _spineObject.AnimationState.TimeScale, DebugTexture = _spineObject.DebugTexture, DebugBounds = _spineObject.DebugBounds, @@ -427,6 +434,7 @@ namespace SpineViewer.Models SetProperty(_spineObject.Skeleton.Y, value.Y, v => _spineObject.Skeleton.Y = v, nameof(Y)); SetProperty(_spineObject.UsePma, value.UsePma, v => _spineObject.UsePma = v, nameof(UsePma)); SetProperty(_spineObject.Physics, Enum.Parse(value.Physics ?? "Update", true), v => _spineObject.Physics = v, nameof(Physics)); + SetProperty(_spineObject.AnimationState.TimeScale, value.TimeScale, v => _spineObject.AnimationState.TimeScale = v, nameof(TimeScale)); foreach (var name in _spineObject.Data.Skins.Select(v => v.Name).Except(value.LoadedSkins)) if (_spineObject.SetSkinStatus(name, false)) diff --git a/SpineViewer/Resources/Strings/en.xaml b/SpineViewer/Resources/Strings/en.xaml index 06cdd98..dcad18b 100644 --- a/SpineViewer/Resources/Strings/en.xaml +++ b/SpineViewer/Resources/Strings/en.xaml @@ -64,6 +64,8 @@ Show Premultiply Alpha Physics + Time Scale + Time scale for a single model; a negative value plays the animation in reverse. Transform Scale diff --git a/SpineViewer/Resources/Strings/ja.xaml b/SpineViewer/Resources/Strings/ja.xaml index 048d919..2d16f34 100644 --- a/SpineViewer/Resources/Strings/ja.xaml +++ b/SpineViewer/Resources/Strings/ja.xaml @@ -64,6 +64,8 @@ 表示 プレマルチプライドアルファ 物理 + 時間スケール + 単一モデルの時間スケール。負の値にするとアニメーションを逆再生します。 変換 スケール diff --git a/SpineViewer/Resources/Strings/zh.xaml b/SpineViewer/Resources/Strings/zh.xaml index c0ce189..b72d87f 100644 --- a/SpineViewer/Resources/Strings/zh.xaml +++ b/SpineViewer/Resources/Strings/zh.xaml @@ -64,6 +64,8 @@ 显示 预乘Alpha通道 物理 + 时间因子 + 单个模型的时间因子,取负数时可以倒放动画 变换 缩放 diff --git a/SpineViewer/ViewModels/MainWindow/SpineObjectTabViewModel.cs b/SpineViewer/ViewModels/MainWindow/SpineObjectTabViewModel.cs index 5e39f9a..1e74af2 100644 --- a/SpineViewer/ViewModels/MainWindow/SpineObjectTabViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SpineObjectTabViewModel.cs @@ -74,6 +74,7 @@ namespace SpineViewer.ViewModels.MainWindow OnPropertyChanged(nameof(IsShown)); OnPropertyChanged(nameof(UsePma)); OnPropertyChanged(nameof(Physics)); + OnPropertyChanged(nameof(TimeScale)); OnPropertyChanged(nameof(Scale)); OnPropertyChanged(nameof(FlipX)); @@ -217,6 +218,25 @@ namespace SpineViewer.ViewModels.MainWindow } } + public float? TimeScale + { + get + { + if (_selectedObjects.Length <= 0) return null; + var val = _selectedObjects[0].TimeScale; + if (_selectedObjects.Skip(1).Any(it => it.TimeScale != val)) return null; + return val; + } + + set + { + if (_selectedObjects.Length <= 0) return; + if (value is null) return; + foreach (var sp in _selectedObjects) sp.TimeScale = (float)value; + OnPropertyChanged(); + } + } + public float? Scale { get @@ -595,35 +615,44 @@ namespace SpineViewer.ViewModels.MainWindow } } - /// - /// 监听单个模型属性发生变化, 则更新聚合属性值 - /// - private void SingleModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) + private static readonly Dictionary _singleModelPropertyMap = new() { - if (e.PropertyName == nameof(SpineObjectModel.IsShown)) OnPropertyChanged(nameof(IsShown)); - else if (e.PropertyName == nameof(SpineObjectModel.UsePma)) OnPropertyChanged(nameof(UsePma)); - else if (e.PropertyName == nameof(SpineObjectModel.Physics)) OnPropertyChanged(nameof(Physics)); + { nameof(SpineObjectModel.IsShown), nameof(IsShown) }, + { nameof(SpineObjectModel.UsePma), nameof(UsePma) }, + { nameof(SpineObjectModel.Physics), nameof(Physics) }, + { nameof(SpineObjectModel.TimeScale), nameof(TimeScale) }, - else if (e.PropertyName == nameof(SpineObjectModel.Scale)) OnPropertyChanged(nameof(Scale)); - else if (e.PropertyName == nameof(SpineObjectModel.FlipX)) OnPropertyChanged(nameof(FlipX)); - else if (e.PropertyName == nameof(SpineObjectModel.FlipY)) OnPropertyChanged(nameof(FlipY)); - else if (e.PropertyName == nameof(SpineObjectModel.X)) OnPropertyChanged(nameof(X)); - else if (e.PropertyName == nameof(SpineObjectModel.Y)) OnPropertyChanged(nameof(Y)); + { nameof(SpineObjectModel.Scale), nameof(Scale) }, + { nameof(SpineObjectModel.FlipX), nameof(FlipX) }, + { nameof(SpineObjectModel.FlipY), nameof(FlipY) }, + { nameof(SpineObjectModel.X), nameof(X) }, + { nameof(SpineObjectModel.Y), nameof(Y) }, // Skins 变化在 SkinViewModel 中监听 // Slots 变化在 SlotAttachmentViewModel 中监听 // AnimationTracks 变化在 AnimationTrackViewModel 中监听 - else if (e.PropertyName == nameof(SpineObjectModel.DebugTexture)) OnPropertyChanged(nameof(DebugTexture)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugBounds)) OnPropertyChanged(nameof(DebugBounds)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugBones)) OnPropertyChanged(nameof(DebugBones)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugRegions)) OnPropertyChanged(nameof(DebugRegions)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugMeshHulls)) OnPropertyChanged(nameof(DebugMeshHulls)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugMeshes)) OnPropertyChanged(nameof(DebugMeshes)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugBoundingBoxes)) OnPropertyChanged(nameof(DebugBoundingBoxes)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugPaths)) OnPropertyChanged(nameof(DebugPaths)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugPoints)) OnPropertyChanged(nameof(DebugPoints)); - else if (e.PropertyName == nameof(SpineObjectModel.DebugClippings)) OnPropertyChanged(nameof(DebugClippings)); + { nameof(SpineObjectModel.DebugTexture), nameof(DebugTexture) }, + { nameof(SpineObjectModel.DebugBounds), nameof(DebugBounds) }, + { nameof(SpineObjectModel.DebugBones), nameof(DebugBones) }, + { nameof(SpineObjectModel.DebugRegions), nameof(DebugRegions) }, + { nameof(SpineObjectModel.DebugMeshHulls), nameof(DebugMeshHulls) }, + { nameof(SpineObjectModel.DebugMeshes), nameof(DebugMeshes) }, + { nameof(SpineObjectModel.DebugBoundingBoxes), nameof(DebugBoundingBoxes) }, + { nameof(SpineObjectModel.DebugPaths), nameof(DebugPaths) }, + { nameof(SpineObjectModel.DebugPoints), nameof(DebugPoints) }, + { nameof(SpineObjectModel.DebugClippings), nameof(DebugClippings) }, + }; + + /// + /// 监听单个模型属性发生变化, 则更新聚合属性值 + /// + private void SingleModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (_singleModelPropertyMap.TryGetValue(e.PropertyName, out var targetProperty)) + { + OnPropertyChanged(targetProperty); + } } /// diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index 47c4e8c..0c5d294 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -310,6 +310,7 @@ + @@ -323,6 +324,10 @@