You need to enable JavaScript to run this app. C#编辑_CompleteMap时同步修改CurrentMap.MapData的问题求解
优惠活动
大模型
产品
解决方案
定价
更多

C#编辑_CompleteMap时同步修改CurrentMap.MapData的问题求解

提问内容

开发运行在Windows控制台的娱乐小游戏时,DrawGame()方法出现异常。

  • 定义字符串数组string[] _CompleteMap,直接从同为字符串数组的CurrentMap.MapData赋值:string[] _CompleteMap = CurrentMap.MapData;
  • 原本计划将CurrentMap.MapData作为空白底图,通过修改数组内字符串的字符标记玩家、怪物位置,但修改_CompleteMap时,CurrentMap.MapData的内容会同步变化,导致玩家走过的路径留下永久痕迹。

附现有代码:

using System;
using System.Text;
using System.Threading;
using ConsoleAdventure.Engine.BaseClasses;
using Database = ConsoleAdventure.Engine.Database;

namespace ConsoleAdventure
{
    class Program
    {
        private static bool whileGameScene = true;
        private static Engine.BaseClasses.MapBase CurrentMap;

        static unsafe void Main(string[] args)
        {
            // Load and populate the databases.
            Database.ItemDB.LoadItemDB();
            Database.MapDB.LoadMapDB();

            // Set demo map
            CurrentMap = Database.MapDB.Maps[0];

            // Hide cursor
            Console.CursorVisible = false;

            // Start a new thread to capture the user inputs
            new Thread(() =>
                        {
                            while (true)
                            {
                                Thread.CurrentThread.IsBackground = true;

                                ConsoleKeyInfo cki = Console.ReadKey();

                                if (cki.Key == ConsoleKey.A && Player.Data.Location.X > 0)
                                    Player.Data.Location.X--;
                                else if (cki.Key == ConsoleKey.D)
                                    Player.Data.Location.X++;
                                else if (cki.Key == ConsoleKey.W && Player.Data.Location.Y > 0)
                                    Player.Data.Location.Y--;
                                else if (cki.Key == ConsoleKey.S)
                                    Player.Data.Location.Y++;

                                CheckWarpPoints();
                            }        
                        }).Start();

            // Draw the game
            while (whileGameScene)
            {
                DrawGame();
            }
        }

        /// <summary>
        /// Check if player has stood on a warp zone
        /// </summary>
        private static void CheckWarpPoints()
        {
            foreach (MapBase.WarpPoint warp in Database.MapDB.Maps[Player.Data.CurrentMap].WarpPoints)
            {
                if (Player.Data.Location.X == warp.From.X && Player.Data.Location.Y == warp.From.Y)
                {
                    Player.Data.CurrentMap = warp.ToMapIndex;
                    Player.Data.Location = warp.To;
                }
            }
        }

        public static void DrawGame()
        {
            string[] _CompleteMap = CurrentMap.MapData;

            StringBuilder _sbRow = new StringBuilder();

            foreach (var _object in CurrentMap.MapObjects)
            {
                _sbRow = new StringBuilder(_CompleteMap[_object.CurrentLocation.Y]);
                _sbRow[_object.CurrentLocation.X] = _object.Icon;
                _CompleteMap[_object.CurrentLocation.Y] = _sbRow.ToString();
            }

            _sbRow = new StringBuilder(_CompleteMap[Player.Data.Location.Y]);
            _sbRow[Player.Data.Location.X] = 'X';
            _CompleteMap[Player.Data.Location.Y] = _sbRow.ToString();

            for (int i = 0; i < _CompleteMap.Length; i++)
            {
                Console.SetCursorPosition(0, i);
                Console.WriteLine(_CompleteMap[i]);
            }
        }
    }
}
问题解答

核心原因

C#中数组属于引用类型,直接执行string[] _CompleteMap = CurrentMap.MapData时,不会复制数组的实际内容,仅让两个变量指向内存中同一个数组实例。对_CompleteMap的所有元素修改,本质上都是直接修改原CurrentMap.MapData指向的数组内容,导致空白底图被持续污染。

修复方案

创建_CompleteMap时,对原数组做完整复制,而非直接赋值:

// 写法1:使用Array.Clone,无需引入额外命名空间
string[] _CompleteMap = (string[])CurrentMap.MapData.Clone();

// 写法2:引入System.Linq后使用ToArray扩展方法
// string[] _CompleteMap = CurrentMap.MapData.ToArray();

由于数组内元素是不可变的string类型,上述浅复制即可满足需求:修改副本数组的元素时,只会替换副本内的字符串引用,不会影响原数组的底图内容。

额外代码优化

  • 输入线程中Thread.CurrentThread.IsBackground = true写在循环内无效,应在线程启动前设置:
var inputThread = new Thread(() => { /* 原有输入逻辑 */ });
inputThread.IsBackground = true;
inputThread.Start();
  • 玩家移动逻辑缺少右、下边界校验,按D/S键超出地图范围时会触发数组越界异常,补充对应边界判断即可。
  • Main方法标记的unsafe关键字当前无对应不安全代码逻辑,可直接移除,避免项目开启不安全编译带来的不必要风险。
  • 当前绘制逻辑每次全量输出整个地图,控制台开销较大,后续可优化为仅重绘玩家位置变化的前后两行内容。

内容的提问来源于stack exchange,提问作者Paul Baron Gikkingen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 01:06:02