Skip to content

城市与国家

This content is not available in your language yet.

世界地图上的 7 座城市分属 4 个国家,用 Voronoi 最近城市划分领海;每座非自由港城市拥有海上炮台防御与巡逻舰队,玩家靠港可交易、修船、招募、外交,摧毁全部炮台即可占领城市。

城市与国家系统是外循环(航海)的骨架:玩家驾船在海上航行时,脚下的每一片海都归属于某座城市(进而归属某个国家),或者是公海。城市是玩家补给的落脚点(靠港触发港口面板:交易 / 修船 / 招募 / 外交),也是军事目标(打掉全部海上炮台即可占领,改变领土归属并推动胜利进度)。

  • 国家与城市的静态数据来自两张 CSV:countries.csvcities.csv(位于 Assets/StreamingAssets/CitySystem/),策划可直接修改。
  • 场景启动时由 CitySystemInitializer.cs 按 CSV 自动生成所有国家与城市对象,并依次挂上交易、外交、防御、巡逻、显示等组件,最后构建 Voronoi 领地索引。
  • 城市运行时注册到 CityManager.cs(全局单例),它同时对外提供“这个坐标属于哪个国家”的领地查询(TerritoryRegistry),供怪物、遭遇等系统消费。

CSV 中的坐标与半径是“真实尺度”(real)。实际进游戏时所有位置与半径会按场景预设(preset)的 world 轴缩放(ScenarioPreset.csWorldConfig):

world 预设 positionScale(坐标缩放) cityRadiusScale(城市半径缩放) 使用场景
real.json 1.0 1.0 “正常游玩”预设、PlayMode 测试
compact.json 0.1 0.2 大多数开发/AI 测试预设

来源:Assets/StreamingAssets/DataSets/world/real.json / compact.json(CSV 同级 JSON 配置,策划可改)。本页正文数值除特别注明外,均按 real(×1.0)描述。

公式(CitySystemInitializer.cs):

  • 城市世界坐标 = CSV(position_x, position_z) × positionScale + positionOffset(positionOffset = 初始化器自身位置 + world 预设 offset,默认均为 0)
  • 城市触发半径 = CSV radius × cityRadiusScale

国家表(countries.csv,全量 4 行)

Section titled “国家表(countries.csv,全量 4 行)”
country_id 国家名称 区域颜色 中心X 中心Z 领海半径
country_001 西班牙 #4169E1(宝蓝) 0 0 0
country_002 英格兰 #DC143C(绯红) 0 0 0
country_003 法兰西 #FFD700(金黄) 0 0 0
country_free 自由港联合 #C0C0C0(银灰) 500 2500 0

说明:center_x/center_z/territory_radius 列当前不参与领土计算(领土完全由 Voronoi 决定,见下节);区域颜色用于小地图标记染色与战略地图填色(城市中心标记 Cube 恒为黄色,不随国家变色——CityColorMarker.cs 的 Renderer 染色引用未接线)。

city_id 城市名称 所属国家 位置 (X, Z) 半径 城市类型 海域类型
city_001 马德里 country_001 西班牙 (200, 150) 60 Capital 首都 Safe
city_002 塞维利亚 country_001 西班牙 (-1500, 1000) 50 IndustryCity 工业城 Safe
city_003 普利茅斯 country_002 英格兰 (2000, 500) 45 FishingTown 渔村 Safe
city_004 朴次茅斯 country_002 英格兰 (2500, 2000) 55 Fortress 要塞 Moderate
city_005 自由港 country_free 自由港联合 (500, 2500) 60 TradePort 贸易港 Safe
city_006 勒阿弗尔 country_003 法兰西 (-1000, 5000) 55 TradePort 贸易港 Dangerous
city_007 马赛 country_003 法兰西 (2000, 5500) 55 TradePort 贸易港 Dangerous
  • 半径单位:米(世界单位,real 尺度)。半径既是靠港触发距离也是编辑器 Gizmo 圈。
  • use_random_offset / random_seed 列全部为 false/0,当前等同未启用(且生成路径会覆盖随机偏移结果,见“已知限制”)。
  • sea_region_type 列(Safe/Moderate/Dangerous)目前没有任何运行时系统读取(见“已知限制”)。
  • 城市类型(city_type)决定海上炮台防御规模,见“城市防御”。

country_id 为 country_free 的城市(当前只有 city_005 自由港)在生成时跳过三个组件(CitySystemInitializer.cs 硬编码判断):

  1. 不挂 CityDefense.cs —— 不可被占领;
  2. 不挂 CityDiplomacyTrigger.cs —— 无外交操作(永远中立);
  3. 不挂 PatrolShipSpawner.cs —— 不产生巡逻舰;
  4. 也不生成海上炮台。

自由港照常可交易/修船/招募。另外它不出售奢侈品梯度商品(CityTrader.cs 中产地距离衰减算法对 city_005 返回不上架)。

实现:VoronoiTerritoryGrid.cs,由 CityManager.BuildTerritoryGrid 在所有城市生成完毕后构建。

规则(触发条件 → 规则 → 结果):

  • 归属判定:任意海面点属于“离它最近的城市”,该城市属于谁,这片海就是谁的领海。没有按国家画圈的概念——国土 = 该国所有城市的 Voronoi 胞元之并。
  • 公海判定:若该点到最近城市的距离 > 公海阈值,则视为公海(无归属国,CountryId 返回空)。
    • 公海阈值 = 1500 米 × positionScale(TerritoryConstants.cs 代码常量 DemoPublicSeaThresholdRealScale = 1500;compact 下为 150 米)。
  • 世界边界:世界外接矩形 = 全部城市位置的包围盒向外扩 1500 米 × positionScale(TerritoryConstants.cs 常量 WorldBoundsPaddingRealScale = 1500)。该矩形同时注册为全局 IWorldBounds,全屏地图等“显示整个世界”的界面统一使用。
  • 栅格索引图:构建时烘焙一张栅格(列数 = 世界宽度 ÷ 50 米,截断到 [64, 256];行数按宽高比缩放,截断到 [64, 512]),每格存最近城市索引或公海标记 -1。栅格用于提取边界线;实时点查询不走栅格而是直接暴力遍历 7 个种子点取最近(更精确)。
  • 边界三分类BoundarySegment.cs):相邻两格归属不同时产生一段边界,按两侧关系分为:
    • InterCountry(两侧不同国家)—— 国界,粗线渲染;
    • IntraCountry(两侧同国不同城)—— 同国城界,细线/虚线渲染;
    • PublicSeaEdge(一侧是公海)—— 领海外缘,银白色渲染。
  • 城市易手:城市被占领后只改种子点的国别(位置不变),边界分类懒重算;不需要整体重建。城市位置变化才需要整体重建(RebuildTerritoryGrid)。
  • 对外查询TerritoryRegistry(全局注册点)提供 GetCountryAtPosition / GetTerritoryAt,返回(归属国、最近城市、是否公海、到最近城市距离)。Boss 怪物等系统用它判断海域归属,见 遭遇与刷怪

旧的圆柱防御塔已被“海上炮台平台”(harbor platform)替代:每座非自由港城市在港口外海生成若干小型驻防船平台,平台上的机枪炮是城市防御的实体。

生成规则CitySystemInitializer.cs):

  • 触发时机:陆地(岛屿/港口)注册完成、且玩家船甲板铺设完成之后,按城市逐艘串行生成(防止与玩家船初始化竞争)。PlayMode 测试场景会整体抑制生成。
  • 锚点:港口泊位(dock)位置;没有岛屿配置时退回城市中心。
  • 布置:以泊位朝海方向为中轴,在 ±80° 扇形上等分布置,每座平台距锚点 50 米(代码常量 orbitRadius = 50f,朝向公式:方向 = forward × cos(角度) + right × sin(角度),角度在 -80° 到 +80° 间按序号线性插值)。
  • 平台行为:生成后立即切入驻守状态(GarrisonState.cs)——永不移动、进入最高战备(BattleStations)、每 1 秒扫描一次敌人(代码常量 ScanInterval = 1f)、炮塔自动索敌开火;被打也不逃跑不追击。

城市类型 → 防御配置CitySystemInitializer.GetGarrisonConfig,代码硬编码;平台本体数据在 Assets/StreamingAssets/DataSets/fleet/harbor_*.json,策划可改):

城市类型 平台组成 总机枪数 适用城市
FishingTown 渔村 1 × harbor_picket 1 普利茅斯
TradePort 贸易港 2 × harbor_battery 4 勒阿弗尔、马赛
IndustryCity 工业城 2 × harbor_battery 4 塞维利亚
Fortress 要塞 2 × harbor_battery + 1 × harbor_bastion 8 朴次茅斯
Capital 首都 1 × harbor_picket + 2 × harbor_bastion + 1 × harbor_citadel 15 马德里

平台规格表(来源:harbor_picket/battery/bastion/citadel.json,JSON 配置,策划可改):

平台 甲板尺寸 机枪(MachineGun_Prod) 船员 子弹储备 食物/水
harbor_picket 哨戒台 6×6 格 1 门 1 炮手 500 发 各 5
harbor_battery 炮组台 8×8 格 2 门 2 炮手 + 1 乘务 1200 发 各 12
harbor_bastion 棱堡台 10×10 格 4 门 4 炮手 + 1 乘务 2400 发 各 24
harbor_citadel 卫城台 14×14 格 6 门 6 炮手 + 1 乘务 + 1 军医 5000 发 各 50

机枪本体的血量/伤害不在本系统配置——它就是普通的船载武器建筑,数值见 武器与弹药建筑

占领判定CityDefense.cs):

  1. 每座平台生成完毕后,扫描其上所有有人武器的可受伤组件,逐门注册到该城的 CityDefense(计入“防御塔总数”)。
  2. 每门炮被摧毁时存活计数 -1,并记录最后攻击者阵营。
  3. 存活计数归零 → 城市被占领(一次性,不可逆):
    • 占领者阵营解析:攻击者是 “Player” → 取玩家当前国籍;攻击者是 AI 国家 → 直接用其国家 ID。
    • 若解析出有效国家:城市改挂到新国家(颜色、领地立即变更)。玩家无国籍(海盗)时城市归属不变,但防御已永久清零、不再重建。
    • 同步广播占领消息:刷新城市颜色标记(CityColorMarker.cs)、更新 Voronoi 种子国别(CityManager.cs)、推进胜利进度(VictoryManager)、结算阵营声望(FactionEventHandler,见 阵营与外交)。

驻防冬眠GarrisonHibernator.cs,Inspector 序列化字段,运行时动态挂载故实际取代码默认值):

参数 说明
唤醒半径 150 米 玩家船距平台小于此值 → 启用全部组件与渲染
休眠半径 200 米 大于此值 → 禁用全部组件与渲染(滞回防抖)
检查间隔 0.5 秒

冬眠只切组件开关、不销毁实体,因此 CityDefense 持有的炮塔受伤引用始终有效——玩家远程炮击休眠中的平台照样能打掉并触发占领。

关于 CityDefenseConfig.csvAssets/StreamingAssets/FactionSystem/,全量 5 行):

城市类型 tower_count tower_hp city_hp
FishingTown 1 500 1000
TradePort 2 800 2000
IndustryCity 2 1000 2500
Fortress 4 1500 5000
Capital 6 2000 8000

注意:这张表目前没有任何运行时代码消费(只有自动生成的读表类 CityDefenseConfig.cs,无调用方)。它对应旧的“圆柱防御塔”设计,已被上述海上炮台方案取代。改这张表不会改变游戏行为,详见“已知限制”。

每座非自由港城市挂一个 PatrolShipSpawner.cs,目标是让本国海域常驻 2-4 艘巡逻舰。为了性能,巡逻舰平时只是数据层“虚拟船”(一条记录),由全局 PatrolSimulationManager.cs 低频推演位置与战斗;玩家靠近时才实例化为真实船(激活),远离即销毁回数据层(去激活)。

生成参数PatrolShipSpawner.cs,Inspector 序列化字段,组件为运行时动态挂载故实际取代码默认值):

参数 单位 说明
每城目标数量 2 / 3 / 4 随机 城市初始化时随机一次(均匀分布)
补充检查间隔 15 存活数 < 目标数 → 注册 1 艘新虚拟船
开局错峰延迟 0 - 5 随机 防止全部城市同帧涌入
生成最小间距 30 新船出生点与已有巡逻船距离下限(最多重抽 16 次)
激活半径 150 玩家到虚拟船距离小于此值 → 实例化
去激活半径 200 大于此值 → 销毁实体回虚拟态(1.33 倍滞回)
巡逻半径 80 虚拟巡逻航点采样基准半径
巡逻海域倍率 2.5 PatrolZone 半径 = 80 × 2.5 = 200 米
舰队配置 pirate_sloop 代码常量,所有城市巡逻舰同款

巡逻海域(PatrolZone)PatrolZone.cs,全部代码常量):以泊位为圆心、半径 200 米的圆,按 8 米 × 8 米网格离散化为海面格列表;剔除“在岛上或距任一岛岸线不足 12 米安全裕量”的格子,再从泊位侧做四连通洪泛填充,只保留与泊位连通的海面(岛屿背面的飞地海域被排除)。出生点与巡逻航点全部从这些格子里随机采样,保证永不穿陆。

虚拟模拟PatrolSimulationManager.cs):

参数 单位 来源
模拟 tick 间隔 1 Inspector 序列化字段(动态挂载,实际取代码默认值)
虚拟航速 5 米/秒 代码常量 VirtualMoveSpeed
航点到达判定 < 1 代码常量,到达后换下一个随机航点
虚拟战斗距离 50 Inspector 序列化字段
激活检查间隔 2 Inspector 序列化字段
激活最小距离 80 Inspector 序列化字段,玩家太近不刷脸(等虚拟船漂远再激活)
远巡概率 30% Inspector 序列化字段(仅在 PatrolZone 构建失败的回退路径生效)
远巡半径倍率 2.5 同上

虚拟战斗:每个模拟 tick,任意两艘未激活、相距 ≤ 50 米且阵营互相敌对(按阵营关系表,见 阵营与外交)的虚拟船互相结算一次伤害:

单 tick 伤害 = round(10 × 攻方战力 ÷ max(1, 守方战力))(双向同时结算)

战力(CombatRating)与血量在注册时从舰队 JSON 推算(PatrolShipSpawner.cs):

战力 = max(1, 名字含 “Gun”/“Cannon” 的建筑数 + 船员数) 血量 = 100 + 甲板边长² + 建筑数 × 5

代入 pirate_sloop.json(6×6 甲板、8 个建筑、其中 1 门机枪、4 名船员):战力 = 5,血量 = 100 + 36 + 40 = 176。两艘同级巡逻舰对打,每 tick 互扣 10 点,约 18 秒分出同归于尽的结果。

战损掉落(虚拟船血量归零时,PatrolSimulationManager.cs 代码常量):在沉没点 ±10 米圆内随机生成 2-4 堆漂浮物,每堆从下表随机抽一种,存活 600 秒后消失(走战利品冬眠系统,见 战利品与掉落):

物品 每堆数量
Wood 木材 3 - 6
CannonShell 炮弹 2 - 4
Bullet 子弹 5 - 10

激活 / 去激活规则

  • 激活:玩家到虚拟船距离落在 [80, 150) 米区间 → 在虚拟船当前位置实例化真实船(行为 = 巡逻,索敌距离 50 米),漫游锚点固定在泊位、绳长(LeashRadius)= 80 × 2.5 × 1.2 = 240 米,航点继续从 PatrolZone 采样。同一时刻只允许一艘船在激活流程中(互斥锁)。
  • 去激活:距离 > 200 米 → 记录实体当前位置回写虚拟记录,销毁实体。血量不回写——下次激活仍是满血(MVP 简化)。
  • 激活船被击沉:实体销毁被管理器检测到 → 虚拟记录血量置 0 → 走战损掉落与移除。
  • 城市被占领后:旧国别的虚拟船不再计入新主人的配额,生成器会按新国别补满 2-4 艘;旧船保留旧阵营继续游荡直到被消灭。

开局护航:若某城泊位距玩家出生点 < 50 米,该城固定立刻生成并激活 1 艘巡逻舰作为开局护航(绕过 80 米最小激活距离),叙事上是“护航船”。

CityTradingTrigger.cs 每帧检测玩家船与城市的距离。触发参考点优先使用岛屿系统注册的泊位(dock)位置,无岛屿时退回城市中心(见 岛屿与陆地);触发距离 = 城市半径(CSV radius × cityRadiusScale,real 下 45-60 米)。

进入半径时(一次性触发,直到离开):

  1. 记录停靠港(仅非敌对城):写入“最后停靠港口”,用于死亡复活点与船员压力的“靠岸破除”(见 船员);敌对城不算靠岸。
  2. 打开港口面板:右侧主面板切换为 Harbor 面板(Core/UI/MainRight/Harbor/HarborPanel.cs,UI Toolkit,见 界面总览)。
  3. 招募进港:通知招募系统玩家进入该城(敌对城跳过)。
  4. 发现登记:标记该城为“已发现”,自动连带发现所属国家(first-meet 雾战机制,见 探索与情报)。
  5. 港口简报:收集自上次简报以来的世界新闻 + 为该城生成传闻,广播简报消息(见 探索与情报)。

离开半径时:清除停靠状态、关闭 Harbor 面板、若正在与该城交易则强制结束交易、关闭招募面板。

Harbor 面板四按钮

按钮 行为 敌对城
交易 打开交易会话(隐藏 Harbor 面板,交易结束且仍在港内时自动切回) 禁用
修船 一键修复全部损毁地板 + 排空积水,按损毁数量扣金币(费用公式见 船只),金币不足弹红色飘字;支付成功播放金币从船飞向城市的特效 禁用
招募 打开该城招募面板(见 船员 禁用
外交 打开外交面板 始终可用(允许在敌对国港口求和)

敌对判定 = 玩家与城市所属国家的阵营关系为 Hostile(实时刷新:停火成功立即解锁按钮,不必离港重进)。

外交操作CityDiplomacyTrigger.cs,代码常量;机制详情见 阵营与外交):

操作 前置条件 花费(金币)
贸易协定 关系非敌对 5000
停火协议 关系为敌对 10000
申请国籍 由阵营系统校验 0

交易价格的关系修正CityTrader.cs 代码常量;交易系统全貌见 交易):

玩家与城市所属国关系 买入价倍率 卖出价倍率(NPC 付给玩家)
中立 Neutral ×1.2 ×(1/1.2) ≈ ×0.83
友好 Friendly ×1.0 ×1.0
友好 + 同国籍 ×0.9 ×(1/0.9) ≈ ×1.11
敌对 Hostile ×1.5(保底,正常流程到不了交易) ×(1/1.5) ≈ ×0.67

城市在售商品来自 CityInventory.csv(运行时默认读 Assets/StreamingAssets/DataSets/trading/standard/CityInventory.csv,41 条数据行,列:city_id / item_id / stock 库存 / buy_price 买入价 / sell_price 卖出价;预设 trading 轴填 rich 时改读 DataSets/trading/rich/ 同名表),并叠加奢侈品产地距离梯度商品。每条商品换算规则(CityTrader.cs):库存上限 = stock × 2,初始库存 = stock,每日补货 = stock ÷ 5。完整商品经济见 交易配置表总览

城市标记CitySystemInitializer.cs):每城生成一个 10 米见方的黄色 Cube 作为中心标记(Inspector 序列化字段 _cityMarkerSize = 10、颜色黄色),并挂小地图标记(颜色取国家区域色,尺寸 = 触发半径)。

发现显隐CityDiscoveryVisibility.cs):未发现的城市隐藏标记 Cube、禁用颜色染色组件;首次进入其触发半径被“发现”后永久显示。战略地图上未发现城市的领海填透明色、相关边界隐藏、点击不响应。

名字标签(运行时动态创建的世界空间文字,参数为代码默认值):

标签 显示高度阈值 字号 高度缩放系数 位置
城市名(CityNameLabel.cs 相机高度 ≥ 1000 米 50 0.005(标签随高度线性放大,保证屏幕大小恒定) 城市上方 5 米,平铺水面
国家名(CountryNameLabel.cs 相机高度 ≥ 1000 米 90 0.012 该国全部城市位置的几何中心,高 8 米

两者都受发现状态约束:未发现的城市/国家即使高度达标也不显示。

领地渲染双模式TerritoryRenderer.cs,相机高度驱动,阈值为 Inspector 序列化字段、运行时自动创建故取代码默认值 1000 米):

  • 航行模式(高度 < 1000 米,SailingBorderRenderer.cs):只渲染玩家周围 200 米内的边界段为发光条带(宽 6 米、贴水面 0.2 米、每 0.25 秒刷新一次)。条带颜色按“边界另一侧国家与玩家的关系”决定:

    状况 颜色
    另一侧友好 绿
    另一侧中立
    另一侧敌对
    公海边缘 银白
    一侧国家未发现
    两侧都未发现 / 公海边缘的陆侧未发现 不绘制
  • 战略模式(高度 ≥ 1000 米,StrategicMapRenderer.cs):整海面铺一张政治填色图(宽 256 像素的烘焙贴图、整体透明度 0.4)+ 边界线(国界宽 12 米、同国城界宽 4 米)。各国领海填国家区域色;公海填深蓝;敌对国领海向红色混合 40%;未发现国家领海透明(雾战)。

  • 战略点击StrategicMapInteractor.cs):设计为仅战略模式下左键点选城市(射线 5000 米)触发城市点击事件,由外交面板订阅打开,未发现的城市点击无效。但该组件从未被挂载(见“已知限制”),事件实际不会触发。

关系/声望变化会即时通知两个渲染器重算颜色。

项目 公式 / 数值 单位 来源
城市世界坐标 CSV 坐标 × positionScale + positionOffset cities.csv + world/*.json
城市触发半径 CSV radius × cityRadiusScale 同上
公海阈值 1500 × positionScale 代码常量 TerritoryConstants.cs
世界边界外扩 1500 × positionScale 同上
Voronoi 栅格列数 clamp(世界宽 ÷ 50, 64, 256) 代码 VoronoiTerritoryGrid.cs
炮台距泊位 50 代码常量 CitySystemInitializer.cs
炮台扇形 ±80°,按序号等分 同上
驻守扫描间隔 1 代码常量 GarrisonState.cs
驻防冬眠唤醒/休眠/检查 150 / 200 / 0.5 米/米/秒 代码默认值 GarrisonHibernator.cs
占领条件 该城注册的全部炮塔摧毁(存活数 ≤ 0) CityDefense.cs
每城巡逻舰目标数 随机 2 / 3 / 4 代码 PatrolShipSpawner.cs
巡逻补充间隔 15 代码默认值 PatrolShipSpawner.cs
巡逻激活 / 去激活 [80, 150) 激活;> 200 去激活 米(玩家到虚拟船距离) 代码默认值 PatrolSimulationManager.cs / PatrolShipSpawner.cs
巡逻海域半径 80 × 2.5 = 200 代码默认值 PatrolShipSpawner.cs
巡逻海域网格 / 离岸裕量 8 / 12 代码常量 PatrolZone.cs
虚拟航速 5 米/秒 代码常量 PatrolSimulationManager.cs
虚拟模拟 tick / 激活检查 1 / 2 代码默认值 PatrolSimulationManager.cs
虚拟战斗距离 50 同上
虚拟战斗伤害 round(10 × 攻方战力 ÷ max(1, 守方战力)) / tick,双向 PatrolSimulationManager.ComputeDamage(有单元测试佐证)
巡逻舰战力 max(1, 含 Gun/Cannon 建筑数 + 船员数);pirate_sloop = 5 代码 PatrolShipSpawner.cs
巡逻舰血量 100 + 甲板边长² + 建筑数 × 5;pirate_sloop = 176 同上
激活后绳长 巡逻半径 × 2.5 × 1.2 = 240 代码 PatrolSimulationManager.cs
战损掉落 2-4 堆,±10 米散布,600 秒消失 代码常量 PatrolSimulationManager.cs
开局护航判定 泊位距玩家出生点 < 50 米 → 1 艘立即激活 代码常量 PatrolShipSpawner.cs
贸易协定 / 停火花费 5000 / 10000 金币 代码常量 CityDiplomacyTrigger.cs
关系价格倍率 中立 ×1.2;友好同籍 ×0.9;卖出取倒数 代码常量 CityTrader.cs
商品库存换算 上限 = stock × 2;日补 = stock ÷ 5 代码 CityTrader.cs(stock 来自 CityInventory.csv
名字标签显示阈值 城市 / 国家均为相机高度 ≥ 1000 代码默认值 CityNameLabel.cs / CountryNameLabel.cs
领地渲染模式切换 相机高度 ≥ 1000 → 战略填色 代码默认值 TerritoryRenderer.cs
航行边界条带 半径 200 内、宽 6、0.25 秒刷新 米/米/秒 代码默认值 SailingBorderRenderer.cs
战略边界线宽 国界 12 / 同国城界 4 代码默认值 StrategicMapRenderer.cs
修船金币飞行特效 3-15 枚硬币(按金额 ÷ 500 上限插值)、飞行 1.2 秒、弧高 8 米 代码默认值 WorldGoldFlyEffect.cs
  • 阵营与外交:城市的国家归属决定靠港待遇(敌对禁交易/修船/招募)、巡逻舰敌我、边界条带颜色;占领城市会结算声望并可改变领土;外交三操作(贸易协定/停火/国籍)入口在港口面板。见 阵营与外交
  • 交易:城市是主要交易对手,商品表 CityInventory.csv + 奢侈品产地梯度 + 关系价格修正。见 交易
  • 探索与情报:first-meet 发现机制控制城市/国家的标签、领海填色、点击交互可见性;靠港触发新闻简报与传闻。见 探索与情报
  • 岛屿与陆地:泊位(dock)由岛屿系统注册,决定靠港触发点、炮台锚点、巡逻海域中心;巡逻海域剔除陆地依赖岛屿多边形。见 岛屿与陆地
  • 遭遇与刷怪:领地查询(公海/归属国)供 Boss 怪物与遭遇系统判断海域;城市的海域类型列预留给该系统但未接通。见 遭遇与刷怪
  • 船只 / 船员:靠港记录是死亡复活点与船员压力“靠岸破除”的依据;修船走船体浮力系统的修复费用。见 船只船员
  • 武器与弹药 / 伤害与护甲:炮台平台上的机枪是普通船载武器,受伤/死亡走通用伤害管线,城市占领由武器的可受伤组件死亡事件驱动。见 武器与弹药伤害与护甲
  • 战利品与掉落:虚拟巡逻舰战损掉落注册到战利品冬眠管理器。见 战利品与掉落
  • 游戏循环与胜负:城市占领消息推进胜利进度(VictoryManager / 胜利 HUD)。见 游戏循环与胜负
  • 界面总览:Harbor 面板挂 MainRight 槽位;战略地图点击打开外交 Modal。见 界面总览
想调整的体验 改哪里 类型
增删城市、改位置/归属/半径/类型 Assets/StreamingAssets/CitySystem/cities.csv,改后需跑 CSV 代码生成(Tools → CSV Code Generator → Generate All) CSV
增删国家、改国家颜色 Assets/StreamingAssets/CitySystem/countries.csv(颜色为十六进制) CSV
城市在售商品与基础价 Assets/StreamingAssets/DataSets/trading/standard/CityInventory.csv(默认)/ trading/rich/(预设覆盖) CSV
某类城市的防御强度(平台组成) CitySystemInitializer.csGetGarrisonConfig(城市类型 → 平台清单) 代码
单种平台的火力/船员/补给 Assets/StreamingAssets/DataSets/fleet/harbor_*.json JSON 配置
巡逻舰船型与装备 Assets/StreamingAssets/DataSets/fleet/pirate_sloop.json(船型名本身是 PatrolShipSpawner.cs 代码常量) JSON / 代码
每城巡逻数量、激活距离、巡逻半径 PatrolShipSpawner.cs 序列化字段默认值(组件运行时动态挂载,prefab 上改不到,需改代码默认值) 代码
虚拟战斗强度 / 掉落 PatrolSimulationManager.cs(伤害公式、掉落表、TTL 均在此) 代码
公海范围大小 TerritoryConstants.csDemoPublicSeaThresholdRealScale 代码
世界整体缩放(测试用小地图) Assets/StreamingAssets/DataSets/world/compact.json 或新建 world 预设并在 Assets/StreamingAssets/Presets/*.json 引用 JSON 配置
外交花费 CityDiplomacyTrigger.cs 代码常量(5000 / 10000) 代码
关系价格倍率 CityTrader.csGetRelationPriceModifier 代码
边界条带 / 战略填色样式 SailingBorderRenderer.cs / StrategicMapRenderer.cs 颜色与宽度常量 代码
名字标签出现高度与字号 CityNameLabel.cs / CountryNameLabel.cs 序列化字段默认值(动态挂载) 代码
  1. CityDefenseConfig.csv 是死配置:tower_count / tower_hp / city_hp 没有任何运行时消费方,对应已被替代的“圆柱防御塔”旧设计。实际防御强度由 GetGarrisonConfig(代码)+ harbor_*.json(舰队配置)决定。改这张 CSV 无效。
  2. cities.csv 的 sea_region_type 列未接通:Safe/Moderate/Dangerous 当前没有系统读取。
  3. cities.csv 的随机偏移列实际失效:use_random_offset / random_seed 虽有完整的位置生成逻辑(CityPositionGenerator.cs),但 CitySystemInitializer.GenerateCity 随后会用“CSV 原始坐标 × 缩放 + 偏移”直接覆盖城市位置,随机偏移结果被丢弃。当前 CSV 全部为 false/0,无实际影响。
  4. CityLODSwitcher.cs(3D 模型 / 2D 图标 LOD 切换,阈值 800 米)从未被挂载:初始化器不添加它,场景与 prefab 中也无引用,属于未接线的预置组件。当前城市视觉只是标记 Cube,没有 3D 模型 LOD。
  5. 战略层显示阈值与相机上限存在矛盾:主相机(ZoomCamera.cs)距离上限 500 米、俯角上限 80°,可达最大高度约 500 × sin(80°) ≈ 492 米,达不到名字标签 / 战略填色的 1000 米阈值。全图视角实际由按 M 打开的全屏小地图(UI Toolkit)承担,世界空间的战略填色、城市/国家名标签、战略点击在默认相机参数下不可见。TerritoryRenderer.cs 注释中的“Strategic 2500m”为过时描述。
  6. 代码注释中的炮台规格已过时CitySystemInitializer.cs 注释写“Picket 4×4·1 炮…首都 17 炮”,实际 JSON 为 6×6/8×8/10×10/14×14,首都合计 15 门机枪。以 JSON 为准。
  7. 玩家无国籍(海盗)占领城市不变更归属:防御被永久清零(IsConquered = true,不会重建防御),但城市仍挂在原国家名下,颜色与领地不变。先入籍再攻城才能“插旗”。
  8. 巡逻舰激活时血量重置满血:虚拟态战损与实体战损互不延续(MVP 简化);玩家把激活的巡逻舰打残后走远再回来,它又是满血。
  9. 巡逻激活/驻防冬眠半径是绝对值,不随 world 缩放:compact(×0.1)下 150 米激活半径相对世界明显偏大(注释承认 compact 城间距仅 150-600 米),数值是按 compact 体验调的,real 模式下未单独校准。
  10. Service/CitySystem/UI/HarborPanel.cs 是自毁桩:旧 UGUI 港口面板已废弃,运行时 Awake 即销毁自身;真正的港口面板在 Core/UI/MainRight/Harbor/
  11. 城市防御注册不去重:同一门炮如果被重复注册会被计数两次(调用方保证唯一性,当前生成路径不会重复)。
  12. countries.csv 的 center_x / center_z / territory_radius 列不参与任何领土计算(Voronoi 完全由城市位置驱动),仅自由港联合填了非零值,无实际作用。
  13. Assets/StreamingAssets/CitySystem/CityInventory.csv 是无人读取的陈旧副本:运行时商品表实际从 DataSets/trading/standard/(默认)或 DataSets/trading/rich/(预设 trading 轴覆盖)加载。改 CitySystem/ 目录下那份不生效。