Update world.py
parent
1fbbb94f20
commit
ed1bad98d8
150
world.py
150
world.py
|
|
@ -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):
|
||||||
|
if surface_y - 1 - i >= 0:
|
||||||
self.grid[surface_y - 1 - i][x] = WOOD
|
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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue