Я работал над чем-то очень похожим для моего текущего проекта. Это краткое изложение того, как я это делаю, с некоторыми примечаниями о том, как сделать вещи немного проще для себя.
Для меня первая проблема состояла в том, чтобы разбить мир на более мелкие куски, которые бы подходили для загрузки и выгрузки на лету. Поскольку вы используете карту на основе плитки, этот шаг становится значительно проще. Вместо того, чтобы учитывать положение каждого 3D-объекта на уровне, у вас уже есть свой уровень, аккуратно разделенный на плитки. Это позволяет вам просто разбить мир на X на Y фрагментов плитки и загрузить их.
Вы захотите сделать это автоматически, а не вручную. Поскольку вы используете XNA, у вас есть возможность использовать конвейер содержимого с настраиваемым экспортером для содержимого вашего уровня. Если вы не знаете какой-либо способ запуска процесса экспорта без перекомпиляции, я бы честно рекомендовал это сделать. Хотя компиляция C # не так медленна, как в C ++, вам все равно не нужно загружать Visual Studio и перекомпилировать игру каждый раз, когда вы вносите небольшие изменения в карту.
Еще одна важная вещь - убедиться, что вы используете хорошее соглашение об именах для файлов, содержащих чанки вашего уровня. Вы хотите знать, что хотите загрузить или выгрузить блок C, а затем сгенерировать имя файла, которое вам нужно загрузить, чтобы сделать это во время выполнения. Наконец, подумайте о любых мелочах, которые могут помочь вам в будущем. Очень приятно иметь возможность изменить размер блока, выполнить реэкспорт и сразу же увидеть его влияние на производительность.
Во время выполнения это все еще довольно просто. Вам понадобится какой-нибудь способ асинхронной загрузки и выгрузки блоков, но это сильно зависит от того, как работает ваша игра или движок. Ваше второе изображение в точности правильное - вам нужно определить, какие чанки должны быть загружены или выгружены, и сделать соответствующие запросы, если это не так. В зависимости от того, сколько чанков вы загрузили за один раз, вы можете делать это всякий раз, когда игрок пересекает границу от одного чанка к другому. В конце концов, в любом случае, вы хотите убедиться, что загружено достаточно, чтобы даже в наихудшее (разумное) время загрузки блок все еще загружался, прежде чем игрок сможет его увидеть. Возможно, вы захотите много играть с этим числом, пока не получите хороший баланс между производительностью и потреблением памяти.
Что касается фактической архитектуры, вы захотите абстрагировать процесс фактической загрузки и выгрузки данных из памяти от процесса определения того, что следует загружать / выгружать. Для вашей первой итерации я бы даже не беспокоился о производительности загрузки / выгрузки, а просто получил бы простейшую вещь, которая могла бы работать, и гарантировал, что вы генерируете соответствующие запросы в подходящее время. После этого вы можете посмотреть, как оптимизировать загрузку, чтобы свести к минимуму мусор.
Я столкнулся с множеством дополнительных сложностей из-за движка, который использовал, но это довольно специфично для конкретной реализации. Если у вас есть какие-либо вопросы о том, что я сделал, пожалуйста, прокомментируйте, и я сделаю все возможное, чтобы помочь.