📜 ⬆️ ⬇️

Translation SDL Game Framework Series. Part 6 - SDL Entities

In this lesson, as promised, I will tell you about such a thing as "Entities". “Entities” for all game processes are a kind of game objects that can interact in some form or in some way with each other and with the game world. Examples of “Entities” are monsters that you will encounter on your difficult path, treasure chests you can open, coins you can collect, walls to kill, etc. Thus, any object of the game world that somehow moves, exhibits interactivity, can be represented in the form of these “Entities”.

Well, let's say this: you have some kind of “Mountain”, which is part of your map, stands still and simply exists. It is not an "Entity." But if you want to make this “Mountain” move, fall on your hero (simply to interact with the objects of the game world), then it is naturally advisable to present it in the form of “Essence”. The author decided to break the narration into 3 articles (and I understand it perfectly, there is a lot of text and code, the translation will take a lot of time, so wait). In this lesson, everything will be quite simple - we will create a class for working with “Entities” and sort it out by the bones. In the next lesson we will learn how to create a map using tilesets and manage it. Well, at the end of the cycle - a detailed analysis of the interaction processes of game objects (processing of intersections (or collisions) of the “Entities” with other “Entities” and with the card itself).

In the meantime, create, as you already know, two CEntity.cpp and CEntity.h files with the following contents:

CEntity.h
#include <vector> #include "CAnimation.h" #include "CSurface.h" class CEntity { public: static std::vector<CEntity*> EntityList; protected: CAnimation Anim_Control; SDL_Surface* Surf_Entity; public: float X; float Y; int Width; int Height; int AnimState; public: CEntity(); virtual ~CEntity(); public: virtual bool OnLoad(char* File, int Width, int Height, int MaxFrames); virtual void OnLoop(); virtual void OnRender(SDL_Surface* Surf_Display); virtual void OnCleanup(); }; 


Well and accordingly:
')
CEntity.cpp
 #include "CEntity.h" std::vector<CEntity*> CEntity::EntityList; CEntity::CEntity() { Surf_Entity = NULL; X = Y = 0.0f; Width = Height = 0; AnimState = 0; } CEntity::~CEntity() { } bool CEntity::OnLoad(char* File, int Width, int Height, int MaxFrames) { if((Surf_Entity = CSurface::OnLoad(File)) == NULL) { return false; } CSurface::Transparent(Surf_Entity, 255, 0, 255); this->Width = Width; this->Height = Height; Anim_Control.MaxFrames = MaxFrames; return true; } void CEntity::OnLoop() { Anim_Control.OnAnimate(); } void CEntity::OnRender(SDL_Surface* Surf_Display) { if(Surf_Entity == NULL || Surf_Display == NULL) return; CSurface::OnDraw(Surf_Display, Surf_Entity, X, Y, AnimState * Width, Anim_Control.GetCurrentFrame() * Height, Width, Height); } void CEntity::OnCleanup() { if(Surf_Entity) { SDL_FreeSurface(Surf_Entity); } Surf_Entity = NULL; } 


As usual, it is time for me to explain to you what is going on here. I encapsulated from CApp 5 previously used by me (and you) methods (except for event handling - I will tell in the next lesson as I promised). Such an approach will allow us to “separate the wheat from the chaff” and process the “Entities” in a more transparent and simple way than if they were all pushed into a pile in the main ( CApp ) class. Also, we can easily handle something other than “Entities”. Have you already noticed the static vector EntityList ? It is designed to store the list of our game entities and is directly accessible through CEntity :: EntityList , all because it is static. Important: I specifically declared EntityList exactly in CEntity , since this approach will allow to avoid circular dependencies in the future. For example, the interaction of the Card with Entities, when the CMap class is declared as a member of CEntity and CEntity is declared as a member of CMap (here I myself did not understand a little what the author means), will lead to an error at the compilation stage.

So, this vector will store all our game “Entities” in the form of references to them (made with an emphasis on the future, when other classes are inherited from the CEntity class). So, for example, if we were going to make the game Megaman , we would have the CMegaMan class inherited from CEntity . And with the help of polymorphism, we can store objects of the CMegaMan class in an EntityList . This is the reason why we declared the above functions as virtual, and some members of the class are protected.

Our "Entity" has common parameters for all "Entities" - coordinates, dimensions, surface for drawing a picture. There is also a method for downloading this image, the default is just a transparent area. Lyrical digression: do not be afraid to change this code, it is not a postulate, it is not cut out of stone. Change it as you like, and if you make a mistake, the original is always there, will not go anywhere!

In the OnLoop method, we need to implement the basic calculations. But for now we will leave there only the calculation of the animation frames. Also note that we set only the MaxFrames variable for the animation, and left everything else as default. Get accustomed to OnRender . Instead of doing a stupid drawing on the screen, I entered a parameter to make it possible to point to any surface into which we would like to draw the “Entity”. Thus, you can even overlay the rendering of Entities on each other.

And finally, we have OnCleanup , my favorite cleaning of everything and everything (Purgatory is crying for me), the liberator of memory, a small economy.

As I said at the very beginning - we created only the basic structure of the class for the “Entities”, and, without truth, I’ll say that while this monster can do little (but will be able to do the following lessons). But we can make it work now! Open
CApp.h and add a couple of “Entities”:

CApp.h
 #include "CEntity.h" //...      private: CEntity Entity1; CEntity Entity2; 


Load them by writing the code in CApp_OnInit.cpp . (here you will need a picture from the last lesson, or rather 2 copies of it):

CApp_OnInit.cpp
 if(Entity1.OnLoad("./entity1.bmp", 64, 64, 8) == false) { return false; } if(Entity2.OnLoad("./entity2.bmp", 64, 64, 8) == false) { return false; } Entity2.X = 100; CEntity::EntityList.push_back(&Entity1); CEntity::EntityList.push_back(&Entity2); 


Remember how I said that we basically encapsulate the main functions of the game in an entity class? Now you need to call them a little bit. Edit the CApp_OnLoop.cpp :

 for(int i = 0;i < CEntity::EntityList.size();i++) { if(!CEntity::EntityList[i]) continue; CEntity::EntityList[i]->OnLoop(); } 

Those. we go over our vector with “Entities” and call the OnLoop method for each “Entity” (and also perform a small check in order not to run into the null pointer). It remains to do the same in CApp_OnRender.cpp :

 for(int i = 0;i < CEntity::EntityList.size();i++) { if(!CEntity::EntityList[i]) continue; CEntity::EntityList[i]->OnRender(Surf_Display); } 

Cleansing, dear, well, hello:

 for(int i = 0;i < CEntity::EntityList.size();i++) { if(!CEntity::EntityList[i]) continue; CEntity::EntityList[i]->OnCleanup(); } CEntity::EntityList.clear(); 

With the final stroke ( CEntity :: EntityList.clear () ) we nullify the “Entities” vector ... Compile, run, admire!
Thank you all for your attention.

Links to source code:


Links to all lessons:

Source: https://habr.com/ru/post/169295/


All Articles