Jump to content
Unity Insider Forum

Minecraft WeltenGenerator Wie Richtig Erzeugen??


GelegenheitsProgrammierer

Recommended Posts

Hallo erst mal zusammen,

 

ich habe mir letzten mal in den Kopf gesetzt eine grobe Kopie von einem zufälligen WeltenGenerator ala Minecraft zu programmieren. Einfach mal zum reinschnuppern wie so was geht.

 

Ich hab dann bei Google gefragt und die haben mir gesagt ich solle dabei mit Chunk arbeiten. Soweit sogut. Also hab ich ein Programm geschrieben was mir einen zufälligen Chunk generiert mit hilfe eines dreidiminsonalen Arrays. Das Entprodukt sah für meine Augen schon sehr akzeptabel aus.

 

post-5215-0-63900000-1423518371_thumb.png

 

Die Chunks sind 32x64x32 groß. Nun sieht ja ein Chunk alleine relativ klein für eine Welt aus und da hab ich mir gedacht lädst du dann direkt mehrere Chunks gesagt getan und beim Ausprobieren hängt er sich Unity komplett auf. Ich kann die Chunks nur nacheinander laden was dann aber ziemlich viel Zeit in Anspruch nimmt.

 

Mach ich da irgend etwas falsch beim erzeugen. Ich benutze nämlich die Instantiate Methode.

 

Bei anderen Spielen dauert das Generieren vn welten ja auch keine 20 minuten wenn man keinen Rand mehr sehen möchte. ( Mein Rechner ist da auch nicht der Lahmste)

 

Danke für die Antworten schon mal im voraus

 

MFG GelegenheitsProgrammierer

 

Ps: Wenn ihr die Scripte braucht dann sagt bescheiddann reich ich die noch nach

2Ps: Ich hoffe ich hab alles richtig gepostet ?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich bin mir jetzt nicht sicher ob du deinen Chunk einfach nur aus Cubes zusammen generiert hast oder ob du Voxel verwendet hast ?

 

Bei Voxel gibt es ja viele Möglichkeiten zu optimieren zb marching Cubes,Octrees,HiddenSurface-Removal, Zbuffer verfahren. Damit sollte alles schneller gehen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Voxel klingt interessant danke ich werde diesbezüglich Google wieder fragen

 

Was die Scripte angeht weiß ich nicht ob die richtig sind ich poste sie mal

 

Das Script zum erstellen des Chunks

using UnityEngine;
using System.Collections;
public class ChunkGenerator : MonoBehaviour {
public GameObject ErdCube;
public GameObject ErdCubeTop;
public GameObject SteinCube;
public GameObject WasserCube;
public GameObject SandCube;
public GameObject BadCube;

private GameObject CreateCube;
private bool PlaceCube = true;
private const int xChunkMax = 32;
private const int zChunkMax = 32;
private const int yChunkMax = 64;
public Vector3 ChunkPosition;
private GameObject[,,] ChunkCubePosition = new GameObject[xChunkMax,yChunkMax,zChunkMax];
//private Vector3[,,] ChunkCubePosition = new Vector3[xMax,yMax,zMax];
// Use this for initialization
void Start ()
{
 ChunkPosition = transform.position;
 WriteCubes ();
 StartCoroutine (FrameWarten ());
 //CreateChunk ();
}

// Update is called once per frame
void Update ()
{

}
IEnumerator FrameWarten()
{
 for (int y = 0; y < yChunkMax; y++)
 {
  for (int x = 0; x < xChunkMax; x++)
  {
   for (int z = 0; z < zChunkMax; z++)
   {
 CreateChunk (x, y, z);
   }
  }
  yield return new WaitForEndOfFrame ();
  //yield return new WaitForSeconds (0.001F);
 }
}

void CreateChunk(int x,int y,int z)
{
 if (ChunkCubePosition [x, y, z] == null)
 {

 }
 else
 {
  Instantiate (ChunkCubePosition [x, y, z], new Vector3(ChunkPosition.x + x,y,ChunkPosition.z + z), Quaternion.identity);
 }
}
void WriteCubes()
{
 for (int y = 0; y < yChunkMax; y++)
 {
  for (int x = 0; x < xChunkMax; x++)
  {
   for (int z = 0; z < zChunkMax; z++)
   {
 ChooseCube (x, y, z);
   }
  }
 }
}
void ChooseCube (int xPosition,int yPosition,int zPosition)
{
 int posnegChance;
 int PosZwischenSpeicher;
 int ZufallsCube;
 if (yPosition < 2)
 {
  ChunkCubePosition [xPosition, yPosition, zPosition] = BadCube;
 }
 else
 {
  //======================================================================================================================================================================================
  if(yPosition < 15)
  {
   if(ChunkCubePosition [xPosition, yPosition -1, zPosition] == null)
   {
   }
   else
   {
 ChunkCubePosition [xPosition, yPosition , zPosition] = SteinCube;
   }
  }
  else
  {
   //==================================================================================================================================================================================
   if(yPosition < 30)
   {
 if(ChunkCubePosition [xPosition, yPosition -1, zPosition] == null)
 {
 }
 else
 {
  posnegChance = 0;
  ZufallsCube = Random.Range (0, 100);
  PosZwischenSpeicher = yPosition;
  if((xPosition>=2)&&(zPosition>=2))
  {
   if(ChunkCubePosition [xPosition, yPosition -1 , zPosition] == SteinCube)
   {
    posnegChance = posnegChance + 5;
    if(ChunkCubePosition [xPosition -1, yPosition , zPosition] == SteinCube)
    {
	 posnegChance = posnegChance + 5;
    }
    if(ChunkCubePosition [xPosition, yPosition , zPosition -1] == SteinCube)
    {
	 posnegChance = posnegChance + 5;
    }
   }
   if(ChunkCubePosition [xPosition, yPosition -1 , zPosition] == ErdCube)
   {
    posnegChance = posnegChance - 5;
    if(ChunkCubePosition [xPosition -1, yPosition , zPosition] == ErdCube)
    {
	 posnegChance = posnegChance - 5;
    }
    if(ChunkCubePosition [xPosition, yPosition , zPosition-1] == ErdCube)
    {
	 posnegChance = posnegChance - 5;
    }
   }
  }
  if((ZufallsCube + (posnegChance - 25)) > 50)
  {
   ChunkCubePosition [xPosition, yPosition , zPosition] = ErdCube;
  }
  else
  {
   ChunkCubePosition [xPosition, yPosition , zPosition] = SteinCube;
  }
 }
   }
   else
   {
 //==============================================================================================================================================================================
 if(yPosition < 35)
 {
  if(ChunkCubePosition [xPosition, yPosition -1, zPosition] == null)
  {
  }
  else
  {
   ZufallsCube = Random.Range (0, 100);
   PosZwischenSpeicher = yPosition;
   if((ZufallsCube + (PosZwischenSpeicher - 25)) > 20)
   {
    ChunkCubePosition [xPosition, yPosition , zPosition] = ErdCube;
   }
   else
   {
    ChunkCubePosition [xPosition, yPosition , zPosition] = SteinCube;
   }
  }
 }
 else
 {
  //==========================================================================================================================================================================
  if(yPosition < 50)
  {
   if(ChunkCubePosition [xPosition, yPosition -1, zPosition] == null)
   {
   }
   else
   {
    ZufallsCube = Random.Range (0, 100);
    PosZwischenSpeicher = yPosition;
    if(ZufallsCube > 20)
    {
	 ChunkCubePosition [xPosition, yPosition , zPosition] = ErdCube;
    }
    else
    {
	 ChunkCubePosition [xPosition, yPosition - 1 , zPosition] = ErdCubeTop;
    }
   }
  }
  else
  {
   //======================================================================================================================================================================
   if(yPosition < 63)
   {
    if(ChunkCubePosition [xPosition, yPosition -1, zPosition] == null)
    {

    }
    else
    {
    }
   }
   else
   {
    //==================================================================================================================================================================
    if(yPosition == 64)
    {
	 if(ChunkCubePosition [xPosition, yPosition -1, zPosition] == null)
	 {

	 }
	 else
	 {
	 }
    }
   }
  }
 }
   }
  }
 }
}
}

 

Das Script zum erzeugen mehrere Chunks

 

using UnityEngine;
using System.Collections;
public class ChunkSpawn : MonoBehaviour {
public GameObject ChunkPre;
public int MaxGröße;
private int ChunkxPos;
private int ChunkzPos;
// Use this for initialization
void Start ()
{
 StartCoroutine (WaitSomeTimeForBetterPerformence ());
}

// Update is called once per frame
void Update ()
{

}
void SpawnChunk (int xPosition,int zPosition)
{
 Instantiate (ChunkPre, new Vector3(xPosition,0,zPosition), Quaternion.identity);
}
IEnumerator WaitSomeTimeForBetterPerformence() 
{
 for (int x = 0; x < MaxGröße; x++)
 {
  for (int z = 0; z < MaxGröße; z++)
  {
   ChunkxPos = 32 * x;
   ChunkzPos = 32 * z;
   SpawnChunk(ChunkxPos,ChunkzPos);
   yield return new WaitForSeconds(1F);
  }
 }
}
}

 

Sry das noch nicht kommentiert ist

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es liegt bestimmt an Cubes. Es sind leider zu viele Berechnungen. Das schafft Unity nicht. Ich denke das schaffen viele Programme / Engines nicht.

Das muss du leider anders lösen.

 

Wenn du mal bei Minecraft mal "Wallhacking" versucht hast, hast du bestimmt mal gesehen, dass der Boden nicht existiert

Beispiel: 2011-10-29_231016_723302.jpg

 

Da sieht man Beispiel, dass nur Oberflächen bzw. Höhlen generiert sind.

 

Mein Vorschlag (simple)

Du KÖNNTEST quasi so machen, dass nur die OBERFLÄCHE existiert und der Rest der Daten irgendwo gespeichert ist.

 

Wenn du das nicht verstanden hast, dann stelle dir die Welt in 2D vor aber von oben. Jedes mal wenn du ein Cube zerstört ist da aber ein Cube auf der selben stelle. Warum? Weil du weiter runtergräbst. Tatsächlich sind da aber keine Cubes. Du Spawns sie nur danach. In 2D (von oben) kann man natürlich nicht runter graben.

 

Wie machst du das? Mit einem Array (oder was du auch benutzen möchtest :)). In der For-Schleife statt die Cubes zu Spawnen lässt du erst mal die Informationen drinne. Und nachdem ein Cube zerstört / abgebaut wird kannst du ja dann checken ob da schon ein Cube oben, unten, rechts, links usw. ist. Wenn nicht -> spawnen.

 

Die beste Möglichkeit (die ich kenne) wäre eine Welt mit Meshs zu generieren :). Ich glaube Minecraft funktioniert sogar so? Bin mir jetzt nicht sicher.

 

 

EDIT:

IEnumerator WaitSomeTimeForBetterPerformence()
{
 for (int x = 0; x < MaxGröße; x++)
 {
  for (int z = 0; z < MaxGröße; z++)
  {
ChunkxPos = 32 * x;
ChunkzPos = 32 * z;
SpawnChunk(ChunkxPos,ChunkzPos);
yield return new WaitForSeconds(1F);
  }
 }
}

 

So hab ich das eigentlich auch gemacht als ich mal "blöckige" Welt erstellt habe. Sieht man schön wie sie generiert wird :)

 

Nur mal so ein Tip. Es gibt den float height = Mathf.PerlinNoise(x,y) befehl. Damit kann man super solche Welten generieren. Je nach x,y wird die höhe ermittelt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es könnte gut sein das dein Ansatz so gar nicht funktioniert. Die Welt in Minecraft wird auch mit Voxel genieriert.

 

Wenn du die Pro Version hast, könntest du mal folgendes testen:

 

Bau deine Cubes nicht aus einem Cube sondern aus Planes (Einzellne Objekte)

 

Nun nutzt du das Kamera Occlusion Culling um alle sichtbaren Planes auszublenden.

 

Das Kamera Occlusion Culling blendet alle nicht sichtbaren Objekte aus. Somit würden deine Objekt ingame wie Mazy schon sagte nur auf alle sichtbaren Objekte reduziert werden. Da durch nun keine Cubes als ganze Objekte hat kann Unity mehr Objekte ausblenden sprich dein Camera Occlusion Culling wird besser funktionieren.

 

Aber ich tendiere dazu das man eine so große Spielwelt aus Voxel mit verschiedenen Culling Tricks generieren sollte.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...