I am building a cave exploration game (Which is supposed to be infinite on all 3 axis.) that uses a modified version of perlin-noise. I thought I had the optimisation sussed as it runs like butter for the beginning part of the game. If you were to explore further, however, (like Y: -200) then it starts to slow down. I start with a steady 60-100 FPS but it slowly drops down to 20-50 FPS. I'm using a chunk based system and it disables the chunk whenever the player is out of reach. I'm using .SetActive(false/true) on the chunks. I think the main problem is that I have too many GameObjects and the script is having to refer to Lists which are (sometimes) 400+ GameObjects/Vector3's long.
I am trying to think of different ways to go about the problem such as .Destroy() but that would be an even bigger issue for .Destory() is fairly costly, performance wise, as I am sometimes having to destroy 5-7 GameObjects (which contain other GameObjects which contain other GameObjects and so on...) every few seconds. This is also effected by how fast the player is travelling....
I'm going to give the code but it incorporates other parts which have nothing to do with this so feel free to ask questions. I will also put a screen shot.
(P.S. Chunks of gameobjects are called "Parts" and a GameObject inside of the "Part" is called a "Chunk" and inside of "Chunks" are "Rocks". Just to make things confusing. :-p (It was something that happened at the beginning of my code ages ago that I haven't been bothered to change.))
(P.P.S The "Rocks" positions are also perlin-noised. This is probably also a big factor.)
Code:
using UnityEngine;
using System.Collections;
using SimplexNoise;
using System.Collections.Generic;
public class World : MonoBehaviour {
public GameObject rock;
public GameObject chunkTemplate;
public GameObject rawmatter;
public float maxPartDistance = 30f;
public static float maxChunkDistFromPlayer = 0f;
public float seed;
public Transform Player;
public int PartSize;
public List Parts = new List();
public List PartPositions = new List();
List ChunkPositions = new List();
bool startPosOneTime = true;
Camera cam;
// Use this for initialization
void Start () {
Player = GameObject.FindGameObjectWithTag("Player").transform;
maxChunkDistFromPlayer = maxPartDistance;
if(!Application.isEditor)
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
cam = GameObject.FindGameObjectWithTag("Player").GetComponentInChildren();
}
Vector3 playerToPartPosHasChangedCheck = Vector3.zero;
bool PTPPhasChanged = true;
void Update()
{
Vector3 playerPos = Player.position;
foreach(GameObject go in Parts)
{
if(Vector3.Distance(go.transform.position, playerPos) > maxPartDistance)
{
go.SetActive(false);
}
else
{
go.SetActive(true);
}
}
Vector3 playerToPartPos = new Vector3(Mathf.Round(playerPos.x / PartSize) * PartSize,
Mathf.Round(playerPos.y / PartSize) * PartSize,
Mathf.Round(playerPos.z / PartSize) * PartSize);
if(playerToPartPosHasChangedCheck != playerToPartPos)
{
PTPPhasChanged = true;
}
if(PTPPhasChanged)
{
//Centre
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z))){
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z));
}
//Forward
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z + PartSize));
}
//Backwards
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z - PartSize));
}
//Forward x 2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z + (PartSize * 2))))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z + (PartSize * 2)));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z + (PartSize * 2)));
}
//Backwards x 2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z - (PartSize * 2))))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z - (PartSize * 2)));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y,
playerToPartPos.z - (PartSize * 2)));
}
//Left
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z));
}
//Right
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z));
}
//Left x 2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z));
}
//Right x 2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z));
}
//Forward, Left
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z + PartSize));
}
//Forward, Right
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z + PartSize));
}
// //Forwardx2, Left
// if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
// playerToPartPos.y,
// playerToPartPos.z + (PartSize * 2))))
// {
// CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
// playerToPartPos.y,
// playerToPartPos.z + (PartSize * 2)));
// PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
// playerToPartPos.y,
// playerToPartPos.z + (PartSize * 2)));
// }
//
// //Forwardx2, Right
// if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
// playerToPartPos.y,
// playerToPartPos.z + (PartSize * 2))))
// {
// CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
// playerToPartPos.y,
// playerToPartPos.z + (PartSize * 2)));
// PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
// playerToPartPos.y,
// playerToPartPos.z + (PartSize * 2)));
// }
//Forward, Left x2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z + PartSize));
}
//Forward, Right x2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z + PartSize));
}
//Backwards, Left
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y,
playerToPartPos.z - PartSize));
}
//Backwards, Right
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y,
playerToPartPos.z - PartSize));
}
// //Backwards x2, Left
// if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
// playerToPartPos.y,
// playerToPartPos.z - (PartSize * 2))))
// {
// CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
// playerToPartPos.y,
// playerToPartPos.z - (PartSize * 2)));
// PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
// playerToPartPos.y,
// playerToPartPos.z - (PartSize * 2)));
// }
//
// //Backwards x2, Right
// if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
// playerToPartPos.y,
// playerToPartPos.z - (PartSize * 2))))
// {
// CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
// playerToPartPos.y,
// playerToPartPos.z - (PartSize * 2)));
// PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
// playerToPartPos.y,
// playerToPartPos.z - (PartSize * 2)));
// }
//Backwards, Left x2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x - (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z - PartSize));
}
//Backwards, Right x2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x + (PartSize * 2),
playerToPartPos.y,
playerToPartPos.z - PartSize));
}
//Up
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y + PartSize,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y + PartSize,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y + PartSize,
playerToPartPos.z));
}
//Down
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z));
}
//Down, Left
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z));
}
//Down, Right
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z));
}
//Down, Forward
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize));
}
//Down, Backwards
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize));
}
//Down, Forward, Left
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize));
}
//Down, Forward, Right
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z + PartSize));
}
//Down, Backwards, Left
if(!PartPositions.Contains(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x - PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize));
}
//Down Backwards, Right
if(!PartPositions.Contains(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize));
PartPositions.Add(new Vector3(playerToPartPos.x + PartSize,
playerToPartPos.y - PartSize,
playerToPartPos.z - PartSize));
}
//Down x2
if(!PartPositions.Contains(new Vector3(playerToPartPos.x,
playerToPartPos.y - (PartSize * 2),
playerToPartPos.z)))
{
CreatePart(PartSize, new Vector3(playerToPartPos.x,
playerToPartPos.y - (PartSize * 2),
playerToPartPos.z));
PartPositions.Add(new Vector3(playerToPartPos.x,
playerToPartPos.y - (PartSize * 2),
playerToPartPos.z));
}
//PTPPhasChanged = false;
}
playerToPartPosHasChangedCheck = playerToPartPos;
}
void CreatePart(int partSize, Vector3 pos)
{
GameObject part = new GameObject();
part.transform.position = pos;
part.name = "Part";
part.transform.parent = transform;
for(int y = 0; y < partSize; y++)
{
NoiseMethod method = PerlinWorms.valueMethods[2];
Vector3 point00 = transform.TransformPoint(new Vector3(seed - 0.5f, seed - 0.5f, y)) + pos;
Vector3 point10 = transform.TransformPoint(new Vector3(seed + 0.5f, seed - 0.5f, y)) + pos;
Vector3 point01 = transform.TransformPoint(new Vector3(seed - 0.5f, seed + 0.5f, y)) + pos;
Vector3 point11 = transform.TransformPoint( new Vector3(seed + 0.5f, seed + 0.5f, y)) + pos;
float stepSize = 1f / partSize;
for(int z = 0; z < partSize; z++)
{
Vector3 point0 = Vector3.Lerp(point00, point01, (z + 0.5f) * stepSize);
Vector3 point1 = Vector3.Lerp(point10, point11, (z + 0.5f) * stepSize);
for(int x = 0;x< partSize;x++)
{
Vector3 point = Vector3.Lerp(point0, point1, (x+0.5f) * stepSize);
float sample = PerlinWorms.Sum(method, point, 0.5f, 1, 2, 0.5f);
sample = sample * 0.5f + 0.5f;
if(sample > 0.4f && sample < 0.5f)
{
if(Mathf.Round(x) % 2 == 0 && Mathf.Round(y) % 2 == 0 && Mathf.Round(z) % 2 == 0)
if(!ChunkPositions.Contains(new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z)) + pos))
{
CreateChunk(new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z)) + pos, part.transform);
ChunkPositions.Add(new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z)) + pos);
}
}
// else
// {
// if(startPosOneTime == true && x > partSize / 2 && y > partSize / 2 && z > partSize / 2)
// {
// Player.localPosition = new Vector3(x, y, z) + pos;
// startPosOneTime = false;
// }
// }
}
}
}
Parts.Add(part);
}
void CreateChunk(Vector3 position, Transform Parent)
{
GameObject Chunk = (GameObject)Instantiate(chunkTemplate);
Chunk.transform.position = position;
Chunk.name = "Chunk";
Chunk.transform.parent = Parent;
for(int x = 0; x < 2; x++)
{
for(int y = 0; y < 2; y++)
{
for(int z = 0; z < 2; z++)
{
if(z == 0 | z == 1 | x == 0 | x == 1 | y == 0 | y == 1)
{
GameObject currentRock;
currentRock = (GameObject)Instantiate(rock, Vector3.zero, Quaternion.identity);
currentRock.transform.localPosition = new Vector3(x + Mathf.PerlinNoise(seed + position.x + z + 0.1f, seed + position.y + y + 0.1f) + position.x,
y + Mathf.PerlinNoise(seed + position.x + x + 0.1f, seed + position.y + z + 0.1f) + position.y,
z + Mathf.PerlinNoise(seed + position.x + x + 0.1f, seed + position.y + y + 0.1f) + position.z);
currentRock.transform.parent = Chunk.transform;
GameObject currentRawMatter;
//Front and Back
if(Random.Range(0, 18) == 0)
{
float newZ = new float();
currentRawMatter = (GameObject)Instantiate(rawmatter, Vector3.zero, Quaternion.Euler(0, z * 180, 0));
if(z == 0) newZ = -0.5f;
if(z == 1) newZ = 0.5f;
currentRawMatter.transform.position = new Vector3(currentRock.transform.position.x, currentRock.transform.position.y, currentRock.transform.position.z + newZ);
currentRawMatter.transform.parent = currentRock.transform;
Chunk.GetComponent().AddMatter(currentRawMatter.transform.position);
}
//Left and Right
if(Random.Range(0, 18) == 0)
{
currentRawMatter = (GameObject)Instantiate(rawmatter, Vector3.zero, Quaternion.Euler(0, 90f + (x * 180), 0));
float lrnewX = new float();
if(x == 0) lrnewX = -0.5f;
if(x == 1) lrnewX = 0.5f;
currentRawMatter.transform.position = new Vector3(currentRock.transform.position.x + lrnewX, currentRock.transform.position.y, currentRock.transform.position.z);
currentRawMatter.transform.parent = currentRock.transform;
Chunk.GetComponent().AddMatter(currentRawMatter.transform.position);
}
//Top and Bottom
if(Random.Range(0, 18) == 0)
{
currentRawMatter = (GameObject)Instantiate(rawmatter, Vector3.zero, Quaternion.Euler(-90f + (y * 180), 0, 0));
float tbnewY = new float();
if(y == 0) tbnewY = -0.5f;
if(y == 1) tbnewY = 0.5f;
currentRawMatter.transform.position = new Vector3(currentRock.transform.position.x, currentRock.transform.position.y + tbnewY, currentRock.transform.position.z );
currentRawMatter.transform.parent = currentRock.transform;
Chunk.GetComponent().AddMatter(currentRawMatter.transform.position);
}
}
}
}
}
//chunk.transform.localScale /= 2;
}
}
Screenshots:
Part
![Part][1]
Chunk
![Chunk][2]
[1]: /storage/temp/46550-part.jpg
[2]: /storage/temp/46551-chunk.jpg
These screenshots were taken as soon as the game started. I simply paused it in the editor at the beginning and took the screenshots.
↧