diff --git a/create_map.py b/create_map.py new file mode 100644 index 0000000..2baa481 --- /dev/null +++ b/create_map.py @@ -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}个地块") diff --git a/run.py b/run.py index c147ed3..8de23b7 100644 --- a/run.py +++ b/run.py @@ -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", diff --git a/src/front/front.py b/src/front/front.py index 2adc244..506171a 100644 --- a/src/front/front.py +++ b/src/front/front.py @@ -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: