In the last article, we didn't have a pleasant chat. I don't think we are very suitable for... Shit! What do you say.
In the last article, we just found out how the author of the framework made the game enter the main scene of the game. What really matters is what is done in the main scene of the game. In this article, let's guess what is done in procedure main. (Narrator: sure enough, it's a lie from the beginning. It's always guessing!)
1.OnInit
ProcedureMain is also a process. Naturally, we study it according to the life cycle of the process. The first is OnInit. Even if we guess, it is executed before OnEnter. I'm very sure
Later, I studied it and found that OnInit was invoked before OnEnter, and it was very early, and it was called when the process was initialized (at the same time, it did not switch to Main process). If you're right, it's such a logic. We'll study it further in the future.
protected override void OnInit(ProcedureOwner procedureOwner) { Debug.LogError("OnInit"); base.OnInit(procedureOwner); m_Games.Add(GameMode.Survival, new SurvivalGame()); }
OnInit only does one thing - add the processing class corresponding to the game type.
m_Games is just a dictionary object used to store processing classes corresponding to different game types (such as survival, infinity and level mode).
You don't have to have this m_ The of the Games object is only that the StarForce project does so, which has nothing to do with the Game Framework itself.
Since StartForce only has survival mode, only one type is added here.
2.OnEnter
The most important is the OnEnter function:
protected override void OnEnter(ProcedureOwner procedureOwner) { Debug.LogError("OnEnter"); base.OnEnter(procedureOwner); // Controls whether to return to the marking of the menu m_GotoMenu = false; // Get the game type (GameMode is just an enumeration) GameMode gameMode = (GameMode)procedureOwner.GetData<VarInt>(Constant.ProcedureData.GameMode).Value; // Get the processor corresponding to the game type (let's call it that for the time being) m_CurrentGame = m_Games[gameMode]; // Initialize game m_CurrentGame.Initialize(); }
OnEnter is also very simple. It only does one thing - initializing the game.
However, StarForce is not a demo written at random. It does some simple encapsulation (such as game mode).
Here, you need to get the processing class corresponding to the game mode first, and then call the processing class for initialization.
The operation here is not a fixed routine. You can initialize the game in your own way.
You may have noticed a VarInt type, which is actually an int type (finally), but in order to avoid some bug s, the framework author needs to use the encapsulated type in some cases. Please refer to: http://gameframework.cn/archives/227
3. Game logic (GameBase)
As we saw in the previous step, the SurvivalGame class will be obtained during OnInit to initialize the game.
If you listen to me carefully and do what I say, you should have found that SurvivalGame inherits GameBase (Narrator: I didn't say it at all! I didn't mention it at all! Don't fool around.)
So let's take a look at GameBase first. It is a class of StarForce and is not built in the framework. Therefore, all things done in GameBase can be implemented in our own way. Don't be framed.
There are several functions of GameBase, none of which is important. I'll just tell you about the initialization function:
public virtual void Initialize() { // Subscribe to messages that display entities GameEntry.Event.Subscribe(ShowEntitySuccessEventArgs.EventId, OnShowEntitySuccess); GameEntry.Event.Subscribe(ShowEntityFailureEventArgs.EventId, OnShowEntityFailure); SceneBackground = Object.FindObjectOfType<ScrollableBackground>(); if (SceneBackground == null) { Log.Warning("Can not find scene background."); return; } SceneBackground.VisibleBoundary.gameObject.GetOrAddComponent<HideByBoundary>(); // a key! Show the player's aircraft entity. Here are several layers of packaging GameEntry.Entity.ShowMyAircraft(new MyAircraftData(GameEntry.Entity.GenerateSerialId(), 10000) { Name = "My Aircraft", Position = Vector3.zero, }); GameOver = false; m_MyAircraft = null; }
About the initialization function, I just want to say one - how does it load the player's plane?
I have made comments in the code. Loading the aircraft calls the ShowMyAircraft function, which is not a function of the framework, but a function of StarForce.
After following up layer by layer, you should find that the function finally calls entityextension ShowEntity function in CS:
private static void ShowEntity(this EntityComponent entityComponent, Type logicType, string entityGroup, EntityData data) { if (data == null) { Log.Warning("Data is invalid."); return; } IDataTable<DREntity> dtEntity = GameEntry.DataTable.GetDataTable<DREntity>(); DREntity drEntity = dtEntity.GetDataRow(data.TypeId); if (drEntity == null) { Log.Warning("Can not load entity id '{0}' from data table.", data.TypeId.ToString()); return; } entityComponent.ShowEntity(data.Id, logicType, AssetUtility.GetEntityAsset(drEntity.AssetName), entityGroup, data); }
The focus is on GetDataRow and ShowEntity functions.
Here are roughly two things:
a. Read the configuration file through the ID of the player's aircraft
b. Load the entity according to the configuration of the configuration file
As for how the configuration file is loaded, we don't study it in depth here, but we can see what the configuration file looks like (Assets\GameMain\DataTables directory):
Now recall the initialization function of GameBase:
Did you think of something magical? (Narrator: not at all)
Let's go through the whole process of creating player aircraft entities again:
a. The initialization function in gamebase calls the ShowMyAircraft function, and the parameter is a myaircraft data type, specifying the configuration file id (typeID: 10000)
b. From entity. According to typeID Txt configuration file
c. According to the read configuration data, call the ShowEntity function of the framework to load the entity
d. As for how entities are loaded, I won't go into it for the time being
This is a very simple process. You can understand it by looking at the code.
If you don't understand... Maybe you haven't reached the level of learning framework. In this case, you can write more games first.
4.SurvivalGame processing class
GameBase is just a basic class. It is the basis of all game modes. It does this because all game modes need to create player aircraft entities.
What we want to study is how the game logic is handled in the survival mode, so now let's look at the SurvivalGame class (inheriting GameBase).
SurvivalGame is very simple. There is only one Update function:
public override void Update(float elapseSeconds, float realElapseSeconds) { base.Update(elapseSeconds, realElapseSeconds); m_ElapseSeconds += elapseSeconds; // Create a monster every 1 second if (m_ElapseSeconds >= 1f) { m_ElapseSeconds = 0f; IDataTable<DRAsteroid> dtAsteroid = GameEntry.DataTable.GetDataTable<DRAsteroid>(); // Random x and z coordinates float randomPositionX = SceneBackground.EnemySpawnBoundary.bounds.min.x + SceneBackground.EnemySpawnBoundary.bounds.size.x * (float)Utility.Random.GetRandomDouble(); float randomPositionZ = SceneBackground.EnemySpawnBoundary.bounds.min.z + SceneBackground.EnemySpawnBoundary.bounds.size.z * (float)Utility.Random.GetRandomDouble(); // Load monster entity GameEntry.Entity.ShowAsteroid(new AsteroidData(GameEntry.Entity.GenerateSerialId(), 60000 + Utility.Random.GetRandom(dtAsteroid.Count)) { Position = new Vector3(randomPositionX, 0f, randomPositionZ), }); } }
Survivvalgame does only one thing - create monsters regularly.
The way to create monsters is very simple, just like creating player aircraft entities.
Every 1 seconds, a random coordinate is obtained, and then the ShowAsteroid function is called to create the monster entity (typeID = 60000).
Showasterioid function we don't need to follow in to know what it does (read the configuration file and load the entity according to the configuration).
5. Nag
From the above introduction, we roughly found a secret of the framework author - all objects in the game (such as monsters and players) are loaded from the configuration file and then created. (Narrator: Yes, the framework author said it at the beginning, but you spent a lot of time explaining it)
So far, we haven't entered the most important part. In the next article, let's take a look at how the logical processing class of the player's aircraft is bound to the aircraft object.