diff --git a/world.py b/world.py index 3b25162..8f51484 100644 --- a/world.py +++ b/world.py @@ -1,9 +1,63 @@ import pygame import random +import math from settings import * from tiles import get_tile +# Perlin noise implementation +def perlin_fade(t): + """Fade function for Perlin noise""" + return t * t * t * (t * (t * 6 - 15) + 10) + + +def perlin_lerp(t, a, b): + """Linear interpolation""" + return a + t * (b - a) + + +def perlin_noise_1d(x, seed=42): + """Simple 1D Perlin-like noise""" + xi = int(x) & 0xFF + xf = x - int(x) + + u = perlin_fade(xf) + + # Generate consistent random values + random.seed(seed + xi) + a = random.random() + random.seed(seed + xi + 1) + b = random.random() + + return perlin_lerp(u, a, b) + + +def generate_noise_map(width, height, scale=50, octaves=4, seed=42): + """Generate a noise map using Perlin-like noise""" + noise_map = [[0.0 for _ in range(width)] for _ in range(height)] + + for y in range(height): + for x in range(width): + value = 0.0 + amplitude = 1.0 + frequency = 1.0 + max_value = 0.0 + + for i in range(octaves): + sample_x = (x / scale) * frequency + noise = perlin_noise_1d(sample_x + (y * 73 * frequency), seed + i * 256) + + value += noise * amplitude + max_value += amplitude + + amplitude *= 0.5 + frequency *= 2.0 + + noise_map[y][x] = value / max_value if max_value > 0 else 0.0 + + return noise_map + + class World: def __init__(self): self.width = WORLD_WIDTH @@ -18,31 +72,27 @@ class World: self.generate_world() # ========================================================== - # WORLD GENERATION + # WORLD GENERATION - FLAT WITH TREES # ========================================================== def generate_world(self): - # First generate terrain + """Generate flat world with trees""" + + # Create flat surface at SURFACE_LEVEL for x in range(self.width): - - # Simple terrain height variation - surface_height = SURFACE_LEVEL + random.randint(-3, 3) - for y in range(self.height): - - if y < surface_height: + if y < SURFACE_LEVEL: self.grid[y][x] = AIR - - elif y == surface_height: + elif y == SURFACE_LEVEL: self.grid[y][x] = GRASS - - elif y < surface_height + 5: + elif y < SURFACE_LEVEL + 5: self.grid[y][x] = DIRT - else: self.grid[y][x] = STONE - # Then add trees + ores + # Add trees (more frequently) self.generate_trees() + + # Add ores self.generate_ores() # ========================================================== @@ -63,7 +113,7 @@ class World: tile_id = self.grid[y][x] if tile_id != AIR: - color = get_tile(tile_id).color # FIXED: no more KeyError + color = get_tile(tile_id).color world_rect = pygame.Rect( x * TILE_SIZE, @@ -115,11 +165,22 @@ class World: # ========================================================== # BLOCK BREAKING # ========================================================== - def break_block(self, mouse_pos, camera, inventory): + def break_block(self, mouse_pos, camera, inventory, player_rect): + """Break block at mouse position if in range""" world_x, world_y = camera.screen_to_world(mouse_pos) tile_x = int(world_x // TILE_SIZE) tile_y = int(world_y // TILE_SIZE) + # Check if in range + distance = math.sqrt( + (tile_x * TILE_SIZE - player_rect.centerx) ** 2 + + (tile_y * TILE_SIZE - player_rect.centery) ** 2 + ) + + if distance > BREAK_RANGE * TILE_SIZE: + print(f"DEBUG: Block too far away! Distance: {distance}, Max: {BREAK_RANGE * TILE_SIZE}") + return False + if self.in_bounds(tile_x, tile_y): tile_id = self.grid[tile_y][tile_x] tile = get_tile(tile_id) @@ -127,20 +188,39 @@ class World: if tile_id != AIR: if tile.drop: inventory.add_item(tile.drop, 1) + print(f"DEBUG: Broke {tile.name}, added {tile.drop} to inventory") self.grid[tile_y][tile_x] = AIR + return True + + return False # ========================================================== # BLOCK PLACING # ========================================================== - def place_block(self, mouse_pos, camera, block_type=DIRT): + def place_block(self, mouse_pos, camera, player_rect, block_type=DIRT): + """Place block at mouse position if in range""" world_x, world_y = camera.screen_to_world(mouse_pos) tile_x = int(world_x // TILE_SIZE) tile_y = int(world_y // TILE_SIZE) + # Check if in range + distance = math.sqrt( + (tile_x * TILE_SIZE - player_rect.centerx) ** 2 + + (tile_y * TILE_SIZE - player_rect.centery) ** 2 + ) + + if distance > PLACE_RANGE * TILE_SIZE: + print(f"DEBUG: Block placement too far away!") + return False + if self.in_bounds(tile_x, tile_y): if self.grid[tile_y][tile_x] == AIR: self.grid[tile_y][tile_x] = block_type + print(f"DEBUG: Placed block at {tile_x}, {tile_y}") + return True + + return False # ========================================================== # UTIL @@ -149,7 +229,7 @@ class World: return 0 <= x < self.width and 0 <= y < self.height # ========================================================== - # NEW: Get surface height for player spawn + # Get surface height for player spawn # ========================================================== def get_surface_height(self, x): for y in range(self.height): @@ -158,29 +238,29 @@ class World: return self.height - 1 # ========================================================== - # TREE GENERATION + # TREE GENERATION - MORE TREES # ========================================================== def generate_trees(self): - for x in range(0, self.width, 6): - if random.random() < 0.25: # 25% chance - # find surface - for y in range(self.height): - if self.grid[y][x] == GRASS: - self.spawn_tree(x, y) - break + # Generate trees more frequently (every 4 tiles) + for x in range(0, self.width, 4): + if random.random() < 0.6: # 60% chance for trees + surface_y = SURFACE_LEVEL + if 0 <= x < self.width: + self.spawn_tree(x, surface_y) def spawn_tree(self, x, surface_y): # trunk height - height = random.randint(4, 7) + height = random.randint(5, 8) for i in range(height): - self.grid[surface_y - 1 - i][x] = WOOD + if surface_y - 1 - i >= 0: + self.grid[surface_y - 1 - i][x] = WOOD - # leaves + # leaves - larger canopy leaf_start = surface_y - height - 1 - for y in range(leaf_start, leaf_start - 4, -1): - for lx in range(x - 2, x + 3): + for y in range(leaf_start, leaf_start - 5, -1): + for lx in range(x - 3, x + 4): if 0 <= lx < self.width and 0 <= y < self.height: - if random.random() > 0.25: + if random.random() > 0.2: # 80% leaf density self.grid[y][lx] = LEAVES # ========================================================== @@ -201,3 +281,11 @@ class World: self.grid[y][x] = IRON_ORE else: self.grid[y][x] = GOLD_ORE + if r < 0.5: + self.grid[y][x] = COAL_ORE + elif r < 0.75: + self.grid[y][x] = COPPER_ORE + elif r < 0.9: + self.grid[y][x] = IRON_ORE + else: + self.grid[y][x] = GOLD_ORE