fix:1、更换关卡获取,改为单关一个json文件

This commit is contained in:
2026-06-24 09:24:15 +08:00
parent cd258603ac
commit f0f102fe4c
1040 changed files with 499808 additions and 54942 deletions
-29
View File
@@ -1,29 +0,0 @@
using System.Collections.Generic;
namespace ChillConnect.Editor
{
[System.Serializable]
public class EditorLevelConfig
{
public int levelId;
public string levelName;
public int gridRows;
public int gridCols;
public int pointSpacing;
public List<EditorArrowConfig> arrows;
}
[System.Serializable]
public class EditorArrowConfig
{
public int id;
public int startPoint;
public List<string> path;
}
[System.Serializable]
public class EditorAllLevelRoot
{
public List<EditorLevelConfig> levels;
}
}
-3
View File
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 9188e4d5fc904730b169ca235b32903b
timeCreated: 1781601766
+363
View File
@@ -0,0 +1,363 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ChillConnect;
public class ArrowLevelAutoGenerator : EditorWindow
{
// ----- 参数 -----
private int _levelCount = 10;
private bool _autoSizeByDifficulty = true;
private int _gridRows = 8;
private int _gridCols = 8;
private int _pointSpacing = 60;
private Difficulty _difficulty = Difficulty.Hard;
private GenerationMode _mode = GenerationMode.Random;
private PatternType _pattern = PatternType.Heart;
private bool _randomPattern = false;
private string _outputFileName = "all_levels.json";
private enum Difficulty { Easy, Medium, Hard }
private enum GenerationMode { Random, Pattern }
private enum PatternType { Heart, Star, LetterA, Diamond, Circle, XShape, Random }
[MenuItem("Tools/Arrow Level Auto Generator")]
public static void ShowWindow()
{
GetWindow<ArrowLevelAutoGenerator>("自动生成关卡");
}
private void OnGUI()
{
GUILayout.Label("自动化关卡生成器", EditorStyles.boldLabel);
EditorGUILayout.Space();
_levelCount = EditorGUILayout.IntField("关卡数量", _levelCount);
_autoSizeByDifficulty = EditorGUILayout.Toggle("根据难度自动调整网格尺寸", _autoSizeByDifficulty);
if (!_autoSizeByDifficulty)
{
_gridRows = EditorGUILayout.IntField("网格行数", _gridRows);
_gridCols = EditorGUILayout.IntField("网格列数", _gridCols);
}
else
{
EditorGUILayout.HelpBox("网格尺寸:简单6×6,中等8×8,困难34×21", MessageType.Info);
}
_pointSpacing = EditorGUILayout.IntField("点间距", _pointSpacing);
_difficulty = (Difficulty)EditorGUILayout.EnumPopup("难度", _difficulty);
_mode = (GenerationMode)EditorGUILayout.EnumPopup("生成模式", _mode);
if (_mode == GenerationMode.Pattern)
{
_randomPattern = EditorGUILayout.Toggle("随机图案", _randomPattern);
if (!_randomPattern)
{
_pattern = (PatternType)EditorGUILayout.EnumPopup("指定图案", _pattern);
}
}
_outputFileName = EditorGUILayout.TextField("输出文件名", _outputFileName);
EditorGUILayout.Space();
if (GUILayout.Button("生成关卡", GUILayout.Height(40)))
{
GenerateLevels();
}
}
private void GenerateLevels()
{
if (_levelCount <= 0)
{
EditorUtility.DisplayDialog("错误", "关卡数量必须大于0", "确定");
return;
}
List<LevelConfig> levels = new List<LevelConfig>();
for (int i = 0; i < _levelCount; i++)
{
LevelConfig lv = null;
int rows, cols;
if (_autoSizeByDifficulty)
GetSizeByDifficulty(out rows, out cols);
else
{
rows = _gridRows;
cols = _gridCols;
}
if (_mode == GenerationMode.Pattern)
{
PatternType selectedPattern = _pattern;
if (_randomPattern)
selectedPattern = (PatternType)Random.Range(0, System.Enum.GetValues(typeof(PatternType)).Length - 1);
lv = GeneratePatternLevel(selectedPattern, i + 1, rows, cols);
if (lv == null)
{
Debug.LogWarning($"图案生成失败,回退到随机");
lv = GenerateRandomLevel(i + 1, rows, cols);
}
}
else
{
lv = GenerateRandomLevel(i + 1, rows, cols);
}
if (lv != null)
levels.Add(lv);
}
if (levels.Count == 0)
{
EditorUtility.DisplayDialog("错误", "没有生成任何有效关卡", "确定");
return;
}
AllLevelRoot root = new AllLevelRoot();
root.levels = levels;
string json = JsonUtility.ToJson(root, true);
string path = EditorUtility.SaveFilePanel("保存关卡配置", Application.dataPath, _outputFileName, "json");
if (!string.IsNullOrEmpty(path))
{
File.WriteAllText(path, json);
EditorUtility.DisplayDialog("成功", $"已生成 {levels.Count} 个关卡并保存到 {path}", "确定");
}
}
private void GetSizeByDifficulty(out int rows, out int cols)
{
switch (_difficulty)
{
case Difficulty.Easy: rows = 6; cols = 6; break;
case Difficulty.Medium: rows = 8; cols = 8; break;
case Difficulty.Hard: rows = 34; cols = 21; break;
default: rows = 8; cols = 8; break;
}
}
// ========== 改进的随机生成(无交叉) ==========
private LevelConfig GenerateRandomLevel(int levelId, int rows, int cols)
{
LevelConfig lv = new LevelConfig();
lv.levelId = levelId;
lv.levelName = $"第{levelId}关";
lv.gridRows = rows;
lv.gridCols = cols;
lv.pointSpacing = _pointSpacing;
lv.arrows = new List<ArrowConfig>();
int arrowCount = 0;
int minPathLen=0,maxPathLen=0;
int maxTurns = 0;
switch (_difficulty)
{
case Difficulty.Easy: arrowCount = Random.Range(3, 6); minPathLen = 1; maxPathLen = 3; maxTurns = 1; break;
case Difficulty.Medium: arrowCount = Random.Range(6, 10); minPathLen = 2; maxPathLen = 5; maxTurns = 2; break;
case Difficulty.Hard: arrowCount = Random.Range(25, 40); minPathLen = 4; maxPathLen = 10; maxTurns = 5; break;
}
HashSet<int> occupiedPoints = new HashSet<int>();
int maxAttemptsPerArrow = 200;
int totalAttempts = 0;
int maxTotalAttempts = arrowCount * 50;
for (int i = 0; i < arrowCount; i++)
{
bool success = false;
int attempts = 0;
while (!success && attempts < maxAttemptsPerArrow && totalAttempts < maxTotalAttempts)
{
attempts++;
totalAttempts++;
int start = Random.Range(0, rows * cols);
if (occupiedPoints.Contains(start))
continue;
int pathLen = Random.Range(minPathLen, maxPathLen + 1);
List<string> dirs = new List<string>();
int cur = start;
bool valid = true;
int turns = 0;
string lastDir = "";
List<int> pathPoints = new List<int> { start };
for (int j = 0; j < pathLen; j++)
{
List<string> validDirs = GetValidDirections(cur, rows, cols);
if (validDirs.Count == 0) { valid = false; break; }
string chosenDir = "";
if (turns < maxTurns && !string.IsNullOrEmpty(lastDir))
{
var otherDirs = validDirs.Where(d => d != lastDir).ToList();
if (otherDirs.Count > 0)
chosenDir = otherDirs[Random.Range(0, otherDirs.Count)];
else
chosenDir = validDirs[Random.Range(0, validDirs.Count)];
}
else
{
chosenDir = validDirs[Random.Range(0, validDirs.Count)];
}
if (chosenDir != lastDir && !string.IsNullOrEmpty(lastDir))
turns++;
dirs.Add(chosenDir);
cur = GetNextPoint(cur, chosenDir, cols, rows);
if (cur < 0) { valid = false; break; }
pathPoints.Add(cur);
lastDir = chosenDir;
}
if (!valid) continue;
// 检测冲突
bool conflict = false;
foreach (int p in pathPoints)
{
if (occupiedPoints.Contains(p))
{
conflict = true;
break;
}
}
if (conflict) continue;
// 无冲突,添加箭头
ArrowConfig arrow = new ArrowConfig();
arrow.id = i + 1;
arrow.startPoint = start;
arrow.path = dirs;
lv.arrows.Add(arrow);
foreach (int p in pathPoints)
occupiedPoints.Add(p);
success = true;
}
if (!success)
Debug.LogWarning($"生成第 {levelId} 关时,第 {i+1} 个箭头生成失败,跳过");
}
if (lv.arrows.Count == 0) return null;
return lv;
}
private List<string> GetValidDirections(int point, int rows, int cols)
{
List<string> dirs = new List<string>();
int row = point / cols;
int col = point % cols;
if (row > 0) dirs.Add("up");
if (row < rows - 1) dirs.Add("down");
if (col > 0) dirs.Add("left");
if (col < cols - 1) dirs.Add("right");
return dirs;
}
// ========== 图案生成(简单版) ==========
private LevelConfig GeneratePatternLevel(PatternType pattern, int levelId, int rows, int cols)
{
// 这里仅实现菱形图案,您可自行扩展
return GenerateDiamondPattern(levelId, rows, cols);
}
private LevelConfig GenerateDiamondPattern(int levelId, int rows, int cols)
{
if (rows < 5 || cols < 5) return null;
LevelConfig lv = new LevelConfig();
lv.levelId = levelId;
lv.levelName = $"图案Diamond_{levelId}";
lv.gridRows = rows;
lv.gridCols = cols;
lv.pointSpacing = _pointSpacing;
lv.arrows = new List<ArrowConfig>();
int centerRow = rows / 2;
int centerCol = cols / 2;
int radius = Mathf.Min(rows, cols) / 2 - 1;
if (radius < 2) return null;
List<int> points = new List<int>();
for (int i = 0; i <= radius; i++)
{
int r = centerRow - i;
int c = centerCol + i;
if (r >= 0 && c < cols) points.Add(r * cols + c);
}
for (int i = 1; i <= radius; i++)
{
int r = centerRow + i;
int c = centerCol + radius - i;
if (r < rows && c >= 0) points.Add(r * cols + c);
}
for (int i = 1; i <= radius; i++)
{
int r = centerRow + radius - i;
int c = centerCol - i;
if (r >= 0 && c >= 0) points.Add(r * cols + c);
}
for (int i = 1; i < radius; i++)
{
int r = centerRow - i;
int c = centerCol - radius + i;
if (r >= 0 && c >= 0) points.Add(r * cols + c);
}
if (points.Count < 3) return null;
int maxStep = 4;
int arrowId = 1;
for (int i = 0; i < points.Count - 1;)
{
int remaining = points.Count - 1 - i;
int step = Mathf.Min(maxStep, remaining);
var segment = points.Skip(i).Take(step + 1).ToList();
if (segment.Count >= 2)
{
ArrowConfig arrow = new ArrowConfig();
arrow.id = arrowId++;
arrow.startPoint = segment[0];
arrow.path = new List<string>();
for (int j = 0; j < segment.Count - 1; j++)
{
string dir = GetDirection(segment[j], segment[j + 1], cols);
arrow.path.Add(dir);
}
lv.arrows.Add(arrow);
}
i += step;
}
return lv;
}
// ========== 工具方法 ==========
private int GetNextPoint(int current, string dir, int cols, int rows)
{
int row = current / cols;
int col = current % cols;
switch (dir)
{
case "up": row--; break;
case "down": row++; break;
case "left": col--; break;
case "right": col++; break;
}
if (row < 0 || row >= rows || col < 0 || col >= cols) return -1;
return row * cols + col;
}
private string GetDirection(int from, int to, int cols)
{
int fromRow = from / cols, fromCol = from % cols;
int toRow = to / cols, toCol = to % cols;
if (toRow < fromRow) return "up";
if (toRow > fromRow) return "down";
if (toCol < fromCol) return "left";
if (toCol > fromCol) return "right";
return "up";
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1d00ed1816894c03a2aa8dcf12d00069
timeCreated: 1781774604
+495
View File
@@ -0,0 +1,495 @@
// 文件名: ArrowLevelEditor.cs
// 路径: Assets/Editor/ArrowLevelEditor.cs
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ChillConnect;
public class ArrowLevelEditor : EditorWindow
{
// ========== 多关卡数据 ==========
private List<LevelConfig> _levels = new List<LevelConfig>();
private int _selectedLevelIndex = -1;
private int _nextLevelId = 1;
// ========== 当前正在编辑的箭头路径 ==========
private List<int> _currentPathPoints = new List<int>();
private int _arrowIdCounter = 1;
// ========== 预设颜色 ==========
private readonly Color[] _colorPalette = new Color[]
{
new Color(1f, 0.3f, 0.3f),
new Color(1f, 0.6f, 0.2f),
new Color(1f, 0.9f, 0.2f),
new Color(0.3f, 0.8f, 0.4f),
new Color(0.2f, 0.8f, 0.9f),
new Color(0.3f, 0.5f, 1f),
new Color(0.7f, 0.4f, 1f),
new Color(1f, 0.5f, 0.8f)
};
private Vector2 _scrollPos;
[MenuItem("Tools/Arrow Level Editor")]
public static void ShowWindow()
{
GetWindow<ArrowLevelEditor>("箭头关卡编辑器 (多关卡)");
}
private void OnEnable()
{
if (_levels.Count == 0)
CreateNewLevel("第1关", 8, 8, 60);
if (_selectedLevelIndex < 0 || _selectedLevelIndex >= _levels.Count)
_selectedLevelIndex = 0;
OnLevelChanged();
}
private void OnGUI()
{
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
// ========== 顶部工具栏 ==========
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("导入 all_levels.json", GUILayout.Width(150))) ImportLevels();
if (GUILayout.Button("导出 all_levels.json", GUILayout.Width(150))) ExportAllLevels();
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
// ========== 关卡管理 ==========
EditorGUILayout.BeginHorizontal();
GUILayout.Label("关卡列表", EditorStyles.boldLabel);
if (GUILayout.Button("新建关卡", GUILayout.Width(80)))
CreateNewLevel($"第{_levels.Count + 1}关", 8, 8, 60);
if (GUILayout.Button("删除当前", GUILayout.Width(80)))
{
if (_selectedLevelIndex >= 0 && _selectedLevelIndex < _levels.Count)
{
if (EditorUtility.DisplayDialog("删除关卡", $"确定删除 '{_levels[_selectedLevelIndex].levelName}'", "确定", "取消"))
{
_levels.RemoveAt(_selectedLevelIndex);
if (_levels.Count == 0) CreateNewLevel("第1关", 8, 8, 60);
_selectedLevelIndex = Mathf.Clamp(_selectedLevelIndex, 0, _levels.Count - 1);
OnLevelChanged();
}
}
}
if (GUILayout.Button("复制当前", GUILayout.Width(80)))
{
if (_selectedLevelIndex >= 0)
{
var src = _levels[_selectedLevelIndex];
LevelConfig copy = new LevelConfig();
copy.levelId = _nextLevelId++;
copy.levelName = src.levelName + "_副本";
copy.gridRows = src.gridRows;
copy.gridCols = src.gridCols;
copy.pointSpacing = src.pointSpacing;
copy.arrows = new List<ArrowConfig>();
foreach (var a in src.arrows)
{
ArrowConfig newA = new ArrowConfig();
newA.id = a.id;
newA.startPoint = a.startPoint;
newA.path = new List<string>(a.path);
copy.arrows.Add(newA);
}
_levels.Add(copy);
_selectedLevelIndex = _levels.Count - 1;
OnLevelChanged();
}
}
EditorGUILayout.EndHorizontal();
// 显示关卡列表
for (int i = 0; i < _levels.Count; i++)
{
var lv = _levels[i];
EditorGUILayout.BeginHorizontal();
if (i == _selectedLevelIndex) GUI.backgroundColor = Color.green;
if (GUILayout.Button($"ID:{lv.levelId} {lv.levelName} ({lv.arrows.Count}箭头)", GUILayout.MinWidth(150)))
{
if (_selectedLevelIndex != i)
{
_selectedLevelIndex = i;
OnLevelChanged();
}
}
GUI.backgroundColor = Color.white;
EditorGUILayout.EndHorizontal();
}
GUILayout.Space(10);
// ========== 当前关卡编辑区 ==========
if (_selectedLevelIndex >= 0 && _selectedLevelIndex < _levels.Count)
{
LevelConfig currentLevel = _levels[_selectedLevelIndex];
EditorGUILayout.LabelField($"编辑关卡: {currentLevel.levelName}", EditorStyles.boldLabel);
currentLevel.levelId = EditorGUILayout.IntField("关卡ID", currentLevel.levelId);
currentLevel.levelName = EditorGUILayout.TextField("关卡名称", currentLevel.levelName);
currentLevel.gridRows = EditorGUILayout.IntField("行数", currentLevel.gridRows);
currentLevel.gridCols = EditorGUILayout.IntField("列数", currentLevel.gridCols);
currentLevel.pointSpacing = EditorGUILayout.IntField("点间距", currentLevel.pointSpacing);
GUILayout.Space(10);
EditorGUILayout.LabelField("绘制当前箭头", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("撤销上一点") && _currentPathPoints.Count > 0)
_currentPathPoints.RemoveAt(_currentPathPoints.Count - 1);
if (GUILayout.Button("清空当前路径"))
_currentPathPoints.Clear();
if (GUILayout.Button("清空所有箭头"))
{
if (EditorUtility.DisplayDialog("确认", "删除当前关卡所有箭头?", "确定", "取消"))
{
currentLevel.arrows.Clear();
_arrowIdCounter = 1;
_currentPathPoints.Clear();
}
}
EditorGUILayout.EndHorizontal();
// 网格绘制(增强:显示起点/终点标记)
DrawGridWithArrows(currentLevel);
// 确认生成
if (GUILayout.Button("确认生成当前箭头 (加入列表)"))
{
if (_currentPathPoints.Count < 2)
{
EditorUtility.DisplayDialog("错误", "路径至少需要2个点", "确定");
}
else
{
ArrowConfig newArrow = new ArrowConfig();
newArrow.id = _arrowIdCounter++;
newArrow.startPoint = _currentPathPoints[0];
newArrow.path = new List<string>();
for (int i = 0; i < _currentPathPoints.Count - 1; i++)
{
newArrow.path.Add(GetDirection(_currentPathPoints[i], _currentPathPoints[i + 1], currentLevel.gridCols));
}
int colorIdx = (currentLevel.arrows.Count) % _colorPalette.Length;
newArrow.runtimeColor = _colorPalette[colorIdx];
currentLevel.arrows.Add(newArrow);
_currentPathPoints.Clear();
Debug.Log($"箭头已生成,当前箭头总数 {currentLevel.arrows.Count}");
}
}
// 箭头列表(显示起点→终点)
GUILayout.Space(10);
EditorGUILayout.LabelField($"当前箭头 ({currentLevel.arrows.Count})", EditorStyles.boldLabel);
for (int i = 0; i < currentLevel.arrows.Count; i++)
{
var arrow = currentLevel.arrows[i];
// 计算终点
int endPoint = arrow.startPoint;
if (arrow.path.Count > 0)
{
int cur = arrow.startPoint;
foreach (string dir in arrow.path)
{
int next = GetNextPoint(cur, dir, currentLevel.gridCols, currentLevel.gridRows);
if (next >= 0) cur = next;
}
endPoint = cur;
}
EditorGUILayout.BeginHorizontal();
Color arrowColor = arrow.runtimeColor;
if (arrowColor == default)
{
arrowColor = _colorPalette[i % _colorPalette.Length];
arrow.runtimeColor = arrowColor;
}
GUI.backgroundColor = arrowColor;
GUILayout.Label(" ", GUILayout.Width(20), GUILayout.Height(18));
GUI.backgroundColor = Color.white;
if (GUILayout.Button($"ID:{arrow.id} {arrow.startPoint} → {endPoint} 路径:{string.Join(",", arrow.path)}", GUILayout.MinWidth(200)))
{
// 可扩展高亮
}
if (GUILayout.Button("✕", GUILayout.Width(20)))
{
if (EditorUtility.DisplayDialog("删除箭头", $"删除箭头 ID:{arrow.id}", "确定", "取消"))
{
currentLevel.arrows.RemoveAt(i);
i--;
}
}
EditorGUILayout.EndHorizontal();
}
}
else
{
EditorGUILayout.HelpBox("请先创建或选择一个关卡", MessageType.Info);
}
EditorGUILayout.EndScrollView();
}
// ========== 辅助方法 ==========
private void CreateNewLevel(string name, int rows, int cols, int spacing)
{
LevelConfig lv = new LevelConfig();
lv.levelId = _nextLevelId++;
lv.levelName = name;
lv.gridRows = rows;
lv.gridCols = cols;
lv.pointSpacing = spacing;
lv.arrows = new List<ArrowConfig>();
_levels.Add(lv);
_selectedLevelIndex = _levels.Count - 1;
OnLevelChanged();
}
private void OnLevelChanged()
{
_currentPathPoints.Clear();
if (_selectedLevelIndex >= 0 && _selectedLevelIndex < _levels.Count)
{
var lv = _levels[_selectedLevelIndex];
_arrowIdCounter = lv.arrows.Count + 1;
for (int i = 0; i < lv.arrows.Count; i++)
{
if (lv.arrows[i].runtimeColor == default)
lv.arrows[i].runtimeColor = _colorPalette[i % _colorPalette.Length];
}
}
}
// ========== 增强的网格绘制(标记起点/终点) ==========
private void DrawGridWithArrows(LevelConfig level)
{
int totalPoints = level.gridRows * level.gridCols;
int rows = level.gridRows;
int cols = level.gridCols;
// 构建:点ID -> (箭头索引, 是否起点, 是否终点)
var pointInfo = new Dictionary<int, List<(int idx, bool isStart, bool isEnd)>>();
for (int i = 0; i < level.arrows.Count; i++)
{
var arrow = level.arrows[i];
List<int> allPoints = new List<int> { arrow.startPoint };
int cur = arrow.startPoint;
foreach (string dir in arrow.path)
{
int next = GetNextPoint(cur, dir, cols, rows);
if (next >= 0) allPoints.Add(next);
cur = next;
}
// 终点是路径最后一个点
int end = allPoints.LastOrDefault();
for (int j = 0; j < allPoints.Count; j++)
{
int pid = allPoints[j];
bool isStart = (j == 0);
bool isEnd = (j == allPoints.Count - 1);
if (!pointInfo.ContainsKey(pid))
pointInfo[pid] = new List<(int, bool, bool)>();
pointInfo[pid].Add((i, isStart, isEnd));
}
}
// 构建每个点的显示标签
var pointLabels = new Dictionary<int, string>();
foreach (var kv in pointInfo)
{
int pid = kv.Key;
var list = kv.Value;
bool hasStart = list.Any(x => x.isStart);
bool hasEnd = list.Any(x => x.isEnd);
bool multi = list.Count > 1;
string label = "";
if (hasStart && hasEnd)
label = "S/E";
else if (hasStart)
label = "S";
else if (hasEnd)
label = "E";
if (multi && (hasStart || hasEnd))
label += "+";
else if (multi && !hasStart && !hasEnd)
label = "+";
pointLabels[pid] = label;
}
// 绘制网格
for (int i = 0; i < totalPoints; i++)
{
int row = i / cols;
int col = i % cols;
if (col == 0) EditorGUILayout.BeginHorizontal();
bool isInCurrentPath = _currentPathPoints.Contains(i);
bool isInSavedPath = pointInfo.ContainsKey(i);
Color bgColor = GUI.backgroundColor;
string label = i.ToString();
if (isInSavedPath)
{
var owners = pointInfo[i];
if (owners.Count == 1)
{
int idx = owners[0].idx;
bgColor = level.arrows[idx].runtimeColor;
}
else
{
bgColor = Color.gray;
}
// 添加起点/终点标记
if (pointLabels.ContainsKey(i))
label += pointLabels[i];
}
if (isInCurrentPath)
{
bgColor = Color.green;
label = i + "●";
}
// 起点/终点特殊颜色边框(仅当无重叠时)
if (isInSavedPath && pointInfo[i].Count == 1)
{
var info = pointInfo[i][0];
if (info.isStart)
bgColor = Color.Lerp(bgColor, Color.green, 0.3f);
else if (info.isEnd)
bgColor = Color.Lerp(bgColor, Color.red, 0.3f);
}
GUI.backgroundColor = bgColor;
if (GUILayout.Button(label, GUILayout.Width(50), GUILayout.Height(30))) // 增加宽度容纳标记
{
if (_currentPathPoints.Count == 0)
_currentPathPoints.Add(i);
else
{
int last = _currentPathPoints[_currentPathPoints.Count - 1];
if (IsAdjacent(last, i, cols))
{
if (isInSavedPath)
Debug.LogWarning($"点 {i} 已被其他箭头占用,可能重叠");
_currentPathPoints.Add(i);
}
else
EditorUtility.DisplayDialog("提示", $"必须与上一个点 ({last}) 相邻", "确定");
}
}
GUI.backgroundColor = Color.white;
if (col == cols - 1) EditorGUILayout.EndHorizontal();
}
}
// ========== 工具方法 ==========
private int GetNextPoint(int current, string dir, int cols, int rows)
{
int row = current / cols;
int col = current % cols;
switch (dir)
{
case "up": row--; break;
case "down": row++; break;
case "left": col--; break;
case "right": col++; break;
}
if (row < 0 || row >= rows || col < 0 || col >= cols) return -1;
return row * cols + col;
}
private bool IsAdjacent(int a, int b, int cols)
{
int aRow = a / cols, aCol = a % cols;
int bRow = b / cols, bCol = b % cols;
return (Mathf.Abs(aRow - bRow) + Mathf.Abs(aCol - bCol)) == 1;
}
private string GetDirection(int from, int to, int cols)
{
int fromRow = from / cols, fromCol = from % cols;
int toRow = to / cols, toCol = to % cols;
if (toRow < fromRow) return "up";
if (toRow > fromRow) return "down";
if (toCol < fromCol) return "left";
if (toCol > fromCol) return "right";
return "up";
}
// ========== 导入/导出 ==========
private void ImportLevels()
{
string path = EditorUtility.OpenFilePanel("导入 all_levels.json", Application.dataPath, "json");
if (string.IsNullOrEmpty(path)) return;
try
{
string json = File.ReadAllText(path);
AllLevelRoot root = JsonUtility.FromJson<AllLevelRoot>(json);
if (root != null && root.levels != null && root.levels.Count > 0)
{
_levels = root.levels;
foreach (var lv in _levels)
for (int i = 0; i < lv.arrows.Count; i++)
lv.arrows[i].runtimeColor = _colorPalette[i % _colorPalette.Length];
int maxId = _levels.Max(l => l.levelId);
_nextLevelId = maxId + 1;
_selectedLevelIndex = 0;
OnLevelChanged();
Debug.Log($"导入成功,共 {_levels.Count} 个关卡");
}
else
EditorUtility.DisplayDialog("导入失败", "文件格式不正确或为空", "确定");
}
catch (System.Exception e)
{
EditorUtility.DisplayDialog("导入错误", e.Message, "确定");
}
}
private void ExportAllLevels()
{
if (_levels.Count == 0) { EditorUtility.DisplayDialog("错误", "没有关卡可导出", "确定"); return; }
AllLevelRoot root = new AllLevelRoot();
root.levels = new List<LevelConfig>();
foreach (var lv in _levels)
{
LevelConfig copy = new LevelConfig();
copy.levelId = lv.levelId;
copy.levelName = lv.levelName;
copy.gridRows = lv.gridRows;
copy.gridCols = lv.gridCols;
copy.pointSpacing = lv.pointSpacing;
copy.arrows = new List<ArrowConfig>();
foreach (var a in lv.arrows)
{
ArrowConfig newA = new ArrowConfig();
newA.id = a.id;
newA.startPoint = a.startPoint;
newA.path = new List<string>(a.path);
copy.arrows.Add(newA);
}
root.levels.Add(copy);
}
string json = JsonUtility.ToJson(root, true);
string path = EditorUtility.SaveFilePanel("保存 all_levels.json", Application.dataPath, "all_levels.json", "json");
if (!string.IsNullOrEmpty(path))
{
File.WriteAllText(path, json);
EditorUtility.DisplayDialog("成功", $"已保存 {root.levels.Count} 个关卡", "确定");
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a75099f55ed545f9b5c1fe0aedc9c82c
timeCreated: 1781769832
-271
View File
@@ -1,271 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
using ChillConnect;
namespace ChillConnect.Editor
{
public static class ArrowLevelGenerator
{
private const int MaxGenerateAttempts = 500; // 单关最大尝试次数
private static readonly string[] Directions = { "up", "down", "left", "right" };
/// <summary>
/// 生成单个关卡
/// </summary>
public static EditorLevelConfig GenerateLevel(int levelId, LevelDifficultyPreset preset)
{
for (int attempt = 0; attempt < MaxGenerateAttempts; attempt++)
{
EditorLevelConfig level = new EditorLevelConfig
{
levelId = levelId,
levelName = $"第{levelId - 1000}关",
gridRows = preset.gridRows,
gridCols = preset.gridCols,
pointSpacing = 60,
arrows = new List<EditorArrowConfig>()
};
bool[,] occupied = new bool[preset.gridRows, preset.gridCols];
int arrowId = 1;
int failedCount = 0;
// 逐个生成箭头,直到达到目标数量或多次失败
while (level.arrows.Count < preset.arrowCount && failedCount < 100)
{
if (TryGenerateArrow(preset, occupied, level.gridRows, level.gridCols,
out EditorArrowConfig arrow))
{
arrow.id = arrowId++;
level.arrows.Add(arrow);
// 标记占用
MarkOccupied(arrow, occupied, level.gridCols);
}
else
{
failedCount++;
}
}
// 箭头数太少,放弃本次
if (level.arrows.Count < preset.minArrowCount)
continue;
// 可解性校验
if (CheckSolvable(level))
{
return level;
}
}
Debug.LogWarning($"关卡 {levelId} 达到最大尝试次数仍未生成合格关卡");
return null;
}
/// <summary>
/// 尝试生成单个合法箭头
/// </summary>
private static bool TryGenerateArrow(LevelDifficultyPreset preset, bool[,] occupied,
int rows, int cols, out EditorArrowConfig arrow)
{
arrow = null;
// 随机起点
int startRow = Random.Range(0, rows);
int startCol = Random.Range(0, cols);
if (occupied[startRow, startCol])
return false;
// 随机路径长度和折数
int pathLength = Random.Range(preset.minPathLength, preset.maxPathLength + 1);
int maxTurns = preset.maxTurnCount;
int turns = 0;
List<string> path = new List<string>();
List<(int r, int c)> pathPoints = new List<(int r, int c)> { (startRow, startCol) };
string lastDir = Directions[Random.Range(0, Directions.Length)];
int curRow = startRow;
int curCol = startCol;
for (int i = 0; i < pathLength; i++)
{
string curDir = lastDir;
// 有概率转向
if (i > 0 && turns < maxTurns && Random.value < preset.turnProbability)
{
// 随机换一个方向(不能回头)
List<string> validDirs = new List<string>(Directions);
validDirs.Remove(GetOppositeDir(lastDir));
curDir = validDirs[Random.Range(0, validDirs.Count)];
turns++;
}
// 计算下一点
(int nr, int nc) = MoveDir(curRow, curCol, curDir);
// 越界或已占用,终止
if (nr < 0 || nr >= rows || nc < 0 || nc >= cols || occupied[nr, nc])
break;
path.Add(curDir);
pathPoints.Add((nr, nc));
curRow = nr;
curCol = nc;
lastDir = curDir;
}
// 路径太短,无效
if (path.Count < 1)
return false;
// 构造箭头
arrow = new EditorArrowConfig
{
startPoint = startRow * cols + startCol,
path = path
};
return true;
}
/// <summary>
/// 标记箭头占用的网格点
/// </summary>
private static void MarkOccupied(EditorArrowConfig arrow, bool[,] occupied, int totalCols)
{
int pointId = arrow.startPoint;
int row = pointId / totalCols;
int col = pointId % totalCols;
occupied[row, col] = true;
foreach (string dir in arrow.path)
{
(row, col) = MoveDir(row, col, dir);
occupied[row, col] = true;
}
}
/// <summary>
/// 可解性校验:贪心模拟消除法
/// </summary>
public static bool CheckSolvable(EditorLevelConfig level)
{
int rows = level.gridRows;
int cols = level.gridCols;
// 复制占用矩阵
bool[,] occupied = new bool[rows, cols];
foreach (var arrow in level.arrows)
{
MarkOccupied(arrow, occupied, cols);
}
List<EditorArrowConfig> remaining = new List<EditorArrowConfig>(level.arrows);
int roundCount = 0;
const int maxRounds = 200;
while (remaining.Count > 0 && roundCount < maxRounds)
{
roundCount++;
List<EditorArrowConfig> canRemove = new List<EditorArrowConfig>();
foreach (var arrow in remaining)
{
if (CanArrowFlyOut(arrow, occupied, rows, cols))
{
canRemove.Add(arrow);
}
}
if (canRemove.Count == 0)
return false; // 死局
// 消除第一个可消除的箭头,释放占用
var toRemove = canRemove[0];
ReleaseOccupied(toRemove, occupied, cols);
remaining.Remove(toRemove);
}
return remaining.Count == 0;
}
/// <summary>
/// 判断箭头是否能直接飞出(前方无阻挡)
/// </summary>
private static bool CanArrowFlyOut(EditorArrowConfig arrow, bool[,] occupied, int rows, int cols)
{
// 获取最终射出方向
string finalDir = arrow.path[arrow.path.Count - 1];
// 获取箭头头部位置(路径终点)
int pointId = arrow.startPoint;
int row = pointId / cols;
int col = pointId % cols;
foreach (string dir in arrow.path)
{
(row, col) = MoveDir(row, col, dir);
}
// 沿射出方向一路检查到边界
while (true)
{
(row, col) = MoveDir(row, col, finalDir);
if (row < 0 || row >= rows || col < 0 || col >= cols)
return true; // 飞出边界
if (occupied[row, col])
return false; // 前方有阻挡
}
}
/// <summary>
/// 释放箭头占用
/// </summary>
private static void ReleaseOccupied(EditorArrowConfig arrow, bool[,] occupied, int totalCols)
{
int pointId = arrow.startPoint;
int row = pointId / totalCols;
int col = pointId % totalCols;
occupied[row, col] = false;
foreach (string dir in arrow.path)
{
(row, col) = MoveDir(row, col, dir);
occupied[row, col] = false;
}
}
#region
private static (int r, int c) MoveDir(int row, int col, string dir)
{
switch (dir)
{
case "up": return (row - 1, col);
case "down": return (row + 1, col);
case "left": return (row, col - 1);
case "right": return (row, col + 1);
default: return (row, col);
}
}
private static string GetOppositeDir(string dir)
{
switch (dir)
{
case "up": return "down";
case "down": return "up";
case "left": return "right";
case "right": return "left";
default: return dir;
}
}
#endregion
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f1de2afcf128468783594983d832f7a2
timeCreated: 1781601376
-106
View File
@@ -1,106 +0,0 @@
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using ChillConnect;
namespace ChillConnect.Editor
{
public class ArrowLevelGeneratorWindow : EditorWindow
{
private int _startLevelId = 1001;
private int _generateCount = 100;
private string _outputPath = "Assets/StreamingAssets/all_levels.json";
private Vector2 _scrollPos;
private List<EditorLevelConfig> _generatedLevels = new List<EditorLevelConfig>();
[MenuItem("Tools/箭头游戏/关卡生成器")]
public static void ShowWindow()
{
GetWindow<ArrowLevelGeneratorWindow>("箭头关卡生成器");
}
private void OnGUI()
{
GUILayout.Label("基础设置", EditorStyles.boldLabel);
_startLevelId = EditorGUILayout.IntField("起始关卡ID", _startLevelId);
_generateCount = EditorGUILayout.IntSlider("生成关卡数量", _generateCount, 1, 200);
_outputPath = EditorGUILayout.TextField("输出路径", _outputPath);
GUILayout.Space(10);
if (GUILayout.Button("一键生成 100 关(含预设难度+图案关)", GUILayout.Height(40)))
{
GenerateAllLevels();
}
GUILayout.Space(10);
if (GUILayout.Button("导出到 JSON 文件"))
{
ExportToJson();
}
GUILayout.Space(10);
GUILayout.Label($"已生成关卡数:{_generatedLevels.Count}", EditorStyles.boldLabel);
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
foreach (var level in _generatedLevels)
{
EditorGUILayout.LabelField(
$"关卡 {level.levelId} | {level.gridRows}x{level.gridCols} | 箭头数:{level.arrows.Count}");
}
EditorGUILayout.EndScrollView();
}
private void GenerateAllLevels()
{
_generatedLevels.Clear();
int levelId = _startLevelId;
for (int i = 0; i < _generateCount; i++)
{
// 获取当前关卡难度预设
var preset = LevelDifficultyPreset.GetPreset(i + 1);
// 生成关卡
var level = ArrowLevelGenerator.GenerateLevel(levelId, preset);
if (level != null)
{
_generatedLevels.Add(level);
Debug.Log($"生成成功:关卡 {levelId},箭头数 {level.arrows.Count}");
}
else
{
Debug.LogError($"关卡 {levelId} 生成失败,已跳过");
}
levelId++;
}
EditorUtility.DisplayDialog("生成完成",
$"成功生成 {_generatedLevels.Count} 个关卡", "确定");
}
private void ExportToJson()
{
if (_generatedLevels.Count == 0)
{
EditorUtility.DisplayDialog("提示", "请先生成关卡", "确定");
return;
}
var root = new EditorAllLevelRoot { levels = _generatedLevels };
string json = JsonUtility.ToJson(root, true);
string fullPath = Path.Combine(Application.dataPath,
_outputPath.Replace("Assets/", ""));
File.WriteAllText(fullPath, json);
AssetDatabase.Refresh();
EditorUtility.DisplayDialog("导出成功",
$"已导出到:{fullPath}", "确定");
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 338d551bc0c34285a64c42de35c20a1b
timeCreated: 1781601358
+261
View File
@@ -0,0 +1,261 @@
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace ChillConnect.Editor
{
/// <summary>
/// 第三方关卡配置批量转换工具
/// 输入:文件夹内所有第三方单关JSON
/// 输出:对应转换后的我方格式单关JSON
/// </summary>
public class LevelBatchConverter : EditorWindow
{
#region
// 第三方单关结构(只声明需要的字段,多余自动忽略)
[System.Serializable]
private class ThirdPartyLevel
{
public Vector2Int size;
public string name;
public List<ThirdPartyArrow> arrows;
}
[System.Serializable]
private class ThirdPartyArrow
{
public List<Vector2Int> nodes;
public int color;
}
// 我方单关结构(和运行时对齐)
[System.Serializable]
public class ArrowConfig
{
public int id;
public int startPoint;
public List<string> path = new List<string>();
}
[System.Serializable]
public class LevelConfig
{
public int levelId;
public string levelName;
public int gridRows;
public int gridCols;
public int pointSpacing = 60;
public List<ArrowConfig> arrows = new List<ArrowConfig>();
}
#endregion
private string _inputFolder = "";
private string _outputFolder = "";
private int _pointSpacing = 60;
private Vector2 _scrollPos;
private List<string> _logList = new List<string>();
[MenuItem("Window/Arrow Game/批量关卡转换工具")]
public static void ShowWindow()
{
var window = GetWindow<LevelBatchConverter>("批量关卡转换");
window.minSize = new Vector2(500, 400);
}
private void OnGUI()
{
EditorGUILayout.Space(10);
// 输入文件夹
EditorGUILayout.LabelField("输入文件夹(第三方单关JSON", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
_inputFolder = EditorGUILayout.TextField(_inputFolder);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string path = EditorUtility.OpenFolderPanel("选择输入文件夹", Application.dataPath, "");
if (!string.IsNullOrEmpty(path))
_inputFolder = path;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(8);
// 输出文件夹
EditorGUILayout.LabelField("输出文件夹(转换后JSON", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
_outputFolder = EditorGUILayout.TextField(_outputFolder);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string path = EditorUtility.OpenFolderPanel("选择输出文件夹", Application.dataPath, "");
if (!string.IsNullOrEmpty(path))
_outputFolder = path;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(8);
// 基础配置
_pointSpacing = EditorGUILayout.IntField("默认点间距", _pointSpacing);
EditorGUILayout.Space(10);
// 转换按钮
if (GUILayout.Button("开始批量转换", GUILayout.Height(30)))
{
BatchConvert();
}
EditorGUILayout.Space(10);
// 日志区域
EditorGUILayout.LabelField("转换日志", EditorStyles.boldLabel);
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.ExpandHeight(true));
foreach (string log in _logList)
{
EditorGUILayout.LabelField(log);
}
EditorGUILayout.EndScrollView();
}
/// <summary>
/// 批量转换核心逻辑
/// </summary>
private void BatchConvert()
{
_logList.Clear();
if (string.IsNullOrEmpty(_inputFolder) || !Directory.Exists(_inputFolder))
{
_logList.Add("❌ 输入文件夹不存在");
return;
}
if (string.IsNullOrEmpty(_outputFolder))
{
_logList.Add("❌ 请选择输出文件夹");
return;
}
// 创建输出目录
if (!Directory.Exists(_outputFolder))
{
Directory.CreateDirectory(_outputFolder);
}
// 获取所有json文件
string[] files = Directory.GetFiles(_inputFolder, "*.json", SearchOption.TopDirectoryOnly);
if (files.Length == 0)
{
_logList.Add("⚠️ 输入文件夹内未找到JSON文件");
return;
}
_logList.Add($"找到 {files.Length} 个JSON文件,开始转换...");
int successCount = 0;
int failCount = 0;
for (int i = 0; i < files.Length; i++)
{
string filePath = files[i];
string fileName = Path.GetFileNameWithoutExtension(filePath);
try
{
// 1. 读取并解析第三方配置
string json = File.ReadAllText(filePath);
ThirdPartyLevel thirdLevel = JsonUtility.FromJson<ThirdPartyLevel>(json);
if (thirdLevel == null || thirdLevel.arrows == null)
{
_logList.Add($"❌ {fileName}:解析失败,格式不匹配");
failCount++;
continue;
}
// 2. 转换为我方格式
LevelConfig level = ConvertLevel(thirdLevel, fileName, i + 1);
// 3. 导出到输出文件夹
string outJson = JsonUtility.ToJson(level, true);
string outPath = Path.Combine(_outputFolder, $"{fileName}.json");
File.WriteAllText(outPath, outJson);
_logList.Add($"✅ {fileName}:转换成功 | {level.gridCols}×{level.gridRows} | {level.arrows.Count}个箭头");
successCount++;
}
catch (System.Exception e)
{
_logList.Add($"❌ {fileName}:转换异常 - {e.Message}");
failCount++;
}
}
_logList.Add("");
_logList.Add($"===== 转换完成 =====");
_logList.Add($"成功:{successCount} 个");
_logList.Add($"失败:{failCount} 个");
_logList.Add($"输出路径:{_outputFolder}");
EditorUtility.DisplayDialog("批量转换完成",
$"成功:{successCount}\n失败:{failCount}\n输出路径:{_outputFolder}",
"确定");
AssetDatabase.Refresh();
}
/// <summary>
/// 单个关卡转换逻辑(和之前编辑器内转换完全一致)
/// </summary>
private LevelConfig ConvertLevel(ThirdPartyLevel thirdLevel, string fileName, int index)
{
LevelConfig level = new LevelConfig
{
levelId = index,
levelName = string.IsNullOrEmpty(thirdLevel.name) ? fileName : thirdLevel.name,
gridCols = thirdLevel.size.x,
gridRows = thirdLevel.size.y,
pointSpacing = _pointSpacing,
arrows = new List<ArrowConfig>()
};
for (int i = 0; i < thirdLevel.arrows.Count; i++)
{
var thirdArrow = thirdLevel.arrows[i];
if (thirdArrow.nodes == null || thirdArrow.nodes.Count == 0)
continue;
ArrowConfig arrow = new ArrowConfig
{
id = i + 1,
path = new List<string>()
};
// 起点转换:(x,y) → 点ID = y * 列数 + x
Vector2Int startNode = thirdArrow.nodes[0];
arrow.startPoint = startNode.y * level.gridCols + startNode.x;
// 路径转换:相邻节点计算方向
for (int j = 1; j < thirdArrow.nodes.Count; j++)
{
Vector2Int prev = thirdArrow.nodes[j - 1];
Vector2Int cur = thirdArrow.nodes[j];
int dx = cur.x - prev.x;
int dy = cur.y - prev.y;
if (dx == 1) arrow.path.Add("right");
else if (dx == -1) arrow.path.Add("left");
else if (dy == 1) arrow.path.Add("down");
else if (dy == -1) arrow.path.Add("up");
}
level.arrows.Add(arrow);
}
return level;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 027b5eb354fe4e4698f807233ca6dc5d
timeCreated: 1782205667
-158
View File
@@ -1,158 +0,0 @@
using ChillConnect;
namespace ChillConnect.Editor
{
[System.Serializable]
public class LevelDifficultyPreset
{
public int gridRows;
public int gridCols;
public int arrowCount; // 目标箭头数
public int minArrowCount; // 最小接受箭头数
public int minPathLength; // 单箭头最小长度(格数)
public int maxPathLength; // 单箭头最大长度
public int maxTurnCount; // 最大折数
public float turnProbability; // 每步转向概率
public bool isPatternLevel; // 是否图案关
/// <summary>
/// 根据关卡序号(从1开始)获取对应难度预设
/// </summary>
public static LevelDifficultyPreset GetPreset(int levelIndex)
{
LevelDifficultyPreset preset = new LevelDifficultyPreset();
// ===== 第1-2关:起步适应 8x8 =====
if (levelIndex <= 2)
{
preset.gridRows = 8;
preset.gridCols = 8;
preset.arrowCount = 7;
preset.minArrowCount = 5;
preset.minPathLength = 2;
preset.maxPathLength = 4;
preset.maxTurnCount = 0; // 纯直线
preset.turnProbability = 0f;
preset.isPatternLevel = false;
}
// ===== 第3关:难度突变 13x13 =====
else if (levelIndex == 3)
{
preset.gridRows = 13;
preset.gridCols = 13;
preset.arrowCount = 14;
preset.minArrowCount = 10;
preset.minPathLength = 2;
preset.maxPathLength = 5;
preset.maxTurnCount = 0;
preset.turnProbability = 0f;
preset.isPatternLevel = false;
}
// ===== 第4关:第一个图案关 =====
else if (levelIndex == 4)
{
preset.gridRows = 13;
preset.gridCols = 13;
preset.arrowCount = 12;
preset.minArrowCount = 10;
preset.minPathLength = 2;
preset.maxPathLength = 6;
preset.maxTurnCount = 0;
preset.turnProbability = 0f;
preset.isPatternLevel = true;
}
// ===== 第5-10关:快速跃升期 =====
else if (levelIndex <= 10)
{
preset.gridRows = 13;
preset.gridCols = 13;
preset.arrowCount = 14 + (levelIndex - 5) * 1;
preset.minArrowCount = preset.arrowCount - 3;
preset.minPathLength = 2;
preset.maxPathLength = 6;
preset.maxTurnCount = 1;
preset.turnProbability = 0.15f;
preset.isPatternLevel = levelIndex == 8;
}
// ===== 第11-15关:进阶爬坡 =====
else if (levelIndex <= 15)
{
preset.gridRows = 13;
preset.gridCols = 13;
preset.arrowCount = 20 + (levelIndex - 11);
preset.minArrowCount = preset.arrowCount - 3;
preset.minPathLength = 2;
preset.maxPathLength = 7;
preset.maxTurnCount = 1;
preset.turnProbability = 0.2f;
preset.isPatternLevel = levelIndex == 13;
}
// ===== 第15关突变:折数提升 =====
else if (levelIndex <= 25)
{
preset.gridRows = 13;
preset.gridCols = 13;
preset.arrowCount = 22 + (levelIndex - 15);
preset.minArrowCount = preset.arrowCount - 4;
preset.minPathLength = 2;
preset.maxPathLength = 7;
preset.maxTurnCount = 2;
preset.turnProbability = 0.25f;
preset.isPatternLevel = levelIndex == 19;
}
// ===== 第26-35关 =====
else if (levelIndex <= 35)
{
preset.gridRows = 14;
preset.gridCols = 14;
preset.arrowCount = 25 + (levelIndex - 26);
preset.minArrowCount = preset.arrowCount - 4;
preset.minPathLength = 2;
preset.maxPathLength = 8;
preset.maxTurnCount = 2;
preset.turnProbability = 0.28f;
preset.isPatternLevel = levelIndex == 26 || levelIndex == 33;
}
// ===== 第36-50关:高难起步 =====
else if (levelIndex <= 50)
{
preset.gridRows = 14;
preset.gridCols = 14;
preset.arrowCount = 28 + (levelIndex - 36);
preset.minArrowCount = preset.arrowCount - 5;
preset.minPathLength = 2;
preset.maxPathLength = 8;
preset.maxTurnCount = 2;
preset.turnProbability = 0.3f;
preset.isPatternLevel = levelIndex == 41 || levelIndex == 49;
}
// ===== 第50关突变:15x15 =====
else if (levelIndex <= 75)
{
preset.gridRows = 15;
preset.gridCols = 15;
preset.arrowCount = 30 + (levelIndex - 50) / 2;
preset.minArrowCount = preset.arrowCount - 5;
preset.minPathLength = 2;
preset.maxPathLength = 9;
preset.maxTurnCount = 3;
preset.turnProbability = 0.32f;
preset.isPatternLevel = levelIndex == 57 || levelIndex == 65 || levelIndex == 72;
}
// ===== 第76-100关:终极挑战 16x16 =====
else
{
preset.gridRows = 16;
preset.gridCols = 16;
preset.arrowCount = 32 + (levelIndex - 75) / 3;
preset.minArrowCount = preset.arrowCount - 6;
preset.minPathLength = 2;
preset.maxPathLength = 9;
preset.maxTurnCount = 3;
preset.turnProbability = 0.35f;
preset.isPatternLevel = levelIndex == 80 || levelIndex == 87 || levelIndex == 93 || levelIndex == 100;
}
return preset;
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 67fd199fe89b44419a7b51e08285ba5a
timeCreated: 1781601394