海洋层生成异常及游戏卡顿问题技术求助
问题修复与性能优化方案
一、海洋覆盖岛屿问题修复
问题根源
当前代码使用独立的海洋噪声和海拔噪声,且海洋判断优先级高于海拔:只要海洋噪声低于阈值,不管该区域海拔有多高,都会被强制设为海洋颜色,直接覆盖了原本应该是岛屿的高海拔地形。
修复方案
取消独立的海洋噪声层,将海洋定义为低于水位线的低海拔区域,用统一的海拔噪声控制地形,确保高海拔区域始终保留为陆地生物群系:
- 删除单独的
noise_ocean变量,复用海拔噪声判断海洋 - 调整海洋判定逻辑:当海拔低于70(对应biomes中water的海拔范围下限)时,直接设为海洋
- 调整生物群系匹配顺序,优先匹配海洋,再处理陆地生物群系
二、游戏卡顿性能优化
卡顿根源
- 每帧重复生成Chunk:游戏循环每帧都重新计算整个Chunk的Perlin噪声,噪声计算属于高开销操作
- 逐块绘制矩形:每帧需要绘制10000个独立矩形,大量的绘图API调用严重拖慢渲染速度
- 无Chunk缓存:玩家移动时重复生成已访问过的Chunk,浪费计算资源
优化方案
- 添加Chunk缓存字典:存储已生成的Chunk数据和预渲染的Surface,避免重复计算
- 预渲染Chunk Surface:每个Chunk生成后,一次性渲染到Surface上,后续只需将Surface blit到屏幕
- 按需生成Chunk:仅当玩家移动跨越Chunk边界时,才加载新的Chunk,而非每帧生成
- 统一噪声种子:为noise库设置固定种子,确保世界生成的一致性
修改后的完整代码
import pygame import random import noise # Initialize Pygame pygame.init() # Screen settings screen_width = 900 screen_height = 600 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("Infinite Scrollable World") # Color palette colors = { "land": (134, 168, 83), # Light green "water": (30, 144, 255), # Deep blue "desert": (244, 164, 96), # Sandy color "mountains": (139, 137, 137), # Gray "snow": (255, 250, 250), # Snow white "forest": (34, 139, 34), # Forest green "swamp": (105, 139, 34), # Swampy green "beach": (238, 214, 175), # Light beige "tundra": (192, 192, 192) # Light gray } # Biome definitions biomes = { "water": {"elevation": (0, 70), "temperature": (0.0, 1.0), "moisture": (0.0, 1.0), "color": colors["water"]}, "beach": {"elevation": (71, 100), "temperature": (0.2, 0.8), "moisture": (0.2, 0.8), "color": colors["beach"]}, "desert": {"temperature": (0.4, 1.0), "moisture": (0.0, 0.3), "elevation": (101, 200), "color": colors["desert"]}, "grassland": {"temperature": (0.2, 0.8), "moisture": (0.2, 0.6), "elevation": (101, 200), "color": colors["land"]}, "forest": {"temperature": (0.0, 0.7), "moisture": (0.5, 1.0), "elevation": (101, 200), "color": colors["forest"]}, "mountains": {"elevation": (201, 255), "temperature": (0.0, 0.5), "moisture": (0.2, 0.8), "color": colors["mountains"]}, "snow": {"temperature": (-1.0, 0.0), "moisture": (0.5, 1.0), "elevation": (256, 300), "color": colors["snow"]}, "swamp": {"temperature": (0.0, 0.7), "moisture": (0.8, 1.0), "elevation": (101, 200), "color": colors["swamp"]}, "tundra": {"temperature": (-1.0, 0.5), "moisture": (0.3, 0.6), "elevation": (201, 255), "color": colors["tundra"]} } # Chunk cache: key is (chunk_x, chunk_y), value is (surface, data) chunk_cache = {} tile_size = 10 # Generate a single chunk and pre-render its surface def generate_chunk(chunk_coord_x, chunk_coord_y, chunk_size): # Calculate world coordinates for the chunk world_x_start = chunk_coord_x * chunk_size world_y_start = chunk_coord_y * chunk_size # Create surface for the chunk chunk_surface = pygame.Surface((chunk_size * tile_size, chunk_size * tile_size)) chunk_data = [] for y in range(chunk_size): row = [] world_y = world_y_start + y for x in range(chunk_size): world_x = world_x_start + x # Combine multiple Perlin noise layers noise_elevation = noise.snoise2(world_x * 0.005, world_y * 0.005, octaves=4) noise_temperature = noise.snoise2(world_x * 0.01, world_y * 0.01, octaves=4) noise_moisture = noise.snoise2(world_x * 0.015, world_y * 0.015, octaves=4) elevation = int((noise_elevation + 1) * 128) temperature = min(max(noise_temperature, -1.0), 1.0) moisture = min(max(noise_moisture, -1.0), 1.0) # Assign biome based on elevation, temperature, and moisture color = colors["water"] # Default to water if elevation > biomes["water"]["elevation"][1]: # Match land biomes for biome_name, info in biomes.items(): if biome_name == "water": continue if (elevation >= info["elevation"][0] and elevation <= info["elevation"][1] and temperature >= info["temperature"][0] and temperature <= info["temperature"][1] and moisture >= info["moisture"][0] and moisture <= info["moisture"][1]): color = info["color"] break row.append((elevation, color)) # Draw tile to chunk surface pygame.draw.rect(chunk_surface, color, pygame.Rect(x*tile_size, y*tile_size, tile_size, tile_size)) chunk_data.append(row) return chunk_surface, chunk_data # Function to generate a new random seed for world generation def generate_new_seed(): return random.randint(0, 1000000) # Player movement variables player_x = screen_width // 2 player_y = screen_height // 2 scroll_speed = 5 # World generation parameters chunk_size = 100 # Current visible chunk coordinates current_chunks = set() # Set initial random seed for world generation random_seed = generate_new_seed() random.seed(random_seed) noise.seed(random_seed) # Set seed for noise library too # Game loop running = True clock = pygame.time.Clock() while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_n: # Press "N" key to generate a new world random_seed = generate_new_seed() random.seed(random_seed) noise.seed(random_seed) chunk_cache.clear() # Clear old chunks print(f"Generating new world with seed: {random_seed}") # Player movement keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: player_x -= scroll_speed if keys[pygame.K_RIGHT]: player_x += scroll_speed if keys[pygame.K_UP]: player_y -= scroll_speed if keys[pygame.K_DOWN]: player_y += scroll_speed # Calculate which chunks are visible visible_chunk_x_min = (player_x - screen_width//2) // (chunk_size * tile_size) visible_chunk_x_max = (player_x + screen_width//2) // (chunk_size * tile_size) visible_chunk_y_min = (player_y - screen_height//2) // (chunk_size * tile_size) visible_chunk_y_max = (player_y + screen_height//2) // (chunk_size * tile_size) # Load visible chunks new_current_chunks = set() for chunk_x in range(visible_chunk_x_min - 1, visible_chunk_x_max + 2): for chunk_y in range(visible_chunk_y_min - 1, visible_chunk_y_max + 2): chunk_key = (chunk_x, chunk_y) new_current_chunks.add(chunk_key) if chunk_key not in chunk_cache: # Generate new chunk if not in cache chunk_surface, chunk_data = generate_chunk(chunk_x, chunk_y, chunk_size) chunk_cache[chunk_key] = (chunk_surface, chunk_data) current_chunks = new_current_chunks # Clear screen and draw visible chunks screen.fill((0, 0, 0)) for chunk_x, chunk_y in current_chunks: chunk_surface, _ = chunk_cache[(chunk_x, chunk_y)] # Calculate position on screen screen_x = chunk_x * chunk_size * tile_size - (player_x - screen_width//2) screen_y = chunk_y * chunk_size * tile_size - (player_y - screen_height//2) screen.blit(chunk_surface, (screen_x, screen_y)) # Update display pygame.display.flip() clock.tick(60) pygame.quit()
内容的提问来源于stack exchange,提问作者Nery Lemus Salguero - Student
相关产品推荐
相关产品推荐

