Update world.py

main
Rihards Ševčuks 2026-02-25 06:29:41 +00:00
parent 1fbbb94f20
commit ed1bad98d8
1 changed files with 120 additions and 32 deletions

152
world.py
View File

@ -1,9 +1,63 @@
import pygame import pygame
import random import random
import math
from settings import * from settings import *
from tiles import get_tile 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: class World:
def __init__(self): def __init__(self):
self.width = WORLD_WIDTH self.width = WORLD_WIDTH
@ -18,31 +72,27 @@ class World:
self.generate_world() self.generate_world()
# ========================================================== # ==========================================================
# WORLD GENERATION # WORLD GENERATION - FLAT WITH TREES
# ========================================================== # ==========================================================
def generate_world(self): def generate_world(self):
# First generate terrain """Generate flat world with trees"""
# Create flat surface at SURFACE_LEVEL
for x in range(self.width): for x in range(self.width):
# Simple terrain height variation
surface_height = SURFACE_LEVEL + random.randint(-3, 3)
for y in range(self.height): for y in range(self.height):
if y < SURFACE_LEVEL:
if y < surface_height:
self.grid[y][x] = AIR self.grid[y][x] = AIR
elif y == SURFACE_LEVEL:
elif y == surface_height:
self.grid[y][x] = GRASS self.grid[y][x] = GRASS
elif y < SURFACE_LEVEL + 5:
elif y < surface_height + 5:
self.grid[y][x] = DIRT self.grid[y][x] = DIRT
else: else:
self.grid[y][x] = STONE self.grid[y][x] = STONE
# Then add trees + ores # Add trees (more frequently)
self.generate_trees() self.generate_trees()
# Add ores
self.generate_ores() self.generate_ores()
# ========================================================== # ==========================================================
@ -63,7 +113,7 @@ class World:
tile_id = self.grid[y][x] tile_id = self.grid[y][x]
if tile_id != AIR: if tile_id != AIR:
color = get_tile(tile_id).color # FIXED: no more KeyError color = get_tile(tile_id).color
world_rect = pygame.Rect( world_rect = pygame.Rect(
x * TILE_SIZE, x * TILE_SIZE,
@ -115,11 +165,22 @@ class World:
# ========================================================== # ==========================================================
# BLOCK BREAKING # 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) world_x, world_y = camera.screen_to_world(mouse_pos)
tile_x = int(world_x // TILE_SIZE) tile_x = int(world_x // TILE_SIZE)
tile_y = int(world_y // 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): if self.in_bounds(tile_x, tile_y):
tile_id = self.grid[tile_y][tile_x] tile_id = self.grid[tile_y][tile_x]
tile = get_tile(tile_id) tile = get_tile(tile_id)
@ -127,20 +188,39 @@ class World:
if tile_id != AIR: if tile_id != AIR:
if tile.drop: if tile.drop:
inventory.add_item(tile.drop, 1) inventory.add_item(tile.drop, 1)
print(f"DEBUG: Broke {tile.name}, added {tile.drop} to inventory")
self.grid[tile_y][tile_x] = AIR self.grid[tile_y][tile_x] = AIR
return True
return False
# ========================================================== # ==========================================================
# BLOCK PLACING # 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) world_x, world_y = camera.screen_to_world(mouse_pos)
tile_x = int(world_x // TILE_SIZE) tile_x = int(world_x // TILE_SIZE)
tile_y = int(world_y // 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.in_bounds(tile_x, tile_y):
if self.grid[tile_y][tile_x] == AIR: if self.grid[tile_y][tile_x] == AIR:
self.grid[tile_y][tile_x] = block_type self.grid[tile_y][tile_x] = block_type
print(f"DEBUG: Placed block at {tile_x}, {tile_y}")
return True
return False
# ========================================================== # ==========================================================
# UTIL # UTIL
@ -149,7 +229,7 @@ class World:
return 0 <= x < self.width and 0 <= y < self.height 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): def get_surface_height(self, x):
for y in range(self.height): for y in range(self.height):
@ -158,29 +238,29 @@ class World:
return self.height - 1 return self.height - 1
# ========================================================== # ==========================================================
# TREE GENERATION # TREE GENERATION - MORE TREES
# ========================================================== # ==========================================================
def generate_trees(self): def generate_trees(self):
for x in range(0, self.width, 6): # Generate trees more frequently (every 4 tiles)
if random.random() < 0.25: # 25% chance for x in range(0, self.width, 4):
# find surface if random.random() < 0.6: # 60% chance for trees
for y in range(self.height): surface_y = SURFACE_LEVEL
if self.grid[y][x] == GRASS: if 0 <= x < self.width:
self.spawn_tree(x, y) self.spawn_tree(x, surface_y)
break
def spawn_tree(self, x, surface_y): def spawn_tree(self, x, surface_y):
# trunk height # trunk height
height = random.randint(4, 7) height = random.randint(5, 8)
for i in range(height): 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 leaf_start = surface_y - height - 1
for y in range(leaf_start, leaf_start - 4, -1): for y in range(leaf_start, leaf_start - 5, -1):
for lx in range(x - 2, x + 3): for lx in range(x - 3, x + 4):
if 0 <= lx < self.width and 0 <= y < self.height: 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 self.grid[y][lx] = LEAVES
# ========================================================== # ==========================================================
@ -201,3 +281,11 @@ class World:
self.grid[y][x] = IRON_ORE self.grid[y][x] = IRON_ORE
else: else:
self.grid[y][x] = GOLD_ORE 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