In this tutorial we will look at one part of initialization which would be to load a level from a text file.
We will be taking our game Polar as the reference so we would be loading specific data needed for defining levels from a text file. We did not build a level editor because we did not feel the need for it as the definitions of the objects in the levels was not that complicated. But in future if we were to build some sort of a level editor we will give tutorials for that also. In the meantime, you can play games such as 겜블시티 라이브카지노.
We stored the data in text format as it was easier to read the text files from editors and then to edit them to manipulate levels. Two files were made. One contained the objects’ information (positions of enemies, collectibles etc) and the other the level information (like the time limit etc). Here are the classes associated with it.
BaseParser.java
public abstract class BaseParser{ static final String LEVEL_SPLITTER="#"; static final String DATA_SPLITTER=","; String readStr; public ReadFile(String file){ FileHandle file=Gdx.files.internal(file); //Gdx command to load file from "Assets" folder readStr=file.readString(); //This reads the whole file in a string object } }
BaseParser is a small abstract class to read the text file containing the data. Our parsers for Objects and Levels would derive from base parser.
LevelInfo class
public class LevelInfo{ public int LevelNumber; public String LevelName; public float TimeLimit; public LevelInfo(){ } public void Set(int n,String s,float t){ LevelNumber=n; LevelName=s; TimeLimit=t; } }
LevelInfo is a small class which contains the properties of the level.
LevelParser
public class LevelParser extends BaseParser{ LevelInfo level; static final int LEVEL_NUMBER=0; static final int LEVEL_NAME=1; static final int LEVEL_TIME=2; public LevelParser(String file){ ReadFile(file); } public LevelInfo GetLevel(int levelNumber){ String[] levels=readStr.split(LEVEL_SPLITTER); //Search for the level for(int i=0;i<levels.length;i++) String[] str=levels[i].split(DATA_SPLITTER); int l=Integer.parseInt(str[LEVEL_NUMBER]); if(l==levelNumber){ String lName=str[LEVEL_NAME]; float lTime=float.partseFloat(str[LEVEL_TIME]); MakeLevel(l,lName,lTime); break; } return level; } void MakeLevel(l,lName,lTime){ if(level==null) level=new LevelInfo(); level.Set(l,lName,lTime); } }
Level Parser first splits the read String into an array containing string data for each level. Then we parse the particular level needed to instantiate a levelInfo object to store the current level properties. We have defined constants in order of their position in the text file so its easier to manage. Also later if some properties get inserted or added its easier to just modify the value of the constant to handle the change. Also all the values in the data have to parsed to the correct type so Integer.parseInt and float.parseFloat are required respectively.
In this way we handle the level information like name and the time limit. The objects’ strcuture is mostly similar only we would have one more layer of data in it.
public abstract class BaseObject{ public Vector2 Position; public Boolean IsActive; public int UniqueID; public abstract void Destroy(); }
All objects in our game extend from BaseObject. We assume that every object would have a position and also added a variable to check if it is active for update/render processes.
ObjectParser Class
public class ObjectParser extends BaseParser{ static final String OBJECT_SPLITTER=";"; public BaseObject[] Objects; static final int OBJ_POS_X=0; static final int OBJ_POS_Y=1; static final int OBJ_POS_TYPE=2; public ObjectParser(String file){ ReadFile(file); } public void ParseObject(int level){ String[] levels=readStr.split(LEVEL_SPLITTER); //The levels' objects stored in the file are in ascending order so //we will be taking level-1 as the index of the string to get the objects information String[] str=levels[level-1].split(OBJECT_SPLITTER); Objects=new BaseObject[str.length]; for(int i=0;i<objects.length;i++){ String[] dataStr=str[i].split(DATA_SPLITTER); int x=Integer.parseInt(dataStr[OBJ_POS_X); int y=Integer.parseInt(dataStr[OBJ_POS_Y); int type=Integer.parseInt(dataStr[OBJ_POS_TYPE); swtich(type){ case OBJECT1: Object1 obj=new Object1(); //.................... Objects[i]=obj; break; case OBJECT2: Object2 obj=new Object2(); //.................... Objects[i]=obj; break; //...And load all the different type of objects in the game } } } }
In Object parser we use LEVEL_SPLITTER to get all objects for the particular level and then OBJECT_SPLITTER to get a particular object and then DATA_SPLITTER to get unit information like x position, y position and type of object. Then all objects are loaded in an array which can be used to udpate and render them on the screen.
Roughly, initialization would be instantiating spritebatch (for rendering), load textures and fonts (similar to menu), load objects from files or from other places in code, setting initial position for player, initializing the game time etc.
Before we end this tutorial we will go over one small class which we made for time as time handling is required in various places in games like game time, animation time, objecting waiting time etc.
TimeTicker.java
public class TimeTicker{ float ticker; public float TimeLimit; boolean hasCrossedTimeLimit; public boolean IsActive; public TimeTicker(float timeLimit){ TimeLimit=timeLimit; Reset(); } public void Reset(){ hasCrossedTimeLimit=false; } public void ResetTicker(){ ticker=0; } public void Update(float dt){ if(IsActive && !hasCrossedTimeLimit){ ticker+=dt; if(ticker>TimeLimit){ hasCrossedTimeLimit=true; ticker-=TimeLimit; } } } public Boolean HasCrossedTimeLimit(){ return hasCrossedTimeLimit; } }
So its a simple wrapper which we used for our game time. In the update of our game we call this function and check if the time limit is crossed then do the respective actions. You can add autoreset to it so it resets automatically from here rather than other parts of the code; it all depends on your game’s needs. We have two different functions to reset the values for the boolean and another for ticker. The reason is that usually when ticker crosses the timeLimit it usually wont be equal to timeLimit but would have some delta to it like ticker=TimeLimit+deltaTime. So in order to not lose the deltaTime in next iteration we subtract TimeLimit from ticker. But when we are restarting the level we set ticker to 0.
Next Tutorial:
In the next tutorial we will start developing the protagonist from our game Polar.
Let us know any of your doubts/suggestions; please put them in the comments section and we would try to answer them.
Thank you for the patience.
1 thought on “Game Development in Android using Libgdx Part VI”
Comments are closed.