Skip to content

Game View Layer

enriquegr84 edited this page Mar 9, 2020 · 1 revision

A game view is a collection of systems that communicates with the game logic to present the game from a certain perspective. The BaseGameView interface shows the functions that the game application uses to update and render game views once every game tick, to restore game views when they are broken, and to process device messages from the application layer. Any conceivable message that the game views want to see will be passed and translated into the generic message form by the application layer.

class BaseGameView
{
public:
	virtual bool OnRestore()=0;
	virtual void OnRender(double time, float elapsedTime)=0;
	virtual void OnUpdate(unsigned int timeMs, unsigned long deltaMs)=0;

	virtual bool OnLostDevice()=0;
	virtual GameViewType GetType()=0;
	virtual GameViewId GetId() const=0;
	virtual ActorId GetActorId() const=0;
	virtual void OnAttach(GameViewId vid, ActorId aid)=0;

	virtual bool OnMsgProc(const Event& event)=0;

	virtual ~BaseGameView() { };
};

The engine present three different point of views which can be attached to the game application; the Human view interacts and presents the game to a human player; the AI view controls an NPC and the Remote view controls a human player over network.

Human View. This game view uses the graphic system to display the scene for a human player. Audio is another important system of the game view used for displaying sounds, ambient music, speech and many other effects which can be processed by the engine.

class HumanView : public BaseGameView
{
public:
   	bool LoadGame(tinyxml2::XMLElement* pLevelData);
        eastl::list<eastl::shared_ptr<BaseScreenElement>> mScreenElements;

   	eastl::shared_ptr<BaseMouseHandler> mMouseHandler;
   	eastl::shared_ptr<BaseKeyboardHandler> mKeyboardHandler;

        bool InitAudio();
  	ProcessManager* GetProcessManager() { return mProcessManager; }

   	eastl::shared_ptr<ScreenElementScene> mScene;
	eastl::shared_ptr<CameraNode> mCamera;
};

This class handle a list of active screens such as menus, game scenes, cut scenes and any other format which requires of graphic visualization. A screen element is anything that draws and accepts input. It could be anything from a user interface (UI) to the rendered 3D world. Screen elements in various configurations create the UI for the game, such as a menu or inventory screen. Some run on top of the main game screen, but others might completely overlay the main view and even pause the game. In addition to acting as a container for user controls, screen elements parse input device messages from the application layer and translate them into generic message form which will be passed to all the game views.

The BaseScreenElement interface has basic operations applied to the screen such us, rendering or restoring its graphic elements, apply the rendering order in relation to other screen elements, and set or get visibility.

class BaseScreenElement
{
public:
	virtual bool OnInit() = 0;
	virtual bool OnRestore() = 0;
	virtual bool OnLostDevice() = 0;

	virtual bool OnRender(double time, float elapsedTime) = 0;
	virtual void OnUpdate(unsigned int timeMs, unsigned long deltaMs)=0;

	virtual int GetZOrder() const = 0;
	virtual void SetZOrder(int const zOrder) = 0;
	virtual bool IsVisible() = 0;
	virtual void SetVisible(bool visible) = 0;

	virtual bool OnMsgProc(const Event& event) = 0;

	virtual bool const operator <(BaseScreenElement const &other) 
	{ return GetZOrder() < other.GetZOrder(); }
};

The game application initializes all human views by calling their LoadGame() member function. This function is responsible for creating view-specific elements from an XML file that defines all the elements in the game. For example, it might include a background music track, which could be appreciated by the human player but is inconsequential for the game logic.

The OnRender() method is responsible for rendering the view. It implements a loop which iterates through the screen elements and call their render method in case that they are visible. The 3D Renderer is responsible for displaying the view at a tolerable frame rate to the observer and is designed based on an abstract interface which implements each render API, that is, Direct3D and OpenGL.

The OnRestore() method is responsible for recreating anything that might be lost while the game is running. The OnLostDevice() will be called prior to OnRestore() in order to release the objects so they will be re-created in the call OnRestore().

The OnMsgProc() method iterates through the list of screens attached to the human view, forward the message on the visible ones. If the message hasn’t been consumed, then it tries to pass it to the mouse and keyboard handlers of the human view.

The OnUpdate() method is called once per frame by the application layer so that it can perform non-rendering updating tasks. This method updates any of the screen elements attached to the human view, such as the objects in the 3D scene. A game object that exists in the game universe and is affected by game rules, like physics, belongs to the game logic. Whenever the game object moves or change its state, it fires off events that the views will receive for updating the visual representation. Some of these visual representations such as particle effects, only exist visually and have no real effect on the world themselves. Since the game logic knows nothing about them, they are completely contained and updated in the human view.

The logic layer updates the audio system which is a process that we attach to the ProcessManager. The audio system is another example of what human perceives but the game logic does not. Background music and ambient sound effects have no effect on the game logic per se and therefore can safely belong to the human view. The Audio base is an abstract class that provides means to display sounds for multiple platforms through a generic interface. Currently it is implemented the DirectSoundAudio class which completes the Audio interface using DirectSound calls.

AI View. The engine has separated the AI logic which manages the stimulus interpreter and decision-making system from the AI view which manages basic behavior such as moving, attacking and any other kind of action designed in the game. This approach makes a clear separation of the AI logic layer, specialized on thinking processes and decision making for every type of NPC and the AI view layer which is concerned with NPCs basic actions. The communication between logic and view is as always through an event-based interface. Each decision made in the AI logic is translated into an action and sent to the AI view through events.

Another approach would be to implement the AI behavior in terms of thinking and acting as a whole. The top-level decision-making and the low-level behaviors would be implemented in the same AI view. This approach has the benefit that simple AI can be easily developed without any communication concerns. If the AI is a scalable system, the first option would be a better design approach.

Remote view. A remote view involves the creation of two separated game logic/view communicated over network; the authoritative server and the remote client.

The game logic in the authoritative server is the real course of action that the game takes. The game view in the authoritative server and the game logic in the remote client keeps both-sided communication between client/server machines but the events are packaged up via TCP or UDP across the network. From one side, the authoritative server sends events to the remote game logic and from other side, it receives controller input as game commands from the remote game logic. The difference is that the game logic from the remote client needs to adjust its game state to the server game state and also needs to predict authoritative decisions to handle possible delays in internet. On the other side, the authoritative server logic interpreters the controller input commands from the remote game logic and makes the final decision of what happens in the game.

Clone this wiki locally