I do a bit of solo game development and always get stuck on some part of the architecture where I can’t decide what the best way to tackle a problem is. I’ve just run into a good architecture problem, and I’m hoping I’ll be able to use lessons learned from it down the road. I’ll abstract it down a bit to a theoretical problem:

Say my game has two abilities, “Heal Player” and “Stun Enemies”. Each of the abilities is reusable with a cooldown. The game will need a separate button to activate each of the abilities.

The core class for gameplay is called GameplayCore. My GUI is all contained in an HUD class, and the enemies are all controlled by an EnemyManager. The Player class contains the player’s health. GameplayCore creates and stores the HUD instance, EnemyManager instance, and Player instance.

Obviously I want to separate the UI code from the functionality code. So say on the GUI side I’ve got HealButton, StunButton, and HealthBar classes that define the appearance and behavior of those controls. On the functionality side, I’ve got the Player class with a health property, an AbstractAbility class that defines shared ability behavior including cooldown, and the HealAbility and StunAbility classes that extend it to define concrete implementations.

To keep GameplayCore from getting too bloated, I make an AbilitySet class to create and manage the HealAbility and StunAbility instances, and make an instance of AbilitySet in GameplayCore.


Here’s where things start to fall apart. I want to be able to change the appearance of the buttons as their cooldowns elapse. I want the cooldown code to be self-contained in AbstractAbility, so HealAbility and StunAbility need references to their corresponding buttons. Now I need to pass those references back from HUD to GameplayCore and then into the constructor of AbilitySet so they can be passed into the constructors for the ability buttons. HealAbility needs references to the HealthBar (in HUD) and the Player (in GameplayCore). StunAbility needs a reference to EnemyManager so it can retrieve the collection of enemies to loop through and stun them. But HUD needs references to the HealAbility and StunAbility so it can call them when the buttons are pressed.

Everything has gotten pretty tangled; there is too much coupling and I’m honestly not sure where the best place to construct the ability classes is. I’m very tempted to merge all of the ability code into the ability buttons, which would greatly simplify everything, but then I’d have important functionality code mixed into a UI class.


What’s a good organizational approach to this problem? What are some good architectural strategies I could use to keep the code from getting too tangled? Is my entire approach heavily flawed?

edit: I should note this particular project is in ActionScript 3, which does include an event system (with its own quirks and limitations).

9

I have actually written a large scale game gui that implements (among many other things) precisely those actions that you are talking about. The way it worked is that the gui was completely separated from the game logic, so you could, in theory, play the game without the gui, or instantiate two guis on the same gamelogic. Nobody ever tried that, but it was theoretically possible, and the fact that it was possible reveals an important characteristic of the design:

The gui must know the gamelogic.

The gamelogic should know absolutely nothing about the gui.

The way this is accomplished is by making everything in the gamelogic observable, and making the gui register various observers to receive notifications from the gamelogic.

So, when the user clicks the button, the button tells the gamelogic to perform the corresponding action.

The action does whatever it is supposed to do, and then it sets its own time-to-unblock to 100%. Since the state of the action object has now changed, it issues a notification to that effect.

The gui has registered with the gamelogic to receive events about the action, so it receives this notification, it retrieves the new state of the action, and it paints the button as fully disabled.

Then on the next tick (the next iteration of the main loop of the game) the action reduces the time-to-unblock to, say, 95%, and issues another event about that change.

The gui receives this event and repaints the button to show it partially disabled. And so on, and so forth.

3

As Stephen suggested in his comment, you could use the observer Pattern to connect the different parts of your application.

However, this is a rather static approach, and you will have to implement interfaces everywhere and the dependencies are still strong. Since this is a game, your structure, logic and gameplay might will change over time.

I’d recommend using an event-based approach. It works similar to the Observer, with the difference that neither the sender nor the receiver know about each other (no explicit “notify”).

You’d simply fire an “HealthChanged”-event, and every component that is interested will just act accordingly.
You can achieve this by using an Event bus.

If you want to make the program really un-coupled and flexible, you might consider using the event mechanics together with an Entity system

It’s a component-based approach: Instead of having a health attribute in the player class, the player would be defined by it’s components : Health, Attack and Position (or whatever else).

Since I’m not sure if this might be too much overhead for a free-time-project like yours, I won’t go into much detail here. But you can check the above link and more detail here

5

Obviously I want to separate the UI code from the functionality code.

In my opinion games are a category where it is very forgivable to abandon this requirement and just couple game logic to UI unless you are aiming for the type of game where such decoupling is beneficial, like one that could run in a completely different GUI environment with a completely different set of graphics and maybe even a completely different set of controls.

That said, if you want to keep it decoupled, you could simply “map/associate” the GUI code to a given ability type, like “StunWidget” to “typeof(StunAbility)”, like so:

MapWidget(typeof(StunAbility), StunWidget)

The mapped widget automatically gets passed the ability instance when it is constructed for a given ability type.

Then when you have a unit selected, you can loop through the abilities available using something like reflection for that unit and create/insert/display the associated GUI controls (given its ability type as key to find the associated ability type widget) for each ability. Then the widget becomes responsible for activating the ability, targeting it if it requires targeting, displaying the cooldown, etc, maybe with a matrix-like display as in Starcraft showing what you can do with the unit:

enter image description here

I love that 3×3 matrix design for the GUI in Starcraft 1, never presenting more than 9 hotkeyable controls to the user at once. I think it’s one of the most optimal workflows for a game that allows selecting multiple units, like an RTS or RPG where you have multiple party members you can select individually (including TRPGs). I think the effectiveness of such a design reveals itself through the players who can perform hundreds of actions per minute under such a workflow.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật