Unity 编辑器扩展:小说阅读器

前言

想看小说又不想多开一个程序在桌面上,写了一个简单的脚本阅读器融合进Unity的检视窗口
其实就是上班摸鱼时用的!😁

要点:

  • 使用的Unity自动的PlayerPrefs进行进度的保存
  • 识别目录用的简单的正则表达式
  • 识别速度还行,2000章的文本用不了1秒就能识别完毕
  • 支持按键绑定

效果演示

在这里插入图片描述

使用步骤

1.引入代码

using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public class NovelFish : MonoBehaviour
{
    private string[] _novelChapters;
    private string[] _novelWords;

    //小说显示内容
    [Multiline(10)]
    public string novel = "";
    //TXT文本文件
    public TextAsset novelFile;
    public KeyCode 上一页 = KeyCode.Mouse0;
    public KeyCode 下一页 = KeyCode.Mouse1;
    public KeyCode 隐藏 = KeyCode.Mouse2;
    public KeyCode 自动播放 = KeyCode.A;
    public KeyCode 上一章 = KeyCode.PageUp;
    public KeyCode 下一章 = KeyCode.PageDown;

    public bool _isPlaying;
    public int ChapterTarget;
    private int ChapterIndex
    {
        get => PlayerPrefs.GetInt("Chapter_" + novelFile.name, 0);
        set => PlayerPrefs.SetInt("Chapter_" + novelFile.name, value);
    }

    private int NowChapterIndex
    {
        get => PlayerPrefs.GetInt("Now_" + novelFile.name, 0);
        set => PlayerPrefs.SetInt("Now_" + novelFile.name, value);
    }


    private void Start()
    {
        LoadNovel();
    }

    //章节跳转
    [ContextMenu("章节跳转")]
    private void JumpPage()
    {
        if (ChapterTarget < 0 || ChapterTarget >= _novelChapters.Length)
            return;
        ChapterIndex = ChapterTarget;
        NowChapterIndex = 0;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterTarget]);
        novel = _novelWords[NowChapterIndex];
    }

    //重置文章
    [ContextMenu("重置文章")]
    private void ResetText()
    {
        NowChapterIndex = 0;
        ChapterIndex = 0;
        LoadNovel();
        print("总章数:" + _novelChapters.Length);
    }

    //文章(按章节)加载
    private void LoadNovel()
    {
        //第1章
        var pattern = @"(?m)^[第][0-9]{1,4}[章]";
        //000 nnn
        // var pattern = @"(?m)^\d{3,4}[\s]";
        //第一章 (中文数字)
	    // var pattern = @"(?m)^[第][\u4e00-\u9fa5]{1,5}[章]";


        var novelChapters = Regex.Split(novelFile.text, pattern);
        for (var i = 0; i < novelChapters.Length; i++)
        {
            novelChapters[i] = "第" + i + "章" + novelChapters[i];
        }

        _novelChapters = novelChapters;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        // novel = _novelWords[NowChapterIndex];
    }

    //按键绑定
    public void Update()
    {
        if (Input.GetKeyDown(下一页))
            PageDown();
        if (Input.GetKeyDown(上一页))
            PageUp();
        if (Input.GetKeyDown(隐藏))
            Hide();
        if (Input.GetKeyDown(自动播放))
            AutoPlay();
        if (Input.GetKeyDown(上一章))
            UpChapter();
        if (Input.GetKeyDown(下一章))
            DownChapter(); 
    }

    //上一章
    private void PageUp()
    {
        NowChapterIndex--;
        if (NowChapterIndex == -1)
        {
            ChapterIndex--;
            _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
            NowChapterIndex = _novelWords.Length - 1;
        }

        novel = _novelWords[NowChapterIndex];
    }

    //下一章
    private void PageDown()
    {
        NowChapterIndex++;
        if (NowChapterIndex == _novelWords.Length)
        {
            ChapterIndex++;
            NowChapterIndex = 0;
            _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        }

        novel = _novelWords[NowChapterIndex];
    }

    //下一页
    private void DownChapter()
    {
        ChapterIndex++;
        NowChapterIndex = 0;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        novel = _novelWords[NowChapterIndex];
    }

    //上一页
    private void UpChapter()
    {
        ChapterIndex--;
        NowChapterIndex = 0;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        novel = _novelWords[NowChapterIndex];
    }

    //自动播放
    private void AutoPlay()
    {
        _isPlaying = !_isPlaying;
        if (_isPlaying)
            StartCoroutine(nameof(AutoPlayIe));
        else
            StopCoroutine(nameof(AutoPlayIe));
    }

    private IEnumerator AutoPlayIe()
    {
        PageDown();
        // 自动播放延迟
        yield return new WaitForSeconds(5f);
        StartCoroutine(nameof(AutoPlayIe));
    }

    //快速隐藏(显示)
    private void Hide()
    {
        var haveWord = novel != "";
        novel = haveWord ? "" : _novelWords[NowChapterIndex];
    }

    //文字最多显示数量
    private const int MaxWordLength = 200;

    /// <summary>
    /// 加载文章片段
    /// </summary>
    private static string[] LoadOriginalWord(string word)
    {
        var novelFileList = new List<string>();
        var originalWord = word.Split('\n');
        for (var i = 0; i < originalWord.Length; i++)
        {
            //处理掉空字符串
            originalWord[i] = Regex.Replace(originalWord[i], @"\s", "");
            if (originalWord[i].Length > 1 && originalWord[i].Length <= 200)
            {
                novelFileList.Add(originalWord[i]);
            }
            else if (originalWord[i].Length > 200)
            {
                var ccl = originalWord[i].Length / MaxWordLength;
                for (var j = 0; j <= ccl; j++)
                {
                    if (originalWord[i].Length != j * MaxWordLength)
                        novelFileList.Add(originalWord[i].Substring(j * MaxWordLength,
                            j == ccl ? (originalWord[i].Length - j * MaxWordLength) - 1 : MaxWordLength));
                }
            }
        }

        return novelFileList.ToArray();
    }
}

odin插件版(它方便序列化了一些面版的按钮)
在这里插入图片描述

using Sirenix.OdinInspector;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;

public class NovelFish : MonoBehaviour
{
    public enum TitleType
    {
        T00Z,  // 00 Z
        D00Z,  // DI 00 Z
        DCNZ,  // DI CNNUME Z
    }
    private string[] _novelChapters;
    private string[] _novelWords;
    private const int MAX_WORD_LENGTH = 200;
    [Multiline(9), ReadOnly]
    public string novel = "";

    [FoldoutGroup("SET")] public TextAsset novelFile;
    [FoldoutGroup("SET")] public TitleType titleType;
    [FoldoutGroup("SET")] public KeyCode Up = KeyCode.Mouse0;
    [FoldoutGroup("SET")] public KeyCode Down = KeyCode.Mouse1;
    [FoldoutGroup("SET")] public KeyCode HideKey = KeyCode.Mouse2;
    [FoldoutGroup("SET")] public KeyCode Auto = KeyCode.A;
    [FoldoutGroup("SET")] public KeyCode PageUpKey = KeyCode.PageUp;
    [FoldoutGroup("SET")] public KeyCode PageDownKey = KeyCode.PageDown;
    [FoldoutGroup("SET")] public KeyCode Stop = KeyCode.P;
    [FoldoutGroup("SET"), Range(1f, 20f)] public float AutoSpeed = 5f;

    private bool _isPlaying;
    private bool _isPaused = true;

    private int ChapterIndex
    {
        get => PlayerPrefs.GetInt("Chapter_" + novelFile.name, 0);
        set => PlayerPrefs.SetInt("Chapter_" + novelFile.name, value);
    }
    private int NowChapterIndex
    {
        get => PlayerPrefs.GetInt("Now_" + novelFile.name, 0);
        set => PlayerPrefs.SetInt("Now_" + novelFile.name, value);
    }

    private void Start()
    {
        if (novelFile == null)
        {
            _isPaused = true;
            return;
        }
        LoadNovel();
    }

    [Button(Expanded = true), FoldoutGroup("SET")]
    private void JumpPage(int num)
    {
        if (num < 0 || num >= _novelChapters.Length)
            return;
        ChapterIndex = num;
        NowChapterIndex = 0;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        novel = _novelWords[NowChapterIndex];
    }

    [Button, FoldoutGroup("SET")]
    private void Clear()
    {
        novel = "";
    }

    [Button, FoldoutGroup("SET")]
    private void ResetText()
    {
        NowChapterIndex = 0;
        ChapterIndex = 0;
        LoadNovel();
        print("Total:" + _novelChapters.Length);
    }

    private void LoadNovel()
    {
        string pattern = string.Empty;
        switch (titleType)
        {
            case TitleType.T00Z:
                pattern = @"(?m)^\d{3,4}[\s]";
                break;
            case TitleType.D00Z:
                pattern = @"(?m)^[第][0-9]{1,4}[章]";
                break;
            case TitleType.DCNZ:
                pattern = @"(?m)^[第][\u4e00-\u9fa5]{1,5}[章]";
                break;
        }

        var novelChapters = Regex.Split(novelFile.text, pattern);
        for (var i = 0; i < novelChapters.Length; i++)
        {
            novelChapters[i] = "第" + i + "章" + novelChapters[i];
        }

        _novelChapters = novelChapters;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
    }

    //按键绑定
    public void Update()
    {
        if (Input.GetKeyDown(Stop))
            _isPaused = !_isPaused;
        if (_isPaused) return;

        if (Input.GetKeyDown(Down))
            PageDown();
        if (Input.GetKeyDown(Up))
            PageUp();
        if (Input.GetKeyDown(HideKey))
            Hide();
        if (Input.GetKeyDown(Auto))
            AutoPlay();
        if (Input.GetKeyDown(PageUpKey))
            UpChapter();
        if (Input.GetKeyDown(PageDownKey))
            DownChapter();
    }

    //上一章
    private void PageUp()
    {
        NowChapterIndex--;
        if (NowChapterIndex == -1)
        {
            ChapterIndex--;
            _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
            NowChapterIndex = _novelWords.Length - 1;
        }
        novel = _novelWords[NowChapterIndex];
    }


    public void PageDown(int page)
    {
        NowChapterIndex += page;
        if (NowChapterIndex >= _novelWords.Length)
        {
            ChapterIndex++;
            NowChapterIndex = 0;
            _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        }

        novel = _novelWords[NowChapterIndex];
    }

    private void PageDown()
    {
        NowChapterIndex++;
        if (NowChapterIndex == _novelWords.Length)
        {
            ChapterIndex++;
            NowChapterIndex = 0;
            _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        }

        novel = _novelWords[NowChapterIndex];
    }


    private void DownChapter()
    {
        ChapterIndex++;
        NowChapterIndex = 0;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        novel = _novelWords[NowChapterIndex];
    }


    private void UpChapter()
    {
        ChapterIndex--;
        NowChapterIndex = 0;
        _novelWords = LoadOriginalWord(_novelChapters[ChapterIndex]);
        novel = _novelWords[NowChapterIndex];
    }

    private void AutoPlay()
    {
        _isPlaying = !_isPlaying;
        if (_isPlaying)
            StartCoroutine(nameof(AutoPlayIe));
        else
            StopCoroutine(nameof(AutoPlayIe));
    }

    private IEnumerator AutoPlayIe()
    {
        PageDown();
        yield return new WaitForSeconds(AutoSpeed);
        if (_isPaused)
        {
            _isPlaying = false;
        }
        else
        {
            StartCoroutine(nameof(AutoPlayIe));
        }
    }

    //快速隐藏(显示)
    private void Hide()
    {
        var haveWord = novel != "";
        novel = haveWord ? "" : _novelWords[NowChapterIndex];
    }

    /// <summary>
    /// 加载文章片段
    /// </summary>
    private static string[] LoadOriginalWord(string word)
    {
        var novelFileList = new List<string>();
        var originalWord = word.Split('\n');
        for (var i = 0; i < originalWord.Length; i++)
        {
            //处理掉空字符串
            originalWord[i] = Regex.Replace(originalWord[i], @"\s", "");
            if (originalWord[i].Length > 1 && originalWord[i].Length <= 200)
            {
                novelFileList.Add(originalWord[i]);
            }
            else if (originalWord[i].Length > 200)
            {
                var ccl = originalWord[i].Length / MAX_WORD_LENGTH;
                for (var j = 0; j <= ccl; j++)
                {
                    if (originalWord[i].Length != j * MAX_WORD_LENGTH)
                        novelFileList.Add(originalWord[i].Substring(j * MAX_WORD_LENGTH,
                            j == ccl ? (originalWord[i].Length - j * MAX_WORD_LENGTH) - 1 : MAX_WORD_LENGTH));
                }
            }
        }

        return novelFileList.ToArray();
    }
}


2.导入的小说文本 TXT

记得要将导入的txt格式设置为UTF-8不然识别不出来
可以用记事本打开让后另存为时设置格式就好了

3.在代码块里选择你下载文件的目录格式

在70行代码左右注释掉不用的正则表达式部分

在这里插入图片描述

4.拖入文本文件再选择重置文章即可

在这里插入图片描述

总结

目前缺陷还是有的,不能自动识别小说目录格式,必须在游戏运行模式下使用(用的Input检测)。
有空还是可以改改的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

又来077

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值