Добавлен , опубликован
Возможно вам хотелось сделать окружающее пространство более живым и органичным? Данная наработка предоставляет возможность поэтапной смены тайлов, демонстрирующей "зарастание" покрова. Для примера будут использованы стандартные тайлы, хотя вы всегда можете подставить свои.
Быстрый старт
code
-- синхронизируем lua рандом
-- только для 1.26
math.randomseed(GetRandomInt(0, 2147483648-1))

local world_rect = GetWorldBounds()
local minX, maxX, minY, maxY = GetRectMinX(world_rect), GetRectMaxX(world_rect), GetRectMinY(world_rect), GetRectMaxY(world_rect)
local step = 128 -- шаг сетки

local Timer = TimerSystem()
local ts_array = SquareArray(minX, maxX, minY, maxY, step) -- квадратный массив для создания TerrainSystem
local ts_set = function (x,y,typ) SetTerrainType(x,y,typ,math.random(4)-1,1,0) end
local ts_get = GetTerrainType
ter_sys = TerrainSystem{
	Timer = Timer,
	array = ts_array,
	get_type = ts_get,
	set_type = ts_set,
}

-- функция конвертации строки-типа в число, для того чтобы показать пример
local function FourCC(str)
	local n, len = 0, #str
	for i = len, 1, -1 do n = n + (str:byte(i,i) << 8*(len-i)) end -- shift by 0,8,16,24
	return n
end

-- создаем 3 участка
SetTerrainType(-200,200, FourCC('Ldrg'), 1, 3, 0)

SetTerrainType(200,-200, FourCC('Lrok'), 1, 3, 0)

SetTerrainType(-200,-200, FourCC('Ybtl'), 1, 3, 0)

-- запуск по всей карте
-- ter_sys:init() 


-- запуск в квадратном участке
-- for x = -384, 384, 128 do
-- 	for y = -384, 384, 128 do
-- 		ter_sys:start_tox(x, y)
-- 	end
-- end

-- Timer.after(1, function()
-- 	ter_sys:stop_tox(0,128)
-- 	ter_sys:modification(128,0, 5)
-- end)
API
local ter_sys = TerrainSystem(...) -- см быстрый старт
ter_sys:start_tox(real x, real y) --> true or false | запустить зарастание
ter_sys:stop_tox(real x, real y) --> остановить зарастание
ter_sys:modification(rela x, real y, real ratio) --> true or false | ускорить или замедлить
-- изначально скорость 1, передача -0.5 ускорит на 50%, передача 3. замедлит на 300%
ter_sys:init() -- запускает start_tox() по всей карте
ter_sys:IsEarth(real x, real y) -- true, если это один из тайлов земли
ter_sys:IsFootballGrass(real x, real y) -- true, если это футбольная трава
ter_sys:IsGreenGrass(real x, real y) -- true, если это зеленая трава
ter_sys:IsYellowGrass(real x, real y)  -- true, если это желтая трава
БД
-- types - цепочки превращений земли до FOOTBALL_GRASS 
-- type - тип почвы
-- time - время перехода до следующей стадии
local EARTH = { 
	{types = {'Ldrt', 'Ldrg', 'Fdrg'}, time = 3},
	{types = {'Lrok', 'Frok'}, time = 4},
}
local FOOTBALL_GRASS = {type = 'Lgrs', time = 5}
local GREEN_GRASS = {type = 'Lgrd', time = 6}
local YELLOW_GRASS = {type = 'Fgrd'}
По кнопке скачать находится архив с исходниками и их адаптированными вариантами для 1.26 и reforget.
Отдельно спасибо МрачныйВорон за спонсирование данной наработки
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Этот комментарий удален
18
  • Обновил библиотеки внутри работы
  • Поправил подсветку синтаксиса в шапке
27
Снова просматривал эту наработку от скуки. Я вот думаю, что почва так не растет. Она оч быстро растет у вас, по видео, но в качестве ознакомительного проекта сойдет.
Вот пример в реале, я на даче заметил, что там где песок, травы не видно. Но стоит туда чернозем завести, вода сделает свое дело, и со временем там зарастает. Стоит туда куслк навоза кинуть, и там уже маленький островок из травы. Если косишь траву, то вся эта скошенная трава становится новым удобрением для будущей травы, так и расширчется по тихоньку. И так далее.
18
Она оч быстро растет
Это ускоренный вариант для видео
18
Залипалово, думал мб подобное сделать, но через клеточные автоматы.
пока только на питоне набросал
код
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as anim
from matplotlib.colors import ListedColormap

np.random.seed(0)

# Цвета состояний
colors = [
    (139/255, 69/255, 19/255),    # 0 - Земля (коричневый)
    (144/255, 238/255, 144/255),  # 1 - Редкая трава (светло-зелёный)
    (34/255, 139/255, 34/255),    # 2 - Обычная трава (зелёный)
    (0/255, 100/255, 0/255),      # 3 - Густая трава (тёмно-зелёный)
    (0/255, 0/255, 255/255),      # 4 - Вода (синий)
    (169/255, 169/255, 169/255),  # 5 - Камень (серый)
]
cmap = ListedColormap(colors)

# Веса состояний
state_weights = {
    0: {  # Земля
        0:  0.001,  # Земля ~ Земля
        1:  0.3,    # Земля ~ Редкая трава
        2:  0.6,    # Земля ~ Обычная трава
        3:  0.9,    # Земля ~ Густая трава
        4:  1.5,    # Земля ~ Вода
        5: -0.5,    # Земля ~ Камень
    },
    1: {  # Редкая трава
        0:  0.001,  # Редкая трава ~ Земля
        1:  0.15,   # Редкая трава ~ Редкая трава
        2:  0.3,    # Редкая трава ~ Обычная трава
        3:  0.45,   # Редкая трава ~ Густая трава
        4:  0.75,   # Редкая трава ~ Вода
        5: -1.0,    # Редкая трава ~ Камень
    },
    2: {  # Обычная трава
        0:  0.001,  # Обычная трава ~ Земля
        1:  0.1,    # Обычная трава ~ Редкая трава
        2:  0.2,    # Обычная трава ~ Обычная трава
        3:  0.3,    # Обычная трава ~ Густая трава
        4:  0.5,    # Обычная трава ~ Вода
        5: -1.5,    # Обычная трава ~ Камень
    },
}

# Размер сетки
grid_size = 100

# Начальная сетка: вся земля
grid = np.zeros((grid_size, grid_size), dtype=int)

# Генерация воды и камней на сетке
for _ in range(np.random.randint(2, 6)):  # Случайные области воды
    x0, y0 = np.random.randint(0, grid_size, size=2)
    w, h = np.random.randint(2, 21, size=2)
    for i in range(w):
        for j in range(h):
            x, y = (x0 + i) % grid_size, (y0 + j) % grid_size
            grid[x, y] = 4  # Вода
for _ in range(np.random.randint(5, 21)):  # Случайные области камней
    x0, y0 = np.random.randint(0, grid_size, size=2)
    w, h = np.random.randint(2, 5, size=2)
    for i in range(w):
        for j in range(h):
            x, y = (x0 + i) % grid_size, (y0 + j) % grid_size
            grid[x, y] = 5  # Камень

# Генерация матрицы весов
def generate_weight_matrix(radius):
    size = 2 * radius + 1
    weight_matrix = np.zeros((size, size), dtype=float)
    for x in range(-radius, radius + 1):
        for y in range(-radius, radius + 1):
            weight_matrix[x + radius, y + radius] = (radius + 1 - abs(x)) * (radius + 1 - abs(y))
    return weight_matrix

# Нормализация матрицы весов
def normalize_matrix(matrix):
    return matrix / matrix.sum()

# Вычисление влияния для ячейки (x, y) на основе её соседей
def calculate_influence_for_cell(grid, weight_matrix, x, y):
    influence = 0
    height, width = grid.shape
    
    weight_height, weight_width = weight_matrix.shape
    
    half_weight_height = weight_height // 2
    half_weight_width = weight_width // 2

    xy_state = grid[x, y]
    
    for i in range(weight_height):
        for j in range(weight_width):
            dx = i - half_weight_height
            dy = j - half_weight_width
            
            nx = (x + dx) % height
            ny = (y + dy) % width
            
            nxny_state = grid[nx, ny]
            
            influence += state_weights[xy_state][nxny_state] * weight_matrix[i, j]
    
    return influence

# Обработка подгруппы ячеек
def process_cells(cells, grid, new_grid):
    for x, y in cells:
        if grid[x, y] >= 0 and grid[x, y] < 3:
            growth_probability = calculate_influence_for_cell(grid, weight_matrix, x, y)
            if np.random.rand() < growth_probability:
                new_grid[x, y] += 1

# Генерация матрицы весов
radius = 2
weight_matrix = normalize_matrix(generate_weight_matrix(radius))

# Подготовка ячеек для обработки
all_cells = [(x, y) for x in range(grid_size) for y in range(grid_size)]

# Количество подгрупп
num_chunks = 20

# Перемешивание и разбиение на подгруппы
def shuffle_and_split_cells(all_cells, num_chunks):
    np.random.shuffle(all_cells)
    return np.array_split(all_cells, num_chunks)

# Изначальное разбиение
chunks = shuffle_and_split_cells(all_cells, num_chunks)
chunk_index = 0
new_grid = grid.copy()

# Анимация
fig, ax = plt.subplots(figsize=(6, 6))
im = ax.imshow(grid, cmap=cmap, vmin=0, vmax=5)
ax.axis("off")

def update(frame):
    global grid, chunk_index, new_grid, chunks

    process_cells(chunks[chunk_index], grid, new_grid)
    chunk_index += 1
    
    if chunk_index >= num_chunks:
        grid[:] = new_grid
        chunks = shuffle_and_split_cells(all_cells, num_chunks)
        chunk_index = 0

    im.set_array(new_grid)
    return [im]

ani = anim.FuncAnimation(fig, update, frames=100, interval=10, blit=True)

plt.show()
Загруженные файлы
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.