UE4 - C++: How to design a local coop game where characters have different input schemes? - c++

this is my first post and I really did a lot of research on the topic before posting here. But now I found several possible solutions and I'm just not sure what is the proper way.
Problem
We are currently developing a local coop game that is a mix of an action game for one player and a puzzle game for the second one. Our actual problem is the input that is currently handled by a player controller that casts on every action mapping delegate received to determine if the possessed Pawn is from type PlayerA or PlayerB to then call the right function.
Let me give you a specific example:
We have two action bindings for the Button B (XBox Controller) currently called "B"
When the delegate is called we cast the possessedPlayer to check whether it shall call PlayerA->Jump or PlayerB->Blink
I'm totally unhappy with the situation that I have to cast everytime we receive an Input just to check wether I have possessed action/puzzle char
Solutions
1) Create 2 PlayerControllers and swap them by using GameMode::SwapPlayerController(Old, New)
I found this function during research but I'm not happy with creating a Player with PlayerControllerA to immediately switch it to use PlayerControllerB,
2) Shift responsibility to the Charatcer class
Another thought would be to delegate the decision making to the Character class by passing down an enum value like E_BUTTON_B from the PlayerController to the Character. We could write a macro that creates this enum based on our input mappings and then delegate the decision to a generic Character->ProcessInput(EnumValue) function. I'm also not quite happy because then the PC does not make so much sense to me.
3) Cache the possessed Pawn to avoid the cast
Another idea would have been to cache the type of the possessed Character whenever the PC possesses a Pawn. This would get rid of the cast per input delegate call.
I would be very glad for advide and any hint how you folks solve such issues in your games. Our main goals are separation of concern, good maintainability and input rebinding.
Cheers and have a nice day,
Parzival

You can create structure like this (written in C++, but this approach could be easily implemented in Blueprints as well):
class MyGameBasePlayerController : public PlayerController
{
// TODO methods common for both controllers (for example Escape key handling)
}
Now specific controllers:
class PuzzlePlayerControler : public MyGameBasePlayerController
{
UPROPERTY(BlueprintReadWrite, Transient, Category = "MyCat"
PuzzleCharacter* puzzleChar;
// TODO handle specific actions for Puzzle chararacter and control handling.
// TODO override base methods / input bindings if necesary
virtual void Possess(APawn* pawn) override;
}
Same goes for ActionPlayerCharacter.
You need to decide, how your characters will differ. If they are same, you can use something like MyGameCharacter : public PlayerCharacter (or you can use broader class PlayerPawn) and your PlayerControllers will call appropriate methods. Then your stored reference to MyGameCharacter can be stored in MyGameBasePlayerController.
Or you can use inheritance as well, so you will have PuzzleCharacter : public MyGameCharacter and ActionCharacter : MyGameCharacter with some common base implementation and extending methods or use virtual method overriding.
Depending on your final structure, you can use overriden Possess method (UE Docs) to get actual pawn instance, cast it to appropriate class (for example PuzzleCharacter or PuzlePawn in PuzzlePlayerController) and store reference for later usage. Be aware that in this case you should implement Unpossess as well, so you can clear your stored reference and behave correctly in any given situation.

Related

Use different subclass functions from base class

Say now I have a base class, let's call it GameEngine. The GameEngine class inherited several functions from another class. Now I have several game states and I need to apply sub-class polymorphism to this problem: several game states all need to draw background of the game window. The point is, I must have only ONE class to initialise my game window. My problem is, when I need to change my game states from one to another, how can I do it? Essentially, how can I use different version of subclass function(say DrawBackground) from my superclass?
The code:
BaseEngine *gameEngine;
gameEngine = new MenuState(this);
iResult = gameEngine->Initialise(...); // To initialise the window
// I need to find a way to transfer my state from Menu to Play after the window is initialised
iResult = gameEngine->MainLoop(); // To refresh the window (in case of background changed)
gameEngine->Deinitialise();
So in the above code, I have a BaseEngine which can do several functions (draw something to the window). And I now have two game states, MenuState and PlayState. There is one virtual function in my BaseEngine called DrawBackground() and I need to redefine it(different behaviour) in my Menu and Play states. Now the point is only one state(whether Base, Menu or Play) can initialise the window. However I need it to use different version of my derived class (Menu and Play) to draw different background when state is changed.
It is not really clear what you are asking but it feels like what you want is strategy pattern (that is, in simple words, changing some internal object/algorithm that does the job).
When dealing with inheritance, you should follow the so-called is-a relationship (Wikipedia on Inheritance). In your question, GameEngine is not a state (specifically MenuState).
What you should actually do is to implement the states as a strategy for GameEngine (See Strategy Pattern on Wikipedia, some, including me, call it Policy Pattern which is more self explanatory I think). You could have several classes inheriting from, say BaseState, and you should set these states on GameEngine via something like GameEngine::setState(std::unique_ptr<BaseState> state). The GameEngine will act differently according to the strategy set on it. So in a simple case, we can say that GameEngine::MainLoop() will call the virtual BaseState::draw() function. So the data that gets drawn is simply controlled by the policy set on the GameEngine using GameEngine::setState().
To put it simply, move the behavior to the BaseState strategy and change the strategy to change the behavior.
Optionally you could use some event mechanism to change the strategy (state). There is Boost.Signal, Qt has its own and there are others but it is straightforward to implement one for simple needs, easier thanks to C++11.

Programming pattern for components that are toggleable at runtime

I'm wondering if there is some kind of logical programming pattern or structure that I should be using if sometimes during runtime a component should be used and other times not. The obvious simple solution is to just use if-else statements everywhere. I'm trying to avoid littering my code with if-else statements since once the component is toggled on, it will more than likely be on for a while and I wonder if its worth it to recheck if the same component is active all over the place when the answer will most likely not have changed between checks.
Thanks
A brief example of what I'm trying to avoid
class MainClass
{
public:
// constructors, destructors, etc
private:
ComponentClass m_TogglableComponent;
}
// somewhere else in the codebase
if (m_TogglableComponent.IsActive())
{
// do stuff
}
// somewhere totally different in the codebase
if (m_TogglableComponent.IsActive())
{
// do some different stuff
}
Looks like you're headed towards a feature toggle. This is a common occurrence when there's a piece of functionality that you need to be able to toggle on or off at run time. The key piece of insight with this approach is to use polymorphism instead of if/else statements, leveraging object oriented practices.
Martin Fowler details an approach here, as well as his rationale: http://martinfowler.com/articles/feature-toggles.html
But for a quick answer, instead of having state in your ComponentClass that tells observers whether it's active or not, you'll want to make a base class, AbstractComponentClass, and two base classes ActiveComponentClass and InactiveComponentClass. Bear in mind that m_TogglableComponent is currently an automatic member, and you'll need to make it a pointer under this new setup.
AbstractComponentClass will define pure virtual methods that both need to implement. In ActiveComponentClass you will put your normal functionality, as if it were enabled. In InactiveComponentClass you do as little as possible, enough to make the component invisible as far as MainClass is concerned. Void functions will do nothing and functions return values will return neutral values.
The last step is creating an instance of one of these two classes. This is where you bring in dependency injection. In your constructor to MainClass, you'll take a pointer of type AbstractComponentClass. From there on it doesn't care if it's Active or Inactive, it just calls the virtual functions. Whoever owns or controls MainClass is the one that injects the kind that you want, either active or inactive, which could be read by configuration or however else your system decides when to toggle.
If you need to change the behaviour at run time, you'll also need a setter method that takes another AbstractComponentClass pointer and replaces the one from the constructor.

Accessing subclass functions of member of collection of parent class objects

(Refer Update #1 for a concise version of the question.)
We have an (abstract) class named Games that has subclasses, say BasketBall and Hockey (and probably many more to come later).
Another class GameSchedule, must contain a collection GamesCollection of various Games objects. The issue is that we would, at times, like to iterate only through the BasketBall objects of GamesCollection and call functions that are specific to it (and not mentioned in the Games class).
That is, GameSchedule deals with a number of objects that broadly belong to Games class, in the sense that they do have common functions that are being accessed; at the same time, there is more granularity at which they are to be handled.
We would like to come up with a design that avoids unsafe downcasting, and is extensible in the sense that creating many subclasses under Games or any of its existing subclasses must not necessitate the addition of too much code to handle this requirement.
Examples:
A clumsy solution that I came up with, that doesn't do any downcasting at all, is to have dummy functions in the Game class for every subclass specific function that has to be called from GameSchedule. These dummy functions will have an overriding implementation in the appropriate subclasses which actually require its implementation.
We could explicitly maintain different containers for various subclasses of Games instead of a single container. But this would require a lot of extra code in GameSchedule, when the number of subclasses grow. Especially if we need to iterate through all the Games objects.
Is there a neat way of doing this?
Note: the code is written in C++
Update# 1: I realized that the question can be put in a much simpler way. Is it possible to have a container class for any object belonging to a hierarchy of classes? Moreover, this container class must have the ability to pick elements belonging to (or derive from) a particular class from the hierarchy and return an appropriate list.
In the context of the above problem, the container class must have functions like GetCricketGames, GetTestCricketGames, GetBaseballGame etc.,
This is exactly one of the problems that The "Tell, Don't Ask" principle was created for.
You're describing an object that holds onto references to other objects, and wants to ask them what type of object they are before telling them what they need to do. From the article linked above:
The problem is that, as the caller, you should not be making decisions based on the state of the called object that result in you then changing the state of the object. The logic you are implementing is probably the called object’s responsibility, not yours. For you to make decisions outside the object violates its encapsulation.
If you break the rules of encapsulation, you not only introduce the runtime risks incurred by rampant downcasts, but also make your system significantly less maintainable by making it easier for components to become tightly coupled.
Now that that's out there, let's look at how the "Tell, Don't Ask" could be applied to your design problem.
Let's go through your stated constraints (in no particular order):
GameSchedule needs to iterate over all games, performing general operations
GameSchedule needs to iterate over a subset of all games (e.g., Basketball), to perform type-specific operations
No downcasts
Must easily accommodate new Game subclasses
The first step to following the "Tell, Don't Ask" principle is identifying the actions that will take place in the system. This lets us take a step back and evaluate what the system should be doing, without getting bogged down into the details of how it should be doing it.
You made the following comment in #MarkB's answer:
If there's a TestCricket class inheriting from Cricket, and it has many specific attributes concerning the timings of the various innings of the match, and we would like to initialize the values of all TestCricket objects' timing attributes to some preset value, I need a loop that picks all TestCricket objects and calls some function like setInningTimings(int inning_index, Time_Object t)
In this case, the action is: "Initialize the inning timings of all TestCricket games to a preset value."
This is problematic, because the code that wants to perform this initialization is unable to differentiate between TestCricket games, and other games (e.g., Basketball). But maybe it doesn't need to...
Most games have some element of time: Basketball games have time-limited periods, while Baseball games have (basically) innings with basically unlimited time. Each type of game could have its own completely unique configuration. This is not something we want to offload onto a single class.
Instead of asking each game what type of Game it is, and then telling it how to initialize, consider how things would work if the GameSchedule simply told each Game object to initialize. This delegates the responsibility of the initialization to the subclass of Game - the class with literally the most knowledge of what type of game it is.
This can feel really weird at first, because the GameSchedule object is relinquishing control to another object. This is an example of the Hollywood Principle. It's a completely different way of solving problems than the approach most developers initially learn.
This approach deals with the constraints in the following ways:
GameSchedule can iterate over a list of Games without any problem
GameSchedule no longer needs to know the subtypes of its Games
No downcasting is necessary, because the subclasses themselves are handling the subclass-specific logic
When a new subclass is added, no logic needs to be changed anywhere - the subclass itself implements the necessary details (e.g., an InitializeTiming() method).
Edit: Here's an example, as a proof-of-concept.
struct Game
{
std::string m_name;
Game(std::string name)
: m_name(name)
{
}
virtual void Start() = 0;
virtual void InitializeTiming() = 0;
};
// A class to demonstrate a collaborating object
struct PeriodLengthProvider
{
int GetPeriodLength();
}
struct Basketball : Game
{
int m_period_length;
PeriodLengthProvider* m_period_length_provider;
Basketball(PeriodLengthProvider* period_length_provider)
: Game("Basketball")
, m_period_length_provider(period_length_provider)
{
}
void Start() override;
void InitializeTiming() override
{
m_period_length = m_time_provider->GetPeriodLength();
}
};
struct Baseball : Game
{
int m_number_of_innings;
Baseball() : Game("Baseball") { }
void Start() override;
void InitializeTiming() override
{
m_number_of_innings = 9;
}
}
struct GameSchedule
{
std::vector<Game*> m_games;
GameSchedule(std::vector<Game*> games)
: m_games(games)
{
}
void StartGames()
{
for(auto& game : m_games)
{
game->InitializeTiming();
game->Start();
}
}
};
You've already identified the first two options that came to my mind: Make the base class have the methods in question, or maintain separate containers for each game type.
The fact that you don't feel these are appropriate leads me to believe that the "abstract" interface you provide in the Game base class may be far too concrete. I suspect that what you need to do is step back and look at the base interface.
You haven't given any concrete example to help, so I'm going to make one up. Let's say your basketball class has a NextQuarter method and hockey has NextPeriod. Instead, add to the base class a NextGameSegment method, or something that abstracts away the game-specific details. All the game-specific implementation details should be hidden in the child class with only a game-general interface needed by the schedule class.
C# supports reflections and by using the "is" keyword or GetType() member function you could do these easily. If you are writing your code in unmanaged C++, I think the best way to do this is add a GetType() method in your base class (Games?). Which in its turn would return an enum, containing all the classes that derive from it (so you would have to create an enum too) for that. That way you can safely determine the type you are dealing with only through the base type. Below is an example:
enum class GameTypes { Game, Basketball, Football, Hockey };
class Game
{
public:
virtual GameTypes GetType() { return GameTypes::Game; }
}
class BasketBall : public Game
{
public:
GameTypes GetType() { return GameTypes::Basketball; }
}
and you do this for the remaining games (e.g. Football, Hockey). Then you keep a container of Game objects only. As you get the Game object, you call its GetType() method and effectively determine its type.
You're trying to have it all, and you can't do that. :) Either you need to do a downcast, or you'll need to utilize something like the visitor pattern that would then require you to do work every time you create a new implementation of Game. Or you can fundamentally redesign things to eliminate the need to pick the individual Basketballs out of a collection of Games.
And FWIW: downcasting may be ugly, but it's not unsafe as long as you use pointers and check for null:
for(Game* game : allGames)
{
Basketball* bball = dynamic_cast<Basketball*>(game);
if(bball != nullptr)
bball->SetupCourt();
}
I'd use the strategy pattern here.
Each game type has its own scheduling strategy which derives from the common strategy used by your game schedule class and decouples the dependency between the specific game and game schedule.

Retrieving values of collection from multiple classes, what's the correct way?

Before anything, thanks for reading!
I'm developing an application in C++ and I want an advice about a design issue. Let me explain:
The main class of my application has some collections, but other classes eventually need to get a value from one of those collections. Something like this:
class MainClass {
private:
// Collections are internally implemented as QHash
Collection<Type1> col1;
Collection<Type2> col2;
};
class RosterUnit {
public:
RosterUnit() {
/* This method needs to get a specific value from col1 and
initialize this class with that data */
}
};
class ObjectAction {
public:
virtual void doAction() = 0;
};
class Action1 : public ObjectAction {
public:
void doAction() {
// This needs a specific value from col2
}
};
class Action2 : public ObjectAction {
public:
void doAction() {
// This needs a specific value from col1
}
};
My first approach was passing the whole collection as parameter when needed, but it is not so good for ObjectAction subclasses, because I would have to pass the two collections and if I later create another subclass of ObjectAction and it needs to get an element from other collection (suppose col3), I would have to modify the doAction() signature of every ObjectAction subclass, and I think that is not too flexible. Also, suppose I have a Dialog and want to create a RosterUnit from there. I would have to pass the collection to the dialog just to create the RosterUnit.
Next I decided to use static variables in RosterUnit and ObjectAction that pointed to the collections, but I'm not very happy with that solution. I think it is not flexible enough.
I have been reading about design patterns and I first thought a Singleton with get functions could be a good choice, but after some more investigation I think it isn't a proper design for my case. It would be easier and more or less the same if I use global variables, which don't seem to be the right way.
So, could you give some advices, please?
Thank you very much!
As mentioned previously, Iterators are good for abstracting away the details of the Collection. But going this route implies that the objects that use the Iterators will need to know about what's inside the Collection. Meaning they will need to know how to decide which object in the Collection they need, thus increasing the coupling. (more details below in the Factory paragraph) This is something you need to consider.
Another approach would be to create accessor methods on the MainClass that take some sort of key and return an object from the Collection (findObject(key)). Internally the MainClass methods would search through the container(s) and return the appropriate object. To use this approach, you will however need access to the MainClass, either by dependancy injection as mentioned before, or possibly making it a Singleton (not recomended in this scenario, though).
With the info provided so far, it may even be better for your ObjectAction Factory to have a reference to the MainClass, and as a part of the ObjectAction creation logic, call the appropriate MainClass accessor and pass the result into the ObjectAction, thus decoupling the ObjectAction Objects from the MainClass.
You probably want to use iterators, they exist exactly for the purpose of abstracting away sequences from specific containers.
If your issue is how to pass the iterators to the code that needs them in the first place, do not give in to the temptation to use globals. It may look more convoluted if you have to pass parameters in, but your code is that much more decoupled for it. "Dependency Injection" is a good keyword if you want to read more about this topic.
I would also advise you to check out std::function or boost::function instead of inheriting from ObjectAction. Functional style is getting more common in modern C++, as opposed to how it's usually done in languages like Java.
There's not enough information here of what you are trying to do. You make it sound like 'at some point in the future, this statically created action needs this data that was left behind.' How does that make any sense? I would say either construct the actions with the data, as you would for instance with a Future or Callable), or have the command ask for the next piece of data, in which case you are just implementing a Work queue.
Sounds like you are trying to do something like a thread pool. If these actions are in any way related, then you should have then in some composing object, implementing something like the Template Method pattern, e.g. execute() is abstract and calls a few other methods in a fixed sequence and that cannot be overridden, the other methods must be (protocol enforcement).

Is creating a base class for all applications of a particular type good design?

I am trying to write a graphics application in C++. It currently uses OGRE for display, but I'd like it to work with Irrlicht or any other engine, even a custom rendering engine which supports my needs. This is a rather long question, so I'd appreciate help on re-tagging/ cleanup (if necessary). I'll start with a little background.
The application has three major states:
1. Display rasterized scene
2. Display a ray traced version of the same scene
3. Display a hybrid version of the scene
Clearly, I can divide my application into four major parts:
1. A state management system to switch between the above modes.
2. An input system that can receive both keyboard and mouse input.
3. The raster engine used for display.
4. The ray tracing system.
Any application encompassing the above needs to be able to:
1. Create a window.
2. Do all the steps needed to allow rendering in that window.
3. Initialize the input system.
4. Initialize the state manager.
5. Start looping (and rendering!).
I want to be able to change the rendering engine/state manager/input system/ ray tracing system at any time, so long as certain minimum requirements are met. Imho, this requires separating the interface from the implementation. With that in mind, I created the interfaces for the above systems.
At that point, I noticed that the application has a common 'interface' as well. So I thought to abstract it out into an ApplicationBase class with virtual methods. A specific application, such as one which uses OGRE for window creation, rendering etc would derive from this class and implement it.
My first question is - is it a good idea to design like this?
Here is the code for the base class:
#ifndef APPLICATION_H
#define APPLICATION_H
namespace Hybrid
{
//Forward declarations
class StateManager;
class InputSystem;
//Base Class for all my apps using hybrid rendering.
class Application
{
private:
StateManager* state_manager;
InputSystem* input_system;
public:
Application()
{
try
{
//Create the state manager
initialise_state_manager();
//Create the input system
initialise_input_system();
}
catch(...) //Change this later
{
//Throw another exception
}
}
~Application()
{
delete state_manager;
delete input_system;
}
//If one of these fails, it throws an
//exception.
virtual void initialise_state_manager() = 0;
virtual void initialise_input_system() = 0;
virtual void create_window() = 0;
//Other methods.
};
#endif
When I use OGRE, I rely on OGRE to create the window. This requires OGRE to be initialised before the createWindow() function is called in my derived class. Of course, as it is, createWindow is going to be called first! That leaves me with the following options:
1. Leave the base class constructor empty.
2. In the derived class implementation, make initialising OGRE part of the createWindow function.
3. Add an initialize render system pure virtual function to my base class. This runs the risk of forcing a dummy implementation in derived classes which have no use for such a method.
My second question is- what are your recommendations on the choice of one of these strategies for initialising OGRE?
You are mixing two unrelated functions in one class here. First, it serves as a syntactic shortcut for declaring and initializing StateManager and InputSystem members. Second, it declares abstract create_window function.
If you think there should be a common interface - write an interface (pure abstract class).
Additionally, write something like OgreManager self-contained class with initialization (looping etc) methods and event callbacks. Since applications could create and initialize this object at any moment, your second question is solved automatically.
Your design may save a few lines of code for creating new application objects, but the price is maintaining soup-like master object with potentially long inheritance line.
Use interfaces and callbacks.
P.S.: not to mention that calling virtual functions in constructor doesn't mean what you probably expect.
Yes, that is a good design, and it is one that I use myself.
For your second question, I would remove anything from the base constructor that has any possibility of not being applicable to a derived class. If OGRE wants to create the window itself then you need to allow it to do that, and I don't think that it makes sense to initialize OGRE in createWindow (it's misleading).
You could add an initialize render system virtual method, but I think you should just leave that task to the derived class's constructor. Application initialization is always a tricky task, and really, really difficult to abstract. From my experience, it's best not to make any assumptions about what the derived class might want to do, and just let it do the work itself in any way that it wants.
That said, if you can think of something that will absolutely apply to any conceivable derived class then feel free to add that to the base constructor.