Без параллельности можно обойтись — и поначалу лучше обойдитесь.
Если уж хочется помногопоточить — я бы разбил на два потока, интеллект и графику.
У каждого юнита три одинаковых структуры, renderInfo, bufferedInfo и aiInfo. Там могут быть координаты, курс, HP, ссылка на следующего — всё, что угодно. Ссылка на следующего — это важно, ведь юниты могут появляться и исчезать.
Поток интеллекта работает с aiInfo; где-то здесь есть и код мультиплеера. Закончив шаг, поток захватывает мьютекс и для всех юнитов (понятие «все» определяется по aiInfo) даёт bufferedInfo = aiInfo.
Поток прорисовки захватывает тот же мьютекс и для всех юнитов («все» по bufferedInfo) даёт renderInfo = bufferedInfo. А затем, освободив мьютекс, делает с этим renderInfo что хочет.
Под мьютексом будем сидеть очень мало: ни прорисовки, ни мультиплеера там нет.
Поскольку юнит исчезает из памяти только тогда, когда на него пропадают ссылки во всех трёх структурах, надо делать или объектный пул (т.е. юнит, будучи созданным, остаётся навсегда, но впоследствии этот блок памяти можно будет задействовать на другой юнит), или какие-нибудь «мусорные» указатели наподобие std::shared_ptr.
Такая система аналогична тройной буферизации в прорисовке. Только в видяшной тройной буферизации асинхронно действуют кадры монитора и кадры рендерера; у нас — такты игры и кадры рендерера.
Разбивать интеллект на потоки откровенно тяжело, и в игре с мультиплеером я просто не знаю, как. RTS обычно передают по сети короткие пакеты наподобие «выделить юнитов в квадрате (X,Y) — (X,Y)», «добавить к выделению юнита 1234» и «отправиться в точку (X, Y)». Эти команды, будучи выполненными на разных компьютерах, выполняются одинаково.
Если объединить эти две конструкции — повторяемые расчёты и асинхронный рендеринг — возможны неточности, и, надеюсь, они будут приемлемыми — на экране (renderInfo) юнит попадает в отмеченный квадрат, а в aiInfo уже нет, посколько сдвинулся.
Отдельный вопрос — компенсация пинга в играх по интернету. Не думал пока над этим. Наверно, придётся иметь officialAiInfo и lagCompensatedAiInfo…
ЗЫ. Подсказывают, что такт игры в такой ситуёвине длится порядка 0,1 с, т.е. может продлиться несколько кадров. Тогда во всех этих …info надо описать движение так, чтобы в любой момент получить промежуточное x(t), y(t), yaw(t)… Для танка — bodyYaw(t) и turretYaw(t), для человечка — фазу анимации…
ЗЗЫ. Если игра трёхмерная и вид хоть как-то настраивается, одна из команд игры будет выглядеть «выделить юнитов в квадрате (X,Y) — (X,Y) с матрицей преобразования A».
ЗЗЗЫ. Чтобы игра была повторяемой (важно для мультиплеера), все расчёты, влияющие на течение игры, проводить в фиксированной запятой. Все переменные, с этим связанные, чем угодно, хоть нулём, но инициализировать.