You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity打包iPhone后基于RTF生成的关卡无法加载求助

问题描述

我在Unity开发一款关卡制移动游戏,通过读取RTF文件内的布局字符生成对应预制件来创建关卡。编辑器内运行完全正常,但打包到iPhone设备后,其他功能均正常,唯独关卡无法加载,游戏启动后没有平台,立方体因失去支撑持续坠落。

原LevelGenerator脚本
public class LevelGenerator : MonoBehaviour
{
    public Transform [] platformPrefabs;
    public Transform startingPlatformPrefab;
    public Transform endingPlatformPrefab;
    public Transform teleportPlatformPrefab;
    public Transform shiftingPlatformPrefab;
    public Transform movingPlatformPrefab;
    public Transform buttonPlatformPrefab;

    [SerializeField] Transform levelPosition;

    public static LevelGenerator Instance { get; private set; }

    private void Awake()
    {
        if(Instance == null) { Instance = this; }
        else { Destroy(gameObject); }
    }

    public Transform GenerateLevel(int level)
    {
        string levelFilePath = $"Assets/Levels/{level}.rtf";

        // 读取关卡RTF文档
        string rtfContent = File.ReadAllText(levelFilePath);
        string plainTextContent = ReadRtfAsPlainText(rtfContent);

        string[] levelLines = plainTextContent.Split('\n');

        int width = levelLines[0].Length;
        int height = levelLines.Length;

        GameObject levelObject = new GameObject("Level");
        Transform levelTransform = levelObject.transform;

        bool useFirstPlatform = true;

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                // 检查当前行是否有足够的字符
                if (x >= levelLines[y].Length)
                    break;

                char currentChar = levelLines[y][x];
                Vector3 position = new Vector3(x, Global.platformYPos, y);

                switch (currentChar)
                {
                    case 'P':
                        // 生成普通平台预制件
                        Transform platformPrefab = useFirstPlatform ? platformPrefabs[0] : platformPrefabs[1];
                        PlaceBlock(platformPrefab, position, levelTransform, currentChar);
                        useFirstPlatform = !useFirstPlatform;
                        break;
                    case 'S':
                        // 生成起点平台预制件
                        PlaceBlock(startingPlatformPrefab, position, levelTransform, currentChar);
                        break;
                    case 'B':
                        // 生成按钮平台预制件
                        PlaceBlock(buttonPlatformPrefab, position, levelTransform, currentChar);
                        break;
                    case 'T':
                        // 生成移动平台预制件
                        PlaceBlock(movingPlatformPrefab, position, levelTransform, currentChar);
                        break;
                    case 'Q':
                        // 生成切换平台预制件
                        PlaceBlock(shiftingPlatformPrefab, position, levelTransform, currentChar);
                        break;
                    case 'E':
                        // 生成终点平台预制件
                        PlaceBlock(endingPlatformPrefab, position, levelTransform, currentChar);
                        break;
                    case 'K':
                        // 生成传送平台预制件
                        PlaceBlock(teleportPlatformPrefab, position, levelTransform, currentChar);
                        break;
                    case 'M':
                        // 设置移动平台的目标位置
                        movingPlatformPrefab.GetComponent<MovingPlatform>().targetPosition = position;
                        break;
                    case 'W':
                        // 设置切换平台的目标点
                        shiftingPlatformPrefab.GetComponent<ShiftingPlatform>().pointB = new Vector3(position.x, 0, position.z);
                        break;
                    default:
                        break;
                }
            }
        }
        levelTransform.position = new Vector3(levelPosition.position.x, Global.levelParentYPos, levelPosition.position.z);
        
        return levelTransform;
    }

    private void PlaceBlock(Transform prefab, Vector3 position, Transform levelTransform, char currentChar)
    {
        Instantiate(prefab, position, Quaternion.identity, levelTransform);
    }

    string ReadRtfAsPlainText(string rtfContent)
    {
        // 创建临时文本区域提取RTF中的纯文本
        TextEditor textEditor = new();
        textEditor.text = new GUIContent(rtfContent).ToString();
        textEditor.SelectAll();
        textEditor.Copy();

        return GUIUtility.systemCopyBuffer;
    }
}
问题原因
  • 文件路径不兼容:编辑器中Assets/Levels/{level}.rtf的路径能直接读取文件,但iOS真机打包后资源结构变化,此路径无法找到文件。
  • RTF解析依赖编辑器API:ReadRtfAsPlainText方法使用了TextEditor和GUIUtility,这些是Unity编辑器专用API,在iOS真机环境下无法正常执行,导致无法提取RTF内的纯文本布局信息。
  • 资源未正确打包:RTF文件未被标记为随游戏打包的资源,导致真机中不存在该文件。
解决方法

1. 修正文件读取路径与方式

将RTF文件移动到Assets/StreamingAssets目录下(该目录资源默认会被打包到各平台),针对iOS平台需用UnityWebRequest读取(iOS中StreamingAssets是URL路径,无法用File.ReadAllText直接读取):

public IEnumerator GenerateLevelCoroutine(int level)
{
    string rtfContent = string.Empty;
    string levelFilePath;
    #if UNITY_EDITOR
    levelFilePath = $"Assets/StreamingAssets/Levels/{level}.rtf";
    rtfContent = File.ReadAllText(levelFilePath);
    #elif UNITY_IOS
    levelFilePath = Path.Combine(Application.streamingAssetsPath, $"Levels/{level}.rtf");
    UnityWebRequest www = UnityWebRequest.Get(levelFilePath);
    yield return www.SendWebRequest();
    if (www.result != UnityWebRequest.Result.Success)
    {
        Debug.LogError($"读取关卡文件失败: {www.error}");
        yield break;
    }
    rtfContent = www.downloadHandler.text;
    #endif

    // 后续解析与生成逻辑
    string plainTextContent = ParseRtfToPlainText(rtfContent);
    // ...剩余代码保持不变
}

2. 替换RTF解析方案

放弃编辑器API解析RTF,改用以下两种兼容方案:

  • 转换为纯文本文件:将RTF文件另存为.txt格式,直接读取纯文本内容,无需解析步骤,兼容性更强。
  • 使用跨平台RTF解析库:引入如RTFSharp等纯C#编写的RTF解析库,实现跨平台的RTF转纯文本功能。

3. 确保资源正确打包

  • 确认RTF文件位于StreamingAssets目录下,该目录资源默认会被打包。
  • 若使用Asset Bundle,需给RTF文件设置对应的Asset Bundle标签,并在打包时包含该Bundle。

4. 真机调试定位问题

通过Xcode连接iPhone设备,查看Unity调试日志:

  • 在文件读取、RTF解析等关键步骤添加Debug.Log输出,比如打印文件路径、解析后的纯文本内容。
  • 根据日志信息精准定位是文件找不到、解析失败还是后续生成逻辑出错。

内容的提问来源于stack exchange,提问作者MIM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:07:01