- Home /
Storing level data from a texture file, and drawing at speed.
Hello,
I am working with a partner to create a Zelda style Action RPG game. We have opted to create levels using texture files, and then draw them by converting pixel data into objects. However when drawing the levels it will lag quite badly during redraws, I believe this is because of the way I am storing them ingame. However this method is giving me about 18fps on a 4096x map which is fairly big, but we wish to have a lot going on within our game, so I'd like to minimize the lag as much as possible. We are testing with a 512x map at the moment, that has a steady fps of about 80, but if we move too quickly, it can drop to 40fps very quickly. Below is the code that I am currently working with:
public class Level : MonoBehaviour
{
[HideInInspector] public int levelWidth;
[HideInInspector] public int levelHeight;
public List<Transform> tiles;
public List<Color> tileColors;
public List<Transform> treeObjects;
public List<Transform> mobObjects;
public Transform spawnerPrefab;
public Texture2D levelTexture;
public TextAsset levelJSON;
private string json;
private Color[] levelColors;
private GameObject player;
private int posX;
private int posY;
private int lastPosX = 0;
private int lastPosY = 0;
private int moveDistanceBeforeRedraw = 1;
private int drawDistanceX = 25;
private int drawDistanceY = 25;
private List<Transform> drawnTiles;
private List<Transform> drawnObjects;
private JsonData data;
// Use this for initialization
void Start ()
{
levelWidth = levelTexture.width;
levelHeight = levelTexture.height;
json = levelJSON.text;
data = JsonMapper.ToObject(json);
player = GameObject.FindGameObjectWithTag("Player");
SetupPlayerSpawn();
drawnTiles = new List<Transform>();
drawnObjects = new List<Transform>();
DrawEntites();
}
// Update is called once per frame
void Update ()
{
posX = (int)Camera.main.transform.position.x;
posY = (int)Camera.main.transform.position.y;
if( Mathf.Abs( posX - lastPosX ) > moveDistanceBeforeRedraw || Mathf.Abs( posY - lastPosY ) > moveDistanceBeforeRedraw )
{
DrawLevel();
lastPosX = posX;
lastPosY = posY;
}
HandleEntities();
}
private void SetupPlayerSpawn()
{
if( (bool) data["Entities"]["Player"]["UseDefault"] )
{
int xSpawnPoint = (int)data["Entities"]["Player"]["DefaultSpawn"][0];
int ySpawnPoint = (int)data["Entities"]["Player"]["DefaultSpawn"][1];
Debug.Log("Setting player position: " + xSpawnPoint + ", " + ySpawnPoint );
player.transform.position = new Vector3( xSpawnPoint, ySpawnPoint, 0 );
}
}
public void DrawLevel()
{
drawDistanceX = Mathf.CeilToInt( Camera.main.orthographicSize * Camera.main.aspect + 3 );
drawDistanceY = Mathf.CeilToInt( Camera.main.orthographicSize + 3 );
levelColors = levelTexture.GetPixels ();
foreach( Transform t in drawnTiles )
{
Destroy( t.gameObject );
}
drawnTiles.Clear();
for( int x=posX - drawDistanceX; x<posX + drawDistanceX; x++ )
{
for( int y=posY - drawDistanceY; y<posY + drawDistanceY; y++ )
{
int pos = x + y*levelWidth;
if( pos < 0 || pos > levelColors.Length-1 ) continue;
Color c = levelColors[pos];
if( tileColors.Contains( c ) )
{
Transform t = tiles[tileColors.IndexOf( c )];
drawnTiles.Add(Instantiate ( t, new Vector2( x, y ), Quaternion.identity ) as Transform);
}
}
}
}
public void DrawEntites()
{
for( int i=0; i<(int)data["Entities"]["Trees"]["NumberOfTrees"]; i++ )
{
int xPos = (int)data["Entities"]["Trees"][""+i+"-pos"][0];
int yPos = (int)data["Entities"]["Trees"][""+i+"-pos"][1];
Transform t = Instantiate (treeObjects[ (int)data["Entities"]["Trees"][""+i+"-treeID"] ], new Vector2( xPos, yPos), Quaternion.identity) as Transform;
drawnObjects.Add( t );
}
for( int j=0; j<(int)data["Entities"]["MobSpawners"]["NumberOfSpawners"]; j++ )
{
int xPos = (int)data["Entities"]["MobSpawners"][j.ToString ()]["pos"][0];
int yPos = (int)data["Entities"]["MobSpawners"][j.ToString ()]["pos"][1];
Transform t = Instantiate (spawnerPrefab, new Vector2( xPos, yPos), Quaternion.identity) as Transform;
drawnObjects.Add( t );
Spawner s = t.GetComponent<Spawner>();
s.mobPrefab = mobObjects[(int)data["Entities"]["MobSpawners"][j.ToString ()]["mobID"]];
s.numberToSpawn = (int)data["Entities"]["MobSpawners"][j.ToString ()]["numberToSpawn"];
s.spawnInterval = ((int)data["Entities"]["MobSpawners"][j.ToString ()]["spawnIntervalMilli"])/1000f;
s.regenerationInterval = (int)data["Entities"]["MobSpawners"][j.ToString()]["regenIntervalSeconds"];
}
}
public void HandleEntities()
{
foreach( Transform g in drawnObjects )
{
g.GetComponent<Entity>().CheckVisibility();
}
}
}
I am using the LitJson C# plugin to handle my Json requirements to handle entities such as trees etc, I'm not too worried about the annoyance in level design because I am intending to create a level editor as soon as I have the drawing part optimized.
I believe one method of improving speed is to use a Dictionary method to store map data, but I have no idea where to start with this, so I'd appreciate any advice on good tutorials for that.
Is there any other way I could optimize this to load data then spawn the level faster?
Kind Regards, John
$$anonymous$$aybe ins$$anonymous$$d of the usual 0,0 -> x,y you should start your process at your character first and do offscreen-processing in subsequent frames. If it takes your character 30 seconds to get to the edge of the map thats at least 25 seconds of processing you can fit in, easing the process.
Also ins$$anonymous$$d of creating so many GOs, look in to voxels.
Thanks $$anonymous$$eat5000, I'll look into voxeling now. Am I right in thinking you are referring to creating meshes ingame and applying the textures to them?
The reason I've not tried this yet is because I'm not really sure How I would go about applying collision regions to them.