292 lines
7.3 KiB
C#
292 lines
7.3 KiB
C#
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using Godot;
|
||
using Milimoe.FunGame.Core.Api.Utility;
|
||
using Milimoe.FunGame.Core.Model;
|
||
|
||
namespace Milimoe.GodotGame;
|
||
|
||
public partial class NovelController : CanvasLayer, ISaveSelectionEvent
|
||
{
|
||
public string NovelName { get; set; } = "";
|
||
public string SceneName { get; set; } = "";
|
||
public NovelConfig NovelConfig { get; set; } = null;
|
||
public NovelNode Current { get; set; } = null;
|
||
public INovelEndEvent ChapterObject { get; set; } = null;
|
||
public IMenuObject MenuObject { get; set; } = null;
|
||
public IFadeInFadeOutBlack FadeObject { get; set; } = null;
|
||
public bool Automatic { get; set; } = false;
|
||
|
||
[Export]
|
||
public SavedSelection SavedSelection;
|
||
|
||
[Signal]
|
||
public delegate void CloseSavedSelectionEventHandler(bool selected, int index);
|
||
|
||
private TextureRect _portrait1;
|
||
private TextureRect _portrait2left;
|
||
private TextureRect _portrait2right;
|
||
private TextureRect _image1;
|
||
private TextureRect _image2left;
|
||
private TextureRect _image2right;
|
||
private Panel _panel;
|
||
private Panel _namePanel;
|
||
private Label _name;
|
||
private RichTextLabel _content;
|
||
private AnimatedRichTextLabel _content_richLabel;
|
||
private VBoxContainer _vBoxContainer;
|
||
private ColorRect _colorRect;
|
||
private Button _autoPlay;
|
||
private Button _load;
|
||
private Button _save;
|
||
private Button _menu;
|
||
|
||
public override void _Ready()
|
||
{
|
||
Visible = false;
|
||
_portrait1 = GetNode<TextureRect>("立绘1");
|
||
_portrait2left = GetNode<TextureRect>("立绘2左");
|
||
_portrait2right = GetNode<TextureRect>("立绘2右");
|
||
_image1 = _portrait1.GetNode<TextureRect>("Image");
|
||
_image2left = _portrait2left.GetNode<TextureRect>("Image");
|
||
_image2right = _portrait2right.GetNode<TextureRect>("Image");
|
||
_panel = GetNode<Panel>("Panel");
|
||
_namePanel = _panel.GetNode<Panel>("NamePanel");
|
||
_name = _namePanel.GetNode<Label>("Name");
|
||
_content = _panel.GetNode<RichTextLabel>("Content");
|
||
if (_content is AnimatedRichTextLabel richLabel)
|
||
{
|
||
_content_richLabel = richLabel;
|
||
_content_richLabel.NovelController = this;
|
||
}
|
||
_colorRect = GetNode<ColorRect>("透明挡板");
|
||
_vBoxContainer = GetNode<VBoxContainer>("选项框");
|
||
if (_colorRect != null)
|
||
{
|
||
_colorRect.GuiInput += ColorRect_GuiInput;
|
||
}
|
||
_autoPlay = GetNode<Button>("自动播放");
|
||
_load = GetNode<Button>("读取存档");
|
||
_save = GetNode<Button>("保存存档");
|
||
_menu = GetNode<Button>("游戏菜单");
|
||
if (_autoPlay != null)
|
||
{
|
||
_autoPlay.Pressed += () => Automatic = _autoPlay.ButtonPressed;
|
||
}
|
||
if (_load != null)
|
||
{
|
||
_load.Pressed += () => OnLoadSaveButtonPressed(false);
|
||
}
|
||
if (_save != null)
|
||
{
|
||
_save.Pressed += () => OnLoadSaveButtonPressed(true);
|
||
}
|
||
if (_menu != null)
|
||
{
|
||
_menu.Pressed += OnMenuButtonPressed;
|
||
}
|
||
}
|
||
|
||
public void InitNovel(string novel_name, string scene_name)
|
||
{
|
||
NovelName = novel_name;
|
||
SceneName = scene_name;
|
||
if (NovelName != "" && SceneName != "")
|
||
{
|
||
NovelConfig ??= NovelConfig.LoadFrom(ProjectSettings.GlobalizePath("res://resources/novels/第一章/场景一.json"), NovelName, false);
|
||
if (NovelConfig.Count > 0)
|
||
{
|
||
ShowNode(NovelConfig.Values.First());
|
||
}
|
||
}
|
||
}
|
||
|
||
public void ShowNode(NovelNode node)
|
||
{
|
||
if (node != null)
|
||
{
|
||
GameConstant.NovelName = NovelName;
|
||
GameConstant.SceneName = SceneName;
|
||
GameConstant.NovelNodeKey = node.Key;
|
||
_name.Text = node.Name;
|
||
_namePanel.Visible = _name.Text != "";
|
||
_name.Visible = _name.Text != "";
|
||
if (node.PortraitImagePath != "")
|
||
{
|
||
using Texture2D texture = GD.Load<CompressedTexture2D>(node.PortraitImagePath);
|
||
_image1.Texture = texture;
|
||
_image1.Visible = true;
|
||
}
|
||
else _image1.Visible = false;
|
||
if (_content_richLabel != null)
|
||
{
|
||
_content_richLabel.SetText(node.Content);
|
||
_content_richLabel.StartAnimation();
|
||
}
|
||
else _content.Text = node.Content;
|
||
foreach (Node child in _vBoxContainer.GetChildren())
|
||
{
|
||
child.QueueFree();
|
||
}
|
||
_vBoxContainer.Visible = false;
|
||
_colorRect.Visible = true;
|
||
Current = node;
|
||
Visible = true;
|
||
}
|
||
else Visible = false;
|
||
}
|
||
|
||
public async void TextAnimationHasFinished()
|
||
{
|
||
if (Current != null)
|
||
{
|
||
await Task.Delay(500);
|
||
if (_vBoxContainer.Visible)
|
||
{
|
||
return;
|
||
}
|
||
foreach (NovelOption option in Current.AvailableOptions)
|
||
{
|
||
Button button = new()
|
||
{
|
||
Text = option.Name,
|
||
Theme = GD.Load<Theme>("res://resources/themes/option.tres")
|
||
};
|
||
button.Pressed += () => OnOptionButtonClick(option);
|
||
_vBoxContainer.AddChild(button);
|
||
}
|
||
if (Current.AvailableOptions.Count == 0)
|
||
{
|
||
// 透明挡板用于控制在没有选项时继续
|
||
_colorRect.Visible = true;
|
||
// 如果是自动播放剧情,则在800ms后,自动下一句
|
||
if (Automatic)
|
||
{
|
||
await Task.Delay(800);
|
||
// 需要再次判断
|
||
if (Automatic && !_content_richLabel.IsAnimationRunning)
|
||
{
|
||
NovelNode next = Current.Next;
|
||
if (next != null)
|
||
{
|
||
ShowNode(next);
|
||
}
|
||
else
|
||
{
|
||
ChapterObject.OnNovelEnd(this, NovelName, SceneName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 显示选项框
|
||
_vBoxContainer.Visible = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
public void OnOptionButtonClick(NovelOption option)
|
||
{
|
||
if (option != null && option.Targets.Count > 0)
|
||
{
|
||
NovelNode next = option.Targets.First();
|
||
ShowNode(next);
|
||
}
|
||
}
|
||
|
||
private void ColorRect_GuiInput(InputEvent @event)
|
||
{
|
||
if (@event is InputEventMouseButton mouseButtonEvent)
|
||
{
|
||
if (mouseButtonEvent.ButtonIndex == MouseButton.Left && mouseButtonEvent.Pressed)
|
||
{
|
||
if (_content_richLabel.IsAnimationRunning)
|
||
{
|
||
_content_richLabel.SkipAnimation();
|
||
}
|
||
else
|
||
{
|
||
if (Current.AvailableOptions.Count > 0)
|
||
{
|
||
return;
|
||
}
|
||
NovelNode next = Current.Next;
|
||
if (next != null)
|
||
{
|
||
ShowNode(next);
|
||
}
|
||
else
|
||
{
|
||
ChapterObject.OnNovelEnd(this, NovelName, SceneName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnLoadSaveButtonPressed(bool isSave)
|
||
{
|
||
if (isSave)
|
||
{
|
||
// 保存游戏
|
||
GD.Print("Save Game!");
|
||
SavedSelection.SetIsSave(true);
|
||
}
|
||
else
|
||
{
|
||
// 载入游戏
|
||
GD.Print("Load Game!");
|
||
SavedSelection.SetIsSave(false);
|
||
}
|
||
|
||
// 使用动画效果显示存档列表
|
||
if (SavedSelection != null)
|
||
{
|
||
SavedSelection.Show();
|
||
SavedSelection.GetNode<ColorRect>("ColorRect").GetNode<AnimationPlayer>("AnimationPlayer").Play("flyin");
|
||
}
|
||
}
|
||
|
||
private void OnMenuButtonPressed()
|
||
{
|
||
// 打开游戏菜单
|
||
GD.Print("Open Game Menu!");
|
||
if (MenuObject is IMenuObject obj)
|
||
{
|
||
obj.ChangeState();
|
||
}
|
||
}
|
||
|
||
public async void OnSaveSelectionClosed(bool selected, int index, bool isSave)
|
||
{
|
||
if (SavedSelection != null && !SavedSelection.IsClosing)
|
||
{
|
||
// 关闭存档选择界面
|
||
SavedSelection.IsClosing = true;
|
||
SavedSelection.GetNode<ColorRect>("ColorRect").GetNode<AnimationPlayer>("AnimationPlayer").Play("flyout");
|
||
await Task.Delay(300);
|
||
SavedSelection.IsClosing = false;
|
||
SavedSelection.Hide();
|
||
if (selected && index >= 0)
|
||
{
|
||
if (!isSave)
|
||
{
|
||
// 载入游戏
|
||
GD.Print($"Selected Saved: {index}!");
|
||
if (FadeObject != null)
|
||
{
|
||
await FadeObject.FadeInBlack(1f);
|
||
}
|
||
else await Task.Delay(1000);
|
||
GetTree().Quit();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
GD.Print("Close SavedSelection!");
|
||
}
|
||
}
|
||
}
|
||
}
|