mirror of
https://github.com/LorisYounger/VPet.ModMaker.git
synced 2024-08-30 18:22:21 +00:00
更新
This commit is contained in:
parent
171c49012c
commit
c58ddf25fa
@ -23,19 +23,19 @@ public class FoodAnimeModel
|
||||
/// <summary>
|
||||
/// 后图像列表
|
||||
/// </summary>
|
||||
public ObservableCollection<ImageModel> BackImages { get; } = new();
|
||||
public ObservableValue<FoodImagesPath> BackImagesPath { get; } = new();
|
||||
public ObservableCollection<ImageModel> BackImages { get; set; } = new();
|
||||
public ObservableValue<FoodImagesPath?> BackImagesPath { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 前图像列表
|
||||
/// </summary>
|
||||
public ObservableCollection<ImageModel> FrontImages { get; } = new();
|
||||
public ObservableValue<FoodImagesPath> FrontImagesPath { get; } = new();
|
||||
public ObservableCollection<ImageModel> FrontImages { get; set; } = new();
|
||||
public ObservableValue<FoodImagesPath?> FrontImagesPath { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 食物定位列表
|
||||
/// </summary>
|
||||
public ObservableCollection<FoodLocationInfoModel> FoodLocations { get; } = new();
|
||||
public ObservableCollection<FoodLocationModel> FoodLocations { get; } = new();
|
||||
|
||||
public FoodAnimeModel() { }
|
||||
|
||||
@ -46,7 +46,7 @@ public class FoodAnimeModel
|
||||
{
|
||||
//var index = int.Parse(item.Name.Substring(1));
|
||||
var infos = item.Info.Split(',');
|
||||
var foodLocationInfo = new FoodLocationInfoModel();
|
||||
var foodLocationInfo = new FoodLocationModel();
|
||||
foodLocationInfo.Duration.Value = int.Parse(infos[0]);
|
||||
if (infos.Length > 1)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ using LinePutScript.Localization.WPF;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -24,6 +25,11 @@ public class FoodAnimeTypeModel
|
||||
/// </summary>
|
||||
public ObservableValue<string> Name { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 动作类型
|
||||
/// </summary>
|
||||
public GraphInfo.GraphType GraphType => GraphInfo.GraphType.Common;
|
||||
|
||||
/// <summary>
|
||||
/// 开心动画
|
||||
/// </summary>
|
||||
@ -46,28 +52,73 @@ public class FoodAnimeTypeModel
|
||||
|
||||
public FoodAnimeTypeModel()
|
||||
{
|
||||
HappyAnimes.CollectionChanged += Animes_CollectionChanged;
|
||||
//Name.ValueChanged += (_, _) =>
|
||||
//{
|
||||
// Id.Value = $"{GraphType.Value}_{Name.Value}";
|
||||
//};
|
||||
}
|
||||
|
||||
private void Animes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.NewItems is not null)
|
||||
{
|
||||
foreach (var model in e.NewItems.Cast<FoodAnimeModel>())
|
||||
{
|
||||
SetImagesPathValueChanged(model);
|
||||
}
|
||||
}
|
||||
if (e.OldItems is not null)
|
||||
{
|
||||
foreach (var model in e.OldItems.Cast<FoodAnimeModel>())
|
||||
{
|
||||
SetImagesPathValueChanged(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetImagesPathValueChanged(FoodAnimeModel model)
|
||||
{
|
||||
model.FrontImagesPath.ValueChanged += (o, n) =>
|
||||
{
|
||||
if (n is null)
|
||||
return;
|
||||
if (n.Mode.Value is GameSave.ModeType.Happy)
|
||||
model.FrontImages = HappyAnimes[n.Index.Value].FrontImages;
|
||||
else if (n.Mode.Value is GameSave.ModeType.Nomal)
|
||||
model.FrontImages = NomalAnimes[n.Index.Value].FrontImages;
|
||||
else if (n.Mode.Value is GameSave.ModeType.PoorCondition)
|
||||
model.FrontImages = PoorConditionAnimes[n.Index.Value].FrontImages;
|
||||
else if (n.Mode.Value is GameSave.ModeType.Ill)
|
||||
model.FrontImages = IllAnimes[n.Index.Value].FrontImages;
|
||||
};
|
||||
model.BackImagesPath.ValueChanged += (o, n) =>
|
||||
{
|
||||
if (n is null)
|
||||
return;
|
||||
if (n.Mode.Value is GameSave.ModeType.Happy)
|
||||
model.BackImages = HappyAnimes[n.Index.Value].BackImages;
|
||||
else if (n.Mode.Value is GameSave.ModeType.Nomal)
|
||||
model.BackImages = NomalAnimes[n.Index.Value].BackImages;
|
||||
else if (n.Mode.Value is GameSave.ModeType.PoorCondition)
|
||||
model.BackImages = PoorConditionAnimes[n.Index.Value].BackImages;
|
||||
else if (n.Mode.Value is GameSave.ModeType.Ill)
|
||||
model.BackImages = IllAnimes[n.Index.Value].BackImages;
|
||||
};
|
||||
}
|
||||
|
||||
public FoodAnimeTypeModel(string path)
|
||||
: this()
|
||||
{
|
||||
Name.Value = Path.GetFileName(path);
|
||||
var infoFile = Path.Combine(path, ModMakerInfo.InfoFile);
|
||||
if (File.Exists(infoFile) is false)
|
||||
if (
|
||||
Directory.EnumerateFiles(path, ModMakerInfo.InfoFile, SearchOption.AllDirectories).Any()
|
||||
is false
|
||||
)
|
||||
throw new Exception("信息文件\n{0}\n不存在".Translate(infoFile));
|
||||
var lps = new LPS(infoFile);
|
||||
var foodAnime = lps.FindAllLineInfo(nameof(FoodAnimation));
|
||||
if (foodAnime.Any() is false)
|
||||
throw new Exception("信息文件\n{0}\n未包含食物动画信息".Translate(infoFile));
|
||||
var anime = lps.FindAllLineInfo(nameof(PNGAnimation));
|
||||
foreach (var foodAnimation in foodAnime)
|
||||
{
|
||||
ParseFoodAnimeInfo(foodAnimation);
|
||||
}
|
||||
if (File.Exists(infoFile))
|
||||
ParseInfoFile(path, infoFile);
|
||||
}
|
||||
|
||||
public FoodAnimeTypeModel(FoodAnimeTypeModel model)
|
||||
@ -104,21 +155,115 @@ public class FoodAnimeTypeModel
|
||||
}
|
||||
}
|
||||
|
||||
public void ParseFoodAnimeInfo(ILine line)
|
||||
public void ParseInfoFile(string path, string infoPath)
|
||||
{
|
||||
var mode = (GameSave.ModeType)Enum.Parse(typeof(GameSave.ModeType), line.Find("mode").Info);
|
||||
if (mode is GameSave.ModeType.Happy)
|
||||
AddModeAnime(HappyAnimes, line);
|
||||
else if (mode is GameSave.ModeType.Nomal)
|
||||
AddModeAnime(NomalAnimes, line);
|
||||
else if (mode is GameSave.ModeType.PoorCondition)
|
||||
AddModeAnime(PoorConditionAnimes, line);
|
||||
else if (mode is GameSave.ModeType.Ill)
|
||||
AddModeAnime(IllAnimes, line);
|
||||
var lps = new LPS(infoPath);
|
||||
var foodAnimeInfos = lps.FindAllLineInfo(nameof(FoodAnimation));
|
||||
if (foodAnimeInfos.Any() is false)
|
||||
throw new Exception("信息文件\n{0}\n未包含食物动画信息".Translate(infoPath));
|
||||
var pngAnimeInfos = lps.FindAllLineInfo(nameof(PNGAnimation))
|
||||
.Select(
|
||||
i =>
|
||||
new PNGAnimeInfo(
|
||||
i.Info,
|
||||
i.Find("infoPath").Info,
|
||||
(GameSave.ModeType)
|
||||
Enum.Parse(typeof(GameSave.ModeType), i.Find("mode").Info, true)
|
||||
)
|
||||
)
|
||||
.ToList();
|
||||
foreach (var foodAnimation in foodAnimeInfos)
|
||||
{
|
||||
ParseFoodAnimeInfo(path, foodAnimation, pngAnimeInfos);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddModeAnime(ObservableCollection<FoodAnimeModel> foodAnimes, ILine line)
|
||||
public void ParseFoodAnimeInfo(string path, ILine line, List<PNGAnimeInfo> pngAnimeInfos)
|
||||
{
|
||||
foodAnimes.Add(new(line));
|
||||
var mode = (GameSave.ModeType)
|
||||
Enum.Parse(typeof(GameSave.ModeType), line.Find("mode").Info, true);
|
||||
if (mode is GameSave.ModeType.Happy)
|
||||
AddModeAnime(path, GameSave.ModeType.Happy, HappyAnimes, line, pngAnimeInfos);
|
||||
else if (mode is GameSave.ModeType.Nomal)
|
||||
AddModeAnime(path, GameSave.ModeType.Nomal, NomalAnimes, line, pngAnimeInfos);
|
||||
else if (mode is GameSave.ModeType.PoorCondition)
|
||||
AddModeAnime(
|
||||
path,
|
||||
GameSave.ModeType.PoorCondition,
|
||||
PoorConditionAnimes,
|
||||
line,
|
||||
pngAnimeInfos
|
||||
);
|
||||
else if (mode is GameSave.ModeType.Ill)
|
||||
AddModeAnime(path, GameSave.ModeType.Ill, IllAnimes, line, pngAnimeInfos);
|
||||
}
|
||||
|
||||
public void AddModeAnime(
|
||||
string path,
|
||||
GameSave.ModeType mode,
|
||||
ObservableCollection<FoodAnimeModel> foodAnimes,
|
||||
ILine line,
|
||||
List<PNGAnimeInfo> pngAnimeInfos
|
||||
)
|
||||
{
|
||||
var anime = new FoodAnimeModel(line);
|
||||
var frontLay = line.Find("front_lay").Info;
|
||||
var backLay = line.Find("back_lay").Info;
|
||||
var frontLayAnimes = pngAnimeInfos.Where(i => i.Name == frontLay).ToList();
|
||||
var backLayAnimes = pngAnimeInfos.Where(i => i.Name == backLay).ToList();
|
||||
// 尝试获取相同模式的动画
|
||||
if (frontLayAnimes.FirstOrDefault(i => i.Mode == mode) is PNGAnimeInfo frontAnimeInfo)
|
||||
{
|
||||
anime.FrontImages = GetImages(path, frontAnimeInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 若没有则获取通用动画
|
||||
anime.FrontImages = GetImages(
|
||||
path,
|
||||
frontLayAnimes.First(i => i.Mode == GameSave.ModeType.Nomal)
|
||||
);
|
||||
}
|
||||
if (backLayAnimes.FirstOrDefault(i => i.Mode == mode) is PNGAnimeInfo backAnimeInfo)
|
||||
{
|
||||
anime.BackImages = GetImages(path, backAnimeInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
anime.BackImages = GetImages(
|
||||
path,
|
||||
backLayAnimes.First(i => i.Mode == GameSave.ModeType.Nomal)
|
||||
);
|
||||
}
|
||||
foodAnimes.Add(anime);
|
||||
|
||||
static ObservableCollection<ImageModel> GetImages(string path, PNGAnimeInfo pngAnimeInfo)
|
||||
{
|
||||
return new(
|
||||
Directory
|
||||
.EnumerateFiles(Path.Combine(path, pngAnimeInfo.Path))
|
||||
.Select(
|
||||
i =>
|
||||
new ImageModel(
|
||||
Utils.LoadImageToMemoryStream(i),
|
||||
int.Parse(Path.GetFileNameWithoutExtension(i).Split('_')[1])
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PNGAnimeInfo
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Path { get; }
|
||||
public GameSave.ModeType Mode { get; }
|
||||
|
||||
public PNGAnimeInfo(string name, string path, GameSave.ModeType mode)
|
||||
{
|
||||
Name = name;
|
||||
Path = path;
|
||||
Mode = mode;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ namespace VPet.ModMaker.Models.ModModel;
|
||||
/// <summary>
|
||||
/// 食物图像模型
|
||||
/// </summary>
|
||||
public class FoodLocationInfoModel
|
||||
public class FoodLocationModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 持续时间
|
||||
@ -32,7 +32,7 @@ public class FoodLocationInfoModel
|
||||
/// </summary>
|
||||
public ObservableValue<double> Opacity { get; } = new(100);
|
||||
|
||||
public FoodLocationInfoModel()
|
||||
public FoodLocationModel()
|
||||
{
|
||||
Rect.Width.ValueChanged += (o, n) =>
|
||||
{
|
||||
@ -40,9 +40,9 @@ public class FoodLocationInfoModel
|
||||
};
|
||||
}
|
||||
|
||||
public FoodLocationInfoModel Copy()
|
||||
public FoodLocationModel Copy()
|
||||
{
|
||||
var model = new FoodLocationInfoModel();
|
||||
var model = new FoodLocationModel();
|
||||
model.Duration.Value = Duration.Value;
|
||||
model.Rect.SetValue(Rect.X.Value, Rect.Y.Value, Rect.Width.Value, Rect.Height.Value);
|
||||
model.Rotate.Value = Rotate.Value;
|
@ -70,6 +70,11 @@ public class PetModel : I18nModel<I18nPetInfoModel>
|
||||
/// </summary>
|
||||
public ObservableCollection<AnimeTypeModel> Animes { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
///食物动画
|
||||
/// </summary>
|
||||
public ObservableCollection<FoodAnimeTypeModel> FoodAnimes { get; } = new();
|
||||
|
||||
public bool IsSimplePetModel { get; } = false;
|
||||
|
||||
public PetModel()
|
||||
|
@ -34,6 +34,11 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 含有值
|
||||
/// </summary>
|
||||
public bool HasValue => Value != null;
|
||||
|
||||
#region Ctor
|
||||
/// <inheritdoc/>
|
||||
public ObservableValue() { }
|
||||
|
@ -106,7 +106,7 @@
|
||||
<Compile Include="Models\Expansions.cs" />
|
||||
<Compile Include="Models\ModModel\FoodAnimeModel.cs" />
|
||||
<Compile Include="Models\ModModel\FoodAnimeTypeModel.cs" />
|
||||
<Compile Include="Models\ModModel\FoodLocationInfoModel.cs" />
|
||||
<Compile Include="Models\ModModel\FoodLocationModel.cs" />
|
||||
<Compile Include="Models\ModModel\FoodModel.cs" />
|
||||
<Compile Include="Models\I18nHelper.cs" />
|
||||
<Compile Include="Models\I18nModel.cs" />
|
||||
|
@ -286,7 +286,6 @@ public class AnimeEditWindowVM
|
||||
return;
|
||||
}
|
||||
} while (Loop.Value);
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -7,8 +7,10 @@ using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using VPet.ModMaker.Models;
|
||||
using VPet.ModMaker.Models.ModModel;
|
||||
using VPet_Simulator.Core;
|
||||
@ -22,25 +24,45 @@ public class FoodAnimeEditWindowVM
|
||||
/// </summary>
|
||||
public PetModel CurrentPet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 食物图片
|
||||
/// </summary>
|
||||
public ObservableValue<BitmapImage> FoodImage { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 比例
|
||||
/// </summary>
|
||||
public ObservableValue<double> LengthRatio { get; } = new(250.0 / 500.0);
|
||||
|
||||
/// <summary>
|
||||
/// 旧动画
|
||||
/// </summary>
|
||||
public AnimeTypeModel OldAnime { get; set; }
|
||||
public FoodAnimeTypeModel OldAnime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 动画
|
||||
/// </summary>
|
||||
public ObservableValue<AnimeTypeModel> Anime { get; } = new(new());
|
||||
public ObservableValue<FoodAnimeTypeModel> Anime { get; } = new(new());
|
||||
|
||||
/// <summary>
|
||||
/// 当前图像模型
|
||||
/// 当前顶层图像模型
|
||||
/// </summary>
|
||||
public ObservableValue<ImageModel> CurrentImageModel { get; } = new();
|
||||
public ObservableValue<ImageModel> CurrentFrontImageModel { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前底层图像模型
|
||||
/// </summary>
|
||||
public ObservableValue<ImageModel> CurrentBackImageModel { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前食物定位模型
|
||||
/// </summary>
|
||||
public ObservableValue<FoodLocationModel> CurrentFoodLocationModel { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前动画模型
|
||||
/// </summary>
|
||||
public ObservableValue<AnimeModel> CurrentAnimeModel { get; } = new();
|
||||
public ObservableValue<FoodAnimeModel> CurrentAnimeModel { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前模式
|
||||
@ -100,13 +122,25 @@ public class FoodAnimeEditWindowVM
|
||||
private bool _playing = false;
|
||||
|
||||
/// <summary>
|
||||
/// 动画任务
|
||||
/// 顶层动画任务
|
||||
/// </summary>
|
||||
private Task _playerTask;
|
||||
private Task _frontPlayerTask;
|
||||
|
||||
/// <summary>
|
||||
/// 底层动画任务
|
||||
/// </summary>
|
||||
private Task _backPlayerTask;
|
||||
|
||||
/// <summary>
|
||||
/// 食物动画任务
|
||||
/// </summary>
|
||||
private Task _foodPlayerTask;
|
||||
|
||||
public FoodAnimeEditWindowVM()
|
||||
{
|
||||
_playerTask = new(Play);
|
||||
_frontPlayerTask = new(FrontPlay);
|
||||
_backPlayerTask = new(BackPlay);
|
||||
_foodPlayerTask = new(FoodPlay);
|
||||
|
||||
CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged;
|
||||
|
||||
@ -121,18 +155,18 @@ public class FoodAnimeEditWindowVM
|
||||
}
|
||||
|
||||
#region LoadAnime
|
||||
private void Anime_ValueChanged(AnimeTypeModel oldValue, AnimeTypeModel newValue)
|
||||
private void Anime_ValueChanged(FoodAnimeTypeModel oldValue, FoodAnimeTypeModel newValue)
|
||||
{
|
||||
CheckGraphType(newValue);
|
||||
}
|
||||
|
||||
private void CheckGraphType(AnimeTypeModel model)
|
||||
private void CheckGraphType(FoodAnimeTypeModel model)
|
||||
{
|
||||
if (AnimeTypeModel.HasMultiTypeAnimes.Contains(model.GraphType.Value))
|
||||
HasMultiType.Value = true;
|
||||
//if (FoodAnimeTypeModel.HasMultiTypeAnimes.Contains(model.GraphType.Value))
|
||||
// HasMultiType.Value = true;
|
||||
|
||||
if (AnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value))
|
||||
HasAnimeName.Value = true;
|
||||
//if (FoodAnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value))
|
||||
// HasAnimeName.Value = true;
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
@ -146,14 +180,14 @@ public class FoodAnimeEditWindowVM
|
||||
MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes
|
||||
)
|
||||
{
|
||||
if (CurrentMode is GameSave.ModeType.Happy)
|
||||
Anime.Value.HappyAnimes.Remove(value);
|
||||
else if (CurrentMode is GameSave.ModeType.Nomal)
|
||||
Anime.Value.NomalAnimes.Remove(value);
|
||||
else if (CurrentMode is GameSave.ModeType.PoorCondition)
|
||||
Anime.Value.PoorConditionAnimes.Remove(value);
|
||||
else if (CurrentMode is GameSave.ModeType.Ill)
|
||||
Anime.Value.IllAnimes.Remove(value);
|
||||
//if (CurrentMode is GameSave.ModeType.Happy)
|
||||
// Anime.Value.HappyAnimes.Remove(value);
|
||||
//else if (CurrentMode is GameSave.ModeType.Nomal)
|
||||
// Anime.Value.NomalAnimes.Remove(value);
|
||||
//else if (CurrentMode is GameSave.ModeType.PoorCondition)
|
||||
// Anime.Value.PoorConditionAnimes.Remove(value);
|
||||
//else if (CurrentMode is GameSave.ModeType.Ill)
|
||||
// Anime.Value.IllAnimes.Remove(value);
|
||||
value.Close();
|
||||
}
|
||||
}
|
||||
@ -223,18 +257,26 @@ public class FoodAnimeEditWindowVM
|
||||
/// <param name="value">动画模型</param>
|
||||
private void RemoveImageCommand_ExecuteEvent(AnimeModel value)
|
||||
{
|
||||
CurrentImageModel.Value.Close();
|
||||
value.Images.Remove(CurrentImageModel.Value);
|
||||
CurrentFrontImageModel.Value.Close();
|
||||
value.Images.Remove(CurrentFrontImageModel.Value);
|
||||
}
|
||||
|
||||
#region Player
|
||||
private void CurrentAnimeModel_ValueChanged(AnimeModel oldValue, AnimeModel newValue)
|
||||
#region FrontPlayer
|
||||
private void CurrentAnimeModel_ValueChanged(FoodAnimeModel oldValue, FoodAnimeModel newValue)
|
||||
{
|
||||
StopCommand_ExecuteEvent();
|
||||
if (oldValue is not null)
|
||||
oldValue.Images.CollectionChanged -= Images_CollectionChanged;
|
||||
{
|
||||
oldValue.FrontImages.CollectionChanged -= Images_CollectionChanged;
|
||||
oldValue.BackImages.CollectionChanged -= Images_CollectionChanged;
|
||||
oldValue.FoodLocations.CollectionChanged -= Images_CollectionChanged;
|
||||
}
|
||||
if (newValue is not null)
|
||||
newValue.Images.CollectionChanged += Images_CollectionChanged;
|
||||
{
|
||||
newValue.FrontImages.CollectionChanged += Images_CollectionChanged;
|
||||
newValue.BackImages.CollectionChanged += Images_CollectionChanged;
|
||||
newValue.FoodLocations.CollectionChanged += Images_CollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void Images_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
@ -268,25 +310,60 @@ public class FoodAnimeEditWindowVM
|
||||
return;
|
||||
}
|
||||
_playing = true;
|
||||
_playerTask.Start();
|
||||
_frontPlayerTask.Start();
|
||||
_backPlayerTask.Start();
|
||||
_foodPlayerTask.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 播放
|
||||
/// 顶层播放
|
||||
/// </summary>
|
||||
private void Play()
|
||||
private void FrontPlay()
|
||||
{
|
||||
do
|
||||
{
|
||||
foreach (var model in CurrentAnimeModel.Value.Images)
|
||||
foreach (var model in CurrentAnimeModel.Value.FrontImages)
|
||||
{
|
||||
CurrentImageModel.Value = model;
|
||||
CurrentFrontImageModel.Value = model;
|
||||
Task.Delay(model.Duration.Value).Wait();
|
||||
if (_playing is false)
|
||||
return;
|
||||
}
|
||||
} while (Loop.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 底层
|
||||
/// </summary>
|
||||
private void BackPlay()
|
||||
{
|
||||
do
|
||||
{
|
||||
foreach (var model in CurrentAnimeModel.Value.BackImages)
|
||||
{
|
||||
CurrentBackImageModel.Value = model;
|
||||
Task.Delay(model.Duration.Value).Wait();
|
||||
if (_playing is false)
|
||||
return;
|
||||
}
|
||||
} while (Loop.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 食物
|
||||
/// </summary>
|
||||
private void FoodPlay()
|
||||
{
|
||||
do
|
||||
{
|
||||
foreach (var model in CurrentAnimeModel.Value.FoodLocations)
|
||||
{
|
||||
CurrentFoodLocationModel.Value = model;
|
||||
Task.Delay(model.Duration.Value).Wait();
|
||||
if (_playing is false)
|
||||
return;
|
||||
}
|
||||
} while (Loop.Value);
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -295,7 +372,9 @@ public class FoodAnimeEditWindowVM
|
||||
private void Reset()
|
||||
{
|
||||
_playing = false;
|
||||
_playerTask = new(Play);
|
||||
_frontPlayerTask = new(FrontPlay);
|
||||
_backPlayerTask = new(BackPlay);
|
||||
_foodPlayerTask = new(FoodPlay);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -46,18 +46,21 @@
|
||||
<Expander.Header>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" MinWidth="200" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox pu:TextBoxHelper.Watermark="{ll:Str 动画Id}" Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Grid.Column="1" Margin="10,0,0,0">
|
||||
<TextBlock Margin="10,0,10,0">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})">
|
||||
<Binding Path="Images.Count" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
pu:TextBoxHelper.Watermark="{ll:Str 动画Id}"
|
||||
Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ComboBox
|
||||
Grid.Column="2"
|
||||
Margin="10,0,0,0"
|
||||
|
@ -32,15 +32,15 @@
|
||||
<MenuItem
|
||||
Command="{Binding PlacementTarget.Tag.AddImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
Header="添加图片" />
|
||||
Header="{ll:Str 添加图片}" />
|
||||
<MenuItem
|
||||
Command="{Binding PlacementTarget.Tag.ClearImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
Header="清空图片" />
|
||||
Header="{ll:Str 清空图片}" />
|
||||
<MenuItem
|
||||
Command="{Binding PlacementTarget.Tag.RemoveAnimeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
Header="删除此项" />
|
||||
Header="{ll:Str 删除此项}" />
|
||||
</ContextMenu>
|
||||
</Expander.ContextMenu>
|
||||
<Expander.Header>
|
||||
@ -50,14 +50,17 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox pu:TextBoxHelper.Watermark="动画Id" Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Grid.Column="1" Margin="10,0,0,0">
|
||||
<TextBlock Margin="10,0,10,0">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})">
|
||||
<Binding Path="Images.Count" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
pu:TextBoxHelper.Watermark="{ll:Str 动画Id}"
|
||||
Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ComboBox
|
||||
Grid.Column="2"
|
||||
Margin="10,0,0,0"
|
||||
@ -66,60 +69,139 @@
|
||||
Visibility="{Binding DataContext.HasMultiType.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Converter={StaticResource FalseToHiddenConverter}}" />
|
||||
</Grid>
|
||||
</Expander.Header>
|
||||
<ListBox
|
||||
d:ItemsSource="{d:SampleData ItemCount=5}"
|
||||
AllowDrop="True"
|
||||
Drop="ListBox_Drop"
|
||||
ItemsSource="{Binding Images, IsAsync=True}"
|
||||
PreviewMouseMove="ListBox_PreviewMouseMove"
|
||||
PreviewMouseWheel="ListBox_PreviewMouseWheel"
|
||||
SelectedItem="{Binding DataContext.CurrentImageModel.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
|
||||
SelectionChanged="ListBox_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Expander, Mode=FindAncestor}}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem
|
||||
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
Header="删除图片" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="150"
|
||||
Height="150"
|
||||
d:DataContext=""
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
|
||||
Source="{Binding Image.Value, IsAsync=True}">
|
||||
<Image.ToolTip>
|
||||
<Image
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding Image.Value, IsAsync=True}" />
|
||||
</Image.ToolTip>
|
||||
</Image>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="持续时间(ms)" />
|
||||
<pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" MinWidth="200" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox>
|
||||
<GroupBox.Header>
|
||||
<Label Content="{ll:Str 顶层图片}" />
|
||||
</GroupBox.Header>
|
||||
<ListBox
|
||||
d:ItemsSource="{d:SampleData ItemCount=5}"
|
||||
AllowDrop="True"
|
||||
Drop="ListBox_Drop"
|
||||
ItemsSource="{Binding Images, IsAsync=True}"
|
||||
PreviewMouseMove="ListBox_PreviewMouseMove"
|
||||
PreviewMouseWheel="ListBox_PreviewMouseWheel"
|
||||
SelectedItem="{Binding DataContext.CurrentImageModel.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
|
||||
SelectionChanged="ListBox_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Expander, Mode=FindAncestor}}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem
|
||||
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
Header="{ll:Str 删除图片}" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="150"
|
||||
Height="150"
|
||||
d:DataContext=""
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
|
||||
Source="{Binding Image.Value, IsAsync=True}">
|
||||
<Image.ToolTip>
|
||||
<Image
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding Image.Value, IsAsync=True}" />
|
||||
</Image.ToolTip>
|
||||
</Image>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="{ll:Str 持续时间(ms)}" />
|
||||
<pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="1">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{ll:Str 底层图片}" />
|
||||
</GroupBox.Header>
|
||||
<ListBox
|
||||
d:ItemsSource="{d:SampleData ItemCount=5}"
|
||||
AllowDrop="True"
|
||||
Drop="ListBox_Drop"
|
||||
ItemsSource="{Binding Images, IsAsync=True}"
|
||||
PreviewMouseMove="ListBox_PreviewMouseMove"
|
||||
PreviewMouseWheel="ListBox_PreviewMouseWheel"
|
||||
SelectedItem="{Binding DataContext.CurrentImageModel.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
|
||||
SelectionChanged="ListBox_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Expander, Mode=FindAncestor}}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem
|
||||
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
|
||||
Header="{ll:Str 删除图片}" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="150"
|
||||
Height="150"
|
||||
d:DataContext=""
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
|
||||
Source="{Binding Image.Value, IsAsync=True}">
|
||||
<Image.ToolTip>
|
||||
<Image
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding Image.Value, IsAsync=True}" />
|
||||
</Image.ToolTip>
|
||||
</Image>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="{ll:Str 持续时间(ms)}" />
|
||||
<pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
<GroupBox Grid.Column="1">
|
||||
<ListBox />
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Expander>
|
||||
</DataTemplate>
|
||||
</Window.Resources>
|
||||
@ -134,38 +216,85 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
x:Name="Image_Back"
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding CurrentImageModel.Value.Image.Value}" />
|
||||
<Image
|
||||
x:Name="Image_Center"
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding CurrentImageModel.Value.Image.Value}" />
|
||||
<Image
|
||||
x:Name="Image_Front"
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding CurrentImageModel.Value.Image.Value}">
|
||||
<Image.ToolTip>
|
||||
<Grid>
|
||||
<Image
|
||||
Width="500"
|
||||
Height="500"
|
||||
Source="{Binding Source, ElementName=Image_Back}" />
|
||||
<Image
|
||||
Width="500"
|
||||
Height="500"
|
||||
Source="{Binding Source, ElementName=Image_Center}" />
|
||||
<Image
|
||||
Width="500"
|
||||
Height="500"
|
||||
Source="{Binding Source, ElementName=Image_Front}" />
|
||||
</Grid>
|
||||
</Image.ToolTip>
|
||||
</Image>
|
||||
<Grid>
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{ll:Str 替换测试食物图片}" />
|
||||
<MenuItem Header="{ll:Str 重置测试食物图片}" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Image
|
||||
x:Name="Image_Back"
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding CurrentBackImageModel.Value.Image.Value}" />
|
||||
<Image
|
||||
x:Name="Image_Center"
|
||||
Width="250"
|
||||
Height="250"
|
||||
Opacity="{Binding CurrentFoodLocationModel.Value.Opacity.Value}"
|
||||
RenderTransformOrigin="0,0">
|
||||
<Image.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform />
|
||||
<SkewTransform />
|
||||
<RotateTransform Angle="{Binding CurrentFoodLocationModel.Value.Rotate.Value}" />
|
||||
<TranslateTransform />
|
||||
</TransformGroup>
|
||||
</Image.RenderTransform>
|
||||
<Image.Style>
|
||||
<Style TargetType="Image">
|
||||
<Setter Property="Width">
|
||||
<Setter.Value>
|
||||
<MultiBinding Converter="{StaticResource CalculatorConverter}" ConverterParameter="*">
|
||||
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.Width.Value" />
|
||||
<Binding Path="LengthRatio.Value" />
|
||||
</MultiBinding>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Height">
|
||||
<Setter.Value>
|
||||
<MultiBinding Converter="{StaticResource CalculatorConverter}" ConverterParameter="*">
|
||||
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.Width.Value" />
|
||||
<Binding Path="LengthRatio.Value" />
|
||||
</MultiBinding>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Margin">
|
||||
<Setter.Value>
|
||||
<MultiBinding Converter="{StaticResource RatioMarginConverter}">
|
||||
<Binding Path="LengthRatio.Value" />
|
||||
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.X.Value" />
|
||||
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.Y.Value" />
|
||||
</MultiBinding>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
<Image
|
||||
x:Name="Image_Front"
|
||||
Width="250"
|
||||
Height="250"
|
||||
Source="{Binding CurrentFrontImageModel.Value.Image.Value}">
|
||||
<Image.ToolTip>
|
||||
<Grid>
|
||||
<Image
|
||||
Width="500"
|
||||
Height="500"
|
||||
Source="{Binding Source, ElementName=Image_Back}" />
|
||||
<Image
|
||||
Width="500"
|
||||
Height="500"
|
||||
Source="{Binding Source, ElementName=Image_Center}" />
|
||||
<Image
|
||||
Width="500"
|
||||
Height="500"
|
||||
Source="{Binding Source, ElementName=Image_Front}" />
|
||||
</Grid>
|
||||
</Image.ToolTip>
|
||||
</Image>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
@ -194,7 +323,7 @@
|
||||
<!--<Label Content="{ll:Str 动画Id}" />
|
||||
<TextBox Grid.Column="1" />-->
|
||||
<Label Content="{ll:Str 动画类型}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding Anime.Value.GraphType.Value}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding Anime.Value.GraphType}" />
|
||||
<Label
|
||||
Grid.Row="1"
|
||||
Content="{ll:Str 动画名称}"
|
||||
|
@ -38,7 +38,6 @@
|
||||
Text="{Binding LowText.Value.Id.Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
<TextBox
|
||||
x:Name="TextBox_Text"
|
||||
Grid.Row="1"
|
||||
d:Text="这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,"
|
||||
pu:TextBoxHelper.Watermark="{ll:Str 文本}"
|
||||
|
Loading…
Reference in New Issue
Block a user