TU-CSCI3362-SP22 / activity-command-crew

activity-command-crew created by GitHub Classroom
MIT License
1 stars 0 forks source link

Command Activity

Phase 1 - Understanding the Code Base

Browse to the DesignPatterns-Command package. We will explain the structure of the code, and you will have time to familiarize yourself with it. You're a gameplay programmer at Earth 3 Interactive, where you are making Earth, but 3. You've been assigned to work on the input handling functionality of the Earth3 engine. Currently, there's only 1 core abstraction for the input in the game: a button. This abstraction can be found in the Button class and its subclasses. To make a button in the current codebase, you create a subclass of Button (ButtonA etc.). Each subclass must implement two abstract methods: isNamed: identifies which button is being implemented, and doAction implements the functionality that the button performs. The entity controlled by the button called GameObject, which holds game state such as the x and y position in posX and posY. The buttons will eventually be attached to a controller by name, but for this prototype they are simply stored in an OrderedCollection and accessed by the literal string for their name: $A, $B, $X, $Y.

There's an example of how this works in the makeExample methods of the ExampleController class. To make it run, call ExampleController new makeExample in the playground.

Phase 2 - Extending the Code Base

Avoiding Cringe but preserving Pog

Turns out the CEO, Kobby Botick, had his son play the game, and his son thought that having jump on ButtonA was "cringe." Your boss told you to make ButtonA instead do duck. So, since everything is currently hardcoded, you'll need to take the code from ButtonB's doAction and copy it into ButtonA's doAction. No big deal!

The problem is, Mr. Botick's other son played the game with that new change, and he said that having jump not be on ButtonA was "not pog." Therefore, your boss has given you a new requirement: the user should be able to switch the buttons' functionality at runtime. In order to accomplish this, create ButtonAJump and ButtonADuck as subclasses of ButtonA, hardcoding the appropriate functionality into each subclass' doAction method. Again, not so bad! When you want to rebind functionality at runtime, add a replaceButton: with: method to GameObject. The two parameters should be a button name ($A) and an instance of that button or a subclass. You can browse the OrderedCollection methods by inspecting OrderedCollection new into the playground, clicking on the Meta tab, and clicking OrderedCollection in the class hierarchy. Finally, update the makeExample method to test this out!

The ButtonB Problem

You've accomplished your task, but now you need to be able to rebind ButtonB's functionality. In order to do this, you'll need to make ButtonBJump and ButtonBDuck as subclasses of ButtonB, having the exact same functionality as the subclasses of ButtonA. You have to do this before you can check in the change and go home because this is the game industry, baby, so do it.

Takeaways:

Interlude: Introducing the Command Pattern

As you contemplate the sheer awfulness of the task that you have been assigned at 8:00 PM in your dark office, you stumble online across something wonderful, something glorious, something that can solve this problem for you with far less code:

✨ 🌈 ✨ 🌈 ✨ The Command Pattern ✨ 🌈 ✨ 🌈 ✨

The command design pattern enables you to separate the requester of an action from the object that actually performs the action. This means the requester does not need to know what the action is or how to execute the action, just how to communicate to the object that can perform it. The separation is accomplished by creating command objects: objects which hold functions and data needed to execute the action. A command object may contain a great deal of state, but exposes only a single execute method. The invoker can then execute the command without having to be aware of what the action is. These command objects can then be assigned to different requesters, and serve as reusable, reassignable, and reified method calls.

A command encapsulates a request into a composed object

Take our example of a controller with 4 buttons, where each button triggers a certain action. Without the command pattern, changing what each button does this can be quite complicated. The command pattern allows you to easily change the assigned actions. Buttons are invokers that hold commands and know how to execute them. The commands themselves are objects, which can be passed around and assigned to different buttons. Instead of needing to create a new subclass for each and every button that wants to do any action, you can simply store the command as an object, and then reuse it at runtime as you please.

Phase 3 - A Commanding Performance

Takeaways:

Further Notes