Whats the right design pattern for: Universal cancel button

Perhaps some real programmers can offer some advice here :slight_smile:

Imagine we have a building game. From various widgets you might select different things you could construct. You click an ACTION BUTTON and that is going to prepare for a certain action.
E.g. the building to be constructed might appear with an xray shader and then once you click, the actual action of building the thing occurs.

But we should be able to cancel that action, either before it starts or during a queue while it is happening.

In case that is not clear, I’ll describe how it might look in a game:

  • Click widget button to select BuildingA
  • Now image of that building follows mouse cursor
  • Left click starts a queue and once the queue is finished the new building appears
  • Right click cancels the order to build, either before you had started the building or during the queue as well

Ideally, this Request > Queue > Action process is encapsulated so that no matter what sort of request and action is meant to happen, a single event will always cancel them.

In order to accomplish that universal cancel, I believe something like a command pattern, in which we encapsulate a request into an object, might be appropriate here?

My idea is that PendingAction is a Uobject that gets created on button press. There would be a parent class which implements an interface, and children instances can implement whatever interface functions/events that they need. So, each instance can handle things in their own way.

One pendingAction object might handle an OnRequest() function by telling the player pawn to show the building model in xray mode. And then it would also handle the left click event and pass that to the player pawn, informing it to start teh queue and proceed with the building.

I suppose then that the Universal cancel could then exist on the parent class, and each instance then would just undo whatever things that had been responsible for doing.

I think that makes sense… If you have any input/advices I do appreciate it. Mostly I am using community for rubber ducky here but I figure it may get me some help and/or it may possibly help other people as well.

I’ve found a good example that appears to be using similar idea. it’s free too:

Hey @BIGTIMEMASTER, it looks like you are on the right track here. The system you propose here is a perfectly valid solution for your problem.

The details of your system will depend mostly on your game. A different solution that I can think of would be if you have more actions in your game that behave in a similar way. By this I mean that the action lifecycle is:

In that case, your pending action would not only be used for building. If you want this action to do other things too, then maybe a better approach would be to have an additional layer to your solution. By this I mean that now your PendingAction will only handle the workflow of the diagram and not worry about the actual functions being called in the process. In this case, you would want to have an interface (lets say IAction) and use that interface in your PendingAction. Then the different classes that implement that interface will handle the actual behavior for said actions. I hope the following diagram helps you get a better idea.

The idea of this, is to separate concerns. This way your PendingAction class only worries about executing an action and makes sure that action’s lifecycle is completed. It doesn’t care about the actual action’s behavior, only that it is completed (or canceled) correctly. This will make things easier to debug for you, since you know that these behaviors are decoupled.

Hope this makes sense to you. As I said, this may not be the right solution for you and you may be ok with the one that you propose in your question. It is a good thinking exercise though. Good luck!

Edit: Oh, and worth mentioning. If you are planning to add more functionalities (different types of actions) in the future, but not right away, then you probably are better off going with the simplest solution. Otherwise you would be adding more complexity to your system for some functionality that you may never end up implementing. This is called needless complexity, feel free to look it up.

2 Likes

hey thanks a lot! unfortunately its a bit late here and i’m too hungry to think :slight_smile:

i’ll go through this carefully tomorrow - it looks like you’ve addressed a couple concerns i had but i’m too scatter brained at the moment to properly mull it over.

taking a quick look at your diagram makes me think the ideas i was just messing with are in same vein- because i do want for a generic “actions” class to be able to cover a broader scope of things. Not just building. But i’ll make a more thought out response tomorrow.

1 Like

This looks like it’s going to work out pretty well for me.

I think I’ve built it almost exactly like you suggested, with one minor change.

I have an Action_Base_BP for the parent. It pretty much does nothing except hold some basic references and functions.

From that I am deriving instances for any type of game action, whether it is aiming a weapon, moving to clicked location, fishing at a spot, etc.

For actions where I want a delay, I derive another type of child from Action_Base_BP, which I call Latent_Action_BP. It adds a boolean for checking if an action is in progress, and an event for when the action has been reported to be finished.

Since I can’t use delays/timers in the object itself, I just put a delay event on the controller which will then call the Action objects Finished event. So it’s just like passing a ball back and forth, pretty easy to conceptualize and manage for a solo-developer like myself.

So the building systems actions would all derive from the Latent_Action parent class - or any other sorts of things where I want it to have a progress bar and take some time to happen.

Well, this feels like a pretty good setup that should give me programming ease. Thanks again for advice.

1 Like