Work with hierarchical effects in iOS games and applications

I started working as an iOS developer about a year and a half ago, and I'm having problems with the architecture and organization of the software. I use the Apple-recommended Model-View-Controller paradigm, and my code is usually very hierarchical: if the screen has (for example) a HUD, a control panel and a display area, I have a main controller for the screen and sub-controllers for the HUD. control panels and display areas. Sub-controllers are usually unaware of their neighboring controllers and use the methods in the main controller to interact with them.

However, especially in games, I often encounter hierarchy-dependent problems that simply cannot be elegantly solved with this model. For example, let's say I have a coin in the control panel area that I want to revive when flying in a HUD. I can either animate the original coin, or a new position that needs a method such as animateCoinToPosition: in the control panel subcontroller and the getPositionForFinalCoinPositionInHUD method in the main controller; or I can hide the original coin and create a duplicate coin either in the main controller or in the HUD controller, which requires a delegate method such as animateCoinToHUDFromStartingPosition :. I don’t like such strange-specific methods in my controllers, because they really exist to solve one problem and additionally reveal the hierarchy. My ideal solution would be to have one method called animateCoinToHUD, but that would require smoothing the whole hierarchy and merging the three controllers into one, which is obviously not worth it. (Or giving subcontrollers access to their brothers and sisters), but this will essentially have the same effect. The subcontrollers will then have dependencies with each other, creating a single messy controller of arachnid pauses instead of the main controller and three mostly independent subcontrollers.)

And it often gets worse. What if I want to display a full-screen animation or particle effect when moving a coin? What should I do if my coin is much more complicated than a simple sprite with many subheadings and details to such an extent that creating a duplicate coin using animateCoinToHUDFromStartingPosition: is ineffective? What if the coin flies to the HUD and then returns to the control panel? Can I “give” a coin look to the main controller, and then return it after the animation is completed, while maintaining the original position / z -order / etc. in temporary variables so that they can be restored? And one more thing: logically, the code belonging to several subcontrollers belongs to the main controller, but if these interactions are common, the main controller grows to a thousand lines, which I saw in many projects, and not just my own.

Is there a consistent way to handle these effects and actions that do not require duplication of code or assets, do not inflate my controllers, and do not allow me to exchange objects between subcontrollers? Or am I using the wrong approach completely?

+4
source share
1 answer

So, I think you might think that “never climbing” the hierarchy is too literal.

I think the idea is that you don’t know exactly what a parent is, but you can define a protocol and know that regardless of your parent, it responds to the specified protocol. You ideally check the code to confirm that it responds to this protocol. Then use the protocol to send the message in a general way, in which you pass the coin object to the parent object and allow the parent object to animate it from the screen and in the HUD.

Subcontrollers then have an instance variable id<parent_protocol> parent; , and their initialization method takes one of them as a parameter. Given your description, you already have something like this in place, or at least enough to implement, "subcontrollers, as a rule, are not aware of their neighboring controllers and use the methods in the main controller to interact with them," as you say it.

So the idea from a design point of view is that a coin acceptor appears on the display panel, and all he knows is that the parent object has a pickupCoin: method that will do what works with the selected coin. The display panel does not know that it goes to the HUD or anything else, the coins just collected are processed by the pickupCoin: parent controller pickupCoin: .

OOP design philosophy is that all parent knowledge is encapsulated in a protocol definition. This makes the child and the parent more loosely coupled so that you can swap any parent who has implemented this protocol, and the children will still work fine.

There are more loose connections that you could use (for example, notifications posted on a global scale), but in the cases when you are describing, I think that something like what I have indicated is probably more appropriate and, probably more productive.

Does it help?

+1
source

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


All Articles