- Home /
C# Better block world loading, generating and saveing
I have been working on this game for a few weeks, and I have gotten flat world generation, world save and world loading working, but it is slow. Moving and loading chunks will pause the game with lag, as will saving chunks. I am wondering if anyone is capable and willing to help, maybe I am doing things the slow way? maybe this would work on a better and faster computer then mine.
This is meant to be a rpg style game, so not too much focus is going to be put on building, but I still want some save-ability and world creation. I want people to make custom maps and share them.
sorry for the mess of code
This is in my move script
public static void CheckChunks (){
Vector3 PosDis = Vector3.zero;
while (PosDis.y < 3){
while (PosDis.z < 3){
while (PosDis.x < 3){
P = PlayerChunk + PosDis;
N = PlayerChunk - PosDis;
if (N.y < 0){N.y = 0;}
string[] ChunkName = new string[]{
P.x.ToString() + "." + P.y.ToString() + "." + P.z.ToString() + ".",
P.x.ToString() + "." + P.y.ToString() + "." + N.z.ToString() + ".",
P.x.ToString() + "." + N.y.ToString() + "." + P.z.ToString() + ".",
P.x.ToString() + "." + N.y.ToString() + "." + N.z.ToString() + ".",
N.x.ToString() + "." + P.y.ToString() + "." + P.z.ToString() + ".",
N.x.ToString() + "." + P.y.ToString() + "." + N.z.ToString() + ".",
N.x.ToString() + "." + N.y.ToString() + "." + P.z.ToString() + ".",
N.x.ToString() + "." + N.y.ToString() + "." + N.z.ToString() + "."
};
CheckChunksNum = new Vector3[]{
new Vector3(P.x , P.y , P.z) ,
new Vector3(P.x , P.y , N.z) ,
new Vector3(P.x , N.y , P.z) ,
new Vector3(P.x , N.y , N.z) ,
new Vector3(N.x , P.y , P.z) ,
new Vector3(N.x , P.y , N.z) ,
new Vector3(N.x , N.y , P.z) ,
new Vector3(N.x , N.y , N.z)
};
int count = 0;
while (count < 7){
if (!GameCore.ChunkLoaded.Contains (ChunkName[count])) {
Chunks.StartChunk(CheckChunksNum[count].x,CheckChunksNum[count].y,CheckChunksNum[count].z);
}
count++;
}
PosDis.x += 1;
}
PosDis.x = 0;
PosDis.z += 1;
}
PosDis.x = 0;
PosDis.z = 0;
PosDis.y += 1;
}
}
this in the move script update
TimeToCheck += 1 * Time.deltaTime;
if (TimeToCheck > 0.005f) {
if (transform.position.y > 0) {
CheckChunks ();
TimeToCheck = 0;
}
}
this is the whole of my chunk loading and generating script
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Chunks : MonoBehaviour {
public static string[] SortChunk;
public static string[] SortBlocks;
public static string[,] HoldChunks = new string[196,14];
public static string[,] ThisBlock = new string[196,14];
public static Vector3 ChunkNumbers = Vector3.zero;
public static GameObject ThisObject;
// Use this for initialization
void Start () {
LoadChunk();
ThisObject = gameObject;
}
public void LoadChunk (){
float X14Sect = Mathf.Floor(GameCore.PlayerLocation.x / 14);
float Y14Sect = 0;
float Z14Sect = Mathf.Floor(GameCore.PlayerLocation.z / 14);
StartChunk(X14Sect,Y14Sect,Z14Sect);
Vector3 AddToSect = Vector3.zero;
bool OutAddToSect = false;
float Switched = 0;
float MultiplyerX = 1;
float MultiplyerZ = 1;
while (!OutAddToSect) {
while (Switched <= 2){
while (AddToSect.x != (4 * MultiplyerX)) {
StartChunk (X14Sect + AddToSect.x, Y14Sect + AddToSect.y, Z14Sect + AddToSect.z);
AddToSect.x += MultiplyerX;
}
AddToSect.x = 0;
Switched += 1;
MultiplyerX *= -1;
}
Switched = 0;
MultiplyerX = 1;
MultiplyerZ = 1;
AddToSect = Vector3.zero;
while (Switched <= 2){
while (AddToSect.x != (4 * MultiplyerX)){
while (AddToSect.y <= 7) {
StartChunk (X14Sect + AddToSect.x, Y14Sect + AddToSect.y, Z14Sect + AddToSect.z);
AddToSect.y += 1;
}
AddToSect.y = 0;
AddToSect.x += MultiplyerX;
}
AddToSect.y = 0;
AddToSect.x = 0;
Switched += 1;
MultiplyerX *= -1;
}
Switched = 0;
MultiplyerX = 1;
MultiplyerZ = 1;
AddToSect = Vector3.zero;
while (Switched <= 3){
while (AddToSect.x != (4 * MultiplyerX)){
while (AddToSect.y <= 7) {
while (AddToSect.z != (4 * MultiplyerZ)) {
StartChunk (X14Sect + AddToSect.x, Y14Sect + AddToSect.y, Z14Sect + AddToSect.z);
AddToSect.z += MultiplyerZ;
}
AddToSect.z = 0;
AddToSect.y += 1;
}
AddToSect.z = 0;
AddToSect.y = 0;
AddToSect.x += MultiplyerX;
}
if (MultiplyerX == -1){ MultiplyerZ = -1; }
AddToSect.z = 0;
AddToSect.y = 0;
AddToSect.x = 0;
Switched += 1;
MultiplyerX *= -1;
}
AddToSect = Vector3.zero;
OutAddToSect = true;
//end while
}
}
public static void StartChunk (float ChunkNumberx, float ChunkNumbery, float ChunkNumberz){
string ChunkName = ChunkNumberx.ToString () + "." + ChunkNumbery.ToString () + "." + ChunkNumberz.ToString ();
ChunkNumbers = new Vector3 (ChunkNumberx,ChunkNumbery,ChunkNumberz);
if (!GameCore.ChunkLoaded.Contains (ChunkName)) {
bool SkipStart = false;
try {
float SetX = ChunkNumberx * 14;
float SetY = ChunkNumbery * 14;
float SetZ = ChunkNumberz * 14;
string text = "";
try {
text = System.IO.File.ReadAllText ( Core.StaticWorldSaveLocation + @"\Dem\Soul\Land\" + ChunkNumberx.ToString () + "." + ChunkNumbery.ToString () + "." + ChunkNumberz.ToString () + ".dat");
}
catch
{
GenChunck(ChunkNumbers);
SkipStart = true;
}
if (!SkipStart){
GameCore.ChunkLoaded.Add (ChunkName);
GameObject ChunckCoreObject;
SortChunk = text.Split ('-');
ChunckCoreObject = (GameObject)Instantiate(Core.StaticChunk, new Vector3 (ChunkNumberx * 7f,ChunkNumbery * 7f,ChunkNumberz * 7f), Quaternion.Euler (0,0,0));
ChunckCoreObject.name = ChunkName;
ChunckCoreObject.GetComponent <ChunkCore> ().ChunkNumber = new Vector3 (ChunkNumberx, ChunkNumbery, ChunkNumberz);
int SortTrys = 0;
while (SortTrys < 14) {
int setChunkDat = 0;
SortBlocks = SortChunk [SortTrys].Split (',');
while (setChunkDat < 196) {
HoldChunks [setChunkDat, SortTrys] = SortBlocks [setChunkDat];
setChunkDat += 1;
}
SortTrys += 1;
//end setting chunk
}
ThisBlock = (HoldChunks);
int blockcount;
SortTrys = 0;
while (SortTrys < 14) {
int setChunkDatInt = 0;
while (setChunkDatInt < 196) {
if (int.Parse (ThisBlock [setChunkDatInt, SortTrys]) > 0) {
int xR = Random.Range (0, 4);
int yR = Random.Range (0, 4);
int zR = Random.Range (0, 4);
int RowNum = setChunkDatInt / 14;
int CollomNum = 14 * RowNum;
GameObject Block = (GameObject)Instantiate (Core.StaticBricks [int.Parse (ThisBlock [setChunkDatInt, SortTrys])], new Vector3 (((setChunkDatInt - CollomNum) + SetX) * 0.5f, (SortTrys + SetY) * 0.5f, (RowNum + SetZ) * 0.5f), Quaternion.Euler (90 * xR, 90 * yR, 90 * zR));
Block.GetComponent <CubeCore> ().CubeChunkCore = ChunckCoreObject;
Block.GetComponent <CubeCore> ().CubeChunk = ChunkName;
Block.GetComponent <CubeCore> ().FromLoad = true;
Block.GetComponent <CubeCore> ().CubeLine = new Vector2 (setChunkDatInt, SortTrys);
ChunckCoreObject.GetComponent <ChunkCore> ().ChunkBlocks[setChunkDatInt, SortTrys] = ThisBlock [setChunkDatInt, SortTrys];
ChunckCoreObject.GetComponent <ChunkCore> ().CubeList[setChunkDatInt, SortTrys] = Block.gameObject;
}
else{
ChunckCoreObject.GetComponent <ChunkCore> ().ChunkBlocks[setChunkDatInt, SortTrys] = "0";
}
setChunkDatInt += 1;
}
SortTrys += 1;
//end spawning blocks
}
}
} catch {GenChunck(ChunkNumbers);
}
}
}
public static void GenChunck(Vector3 ChunkNumber){
int counter = 0;
int countery = 0;
bool CanSave = false;
string[,] ChunkBlocks = new string[196,14];;
if (ChunkNumber.y < 1) {
while (counter<196) {
ChunkBlocks [counter, 0] = "1";
counter++;
}
countery = 1;
while (countery < 14) {
counter = 0;
while (counter<196) {
ChunkBlocks [counter, countery] = "0";
counter++;
}
countery++;
}
}
if (ChunkNumber.y > 0) {
while (countery < 14) {
counter = 0;
while (counter<196) {
ChunkBlocks [counter, countery] = "0";
counter++;
}
countery++;
}
}
string SaveBlocks = "";
int SortTrys = 0;
while (SortTrys < 14 ) {
int setChunkDat = 0;
while (setChunkDat < 195) {
SaveBlocks += ChunkBlocks[setChunkDat,SortTrys] + ",";
setChunkDat += 1;
}
SaveBlocks += ChunkBlocks[setChunkDat,SortTrys] + "-";
SortTrys += 1;
//end setting chunk
}
System.IO.File.WriteAllText( Core.StaticWorldSaveLocation + @"\Dem\Soul\Land\" + ChunkNumber.x + "." + ChunkNumber.y + "." + ChunkNumber.z + ".dat", SaveBlocks);
StartChunk (ChunkNumber.x,ChunkNumber.y,ChunkNumber.z);
}
// Update is called once per frame
void Update () {
//end update
}
}
this is my chunk registration script
using UnityEngine;
using System.Collections;
public class ChunkCore : MonoBehaviour {
public string[,] ChunkBlocks = new string[196,14];
public Vector3 ChunkNumber;
public GameObject[,] CubeList = new GameObject[196,14];
// Use this for initialization
void Start () {
}
public void SaveChunk(){
string SaveBlocks = "";
int SortTrys = 0;
while (SortTrys < 14 ) {
int setChunkDat = 0;
while (setChunkDat < 196) {
SaveBlocks += ChunkBlocks[setChunkDat,SortTrys] + ",";
setChunkDat += 1;
}
SaveBlocks += "-";
SortTrys += 1;
//end setting chunk
}
System.IO.File.WriteAllText( Core.StaticWorldSaveLocation + @"\Dem\Soul\Land\" + transform.name + ".dat", SaveBlocks);
}
float DelayChunkGen = 0;
// Update is called once per frame
void Update () {
DelayChunkGen += 1 * Time.deltaTime;
if (DelayChunkGen > 1.5) {
}
}
}
this is my cube registration script
using UnityEngine;
using System.Collections;
public class CubeCore : MonoBehaviour {
public string CubeName;
public bool FromLoad;
public float CubeNumber;
public float CubeWeight;
public float CubeBurn;
public float CubeBreak;
public string CubeChunk;
public Vector2 CubeLine;
public GameObject CubeChunkCore;
static public string staticCubeName;
static public float staticCubeNumber;
static public float staticCubeWeight;
static public float staticCubeBurn;
static public float staticCubeBreak;
// Use this for initialization
void Start () {
staticCubeName = CubeName;
staticCubeNumber = CubeNumber;
staticCubeWeight = CubeWeight;
staticCubeBurn = CubeBurn;
staticCubeBreak = CubeBreak;
//try{
if (!FromLoad){
try{
Vector3 ChunkName = new Vector3 (Mathf.Floor((transform.position.x )/ 7f) , Mathf.Floor(transform.position.y / 7f), Mathf.Floor(transform.position.z / 7f));
CubeChunk = ChunkName.x.ToString() + "." + ChunkName.y.ToString() + "." + ChunkName.z.ToString();
CubeChunkCore = GameObject.Find(CubeChunk);
CubeLine = new Vector2 (Mathf.Floor((Mathf.Abs(CubeChunkCore.transform.position.x - transform.position.x) + (Mathf.Abs(CubeChunkCore.transform.position.z - (transform.position.z))*14))/0.5f), Mathf.Floor(Mathf.Abs(CubeChunkCore.transform.position.y - transform.position.y)/0.5f));
if (!GameCore.ChunkLoaded.Contains(CubeChunk)){
HardBreak();}
if (CubeChunkCore.GetComponent <ChunkCore> ().ChunkBlocks[(int) CubeLine.x,(int) CubeLine.y] == "0"){
try {
CubeChunkCore.GetComponent <ChunkCore> ().ChunkBlocks[(int) CubeLine.x,(int) CubeLine.y] = CubeNumber.ToString();
CubeChunkCore.GetComponent <ChunkCore> ().CubeList[(int) CubeLine.x,(int) CubeLine.y] = gameObject;
}catch{}
if (!GameCore.SaveChunks.Contains(CubeChunkCore)){
GameCore.SaveChunks.Add(CubeChunkCore);
}
} else{
HardBreak();
}
}catch{HardBreak();}
}
}
public void Break(bool IsDroping){
if (CubeNumber > 2){
CubeChunkCore.GetComponent <ChunkCore> ().ChunkBlocks[(int) CubeLine.x,(int) CubeLine.y] = "0";
Destroy (gameObject);
if (!GameCore.SaveChunks.Contains(CubeChunkCore)){
GameCore.SaveChunks.Add(CubeChunkCore);
}
}
}
public void HardBreak(){
Destroy (gameObject);
//CubeChunkCore.GetComponent <ChunkCore> ().ChunkBlocks[(int) CubeLine.x,(int) CubeLine.y] = "0";
if (!GameCore.SaveChunks.Contains(CubeChunkCore)){
GameCore.SaveChunks.Add(CubeChunkCore);
}
}
public void OverRide(){
CubeChunkCore.GetComponent <ChunkCore> ().ChunkBlocks[(int) CubeLine.x,(int) CubeLine.y] = "0";
}
// Update is called once per frame
void Update () {
}
}
game core script
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class GameCore : MonoBehaviour {
public static Vector3 PlayerLocation = new Vector3 (1,10f,3);
public static List<string> ChunkLoaded = new List<string> ();
public static float VewingDis = 5;
public static int StaticSeed;
public static float BrushSize = 1;
public static float PlayerHight = 1.708f;
public static GameObject PlayerObject;
public int Seed = 500;
public float GameTimerSave = 0;
public float SaveTime = 2;
static public List<GameObject> SaveChunks = new List<GameObject>();
static public bool RunSaveAll = false;
void Start () {
StaticSeed = Seed;
}
void Update () {
GameTimerSave += 1 * Time.deltaTime;
if (RunSaveAll) {
SaveAll();
RunSaveAll = false;
}
if (GameTimerSave >= SaveTime) {
SaveAll();
GameTimerSave = 0;
}
}
public static void SaveAll(){
try{
foreach (GameObject UnsavedChuncks in SaveChunks)
{
UnsavedChuncks.GetComponent <ChunkCore> ().SaveChunk();
}
SaveChunks.Clear();
}catch{
}
}
}
you know, listing all the scrips needed for this to work makes me think maybe I should combined a few scrips.
Wowzers... I don't think anyone is going to take the time to read and figure that out. Can you do a screen grab and post a video of the result? This might help us understand what you are trying to achieve, from which we can hopefully point you in the right direction.
$$anonymous$$y computer can't run most screen capture, and the problem is fps going to 0, so yes a screen shot is what I am seeing, idk if it will help :( I am slowly starting to think it is a lack of good computer problem, also I save to a file directly under C:\, and I am stating to suspect that it may be a part of the problem, and I am trying to fix that now.
also, I A$$anonymous$$ saveing 20 5.3kb files, and I think that might also have an effect.
Answer by JoshuaMcKenzie · Nov 13, 2015 at 01:59 AM
Your code is not documented very well so its a little difficult to pick up, Looking at your CheckChunks() function it appears that when you call this function you're checking a 7x7 grid of chunks and you attempt on checking them 200 times a second. Do you really need to check that many chunks? How big are they? Do you really need to check them that frequently? can you get away with checking a 3x3 once every... say 5 seconds?
You're also attempting to save all Chunks every 2 seconds, thus you're constantly writing to the disc when most times you don't need to. A chunk should be saved when its unloaded and when its changed (you can wait up to 10-20 seconds after the most recent change before attempting a save, long enough to reduce overhead and short enough that won't frustrate the player due to a potential crash).
I see that you are using many Try/Catches in your code. While they can work, they can be noticeably slower, especially if iterated over several times a second. It is better if you can structure your code where a try catch is never needed
I see your writing to file as a Plaintext file which for heavy data objects can slow down Saving and loading, and if its constantly creating new files that has overhead to it as well. If you're going to be loading and saving a lot of data frequently I would recommend a different approach, I would recommend looking into Scriptible Objects and the Live Tutorial. Even though the tutorial itself admits to being boring in the first half, the information it provides is pretty relevant to your performance issues as Scriptible Objects are similar to Databases in the sense that they are able to load/save volumes of data pretty quickly.
I have only seen a tiny portion of your game so I can't fathom how much work you may actually need to fix your issues, it may even be the issues your having are also due to some other code you haven't shown.
Using the Profiler is the easiest way at finding where the performance bottlenecks are.
I have failed to provide vital information in a drastic oversight, despite that you have helped me. ty
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
15625 blocks are making my game lag? Increase performance? 3 Answers