Reputation: 41
Is there a way to incorporate Perlin Noise into the Ursina game engine in Python to give it a Minecraft feeling? I think I may be onto something, but for some reason, the y
value is not varying. Do you mind helping me out?
The code that I have so far:
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
from perlin_noise import PerlinNoise;
app = Ursina()
noise = PerlinNoise(octaves=10, seed=1)
# Define a Voxel class.
# By setting the parent to scene and the model to 'cube' it becomes a 3d button.
class Voxel(Button):
def __init__(self, position=(0,0,0)):
super().__init__(
parent = scene,
position = position,
model = 'cube',
origin_y = .5,
texture = 'white_cube',
color = color.color(0, 0, random.uniform(.9, 1.0)),
highlight_color = color.lime,
)
def input(self, key):
if self.hovered:
if key == 'left mouse down':
voxel = Voxel(position=self.position + mouse.normal)
if key == 'right mouse down':
destroy(self)
for z in range(8):
for x in range(8):
y = .25 + noise([x, z])
voxel = Voxel(position=(x, y,z))
player = FirstPersonController()
app.run()
Upvotes: 0
Views: 644
Reputation: 881
It sounds like Voxel(...)
places a voxel at the specified position, right? If so, then you would need to loop over the whole column to place the blocks into.
And if your noise library doesn't handle frequency and amplitude scaling internally, then you need to do that externally. Multiply the input coordinates by fractions, and multiply the output value by larger values.
min_height = 4.0
max_height = 16.0
for z in range(8):
for x in range(8):
height = # some noise formula
# if noise() range is 0 to 1: min_height + noise([x * 0.05, z * 0.05]) * (max_height - min_height)
# if noise() range is -1 to 1: min_height + (noise([x * 0.05, z * 0.05]) * 0.5 + 0.5) * (max_height - min_height)
for y in range(height): # might need to convert height to an integer
voxel = Voxel(position=(x,y,z))
Also please keep in mind the problems of Perlin for noise in its unmitigated form. The algorithm's popularity by name far outweighs its canonical form's true merit in light of its square alignment issues and the broader space of options we have now, and in spite of the overwhelming amount of content that still teaches it in a vacuum. See the final paragraph from my last answer for more info: https://stackoverflow.com/a/73348943
I would suggest this: https://pypi.org/project/pyfastnoiselite/
from pyfastnoiselite.pyfastnoiselite import (
FastNoiseLite, NoiseType, FractalType,
)
min_height = 4.0
max_height = 16.0
noise = FastNoiseLite(0)
noise.noise_type = NoiseType.NoiseType_OpenSimplex2
noise.fractal_type = FractalType.FractalType_FBm
noise.fractal_octaves = 4
noise.frequency = 0.03
for z in range(8):
for x in range(8):
height = min_height + (noise.get_noise(x, z) * 0.5 + 0.5) * (max_height - min_height)
for y in range(height): # might need to convert height to an integer
Voxel(position=(x,y,z))
or for 3D noise to enable overhangs, you vary that heightmap within Y as well:
from pyfastnoiselite.pyfastnoiselite import (
FastNoiseLite, NoiseType, FractalType,
)
min_height = 4.0
max_height = 16.0
noise = FastNoiseLite(0)
noise.noise_type = NoiseType.NoiseType_OpenSimplex2
noise.fractal_type = FractalType.FractalType_FBm
noise.fractal_octaves = 4
noise.frequency = 0.03
for z in range(8):
for x in range(8):
for y in range(min_height): # might need to convert bounds to integers
Voxel(position=(x,y,z))
for y in range(min_height, max_height): # might need to convert bounds to integers
effective_height = min_height + (noise.get_noise(x, y, z) * 0.5 + 0.5) * (max_height - min_height)
if effective_height > y:
Voxel(position=(x,y,z))
Examples untested. There may be some changes to parameters or even syntax to get these working! Feel free to make the needed edits to this answer to get it working properly.
Also min_height + (noise.get_noise(x, y, z) * 0.5 + 0.5) * (max_height - min_height)
can be simplified down to noise.get_noise(x, y, z) * factor + offset
, where
factor = 0.5 * (max_height - min_height)
offset = factor + min_height
Upvotes: 0
Reputation: 13
First, you did not say "Perlin Noise" correctly, so remove the semi-colon, then you'll use this code:
noise = PerlinNoise(octaves=intgeer,seed=0)
for z in range(8):
for x in range(8):
y = 0. 25 noise([x * 0.02,z * 0.02])
voxel = Voxel(position=(x,y,z))
Upvotes: 0
Reputation: 51
You can use this:
seed=random.randint(1,1000000)
noise = PerlinNoise(octaves=3,seed=seed)
for z in range(8):
for x in range(8):
y = noise([x * 0.02,z * 0.02])
y = math.floor(y * 7.5)
voxel = Voxel(position=(x,y,z))
Upvotes: 1
Reputation: 3598
As shown in the usage examples, you'll have to scale the noise value with an additional division:
for z in range(8):
for x in range(8):
y = .25 + noise([x/8, z/8])
voxel = Voxel(position=(x, y,z))
You'll probably want to replace that magic number with a constant.
Upvotes: 1