前言
想看小说又不想多开一个程序在桌面上,写了一个简单的脚本阅读器融合进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检测)。
有空还是可以改改的。