make better map

This commit is contained in:
bridge
2025-08-26 23:26:51 +08:00
parent ad72830f51
commit 7269d0afe8
3 changed files with 587 additions and 679 deletions

580
create_map.py Normal file
View File

@@ -0,0 +1,580 @@
from src.classes.tile import Map, TileType
from src.classes.essence import Essence, EssenceType
def create_cultivation_world_map() -> Map:
"""
创建修仙世界地图
尺寸: 70x50
西部大漠,南部雨林,北边冰原,最东部和最南部海洋
横向大河从大漠东部流向东南入海
北方纵向山脉
"""
game_map = Map(width=70, height=50)
# 创建基础地形
_create_base_terrain(game_map)
# 创建区域
_create_regions(game_map)
return game_map
def _create_base_terrain(game_map: Map):
"""创建基础地形"""
width, height = game_map.width, game_map.height
# 先创建默认平原
for x in range(width):
for y in range(height):
game_map.create_tile(x, y, TileType.PLAIN)
# 西部大漠 (x: 0-18)
for x in range(19):
for y in range(height):
game_map.tiles[(x, y)].type = TileType.DESERT
# 南部雨林 (y: 35-49)
for x in range(width):
for y in range(35, height):
if game_map.tiles[(x, y)].type != TileType.DESERT:
game_map.tiles[(x, y)].type = TileType.RAINFOREST
# 北边冰原 (y: 0-8)
for x in range(width):
for y in range(9):
if game_map.tiles[(x, y)].type != TileType.DESERT:
game_map.tiles[(x, y)].type = TileType.GLACIER
# 最东部海洋 (x: 65-69)
for x in range(65, width):
for y in range(height):
game_map.tiles[(x, y)].type = TileType.SEA
# 最南部海洋 (y: 46-49)
for x in range(width):
for y in range(46, height):
game_map.tiles[(x, y)].type = TileType.SEA
# 横向大河:从大漠东部(18, 25)流向东南入海,河流更宽
river_tiles = _calculate_wide_river_tiles()
for x, y in river_tiles:
if game_map.is_in_bounds(x, y):
game_map.tiles[(x, y)].type = TileType.WATER
# 北方纵向山脉 (x: 28-32, y: 5-20)
for x in range(28, 33):
for y in range(5, 21):
if game_map.tiles[(x, y)].type == TileType.PLAIN:
game_map.tiles[(x, y)].type = TileType.MOUNTAIN
# 添加其他地形类型
_add_other_terrains(game_map)
def _calculate_wide_river_tiles():
"""计算宽阔大河的所有水域tiles从(18, 25)流向东南到海洋宽度为3-4格"""
river_tiles = []
# 计算河流中心线
center_path = []
x, y = 18, 25
while x < 65 and y < 46:
center_path.append((x, y))
# 向东南流淌
if x < 40:
x += 1
if y < 35:
y += 1
else:
x += 2
y += 1
# 连接到海洋
while x < 68 and y < 48:
center_path.append((x, y))
x += 1
y += 1
# 根据中心线生成宽阔的河流
for i, (cx, cy) in enumerate(center_path):
# 河流宽度随位置变化:源头较窄,入海口较宽
width = 1 if i < len(center_path) // 3 else 2 if i < 2 * len(center_path) // 3 else 3
# 为每个中心点添加周围的水域
for dx in range(-width//2, width//2 + 1):
for dy in range(-width//2, width//2 + 1):
nx, ny = cx + dx, cy + dy
river_tiles.append((nx, ny))
return list(set(river_tiles)) # 去重
def _create_2x2_cities(game_map: Map):
"""创建2*2的城市区域"""
cities = [
{"name": "青云城", "base_x": 34, "base_y": 21, "description": "繁华都市的中心"},
{"name": "沙月城", "base_x": 14, "base_y": 19, "description": "沙漠绿洲中的贸易重镇"},
{"name": "翠林城", "base_x": 54, "base_y": 14, "description": "森林深处的修仙重镇"}
]
for city in cities:
base_x, base_y = city["base_x"], city["base_y"]
for dx in range(2):
for dy in range(2):
x, y = base_x + dx, base_y + dy
if game_map.is_in_bounds(x, y):
game_map.tiles[(x, y)].type = TileType.CITY
def _create_2x2_caves(game_map: Map):
"""创建2*2的洞穴区域"""
caves = [
{"name": "幽深洞府", "base_x": 35, "base_y": 5, "description": "冰原东部的神秘洞穴"},
{"name": "隐秘石窟", "base_x": 40, "base_y": 15, "description": "林海西部的古老石窟"}
]
for cave in caves:
base_x, base_y = cave["base_x"], cave["base_y"]
for dx in range(2):
for dy in range(2):
x, y = base_x + dx, base_y + dy
if game_map.is_in_bounds(x, y):
game_map.tiles[(x, y)].type = TileType.CAVE
def _create_2x2_ruins(game_map: Map):
"""创建2*2的遗迹区域"""
ruins = [
{"name": "古越遗迹", "base_x": 25, "base_y": 40, "description": "雨林深处的上古遗迹"},
{"name": "沧海遗迹", "base_x": 66, "base_y": 47, "description": "沉没在海中的远古文明遗迹"}
]
for ruin in ruins:
base_x, base_y = ruin["base_x"], ruin["base_y"]
for dx in range(2):
for dy in range(2):
x, y = base_x + dx, base_y + dy
if game_map.is_in_bounds(x, y):
game_map.tiles[(x, y)].type = TileType.RUINS
def _add_other_terrains(game_map: Map):
"""添加其他地形类型到合适位置"""
# 草原 (中部区域)
for x in range(20, 40):
for y in range(12, 25):
if game_map.tiles[(x, y)].type == TileType.PLAIN:
game_map.tiles[(x, y)].type = TileType.GRASSLAND
# 森林 (东中部区域)
for x in range(40, 60):
for y in range(10, 30):
if game_map.tiles[(x, y)].type == TileType.PLAIN:
game_map.tiles[(x, y)].type = TileType.FOREST
# 雪山 (北部山脉附近)
for x in range(25, 35):
for y in range(2, 8):
if game_map.tiles[(x, y)].type == TileType.GLACIER:
game_map.tiles[(x, y)].type = TileType.SNOW_MOUNTAIN
# 火山 (单独区域)
for x in range(52, 55):
for y in range(32, 35):
if game_map.tiles[(x, y)].type == TileType.PLAIN:
game_map.tiles[(x, y)].type = TileType.VOLCANO
# 创建2*2城市区域
_create_2x2_cities(game_map)
# 创建2*2洞穴区域
_create_2x2_caves(game_map)
# 创建2*2遗迹区域
_create_2x2_ruins(game_map)
# 农田 (城市附近,改为不与草原重叠的区域)
for x in range(33, 38):
for y in range(25, 30):
if game_map.tiles[(x, y)].type == TileType.PLAIN:
game_map.tiles[(x, y)].type = TileType.FARM
# 沼泽 (河流附近的低洼地区,避开雨林区域)
for x in range(42, 46):
for y in range(30, 34):
if game_map.tiles[(x, y)].type == TileType.PLAIN:
game_map.tiles[(x, y)].type = TileType.SWAMP
def _create_regions(game_map: Map):
"""创建区域并分配灵气"""
# 收集各地形的坐标
terrain_coords = {}
for x in range(game_map.width):
for y in range(game_map.height):
tile_type = game_map.tiles[(x, y)].type
if tile_type not in terrain_coords:
terrain_coords[tile_type] = []
terrain_coords[tile_type].append((x, y))
# 西域流沙 (大漠)
if TileType.DESERT in terrain_coords:
essence = Essence({
EssenceType.FIRE: 8,
EssenceType.EARTH: 7,
EssenceType.GOLD: 6,
EssenceType.WATER: 1,
EssenceType.WOOD: 2
})
game_map.create_region(
"西域流沙",
"茫茫大漠,黄沙漫天。此地火行灵气浓郁,土行次之,乃是修炼火系功法的绝佳之地。",
essence,
terrain_coords[TileType.DESERT]
)
# 南疆蛮荒 (雨林)
if TileType.RAINFOREST in terrain_coords:
essence = Essence({
EssenceType.WOOD: 9,
EssenceType.WATER: 6,
EssenceType.EARTH: 5,
EssenceType.FIRE: 3,
EssenceType.GOLD: 2
})
game_map.create_region(
"南疆蛮荒",
"古木参天,藤蔓缠绕。此地木行灵气极为浓郁,水行次之,是修炼木系功法和炼制灵药的宝地。",
essence,
terrain_coords[TileType.RAINFOREST]
)
# 极北冰原 (冰原)
if TileType.GLACIER in terrain_coords:
essence = Essence({
EssenceType.WATER: 8,
EssenceType.GOLD: 6,
EssenceType.EARTH: 4,
EssenceType.FIRE: 1,
EssenceType.WOOD: 3
})
game_map.create_region(
"极北冰原",
"千里冰封,万年不化。此地水行灵气充沛,金行次之,寒气逼人,唯有修炼寒冰功法者方可久居。",
essence,
terrain_coords[TileType.GLACIER]
)
# 无边碧海 (海洋)
if TileType.SEA in terrain_coords:
essence = Essence({
EssenceType.WATER: 10,
EssenceType.GOLD: 4,
EssenceType.WOOD: 3,
EssenceType.EARTH: 2,
EssenceType.FIRE: 1
})
game_map.create_region(
"无边碧海",
"浩瀚无垠,波涛汹涌。此地水行灵气达到极致,蕴含无穷玄机,是水系修士向往的圣地。",
essence,
terrain_coords[TileType.SEA]
)
# 天河奔流 (大河)
if TileType.WATER in terrain_coords:
essence = Essence({
EssenceType.WATER: 7,
EssenceType.WOOD: 5,
EssenceType.EARTH: 4,
EssenceType.GOLD: 3,
EssenceType.FIRE: 2
})
game_map.create_region(
"天河奔流",
"一江春水向东流,奔腾不息入东海。此河贯穿东西,水行灵气丰沛,滋养两岸万物生灵。",
essence,
terrain_coords[TileType.WATER]
)
# 青峰山脉 (山脉)
if TileType.MOUNTAIN in terrain_coords:
essence = Essence({
EssenceType.EARTH: 8,
EssenceType.GOLD: 7,
EssenceType.FIRE: 5,
EssenceType.WOOD: 3,
EssenceType.WATER: 2
})
game_map.create_region(
"青峰山脉",
"连绵起伏,直插云霄。此地土行灵气深厚,金行次之,乃是修炼土系功法和寻找天材地宝的胜地。",
essence,
terrain_coords[TileType.MOUNTAIN]
)
# 万丈雪峰 (雪山)
if TileType.SNOW_MOUNTAIN in terrain_coords:
essence = Essence({
EssenceType.WATER: 9,
EssenceType.GOLD: 8,
EssenceType.EARTH: 6,
EssenceType.FIRE: 1,
EssenceType.WOOD: 2
})
game_map.create_region(
"万丈雪峰",
"雪峰皑皑,寒风刺骨。此地水行与金行灵气并重,是修炼冰系神通和淬炼法宝的绝佳之地。",
essence,
terrain_coords[TileType.SNOW_MOUNTAIN]
)
# 碧野千里 (草原)
if TileType.GRASSLAND in terrain_coords:
essence = Essence({
EssenceType.WOOD: 6,
EssenceType.EARTH: 6,
EssenceType.WATER: 5,
EssenceType.GOLD: 3,
EssenceType.FIRE: 4
})
game_map.create_region(
"碧野千里",
"芳草萋萋,一望无际。此地木土并重,灵气平和,是修炼基础功法和放牧灵兽的理想之地。",
essence,
terrain_coords[TileType.GRASSLAND]
)
# 青云林海 (森林)
if TileType.FOREST in terrain_coords:
essence = Essence({
EssenceType.WOOD: 8,
EssenceType.WATER: 5,
EssenceType.EARTH: 4,
EssenceType.GOLD: 3,
EssenceType.FIRE: 3
})
game_map.create_region(
"青云林海",
"古树参天,绿意盎然。此地木行灵气浓郁,是修炼木系功法、采集灵草和驯服林间灵兽的宝地。",
essence,
terrain_coords[TileType.FOREST]
)
# 炎狱火山 (火山)
if TileType.VOLCANO in terrain_coords:
essence = Essence({
EssenceType.FIRE: 10,
EssenceType.EARTH: 7,
EssenceType.GOLD: 4,
EssenceType.WATER: 1,
EssenceType.WOOD: 1
})
game_map.create_region(
"炎狱火山",
"烈焰冲天,岩浆奔流。此地火行灵气达到极致,是修炼火系神通和锻造法宝的圣地,常人不可近。",
essence,
terrain_coords[TileType.VOLCANO]
)
# 为每个2*2城市、洞穴和遗迹创建独立区域
_create_city_regions(game_map)
_create_caves_regions(game_map)
_create_ruins_regions(game_map)
# 沃土良田 (农田)
if TileType.FARM in terrain_coords:
essence = Essence({
EssenceType.WOOD: 7,
EssenceType.EARTH: 7,
EssenceType.WATER: 6,
EssenceType.GOLD: 2,
EssenceType.FIRE: 3
})
game_map.create_region(
"沃土良田",
"土地肥沃,五谷丰登。此地木土并重,水行充沛,是种植灵药和培育灵植的理想之地。",
essence,
terrain_coords[TileType.FARM]
)
# 平原地带 (平原)
if TileType.PLAIN in terrain_coords:
essence = Essence({
EssenceType.EARTH: 5,
EssenceType.WOOD: 4,
EssenceType.WATER: 4,
EssenceType.GOLD: 3,
EssenceType.FIRE: 3
})
game_map.create_region(
"平原地带",
"地势平坦,灵气平和。此地五行均衡,是初学修炼者打基础和建立宗门的理想之地。",
essence,
terrain_coords[TileType.PLAIN]
)
# 迷雾沼泽 (沼泽)
if TileType.SWAMP in terrain_coords:
essence = Essence({
EssenceType.WATER: 7,
EssenceType.WOOD: 6,
EssenceType.EARTH: 5,
EssenceType.FIRE: 2,
EssenceType.GOLD: 3
})
game_map.create_region(
"迷雾沼泽",
"雾气缭绕,泥泞不堪。此地水木灵气浓郁,但瘴气丛生,是修炼毒功和寻找奇异灵草的危险之地。",
essence,
terrain_coords[TileType.SWAMP]
)
def _create_city_regions(game_map: Map):
"""为每个2*2城市创建独立区域"""
cities = [
{"name": "青云城", "base_x": 34, "base_y": 21, "description": "繁华都市,人烟稠密,商贾云集。此地金行灵气较为集中,是交易天材地宝、寻找机缘的重要场所。"},
{"name": "沙月城", "base_x": 14, "base_y": 19, "description": "沙漠绿洲中的贸易重镇,各路商队在此集结。金行灵气充沛,是修士补给和交流的重要据点。"},
{"name": "翠林城", "base_x": 54, "base_y": 14, "description": "森林深处的修仙重镇,木行灵气与金行灵气并重。众多修士在此栖居,是修炼和炼宝的理想之地。"}
]
for city in cities:
base_x, base_y = city["base_x"], city["base_y"]
city_coords = []
for dx in range(2):
for dy in range(2):
x, y = base_x + dx, base_y + dy
if game_map.is_in_bounds(x, y):
city_coords.append((x, y))
essence = Essence({
EssenceType.GOLD: 6,
EssenceType.EARTH: 5,
EssenceType.WOOD: 5,
EssenceType.WATER: 4,
EssenceType.FIRE: 4
})
game_map.create_region(
city["name"],
city["description"],
essence,
city_coords
)
def _create_caves_regions(game_map: Map):
"""为每个2*2洞穴创建独立区域"""
caves = [
{"name": "幽深洞府", "base_x": 35, "base_y": 5, "description": "冰原东部的神秘洞穴,深幽莫测,寒气逼人。此地水行与土行灵气并重,常有前辈留下的传承。"},
{"name": "隐秘石窟", "base_x": 40, "base_y": 15, "description": "林海西部的古老石窟,木行与土行灵气交融,机缘与危险并存。"}
]
for cave in caves:
base_x, base_y = cave["base_x"], cave["base_y"]
cave_coords = []
for dx in range(2):
for dy in range(2):
x, y = base_x + dx, base_y + dy
if game_map.is_in_bounds(x, y):
cave_coords.append((x, y))
# 根据洞穴位置调整灵气配置
if cave["name"] == "幽深洞府": # 冰原东部
essence = Essence({
EssenceType.WATER: 7,
EssenceType.EARTH: 6,
EssenceType.GOLD: 5,
EssenceType.FIRE: 2,
EssenceType.WOOD: 3
})
else: # 隐秘石窟,林海西部
essence = Essence({
EssenceType.WOOD: 7,
EssenceType.EARTH: 6,
EssenceType.WATER: 5,
EssenceType.GOLD: 4,
EssenceType.FIRE: 3
})
game_map.create_region(
cave["name"],
cave["description"],
essence,
cave_coords
)
def _create_ruins_regions(game_map: Map):
"""为每个2*2遗迹创建独立区域"""
ruins = [
{"name": "古越遗迹", "base_x": 25, "base_y": 40, "description": "雨林深处的上古遗迹,古藤缠绕,木行灵气与金行灵气交融。蕴藏古老功法与灵药配方。"},
{"name": "沧海遗迹", "base_x": 66, "base_y": 47, "description": "沉没在海中的远古文明遗迹,水行灵气浓郁,潮汐间偶有宝物现世。"}
]
for ruin in ruins:
base_x, base_y = ruin["base_x"], ruin["base_y"]
ruin_coords = []
for dx in range(2):
for dy in range(2):
x, y = base_x + dx, base_y + dy
if game_map.is_in_bounds(x, y):
ruin_coords.append((x, y))
# 根据遗迹位置调整灵气配置
if ruin["name"] == "古越遗迹": # 雨林深处
essence = Essence({
EssenceType.WOOD: 8,
EssenceType.GOLD: 6,
EssenceType.WATER: 5,
EssenceType.EARTH: 4,
EssenceType.FIRE: 3
})
else: # 沧海遗迹,海中
essence = Essence({
EssenceType.WATER: 9,
EssenceType.GOLD: 6,
EssenceType.EARTH: 3,
EssenceType.WOOD: 3,
EssenceType.FIRE: 2
})
game_map.create_region(
ruin["name"],
ruin["description"],
essence,
ruin_coords
)
if __name__ == "__main__":
# 创建地图
cultivation_map = create_cultivation_world_map()
print(f"修仙世界地图创建完成!尺寸: {cultivation_map.width}x{cultivation_map.height}")
# 统计各地形类型
terrain_count = {}
regions_count = {}
for x in range(cultivation_map.width):
for y in range(cultivation_map.height):
tile = cultivation_map.get_tile(x, y)
tile_type = tile.type.value
if tile_type not in terrain_count:
terrain_count[tile_type] = 0
terrain_count[tile_type] += 1
region = cultivation_map.get_region(x, y)
if region.name not in regions_count:
regions_count[region.name] = 0
regions_count[region.name] += 1
print("各地形类型分布:")
for terrain_type, count in terrain_count.items():
print(f" {terrain_type}: {count}个地块")
print("\n各区域分布:")
for region_name, count in regions_count.items():
print(f" {region_name}: {count}个地块")

678
run.py
View File

@@ -21,6 +21,7 @@ from src.classes.essence import Essence, EssenceType
from src.classes.cultivation import CultivationProgress
from src.classes.root import Root
from src.classes.age import Age
from create_map import create_cultivation_world_map
def clamp(value: int, lo: int, hi: int) -> int:
@@ -36,677 +37,6 @@ def circle_points(cx: int, cy: int, r: int, width: int, height: int) -> List[Tup
pts.append((x, y))
return pts
def build_rich_random_map(width: int = 50, height: int = 35, *, seed: int | None = None) -> Map:
if seed is not None:
random.seed(seed)
game_map = Map(width=width, height=height)
# 1) 底色:平原
for y in range(height):
for x in range(width):
game_map.create_tile(x, y, TileType.PLAIN)
# 2) 西部大漠(左侧宽带),先铺设便于后续北/南带覆盖
desert_w = max(6, width // 6) # 增加沙漠宽度
desert_tiles: List[Tuple[int, int]] = []
for y in range(height):
for x in range(0, desert_w):
game_map.create_tile(x, y, TileType.DESERT)
desert_tiles.append((x, y))
# 3) 北部雪山与冰原(顶部宽带,覆盖整宽度)
north_band = max(4, height // 6) # 增加北部带宽度
snow_mountain_tiles: List[Tuple[int, int]] = []
glacier_tiles: List[Tuple[int, int]] = []
for y in range(0, north_band):
for x in range(width):
game_map.create_tile(x, y, TileType.SNOW_MOUNTAIN)
snow_mountain_tiles.append((x, y))
# 局部冰川簇
for _ in range(random.randint(3, 5)): # 增加冰川数量
cx = random.randint(1, width - 2)
cy = random.randint(0, north_band - 1)
r = random.randint(1, 3) # 增加冰川半径
for x, y in circle_points(cx, cy, r, width, height):
if y < north_band:
game_map.create_tile(x, y, TileType.GLACIER)
glacier_tiles.append((x, y))
# 4) 南部热带雨林(底部宽带,覆盖整宽度)
south_band = max(4, height // 6) # 增加南部带宽度
rainforest_tiles: List[Tuple[int, int]] = []
for y in range(height - south_band, height):
for x in range(width):
game_map.create_tile(x, y, TileType.RAINFOREST)
rainforest_tiles.append((x, y))
# 5) 最东海域(右侧宽带),最后铺海以覆盖前面的地形;随后在海中造岛
sea_band_w = max(4, width // 7) # 增加海域宽度
sea_x0 = width - sea_band_w
sea_tiles: List[Tuple[int, int]] = []
for y in range(height):
for x in range(sea_x0, width):
game_map.create_tile(x, y, TileType.SEA)
sea_tiles.append((x, y))
# 岛屿:在海域内生成若干小岛(平原/森林)
for _ in range(random.randint(4, 7)): # 增加岛屿数量
cx = random.randint(sea_x0, width - 2)
cy = random.randint(1, height - 2)
r = random.randint(1, 3) # 增加岛屿半径
kind = random.choice([TileType.PLAIN, TileType.FOREST])
for x, y in circle_points(cx, cy, r, width, height):
if x >= sea_x0:
game_map.create_tile(x, y, kind)
# 6) 若干湖泊(水域圆斑,限制在中部非海域)
for _ in range(random.randint(4, 7)): # 增加湖泊数量
cx = random.randint(max(2, desert_w + 1), sea_x0 - 2)
cy = random.randint(north_band + 1, height - south_band - 2)
r = random.randint(1, 4) # 增加湖泊半径
for x, y in circle_points(cx, cy, r, width, height):
if x < sea_x0:
game_map.create_tile(x, y, TileType.WATER)
# 7) 中部山脉:聚集成为横向山脉群(避开海域和上下带,左移)
mountain_tiles: List[Tuple[int, int]] = []
# 左移山脉生成范围,从沙漠边缘开始,但不要延伸到太右边
mountain_end_x = sea_x0 - max(5, width // 10) # 留出更多空间给东部
# 选择山脉中心区域,让山脉在这个区域内聚集
mountain_center_x = (desert_w + mountain_end_x) // 2
mountain_center_y = (north_band + height - south_band) // 2
# 生成多条横向山脉链,形成山脉群
mountain_chains = random.randint(3, 5) # 3-5条山脉链
for chain in range(mountain_chains):
# 每条山脉链的起始位置在中心区域附近
start_x = mountain_center_x + random.randint(-3, 3)
start_y = mountain_center_y + random.randint(-2, 2)
# 山脉链长度
chain_length = random.randint(12, 20) # 增加山脉长度
# 主要方向:横向为主,允许小幅上下摆动
main_dx = 1 if random.random() < 0.5 else -1 # 主要横向方向
main_dy = 0 # 主要垂直方向为0
x, y = start_x, start_y
for step in range(chain_length):
if 0 <= x < mountain_end_x and north_band <= y < height - south_band:
game_map.create_tile(x, y, TileType.MOUNTAIN)
mountain_tiles.append((x, y))
# 随机添加分支山脉,增加聚集效果
if random.random() < 0.3:
branch_length = random.randint(2, 6)
bx, by = x, y
for _ in range(branch_length):
# 分支方向:倾向于向中心聚集
if bx < mountain_center_x:
branch_dx = random.choice([0, 1])
elif bx > mountain_center_x:
branch_dx = random.choice([0, -1])
else:
branch_dx = random.choice([-1, 0, 1])
if by < mountain_center_y:
branch_dy = random.choice([0, 1])
elif by > mountain_center_y:
branch_dy = random.choice([0, -1])
else:
branch_dy = random.choice([-1, 0, 1])
bx += branch_dx
by += branch_dy
if (0 <= bx < mountain_end_x and north_band <= by < height - south_band and
(bx, by) not in mountain_tiles):
game_map.create_tile(bx, by, TileType.MOUNTAIN)
mountain_tiles.append((bx, by))
# 主要方向移动
x += main_dx
# 垂直方向:允许小幅摆动,但倾向于回归中心线
if random.random() < 0.7: # 70%概率向中心回归
if y > mountain_center_y:
y -= 1
elif y < mountain_center_y:
y += 1
else: # 30%概率随机摆动
y += random.choice([-1, 0, 1])
# 确保y在有效范围内
y = max(north_band, min(height - south_band - 1, y))
# 8) 中部森林:几个圆斑(调整范围与山脉一致)
for _ in range(random.randint(5, 9)): # 增加森林数量
cx = random.randint(desert_w + 1, mountain_end_x - 2)
cy = random.randint(north_band + 1, height - south_band - 2)
r = random.randint(2, 5) # 增加森林半径
for x, y in circle_points(cx, cy, r, width, height):
game_map.create_tile(x, y, TileType.FOREST)
# 8.5) 火山:在中央山脉附近生成一个火山
volcano_tiles: List[Tuple[int, int]] = []
# 在中央山脉的边缘附近生成火山,避免覆盖重要山脉
# 选择山脉区域的边缘位置
volcano_edge_choices = []
# 检查山脉区域的四个边缘
if mountain_center_x > desert_w + 5: # 左边缘
volcano_edge_choices.append((mountain_center_x - 3, mountain_center_y))
if mountain_center_x < mountain_end_x - 5: # 右边缘
volcano_edge_choices.append((mountain_center_x + 3, mountain_center_y))
if mountain_center_y > north_band + 5: # 上边缘
volcano_edge_choices.append((mountain_center_x, mountain_center_y - 3))
if mountain_center_y < height - south_band - 5: # 下边缘
volcano_edge_choices.append((mountain_center_x, mountain_center_y + 3))
# 如果没有合适的边缘位置,选择山脉区域内的非山脉位置
if not volcano_edge_choices:
for attempt in range(10):
vx = mountain_center_x + random.randint(-4, 4)
vy = mountain_center_y + random.randint(-4, 4)
if (0 <= vx < mountain_end_x and north_band <= vy < height - south_band and
game_map.get_tile(vx, vy).type != TileType.MOUNTAIN):
volcano_edge_choices.append((vx, vy))
break
# 如果还是没有找到合适位置,就在山脉中心附近找一个
if not volcano_edge_choices:
volcano_edge_choices.append((mountain_center_x, mountain_center_y))
# 选择火山位置
volcano_center_x, volcano_center_y = random.choice(volcano_edge_choices)
volcano_radius = random.randint(2, 3) # 减小火山半径
# 生成火山,但避免覆盖重要的山脉
for x, y in circle_points(volcano_center_x, volcano_center_y, volcano_radius, width, height):
if (0 <= x < mountain_end_x and north_band <= y < height - south_band):
current_tile = game_map.get_tile(x, y)
# 只在非山脉地形上生成火山,或者在山脉边缘生成
if current_tile.type != TileType.MOUNTAIN or random.random() < 0.3:
game_map.create_tile(x, y, TileType.VOLCANO)
volcano_tiles.append((x, y))
# 8.6) 草原:在平原区域生成一些草原
grassland_tiles: List[Tuple[int, int]] = []
for _ in range(random.randint(4, 7)): # 增加草原数量
cx = random.randint(desert_w + 1, mountain_end_x - 2)
cy = random.randint(north_band + 1, height - south_band - 2)
r = random.randint(2, 5) # 增加草原半径
for x, y in circle_points(cx, cy, r, width, height):
if x < sea_x0:
current_tile = game_map.get_tile(x, y)
if current_tile.type == TileType.PLAIN: # 只在平原上生成草原
game_map.create_tile(x, y, TileType.GRASSLAND)
grassland_tiles.append((x, y))
# 8.7) 沼泽:在水域附近生成一些沼泽
swamp_tiles: List[Tuple[int, int]] = []
for _ in range(random.randint(3, 6)): # 增加沼泽数量
cx = random.randint(desert_w + 1, sea_x0 - 2)
cy = random.randint(north_band + 1, height - south_band - 2)
r = random.randint(1, 3) # 增加沼泽半径
for x, y in circle_points(cx, cy, r, width, height):
if x < sea_x0:
# 检查周围是否有水域
has_water_nearby = False
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
nx, ny = x + dx, y + dy
if game_map.is_in_bounds(nx, ny):
nearby_tile = game_map.get_tile(nx, ny)
if nearby_tile.type in (TileType.WATER, TileType.SEA):
has_water_nearby = True
break
if has_water_nearby:
break
if has_water_nearby:
current_tile = game_map.get_tile(x, y)
if current_tile.type in (TileType.PLAIN, TileType.GRASSLAND):
game_map.create_tile(x, y, TileType.SWAMP)
swamp_tiles.append((x, y))
# 8.8) 洞穴:在山脉附近生成一些洞穴
cave_tiles: List[Tuple[int, int]] = []
for _ in range(random.randint(3, 6)): # 增加洞穴数量
cx = random.randint(desert_w + 1, mountain_end_x - 1)
cy = random.randint(north_band + 1, height - south_band - 2)
# 检查周围是否有山脉
has_mountain_nearby = False
for dx in [-2, -1, 0, 1, 2]:
for dy in [-2, -1, 0, 1, 2]:
nx, ny = cx + dx, cy + dy
if game_map.is_in_bounds(nx, ny):
nearby_tile = game_map.get_tile(nx, ny)
if nearby_tile.type == TileType.MOUNTAIN:
has_mountain_nearby = True
break
if has_mountain_nearby:
break
if has_mountain_nearby:
current_tile = game_map.get_tile(cx, cy)
if current_tile.type in (TileType.PLAIN, TileType.GRASSLAND):
game_map.create_tile(cx, cy, TileType.CAVE)
cave_tiles.append((cx, cy))
# 8.9) 遗迹:随机在一些地方生成古代遗迹
ruins_tiles: List[Tuple[int, int]] = []
for _ in range(random.randint(3, 5)): # 增加遗迹数量
cx = random.randint(desert_w + 1, sea_x0 - 2)
cy = random.randint(north_band + 1, height - south_band - 2)
current_tile = game_map.get_tile(cx, cy)
if current_tile.type in (TileType.PLAIN, TileType.GRASSLAND, TileType.DESERT):
game_map.create_tile(cx, cy, TileType.RUINS)
ruins_tiles.append((cx, cy))
# 9) 城市2~4个2x2格子尽量落在非极端地形
cities = 0
attempts = 0
city_positions = [] # 记录城市位置用于后续生成农田
city_tiles = [] # 记录所有城市格子
while cities < random.randint(2, 4) and attempts < 300: # 增加尝试次数
attempts += 1
# 选择城市左上角位置
x = random.randint(0, width - 2) # 确保有2x2的空间
y = random.randint(0, height - 2)
# 检查2x2区域是否都适合建城
can_build_city = True
for dx in range(2):
for dy in range(2):
nx, ny = x + dx, y + dy
if not game_map.is_in_bounds(nx, ny):
can_build_city = False
break
t = game_map.get_tile(nx, ny)
if t.type in (TileType.WATER, TileType.SEA, TileType.MOUNTAIN, TileType.GLACIER,
TileType.SNOW_MOUNTAIN, TileType.DESERT, TileType.VOLCANO, TileType.SWAMP,
TileType.CAVE, TileType.RUINS):
can_build_city = False
break
if not can_build_city:
break
if can_build_city:
# 创建2x2城市
city_tiles_for_this_city = []
for dx in range(2):
for dy in range(2):
nx, ny = x + dx, y + dy
game_map.create_tile(nx, ny, TileType.CITY)
city_tiles_for_this_city.append((nx, ny))
city_tiles.append((nx, ny))
city_positions.append((x, y)) # 记录左上角位置
cities += 1
# 8.10) 农田:在城市附近生成一些农田
farm_tiles: List[Tuple[int, int]] = []
# 在每个城市周围生成农田
for city_x, city_y in city_positions:
for _ in range(random.randint(4, 8)): # 增加农田数量
# 在城市周围3-6格范围内生成农田
fx = city_x + random.randint(-6, 6)
fy = city_y + random.randint(-6, 6)
if game_map.is_in_bounds(fx, fy):
current_tile = game_map.get_tile(fx, fy)
if current_tile.type in (TileType.PLAIN, TileType.GRASSLAND):
game_map.create_tile(fx, fy, TileType.FARM)
farm_tiles.append((fx, fy))
# 9.5) 生成一条横贯东西的长河(允许小幅上下摆动与随机加宽,避开沙漠和大海)
river_tiles: List[Tuple[int, int]] = []
# 选一条靠近中部的基准纬线,避开极北/极南带
base_y = clamp(height // 2 + random.randint(-3, 3), north_band + 2, height - south_band - 3)
y = base_y
# 确保河流从西边开始,到东边结束,不断流
for x in range(0, width):
# 检查当前位置是否为沙漠或大海,如果是则跳过
current_tile = game_map.get_tile(x, y)
if current_tile.type in (TileType.DESERT, TileType.SEA):
continue
# 开凿主河道
game_map.create_tile(x, y, TileType.WATER)
river_tiles.append((x, y))
# 随机加宽 1-2 格(上下其一或两个),但要避开沙漠和大海
if random.random() < 0.6: # 增加加宽概率
# 选择加宽方向
wide_directions = []
if y > 0:
wide_tile = game_map.get_tile(x, y - 1)
if wide_tile.type not in (TileType.DESERT, TileType.SEA):
wide_directions.append(-1)
if y < height - 1:
wide_tile = game_map.get_tile(x, y + 1)
if wide_tile.type not in (TileType.DESERT, TileType.SEA):
wide_directions.append(1)
# 随机选择1-2个方向加宽
if wide_directions:
num_wide = random.randint(1, min(2, len(wide_directions)))
selected_directions = random.sample(wide_directions, num_wide)
for dy in selected_directions:
wy = y + dy
game_map.create_tile(x, wy, TileType.WATER)
river_tiles.append((x, wy))
# 轻微摆动(-1, 0, 1并缓慢回归基准线
drift_choices = [-1, 0, 1]
dy = random.choice(drift_choices)
# 回归力:偏离过大时更倾向于向 base_y 靠拢
if y - base_y > 3:
dy = -1 if random.random() < 0.8 else dy
elif base_y - y > 3:
dy = 1 if random.random() < 0.8 else dy
y = clamp(y + dy, north_band + 1, height - south_band - 2)
# 11) 聚类函数:用于后续命名山脉/森林
def find_type_clusters(tile_type: TileType) -> list[list[Tuple[int, int]]]:
visited: set[Tuple[int, int]] = set()
clusters: list[list[Tuple[int, int]]] = []
for (tx, ty), t in game_map.tiles.items():
if t.type is not tile_type or (tx, ty) in visited:
continue
stack = [(tx, ty)]
visited.add((tx, ty))
comp: list[Tuple[int, int]] = []
while stack:
cx, cy = stack.pop()
comp.append((cx, cy))
for nx, ny in ((cx + 1, cy), (cx - 1, cy), (cx, cy + 1), (cx, cy - 1)):
if not game_map.is_in_bounds(nx, ny) or (nx, ny) in visited:
continue
tt = game_map.get_tile(nx, ny)
if tt.type is tile_type:
visited.add((nx, ny))
stack.append((nx, ny))
clusters.append(comp)
return clusters
# 高山:阈值较低,便于更多命名;森林:阈值更高,避免碎片
all_mountain_clusters = find_type_clusters(TileType.MOUNTAIN)
mountain_clusters = [c for c in all_mountain_clusters if len(c) >= 8]
forest_clusters = [c for c in find_type_clusters(TileType.FOREST) if len(c) >= 12]
# 组装所有地理信息到一个统一的配置 dict
regions_cfg: List[Dict[str, Any]] = []
if desert_tiles:
regions_cfg.append({
"name": "大漠",
"description": "西部荒漠地带",
"essence": Essence(density={
EssenceType.EARTH: 8,
EssenceType.FIRE: 6,
EssenceType.GOLD: 4,
EssenceType.WOOD: 2,
EssenceType.WATER: 1
}),
"tiles": desert_tiles
})
if sea_tiles:
regions_cfg.append({
"name": "东海",
"description": "最东边的大海",
"essence": Essence(density={
EssenceType.WATER: 10,
EssenceType.EARTH: 3,
EssenceType.GOLD: 2,
EssenceType.WOOD: 1,
EssenceType.FIRE: 1
}),
"tiles": sea_tiles
})
if rainforest_tiles:
regions_cfg.append({
"name": "南疆雨林",
"description": "南部潮湿炎热的雨林",
"essence": Essence(density={
EssenceType.WOOD: 9,
EssenceType.WATER: 7,
EssenceType.FIRE: 5,
EssenceType.EARTH: 3,
EssenceType.GOLD: 2
}),
"tiles": rainforest_tiles
})
if river_tiles:
regions_cfg.append({
"name": "大河",
"description": "发源内陆,奔流入海",
"essence": Essence(density={
EssenceType.WATER: 8,
EssenceType.EARTH: 4,
EssenceType.WOOD: 3,
EssenceType.GOLD: 2,
EssenceType.FIRE: 1
}),
"tiles": river_tiles
})
# 添加山脉region提高金属性灵气
if mountain_tiles:
regions_cfg.append({
"name": "中央山脉",
"description": "横贯大陆的中央山脉,蕴含丰富的金属性灵气",
"essence": Essence(density={
EssenceType.GOLD: 10, # 提高金属性灵气
EssenceType.EARTH: 9,
EssenceType.FIRE: 5,
EssenceType.WATER: 3,
EssenceType.WOOD: 2
}),
"tiles": mountain_tiles
})
# 添加雪山region
if snow_mountain_tiles:
regions_cfg.append({
"name": "北境雪山",
"description": "北部终年积雪的高山地带",
"essence": Essence(density={
EssenceType.WATER: 9,
EssenceType.EARTH: 8,
EssenceType.GOLD: 6,
EssenceType.FIRE: 2,
EssenceType.WOOD: 1
}),
"tiles": snow_mountain_tiles
})
# 添加冰川region
if glacier_tiles:
regions_cfg.append({
"name": "极地冰川",
"description": "北部极寒的冰川地带",
"essence": Essence(density={
EssenceType.WATER: 10,
EssenceType.EARTH: 7,
EssenceType.GOLD: 5,
EssenceType.FIRE: 1,
EssenceType.WOOD: 1
}),
"tiles": glacier_tiles
})
# 添加火山region火属性灵气最高
if volcano_tiles:
regions_cfg.append({
"name": "火山",
"description": "活跃的火山地带,火属性灵气极其浓郁",
"essence": Essence(density={
EssenceType.FIRE: 10, # 火属性灵气最高
EssenceType.EARTH: 8,
EssenceType.GOLD: 6,
EssenceType.WATER: 2,
EssenceType.WOOD: 1
}),
"tiles": volcano_tiles
})
# 添加草原region
if grassland_tiles:
regions_cfg.append({
"name": "青青草原",
"description": "广阔的草原地带,适合放牧和修炼",
"essence": Essence(density={
EssenceType.WOOD: 7,
EssenceType.EARTH: 6,
EssenceType.WATER: 5,
EssenceType.FIRE: 3,
EssenceType.GOLD: 2
}),
"tiles": grassland_tiles
})
# 添加沼泽region
if swamp_tiles:
regions_cfg.append({
"name": "迷雾沼泽",
"description": "危险的沼泽地带,瘴气弥漫但蕴含特殊灵药",
"essence": Essence(density={
EssenceType.WATER: 8,
EssenceType.WOOD: 6,
EssenceType.EARTH: 5,
EssenceType.FIRE: 3,
EssenceType.GOLD: 2
}),
"tiles": swamp_tiles
})
# 添加洞穴region
if cave_tiles:
regions_cfg.append({
"name": "神秘洞穴",
"description": "隐藏在山脉中的神秘洞穴,可能藏有宝物",
"essence": Essence(density={
EssenceType.EARTH: 9,
EssenceType.GOLD: 8,
EssenceType.FIRE: 4,
EssenceType.WATER: 3,
EssenceType.WOOD: 2
}),
"tiles": cave_tiles
})
# 添加遗迹region
if ruins_tiles:
regions_cfg.append({
"name": "古代遗迹",
"description": "上古时代留下的神秘遗迹,蕴含古老的力量",
"essence": Essence(density={
EssenceType.GOLD: 9,
EssenceType.EARTH: 7,
EssenceType.FIRE: 6,
EssenceType.WATER: 5,
EssenceType.WOOD: 4
}),
"tiles": ruins_tiles
})
# 添加农田region
if farm_tiles:
regions_cfg.append({
"name": "良田",
"description": "肥沃的农田,为城市提供粮食",
"essence": Essence(density={
EssenceType.WOOD: 8,
EssenceType.EARTH: 7,
EssenceType.WATER: 6,
EssenceType.FIRE: 3,
EssenceType.GOLD: 2
}),
"tiles": farm_tiles
})
# 添加城市region
if city_tiles:
# 为每个城市创建单独的region
city_names = ["长安", "洛阳", "建康", "临安", "大都", "金陵", "燕京", "成都"]
city_name_index = 0
# 按城市位置分组
city_groups = []
used_positions = set()
for city_x, city_y in city_positions:
if (city_x, city_y) not in used_positions:
# 收集这个2x2城市的所有格子
city_group = []
for dx in range(2):
for dy in range(2):
nx, ny = city_x + dx, city_y + dy
city_group.append((nx, ny))
used_positions.add((nx, ny))
city_groups.append(city_group)
# 为每个城市创建region
for i, city_group in enumerate(city_groups):
if i < len(city_names):
city_name = city_names[i]
else:
city_name = f"城市{i+1}"
regions_cfg.append({
"name": city_name,
"description": f"繁华的都市,人口密集,商业繁荣",
"essence": Essence(density={
EssenceType.GOLD: 9, # 城市金属性灵气最高
EssenceType.FIRE: 8, # 火属性(人气)也很高
EssenceType.EARTH: 7,
EssenceType.WOOD: 6,
EssenceType.WATER: 5
}),
"tiles": city_group
})
for i, comp in enumerate(sorted(mountain_clusters, key=len, reverse=True), start=1):
regions_cfg.append({
"name": f"高山{i}",
"description": "山脉与高峰地带",
"essence": Essence(density={
EssenceType.EARTH: 9,
EssenceType.GOLD: 7,
EssenceType.FIRE: 4,
EssenceType.WATER: 3,
EssenceType.WOOD: 2
}),
"tiles": comp
})
for i, comp in enumerate(sorted(forest_clusters, key=len, reverse=True), start=1):
regions_cfg.append({
"name": f"大林{i}",
"description": "茂密幽深的森林",
"essence": Essence(density={
EssenceType.WOOD: 8,
EssenceType.EARTH: 5,
EssenceType.WATER: 4,
EssenceType.FIRE: 2,
EssenceType.GOLD: 1
}),
"tiles": comp
})
# 应用配置创建 Region并把配置存到 map 上,方便前端/后续逻辑使用
for r in regions_cfg:
game_map.create_region(r["name"], r["description"], r["essence"], r["tiles"])
geo_config: Dict[str, Any] = {"regions": regions_cfg}
setattr(game_map, "geo_config", geo_config)
return game_map
def random_gender() -> Gender:
return Gender.MALE if random.random() < 0.5 else Gender.FEMALE
@@ -760,10 +90,8 @@ def make_avatars(world: World, count: int = 12, current_year: Year = Year(100))
def main():
# 为了每次更丰富,使用随机种子;如需复现可将 seed 固定
# random.seed(42)
width, height = 50, 35 # 使用新的默认尺寸
game_map = build_rich_random_map(width=width, height=height)
game_map = create_cultivation_world_map()
world = World(map=game_map)
# 设置模拟器从第100年开始
@@ -776,7 +104,7 @@ def main():
front = Front(
simulator=sim,
tile_size=24, # 稍微减小tile大小以适应更大的地图
tile_size=19, # 减小20%的tile大小 (24 * 0.8 ≈ 19)
margin=8,
step_interval_ms=350,
window_title="Cultivation World — Front Demo",

View File

@@ -505,8 +505,8 @@ class Front:
image_path = os.path.join(male_dir, filename)
try:
image = pygame.image.load(image_path)
# 调大一倍的头像大小
avatar_size = max(32, self.tile_size * 4 // 3)
# 调整头像大小减小20%
avatar_size = max(26, int(self.tile_size * 4 // 3 * 0.8))
scaled_image = pygame.transform.scale(image, (avatar_size, avatar_size))
self.male_avatars.append(scaled_image)
except pygame.error:
@@ -521,8 +521,8 @@ class Front:
image_path = os.path.join(female_dir, filename)
try:
image = pygame.image.load(image_path)
# 调大一倍的头像大小
avatar_size = max(32, self.tile_size * 4 // 3)
# 调整头像大小减小20%
avatar_size = max(26, int(self.tile_size * 4 // 3 * 0.8))
scaled_image = pygame.transform.scale(image, (avatar_size, avatar_size))
self.female_avatars.append(scaled_image)
except pygame.error: