133 lines
3.6 KiB
Python
133 lines
3.6 KiB
Python
import pygame
|
|
import json, math
|
|
from . import assets, dungeon, level, rand, sprite, tiles
|
|
from .sprite import Sprite
|
|
from .tiles import Tile
|
|
from .vector import *
|
|
|
|
class Map:
|
|
map = []
|
|
sprites = []
|
|
generators = {}
|
|
|
|
def __init__(self, meter):
|
|
self.METER = meter # Pixels per 1 meter
|
|
|
|
def generate(self, z):
|
|
generator = dungeon.Generator(40 + 4 * math.floor(z / 2)) # +4m^2 per level
|
|
generator.generate(self, z)
|
|
self.generators[z] = generator
|
|
|
|
level.populate(self, generator, z)
|
|
|
|
def collides(self, pos, z, rect):
|
|
# Player position handling really needs to be reworked ...
|
|
METER = self.METER
|
|
cx = pos.x + (rect[0] / METER)
|
|
cy = pos.y + (rect[1] / METER)
|
|
px = int(math.floor(cx))
|
|
py = int(math.floor(cy))
|
|
cw = cx + (rect[2] / METER)
|
|
ch = cy + (rect[3] / METER)
|
|
for y in range(py - 1, py + 1 + math.ceil(rect[3] / METER)):
|
|
for x in range(px - 1, px + 2):
|
|
if y >= 0 and y < len(self.map[z]) and x >= 0 and x < len(self.map[z][y]):
|
|
tile = self.map[z][y][x]
|
|
if tile and tile.is_solid():
|
|
if cw >= x and cx <= (x + 1) and ch >= y and cy <= (y + 1):
|
|
return True
|
|
|
|
return False
|
|
|
|
def set_tile(self, x, y, z, name):
|
|
for _ in range(len(self.map), z + 1):
|
|
self.map.append([])
|
|
|
|
for _ in range(len(self.map[z]), y + 1):
|
|
self.map[z].append([])
|
|
|
|
for _ in range(len(self.map[z][y]), x + 1):
|
|
self.map[z][y].append(None)
|
|
|
|
if not name:
|
|
self.map[z][y][x] = None
|
|
elif tiles.registered_tiles[name]:
|
|
self.map[z][y][x] = Tile(name, (x, y, z))
|
|
|
|
def get_tile(self, x, y, z):
|
|
try:
|
|
return self.map[z][y][x]
|
|
except:
|
|
return None
|
|
|
|
def add_sprite(self, x, y, z, name):
|
|
for _ in range(len(self.sprites), z + 1):
|
|
self.sprites.append([])
|
|
|
|
sprite = Sprite(name, Vector(x, y), z)
|
|
sprite.id = rand.rand(0, 65535)
|
|
self.sprites[z].append(sprite)
|
|
return sprite
|
|
|
|
def remove_sprite(self, id):
|
|
for layer in self.sprites:
|
|
for i in range(len(layer)):
|
|
if layer[i].id == id:
|
|
layer.pop(i)
|
|
return
|
|
|
|
# Bresenham's line algorithm
|
|
# Based on https://www.codeproject.com/Articles/15604/Ray-casting-in-a-2D-tile-based-environment
|
|
def raycast(self, pos1, pos2, z):
|
|
p1 = Vector(pos1.x, pos1.y)
|
|
p2 = Vector(pos2.x, pos2.y)
|
|
result = []
|
|
|
|
steep = abs(p2.y - p1.y) > abs(p2.x - p1.x)
|
|
if steep:
|
|
p1 = p1.flip()
|
|
p2 = p2.flip()
|
|
|
|
if p1.x > p2.x:
|
|
oldx = p1.x
|
|
p1.x = p2.x
|
|
p2.x = oldx
|
|
|
|
oldy = p1.y
|
|
p1.y = p2.y
|
|
p2.y = oldy
|
|
|
|
deltax = p2.x - p1.x
|
|
deltay = abs(p2.y - p1.y)
|
|
error = 0
|
|
ystep = 0
|
|
y = p1.y
|
|
if p1.y < p2.y:
|
|
ystep = 0.5
|
|
else:
|
|
ystep = -0.5
|
|
|
|
x = p1.x
|
|
while x <= p2.x:
|
|
check = (x, y)
|
|
if steep:
|
|
check = (y, x)
|
|
|
|
tile = self.get_tile(math.ceil(check[0]), math.ceil(check[1]), z)
|
|
if tile and tile.is_solid():
|
|
result.append(check)
|
|
|
|
error += deltay
|
|
if (2 * error >= deltax):
|
|
y += ystep
|
|
error -= deltax
|
|
|
|
x += 0.5
|
|
|
|
return result
|
|
|
|
def reset(self):
|
|
self.map = []
|
|
self.sprites = []
|
|
self.generators = {}
|