I'm a fan of Minecraft's old terrain generation with amazing overhangs, mountains and generally interesting worlds. My problem is that right now I'm using perlin noise, which while good for smooth terrain doesn't really give sporadic jumps that would allow mountains in a mostly flat area.
On top of that with the method I'm using gets 2d perlin noise, puts it in an array and then gets every Y value under it and sets it to a block; This stops generation of overhangs like this: Old Minecraft Terrain Image
Right now I have this:
public class GenerateIdMap : MonoBehaviour {
[Serializable] public class IBSerDict : SerializableDictionaryBase<int, byte> {};
public int size = 60;
public int worldHeight = 3;
public float perlinScale = 15f;
public int seed;
public int heightScale = 10;
public int maxHeight = 256;
public IBSerDict defaultBlocks = new IBSerDict();
void Start()
{
if (seed != 0) seed = (int)Network.time * 10;
CreateMap();
}
byte[,,] CreateMap()
{
byte[,,] map = new byte[size, maxHeight, size];
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
int y = (int)(Mathf.PerlinNoise((x + seed) / perlinScale, (z + seed) / perlinScale) * heightScale) + worldHeight;
y = Mathf.Clamp(y, 0, maxHeight-1);
while (y > 0)
{
map[x, y, z] = GetBlockType(y);
y--;
}
}
}
return map;
}
byte GetBlockType(int y)
{
SortedDictionary<int, byte> s_defaultBlocks = new SortedDictionary<int, byte>(defaultBlocks);
foreach (var item in s_defaultBlocks.OrderBy(key => key.Key))
{
if (y <= item.Key)
{
print(item.Value);
return item.Value;
}
}
return 0;
} }
The GetBlockType function is new and for getting the default block at that height, I'll fix it up later but it works for now. If you instantiate a prefab at that vector3 you would see terrain. Can someone help me figure out how to make better terrain? Thanks in advance!
Both of your problems should be tackled individually.
The first issue regarding the lack of variation in the generated values can usually be fixed in one of two ways, the first way is to modify the input into the perlin noise, i.e. the octaves and persistance and the second is to mix the output of multiple functions and even use the output of one function as the input to another. By functions, I mean Perlin/Simplex/Voronoi etc.
With the former method, as you mentioned, it can be pretty difficult to get terrain with interesting features over a large area (the generated values are homogeneous), but by playing with the coordinate range and octaves/persistance, it can be possible. The second approach is probably recommended however, because by mixing the inputs and outputs of different functions you can get some really interesting shapes (Voronoi produces circular crator-like shapes).
In order to fix the problem you are having with the overhangs, you would need to change your approach to generating the world slightly. Currently, you are just generating the height values of the terrain and assigning each of those values to give you the terrain surface only. What you ideally would want to do is, generate a pseudo-random value to use as a pass flag for each of the blocks in the 3d space (also those underground). The flag would indicate whether a block should be placed or not in the 3d world.
This is slower, but would generate caves and overhangs as you need.
Related
I am working on a voxel system for my game that uses dynamic loading of chunks. To optimize it, I have a pool of chunks and a render distance, and what I want to do is fill the pool with a proper amount of chunks. So, I need a way to find that amount. I have tried the following but it seems very inefficient.
private void CreatePool()
{
int poolSize = 0;
for (int x = -m_RenderDistance; x <= m_RenderDistance; x++) {
for (int y = -m_RenderDistance; y <= m_RenderDistance; y++) {
for (int z = -m_RenderDistance; z <= m_RenderDistance; z++) {
if (Position3Int.DistanceFromOrigin(new Position3Int(x, y, z)) <= m_RenderDistance)
poolSize++;
}
}
}
}
More formally, the question involes finding the amount of unique cubes with integer coorindates with a certain distance from the origin.
If you think there is a better way to approach this or I am doing something fundamentally wrong, let me know.
Thanks,
Quintin
I assume its the distance check that you think is inefficient? What you've got shouldn't be too bad if you're just getting the count on Start() or Awake().
Draco18s solution is fine if you are okay with a cubed result. If you want a spherical result without a distance check, you can try some formulation of the volume of a sphere: 4/3*PI*r^3
checkout Bresenham's circle.
Here's a approximation algorithm for a filled 3d Bresenham Circle that I have. It is very similar to what you have already, just with a more effecient squared dist check and a minor adjustment to get a more attractive bresenham-looking circle):
public static List<Vector3> Get3DCircleKeys(int radius){
List<Vector3> keys = new List<Vector3>();
for(int y=-radius; y<=radius; y++){
for(int x=-radius; x<=radius; x++){
for(int z =-radius; z<=radius; z++){
// (+ radius*.08f) = minor modification to match Bresenham result
if(x*x+y*y+z*z <= radius*radius + radius*.08f){
keys.Add(new Vector3(x,y,z));
}
}
}
}
return keys;
}
This, however, will deliver a different count than the volume of sphere would give you, but with some tweaking to it or to the sphere volume calculation, it could be good enough, or at least, more efficient than instantiating a full volume of a cube, where many of the voxels will be outside of the bounds of the render distance.
Here's my situation I'm making a 2D maze game(XNA 4.0). I have figured out that the best way to do collision detection is by using per-pixel detection. While searching it up on the internet I have found people explaining or showing code for two things colliding(i.e. mouse & player, player & player, two shapes). What I would like to do is have this collision detect whether the player collides with a wall or not(the background is black but the maze walls are white). Could someone explain how to do this or to give some sort of starting point with the code. Much Appreciated.
P.S. A link to a website or anything relating to my question would also be helpful
The best way to go about this CPU-intensive operation is checking for hitbox collision first, then the per-pixel collision.
Most of this code can be found in this helpful video.
static bool IntersectsPixel(Rectangle hitbox1, Texture2D texture1, Rectangle hitbox2, Texture2D texture2)
{
Color[] colorData1 = new Color[texture1.Width * texture1.Height];
texture1.GetData(colorData1);
Color[] colorData2 = new Color[texture2.Width * texture2.Height];
texture2.GetData(colorData2);
int top = Math.Max(hitbox1.Top, hitbox2.Top);
int bottom = Math.Min(hitbox1.Bottom, hitbox2.Bottom);
int right = Math.Max(hitbox1.Right, hitbox2.Right);
int left = Math.Min(hitbox1.Left, hitbox2.Left);
for(y = top; y< bottom; y++)
{
for(x = left; x < right; x++)
{
Color color1 = colorData1[(x - hitbox1.Left) + (y - hitbox1.Top) * hitbox1.Width]
Color color2 = colorData2[(x - hitbox2.Left) + (y - hitbox2.Top) * hitbox2.Width]
if (color1.A != 0 && color2.A != 0)
return true;
}
}
return false;
}
You can call this method like so:
if (IntersectsPixel(player.hitbox, player.texture, obstacle.hitbox, obstacle.texture))
{
// Action that happens upon collision goes here
}
Hope I could help you out,
- GHC
Create a matrix of bools representing your sprite and a matrix of bools representing your maze (the matrix representing your sprite needs to have the same dimensions as your maze).
then you can do something simple like iterate over all x-y coordinates and check whether or not they're both true
// as an optimization, store a bounding box to minimize the
// coordinates of what you need to check
for(int i = 0; i < width, i++) {
for(int j = 0; j < height, j++) {
if(sprite[i][j] && maze[i][j]) {
collision = true
//you might want to store the coordinates
}
}
}
If you want to be very fancy you can flatten your maze matrix and use bit operations
I'm building a very simple 2d tile map. It just spawns a few different grass tiles in random locations here's what it looks like:
public int tileHeight; //y
public int tileWidth; //x
int tileHeightCounter;
int tileWidthCounter;
public GameObject[] floorTiles;
void Start(){
tileHeightCounter = 0;
tileWidthCounter = 0;
while(tileHeightCounter < tileHeight){
Vector3 tileSpawnPoint = new Vector3 (tileWidthCounter, tileHeightCounter, 0);
GameObject groundTiles = (GameObject)Instantiate (floorTiles[Random.Range(0, floorTiles.Length)], tileSpawnPoint, Quaternion.identity);
groundTiles.transform.parent = transform;
if (tileWidthCounter == tileWidth) {
tileWidthCounter = 0;
tileHeightCounter++;
}
tileWidthCounter++;
}
}
I've run into two problems- say your tileHeight is 10 and your tileWidth is also 10 then the map it generates should be a 10x10 with 100 total tiles randomly distributed.
Instead two weird things are occurring the first is that if your map is 10x10 it actually generates a 10x9 meaning it stops one layer short on the y axis. The second is a grid(grass tile) is being created at 0,0 but the rest of the map is being created with at least x being 1 meaning that the map has a single tile attached to the bottom left sticking out.
I'm a bit confused as to whats going on here or how to fix it. Any help is much appreciated.
The issue is that you're using a < less than, so once it actually hits the tileHeight it exits the loop one iteration too early. Make it <=.
I'm doing a text based game for a school project and I see myself stuck with a quite stupid problem.
The concept is simple, there's a map, a player, some monsters and some items.
For the map data structure I decided to use a 2d array of char's that have a unicode for content.
On top of this, I have a camera, which has a radius. The player never moves on screen, it has a x and y, but what has motion on screen is the camera itself. This works quite fine except when I get to the corners or any outside wall.
I get my camera doing this
int size = cameraSize/2;
int top = player.GetY() - size, bottom = player.GetY() + size;
char[,] camera = new char[cameraSize, cameraSize];
Console.SetCursorPosition(0,0);
for (int i = top; i < bottom; i++)
{
for (int j = top; j < bottom; j++)
{
camera[i, j] = map.ReMapPosition(i, j);
Console.Write(camera[i,j]);
}
Console.Write("\n");
}
Console.SetCursorPosition(cameraSize,cameraSize);
Console.Write(player.GetPlayerChar());
My 'cameraSize' is declared on the beginning of the class and is filled when the constructor is called
private int cameraSize;
cameraSize = difficulty.GetCameraSize();
The class 'difficulty' is irrelevant for my problem.
My problem itself is that I can't make the player positioned on the center when I get to the border walls as there is nothing to get from the array, since these are negative positions.
There are two approaches to this sort of problem.
1) In your loop, check if a value if out of range and output the value by hand.
2) Wrap your array in a custom class which ignores out of range values.
Something like this:
class MyWrapper
{
private readonly char[,] data;
public MyWrapper(char[,] data)
{
this.data=data;
}
private bool InRange(int x, int y)
{
return x >= 0 && y >= 0 && x < data.GetLength(0) && y < data.GetLength(1);
}
public char this[int x, int y]
{
get
{
return InRange(x,y) ? data[x,y] : ' ';
}
set
{
if(InRange(x,y)) data[x,y] = value;
}
}
}
My recommendation is for set to throw an exception when called on out of range values, but my example swallows the failure instead.
C# can't "retrieve values that aren't there", but you do have a couple options
Check to see if you are trying to get a negative position, or a position that's too big, and return a space
Or
Increase the size of the array by cameraSize/2 on all sides, which would effectively increase both the width and the height by cameraSize, and then make it to where your player can only move around in the coordinates (cameraSize/2,cameraSize/2) and (mapWidth-cameraSize/2,mapHeight-cameraSize/2). (<-- The coordinates might by (y,x) because of how 2d arrays work and depending on how your code is written). That way, the camera always has a padding around it, so there shouldn't ever be negative indicies
I've succesfully made a marching cubes class in C# XNA and am using Lib noise to generate 3d perlin noise, but when I tried to generate terrain using the values of the perlin noise as the densities for my marching cubes it generates a large chunk of marching cubes with seemingly random triangles inside of them. I separated the marching cube and gave it arbitrary 3d arrays of densities to run through so I could make sure everything was working and it looked fine, and I had the terrain generation code generate normal cubes and I got a normal looking terrain, but the problem is the corners of each cube gets values from the noise are always switching from negative to positive so fast that the marching cubes just look like a jumbled mess.
This is the code I'm using to generate the terrain:
public MarchingCube[, ,] getTerrainChunk(int size, int stepsize)
{
MarchingCube[, ,] temp = new MarchingCube[size / stepsize, size / stepsize, size / stepsize];
for (int x = 0; x < size; x += stepsize)
{
for (int y = 0; y <size; y += stepsize)
{
for (int z = 0; z < size; z += stepsize)
{
Vector3[] corners = { new Vector3(x,y,z), new Vector3(x,y+stepsize,z),new Vector3(x+stepsize,y+stepsize,z),new Vector3(x+stepsize,y,z), new Vector3(x,y,z+stepsize), new Vector3(x,y+stepsize,z+stepsize),
new Vector3(x+stepsize,y+stepsize,z+stepsize), new Vector3(x+stepsize,y,z+stepsize)};
float[] densities = { GetDensity(corners[0]),GetDensity(corners[1]),GetDensity(corners[2]),GetDensity(corners[3]),GetDensity(corners[4]),
GetDensity(corners[5]),GetDensity(corners[6]),GetDensity(corners[7])};
if (x == 0 && y == 0 && z == 0)
{
temp[x / stepsize, y / stepsize, z / stepsize] = new MarchingCube(densities, corners, device);
}
else
temp[x / stepsize, y / stepsize, z / stepsize] = new MarchingCube(densities, corners);
}
}
}
return temp;
}
and the GetDensity method is as follows:
private float GetDensity(Vector3 point)
{
return (float)terrain.GetValue(point));
}
I think the problem is that I'm not using the noise correctly to get the densities of the marching cubes corners, but so far my google search results haven't been much help at all. So does anyone know how to use the noise properly to generate smooth looking terrain? Or what else may be causing this problem?
I posted screen shots at http://imgur.com/a/D1uMC , the first two are shown using marching cubes and the last one is normal cubes.
Edit:
So from the pictures I figured out that the marching cubes are actually working how they are supposed to with the values they are being given, the problem is defiantly with my noise and how I"m using it. Does anyone know any good resources for 3d terrain generation based on noise?
The problem was how I was reading in the noise, by default I was incredibly "zoomed out" so by changing stepsize to a float and then using smaller increments I was able to get the desired results. Basically "zoomed in" on the area of noise.